elements
lifecycle
browser
- useAudio
- useBattery
- useBluetooth
- useBreakpoints
- useBroadcastChannel
- useBrowserLocation
- useClipboard
- useCopy
- useCssVar
- useDisplayMedia
- useDocumentEvent
- useDocumentTitle
- useDocumentVisibility
- useEventListener
- useEventSource
- useEyeDropper
- useFavicon
- useFileSystemAccess
- useFps
- useFullscreen
- useGamepad
- useGeolocation
- useMeasure
- useMediaControls
- useMediaQuery
- useMemory
- useNetwork
- useObjectUrl
- useOnline
- useOtpCredential
- usePermission
- usePictureInPicture
- usePointerLock
- usePostMessage
- useRaf
- useShare
- useSpeechRecognition
- useSpeechSynthesis
- useSticky
utilities
state
user
sensors
Draft
import {
useClickOutside,
useDebounceCallback,
useDisclosure,
useStateHistory
} from '@siberiacancode/reactuse';
import { CheckIcon, HistoryIcon } from 'lucide-react';
import { useState } from 'react';
const INITIAL = 'Ship faster with reactuse — a collection of essential React hooks.';
const Demo = () => {
const stateHistory = useStateHistory(INITIAL);
const [text, setText] = useState(INITIAL);
const menu = useDisclosure();
const menuRef = useClickOutside<HTMLDivElement>(() => menu.close());
const save = useDebounceCallback((value: string) => {
stateHistory.set(value);
}, 800);
const onChange = (value: string) => {
setText(value);
save(value);
};
const jumpTo = (target: number) => {
const delta = target - stateHistory.index;
if (delta < 0) stateHistory.back(-delta);
if (delta > 0) stateHistory.forward(delta);
setText(stateHistory.history[target]);
menu.close();
};
return (
<section className='flex w-full max-w-md flex-col gap-2 p-4'>
<div className='flex items-center justify-between'>
<span className='text-foreground text-sm font-medium'>Draft</span>
<div className='relative'>
<button
aria-expanded={menu.opened}
data-size='sm'
data-variant='ghost'
type='button'
onClick={() => menu.toggle()}
>
<HistoryIcon className='size-3.5' />
History
</button>
{menu.opened && (
<div
ref={menuRef}
className='absolute top-full right-0 z-10 mt-2 w-72'
data-slot='dropdown-menu-content'
>
<div data-slot='dropdown-menu-label'>Version history</div>
<div className='no-scrollbar max-h-56 overflow-y-auto'>
{stateHistory.history.map((version, index) => {
const active = index === stateHistory.index;
return (
<div key={index} data-slot='dropdown-menu-item' onClick={() => jumpTo(index)}>
<span className='text-muted-foreground w-8 shrink-0 text-xs tabular-nums'>
v{index + 1}
</span>
<span className='truncate'>{version || 'Empty'}</span>
{active && <CheckIcon className='text-primary ml-auto size-4 shrink-0' />}
</div>
);
})}
</div>
</div>
)}
</div>
</div>
<textarea
className='no-scrollbar min-h-40 resize-none'
value={text}
onChange={(event) => onChange(event.target.value)}
/>
</section>
);
};
export default Demo;
Installation
pnpm add @siberiacancode/reactuseUsage
const { value, history, index, set, back, forward, reset, undo, redo, canUndo, canRedo } = useStateHistory(0);Type Declarations
interface UseStateHistoryReturn<Value> {
/** True if a redo operation can be performed */
canRedo: boolean;
/** True if an undo operation can be performed */
canUndo: boolean;
/** All history values */
history: Value[];
/** Current index in history */
index: number;
/** Current value */
value: Value;
/** Go back specified number of steps in history (default: 1) */
back: (steps?: number) => void;
/** Go forward specified number of steps in history (default: 1) */
forward: (steps?: number) => void;
/** Redo the last change */
redo: () => void;
/** Reset history to initial state */
reset: () => void;
/** Set a new value */
set: (value: Value) => void;
/** Undo the last change */
undo: () => void;
}
export type StateHistoryAction<Value> =
| { type: 'BACK'; payload: { steps: number } }
| { type: 'FORWARD'; payload: { steps: number } }
| { type: 'REDO' }
| { type: 'RESET'; payload: { initialValue: Value; capacity: number } }
| { type: 'SET'; payload: { value: Value; capacity: number } }
| { type: 'UNDO' };
export interface StateHistory<Value> {
currentIndex: number;
history: Value[];
redoStack: Value[][];
undoStack: Value[][];
}API
Parameters
| Name | Type | Default | Note |
|---|---|---|---|
| initialValue | Value | - | - The initial value to start the history with |
| capacity | number | 10 | - Maximum number of history entries and undo actions to keep |
Returns
UseStateHistoryReturn<Value>Contributors
ddebabinKKhasan
Last updated on