tcmd: Accordion and popover md elements

This commit is contained in:
2024-02-28 21:41:12 -07:00
parent 2e9bfa1557
commit ff0a4280e2
22 changed files with 729 additions and 68 deletions

12
hooks/useDebounce.ts Normal file
View File

@@ -0,0 +1,12 @@
import { useEffect, useState } from 'react';
export const useDebounce = (value: any, delay: number) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => setDebouncedValue(value), delay);
return () => clearTimeout(handler);
}, [value, delay]);
return debouncedValue;
};

40
hooks/useInput.ts Normal file
View File

@@ -0,0 +1,40 @@
import { useState, ChangeEvent } from 'react';
type InputHookConfig = {
disallowSpaces?: boolean;
spaceReplacer?: string;
}
export const useInput = <T extends string | number>(initialValue: T, config?: InputHookConfig) => {
const [value, setValue] = useState<T>(initialValue);
return {
value,
setValue,
reset: () => setValue(initialValue),
bind: {
value: value,
onChange: (event: ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => {
const changed: string | number = typeof initialValue === 'number' ? parseInt(event.target.value) : config?.disallowSpaces ? event.target.value.replace(' ', config.spaceReplacer || '_') : event.target.value;
setValue(changed as T);
}
}
};
};
export const useCheckbox = (initial: boolean) => {
const [value, setValue] = useState(initial);
return {
value,
setValue,
reset: () => setValue(initial),
bind: {
checked: value,
onClick: () => {
setValue(v => !v);
},
readOnly: true
}
};
};

126
hooks/useObjectState.ts Normal file
View File

@@ -0,0 +1,126 @@
import React, { ChangeEvent, useCallback, useState } from "react";
import { InputBinder } from "../types/inputBinder";
type ObjectStateHookConfig = {
disallowSpaces?: boolean;
spaceReplacer?: string;
};
export const useObjectState = <T extends object>(initial: T) => {
const [state, setState] = useState<T>(initial || {} as T);
const bindProperty = useCallback(
<K extends keyof T>(property: K, config?: ObjectStateHookConfig) => ({
value: state[property] ?? "",
name: property,
onChange: (
event: ChangeEvent<
HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
>,
) =>
setState((value) => (
{
...value,
[event.target.name]: (
(typeof value[property] === "number")
? Number(event.target.value) || 0
: config?.disallowSpaces
? event.target.value.replace(" ", config.spaceReplacer || "_")
: event.target.value
),
}
)),
}),
[state],
);
const bindPropertyCheck = useCallback(<K extends keyof T>(property: K) => ({
checked: !!state[property],
name: property,
onChange: (event: ChangeEvent<HTMLInputElement>) =>
setState((value) => ({
...value,
[event.target.name]: (event.target.checked),
})),
readOnly: true,
}), [state]);
const update = useCallback(
(updates: Partial<T>) => setState((s) => ({ ...s, ...updates })),
[],
);
const reset = useCallback(() => {
setState(initial);
}, [initial]);
return {
bindProperty,
bindPropertyCheck,
update,
state,
setState,
reset,
};
};
export const useObjectStateWrapper = <T extends object>(
state: T,
setState: React.Dispatch<React.SetStateAction<T>>,
) => {
const bindProperty = useCallback(
<K extends keyof T>(
property: K,
config?: ObjectStateHookConfig,
): InputBinder => ({
value: state[property]?.toString() ?? "",
name: property.toString(),
onChange: (
event: ChangeEvent<
HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
>,
) =>
setState((value) => (
{
...value,
[event.target.name]: (
(typeof value[property] === "number")
? Number(event.target.value) || 0
: config?.disallowSpaces
? event.target.value.replace(" ", config.spaceReplacer || "_")
: event.target.value
),
}
)),
}),
[setState, state],
);
const bindPropertyCheck = useCallback(<K extends keyof T>(property: K) => ({
checked: !!state[property],
name: property,
onChange: (event: ChangeEvent<HTMLInputElement>) =>
setState((value) => ({
...value,
[event.target.name]: (event.target.checked),
})),
readOnly: true,
}), [setState, state]);
const update = useCallback(
(updates: Partial<T> | ((arg: T) => Partial<T>)) =>
setState((s) => ({
...s,
...(typeof updates === "function" ? updates(s) : updates),
})),
[setState],
);
return {
bindProperty,
bindPropertyCheck,
update,
state,
setState,
};
};

10
hooks/useQueryParams.ts Normal file
View File

@@ -0,0 +1,10 @@
import { useEffect, useRef } from 'react'
import { QueryParams } from '../utils/queryParams'
export const useQueryParams = (options?: {clean: boolean}) => {
const queryParams = useRef(new QueryParams(options))
useEffect(() => {
console.log(queryParams.current.get('test'))
}, [queryParams.current])
}

19
hooks/useRefCallback.ts Normal file
View File

@@ -0,0 +1,19 @@
import { ReactNode, useCallback, useRef } from 'react'
export const useRefCallback = <T = ReactNode>() : [T | null, (arg: T) => void] => {
const ref = useRef<T | null>(null);
const setRef = useCallback((val: T) => {
console.log(val);
if (ref.current) {
// does something?
}
if (val) {
// also does something?
}
ref.current = val
}, [])
return [ref.current, setRef]
}