Run with deno
:
deno task deps <path to source dir>
import { useCallback, useEffect, useState } from 'react' | |
type UrlInput = Parameters<typeof fetch>[0] | |
type Overrides = { | |
fetch?: typeof fetch | |
onError?: (arg: unknown) => void | |
} | |
export const useRequest = <T>(url: UrlInput, overrides?: Overrides) => { |
Run with deno
:
deno task deps <path to source dir>
export const isAbortError = (err: unknown): err is Error => | |
(err as Error)?.name == 'AbortError' | |
export const abortableFetch = ( | |
url: RequestInfo | URL, | |
options?: RequestInit | undefined, | |
fetchImpl?: typeof fetch | |
): [promise: Promise<Response>, abort: (reason?: any) => void] => { | |
const controller = new AbortController() | |
options = { ...options, signal: controller.signal } |
interface Set<T> { | |
map: <V>( | |
this: Set<T>, | |
mapper: (this: Set<T>, value: T, index: number, set: Set<T>) => V | |
) => Set<V>; | |
filter: ( | |
this: Set<T>, | |
predicate: (this: Set<T>, value: T, index: number, set: Set<T>) => boolean | |
) => Set<T>; | |
reduce: <V>( |
This document gathers possible mitigation strategies when dealing with browser or extension provided autofill suggestions that impact usability of a given website's UI and UX.
You should apply the least amount of workaround you can get away with, since it could affect the accessibility of your website when taken too far. Always verify your application with your intended audience in mind.
export const fetchWithTimeout = ( | |
uri: RequestInfo, | |
timeout: number, | |
options: RequestInit = {} | |
): [Promise<Response>, () => void] => { | |
const controller = new AbortController(); | |
const timer = setTimeout(controller.abort, timeout); | |
const promise = fetch(uri, { ...options, signal: controller.signal }); | |
promise.finally(() => clearTimeout(timer)); | |
return [promise, controller.abort]; |
import { JSX } from 'preact'; | |
import { useEffect, useState } from 'preact/hooks'; | |
export const useAwait = <T,>(value: Promise<T>) => { | |
const [isFulfilled, setFulfilled] = useState<boolean>(false); | |
const [resolved, setResolved] = useState<T>(undefined); | |
const [rejected, setRejected] = useState<any>(undefined); | |
useEffect(() => { | |
// tslint:disable-next-line: no-floating-promises |
const SPECIAL_CHARS = /[-\/\\^$*+?.()|[\]{}]/g; | |
const ESCAPED_CHAR = "\\$&"; | |
const escapeRegExp = (s: string) => s.replace(SPECIAL_CHARS, ESCAPED_CHAR); | |
const regexp = (flags?: string) => | |
(strings: string[], ...values: string[]) => | |
new RegExp(strings[0] + values.map((value, index) => escapeRegExp(value) + strings[index + 1]).join(""), flags); |
const isPrimitive = (obj) => { | |
if (typeof obj === 'number' || typeof obj === 'boolean' || typeof obj === 'string') return true; | |
if (Number.isNaN(obj) || obj === null || obj === undefined) return true; | |
return false; | |
} | |
const isIterable = (obj) => !isPrimitive(obj); | |
const clone = (obj) => { | |
if (isIterable(obj)) { |