Skip to content

Instantly share code, notes, and snippets.

View arabold's full-sized avatar
🦀
Making things. Breaking things.

Andre Rabold arabold

🦀
Making things. Breaking things.
View GitHub Profile
import { Dispatch, useState } from "react";
// Type definitions based on original React `Reducer<S, A>`
export type AsyncReducer<S, A> = (prevState: S, action: A) => Promise<S> | S;
export type AsyncReducerState<R extends AsyncReducer<any, any>> = R extends AsyncReducer<infer S, any> ? S : never;
export type AsyncReducerAction<R extends AsyncReducer<any, any>> = R extends AsyncReducer<any, infer A> ? A : never;
export const useAsyncReducer = <R extends AsyncReducer<any, any>>(
reducer: R,
initialState: AsyncReducerState<R>,
@arabold
arabold / Logger.ts
Last active January 23, 2024 00:20
Simple, opinionated Logger for use with Node.js and Web Browsers
/**
* Simple, opinionated Logger for use with Node.js and Web Browsers with no
* additional dependencies.
*
* The logger supports and auto-detects the following environments:
* - Node.js (with and without JSDOM)
* = Browser
* - Electron
* - React Native - Logs to console or browser window depending on whether a debugger is connected
* - Unit Test & CI/CD - Logs are disabled by default
import produce, { Draft } from "immer";
import { useCallback, useRef, useState } from "react";
export type GetStateFunc<T> = () => Readonly<T>;
export type SetStateFunc<T> = (callback: T | ((draft: Draft<T>) => void)) => void;
/**
*
* @param initialValue
*/
import { useCallback, useRef, useState } from "react";
export type Dispatch<TState> = (action: ThunkAction<TState>) => Promise<void>
/** A thunk action that can be dispatched by the {@link useThunkReducer}. */
export type ThunkAction<TState> = (
dispatch: Dispatch<TState>,
getState: () => Readonly<TState>,
) => Promise<TState | undefined | void> | TState | undefined | void;
import Intl from "intl";
import React, { useMemo } from "react";
import useLocalization from "./useLocalization";
export interface DateTimeFormatProps {
/** The value to format */
value: Date | string | number;
/** Override system locale (not recommended) */
locale?: string;
import Intl from "intl";
import React, { useMemo } from "react";
import useLocalization from "./useLocalization";
export interface NumberFormatProps {
/** The value to format */
value: number;
/** Override system locale (not recommended) */
locale?: string;
/**
* Wrap async handler functions for use with `onPress` and similar React callbacks, which are typically
* not safe to use with promises. `useAsyncFunc` gracefully handles any promise errors.
*
* Note that this hook, unlike `useCallback`, does not memoize the callback function itself. To create
* a memoized function wrap it with `useCallback` instead.
* @example
* ```tsx
/**
* Returns `true` if code is running with JSDOM
*/
static get isJSDOM(): boolean {
return navigator?.userAgent?.includes("Node.js") || navigator?.userAgent?.includes("jsdom");
}
/**
* Returns `true` if code is running in a web browser environment
*/
/** Returns `true` if running in a CI environment, e.g. during an automated build */
static get isCI(): boolean {
if (!Logger.isNode) {
return false;
}
const { CI, CONTINUOUS_INTEGRATION, BUILD_NUMBER, RUN_ID } = process.env;
// Shamelessly stolen from https://github.com/watson/ci-info
return !!(
CI || // Travis CI, CircleCI, Cirrus CI, Gitlab CI, Appveyor, CodeShip, dsari
CONTINUOUS_INTEGRATION || // Travis CI, Cirrus CI
/**
* Destroys circular references for use with JSON serialization
*
* @param from - Source object or array
* @param seen - Array with object already serialized. Set to `[]` (empty array)
* when using this function!
*/
private static _destroyCircular(from: any, seen: any[]) {
let to: any;
if (Array.isArray(from)) {