build ok,
This commit is contained in:
22
002_source/cms/src/hooks/use-dialog.ts
Normal file
22
002_source/cms/src/hooks/use-dialog.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import * as React from 'react';
|
||||
|
||||
interface DialogController<T> {
|
||||
data?: T;
|
||||
handleClose: () => void;
|
||||
handleOpen: (data?: T) => void;
|
||||
open: boolean;
|
||||
}
|
||||
|
||||
export function useDialog<T = unknown>(): DialogController<T> {
|
||||
const [state, setState] = React.useState<{ open: boolean; data?: T }>({ open: false, data: undefined });
|
||||
|
||||
const handleOpen = React.useCallback((data?: T) => {
|
||||
setState({ open: true, data });
|
||||
}, []);
|
||||
|
||||
const handleClose = React.useCallback(() => {
|
||||
setState({ open: false });
|
||||
}, []);
|
||||
|
||||
return { data: state.data, handleClose, handleOpen, open: state.open };
|
||||
}
|
49
002_source/cms/src/hooks/use-media-query.ts
Normal file
49
002_source/cms/src/hooks/use-media-query.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import * as React from 'react';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
|
||||
type Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
||||
|
||||
type FnName = 'up' | 'down' | 'between' | 'only' | 'not';
|
||||
|
||||
export function useMediaQuery(fn: 'up' | 'down', key: Breakpoint | number): boolean;
|
||||
|
||||
export function useMediaQuery(fn: 'between', start: Breakpoint | number, end: Breakpoint | number): boolean;
|
||||
|
||||
export function useMediaQuery(fn: 'only' | 'not', key: Breakpoint): boolean;
|
||||
|
||||
export function useMediaQuery(fn: FnName, start: Breakpoint | number, end?: Breakpoint | number): boolean {
|
||||
const theme = useTheme();
|
||||
const [matches, setMatches] = React.useState<boolean>(false);
|
||||
|
||||
let mq: string;
|
||||
|
||||
if (['up', 'down'].includes(fn) && start) {
|
||||
mq = theme.breakpoints[fn as 'up' | 'down'](start);
|
||||
} else if (fn === 'between' && start && end) {
|
||||
mq = theme.breakpoints[fn as 'between'](start, end);
|
||||
} else if (['only', 'not'].includes(fn) && start) {
|
||||
mq = theme.breakpoints[fn as 'only' | 'not'](start as Breakpoint);
|
||||
} else {
|
||||
throw new Error('Invalid useMediaQuery params');
|
||||
}
|
||||
|
||||
mq = mq.replace(/^@media(?: ?)/m, '');
|
||||
|
||||
React.useEffect((): (() => void) => {
|
||||
setMatches(window.matchMedia(mq).matches);
|
||||
|
||||
function handler(event: MediaQueryListEvent): void {
|
||||
setMatches(event.matches);
|
||||
}
|
||||
|
||||
const mediaQueryList = window.matchMedia(mq);
|
||||
|
||||
mediaQueryList.addEventListener('change', handler);
|
||||
|
||||
return (): void => {
|
||||
mediaQueryList.removeEventListener('change', handler);
|
||||
};
|
||||
}, [mq]);
|
||||
|
||||
return matches;
|
||||
}
|
28
002_source/cms/src/hooks/use-popover.ts
Normal file
28
002_source/cms/src/hooks/use-popover.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import * as React from 'react';
|
||||
|
||||
interface PopoverController<T> {
|
||||
anchorRef: React.MutableRefObject<T | null>;
|
||||
handleOpen: () => void;
|
||||
handleClose: () => void;
|
||||
handleToggle: () => void;
|
||||
open: boolean;
|
||||
}
|
||||
|
||||
export function usePopover<T = HTMLElement>(): PopoverController<T> {
|
||||
const anchorRef = React.useRef<T>(null);
|
||||
const [open, setOpen] = React.useState<boolean>(false);
|
||||
|
||||
const handleOpen = React.useCallback(() => {
|
||||
setOpen(true);
|
||||
}, []);
|
||||
|
||||
const handleClose = React.useCallback(() => {
|
||||
setOpen(false);
|
||||
}, []);
|
||||
|
||||
const handleToggle = React.useCallback(() => {
|
||||
setOpen((prevState) => !prevState);
|
||||
}, []);
|
||||
|
||||
return { anchorRef, handleClose, handleOpen, handleToggle, open };
|
||||
}
|
57
002_source/cms/src/hooks/use-selection.ts
Normal file
57
002_source/cms/src/hooks/use-selection.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface Selection<T = string> {
|
||||
deselectAll: () => void;
|
||||
deselectOne: (key: T) => void;
|
||||
selectAll: () => void;
|
||||
selectOne: (key: T) => void;
|
||||
selected: Set<T>;
|
||||
selectedAny: boolean;
|
||||
selectedAll: boolean;
|
||||
}
|
||||
|
||||
// IMPORTANT: To prevent infinite loop, `keys` argument must be memoized with React.useMemo hook.
|
||||
export function useSelection<T = string>(keys: T[] = []): Selection<T> {
|
||||
const [selected, setSelected] = React.useState<Set<T>>(new Set());
|
||||
|
||||
React.useEffect(() => {
|
||||
setSelected(new Set());
|
||||
}, [keys]);
|
||||
|
||||
const handleDeselectAll = React.useCallback(() => {
|
||||
setSelected(new Set());
|
||||
}, []);
|
||||
|
||||
const handleDeselectOne = React.useCallback((key: T) => {
|
||||
setSelected((prev) => {
|
||||
const copy = new Set(prev);
|
||||
copy.delete(key);
|
||||
return copy;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleSelectAll = React.useCallback(() => {
|
||||
setSelected(new Set(keys));
|
||||
}, [keys]);
|
||||
|
||||
const handleSelectOne = React.useCallback((key: T) => {
|
||||
setSelected((prev) => {
|
||||
const copy = new Set(prev);
|
||||
copy.add(key);
|
||||
return copy;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const selectedAny = selected.size > 0;
|
||||
const selectedAll = selected.size === keys.length;
|
||||
|
||||
return {
|
||||
deselectAll: handleDeselectAll,
|
||||
deselectOne: handleDeselectOne,
|
||||
selectAll: handleSelectAll,
|
||||
selectOne: handleSelectOne,
|
||||
selected,
|
||||
selectedAny,
|
||||
selectedAll,
|
||||
};
|
||||
}
|
14
002_source/cms/src/hooks/use-settings.ts
Normal file
14
002_source/cms/src/hooks/use-settings.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { SettingsContext } from '@/contexts/settings';
|
||||
import type { SettingsContextValue } from '@/contexts/settings';
|
||||
|
||||
export function useSettings(): SettingsContextValue {
|
||||
const context = React.useContext(SettingsContext);
|
||||
|
||||
if (!context) {
|
||||
throw new Error('useSettings must be used within a SettingsProvider');
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
14
002_source/cms/src/hooks/use-user.ts
Normal file
14
002_source/cms/src/hooks/use-user.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import type { UserContextValue } from '@/contexts/auth/types';
|
||||
import { UserContext } from '@/contexts/auth/user-context';
|
||||
|
||||
export function useUser(): UserContextValue {
|
||||
const context = React.useContext(UserContext);
|
||||
|
||||
if (!context) {
|
||||
throw new Error('useUser must be used within a UserProvider');
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
Reference in New Issue
Block a user