@mantine/hooks 9.6.0 → 9.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/use-collapse/use-collapse.cjs +33 -6
- package/cjs/use-collapse/use-collapse.cjs.map +1 -1
- package/cjs/use-collapse/use-horizontal-collapse.cjs +30 -6
- package/cjs/use-collapse/use-horizontal-collapse.cjs.map +1 -1
- package/cjs/use-did-update/use-did-update.cjs +17 -5
- package/cjs/use-did-update/use-did-update.cjs.map +1 -1
- package/cjs/use-interval/use-interval.cjs +5 -9
- package/cjs/use-interval/use-interval.cjs.map +1 -1
- package/cjs/use-mask/use-mask.cjs +4 -2
- package/cjs/use-mask/use-mask.cjs.map +1 -1
- package/cjs/use-scroll-spy/use-scroll-spy.cjs +9 -3
- package/cjs/use-scroll-spy/use-scroll-spy.cjs.map +1 -1
- package/esm/use-collapse/use-collapse.mjs +33 -7
- package/esm/use-collapse/use-collapse.mjs.map +1 -1
- package/esm/use-collapse/use-horizontal-collapse.mjs +30 -6
- package/esm/use-collapse/use-horizontal-collapse.mjs.map +1 -1
- package/esm/use-did-update/use-did-update.mjs +17 -5
- package/esm/use-did-update/use-did-update.mjs.map +1 -1
- package/esm/use-interval/use-interval.mjs +5 -9
- package/esm/use-interval/use-interval.mjs.map +1 -1
- package/esm/use-mask/use-mask.mjs +4 -2
- package/esm/use-mask/use-mask.mjs.map +1 -1
- package/esm/use-scroll-spy/use-scroll-spy.mjs +9 -3
- package/esm/use-scroll-spy/use-scroll-spy.mjs.map +1 -1
- package/lib/use-collapse/use-collapse.d.ts +1 -0
- package/package.json +1 -1
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { useCallbackRef } from "../utils/use-callback-ref/use-callback-ref.mjs";
|
|
2
3
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
4
|
//#region packages/@mantine/hooks/src/use-interval/use-interval.ts
|
|
4
5
|
function useInterval(fn, interval, { autoInvoke = false } = {}) {
|
|
5
6
|
const [active, setActive] = useState(false);
|
|
6
7
|
const intervalRef = useRef(null);
|
|
7
|
-
const
|
|
8
|
+
const handleCallback = useCallbackRef(fn);
|
|
8
9
|
const intervalValueRef = useRef(interval);
|
|
9
10
|
intervalValueRef.current = interval;
|
|
10
11
|
const start = useCallback(() => {
|
|
11
12
|
setActive((old) => {
|
|
12
|
-
if (!old && !intervalRef.current) intervalRef.current = window.setInterval(
|
|
13
|
+
if (!old && !intervalRef.current) intervalRef.current = window.setInterval(handleCallback, intervalValueRef.current);
|
|
13
14
|
return true;
|
|
14
15
|
});
|
|
15
16
|
}, []);
|
|
@@ -25,19 +26,14 @@ function useInterval(fn, interval, { autoInvoke = false } = {}) {
|
|
|
25
26
|
intervalRef.current = null;
|
|
26
27
|
return false;
|
|
27
28
|
}
|
|
28
|
-
if (!intervalRef.current) intervalRef.current = window.setInterval(
|
|
29
|
+
if (!intervalRef.current) intervalRef.current = window.setInterval(handleCallback, intervalValueRef.current);
|
|
29
30
|
return true;
|
|
30
31
|
});
|
|
31
32
|
}, []);
|
|
32
33
|
useEffect(() => {
|
|
33
|
-
fnRef.current = fn;
|
|
34
34
|
active && start();
|
|
35
35
|
return stop;
|
|
36
|
-
}, [
|
|
37
|
-
fn,
|
|
38
|
-
active,
|
|
39
|
-
interval
|
|
40
|
-
]);
|
|
36
|
+
}, [active, interval]);
|
|
41
37
|
useEffect(() => {
|
|
42
38
|
if (autoInvoke) start();
|
|
43
39
|
}, []);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-interval.mjs","names":[],"sources":["../../src/use-interval/use-interval.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport interface UseIntervalOptions {\n /** If set, the interval will start automatically when the component is mounted, `false` by default */\n autoInvoke?: boolean;\n}\n\nexport interface UseIntervalReturnValue {\n /** Starts the interval */\n start: () => void;\n\n /** Stops the interval */\n stop: () => void;\n\n /** Toggles the interval */\n toggle: () => void;\n\n /** Indicates if the interval is active */\n active: boolean;\n}\n\nexport function useInterval(\n fn: () => void,\n interval: number,\n { autoInvoke = false }: UseIntervalOptions = {}\n): UseIntervalReturnValue {\n const [active, setActive] = useState(false);\n const intervalRef = useRef<number | null>(null);\n const
|
|
1
|
+
{"version":3,"file":"use-interval.mjs","names":[],"sources":["../../src/use-interval/use-interval.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport { useCallbackRef } from '../utils';\n\nexport interface UseIntervalOptions {\n /** If set, the interval will start automatically when the component is mounted, `false` by default */\n autoInvoke?: boolean;\n}\n\nexport interface UseIntervalReturnValue {\n /** Starts the interval */\n start: () => void;\n\n /** Stops the interval */\n stop: () => void;\n\n /** Toggles the interval */\n toggle: () => void;\n\n /** Indicates if the interval is active */\n active: boolean;\n}\n\nexport function useInterval(\n fn: () => void,\n interval: number,\n { autoInvoke = false }: UseIntervalOptions = {}\n): UseIntervalReturnValue {\n const [active, setActive] = useState(false);\n const intervalRef = useRef<number | null>(null);\n const handleCallback = useCallbackRef(fn);\n const intervalValueRef = useRef(interval);\n intervalValueRef.current = interval;\n\n const start = useCallback(() => {\n setActive((old) => {\n if (!old && !intervalRef.current) {\n intervalRef.current = window.setInterval(handleCallback, intervalValueRef.current);\n }\n return true;\n });\n }, []);\n\n const stop = useCallback(() => {\n setActive(false);\n if (intervalRef.current) {\n window.clearInterval(intervalRef.current);\n }\n intervalRef.current = null;\n }, []);\n\n const toggle = useCallback(() => {\n setActive((current) => {\n if (current) {\n if (intervalRef.current) {\n window.clearInterval(intervalRef.current);\n }\n intervalRef.current = null;\n return false;\n }\n if (!intervalRef.current) {\n intervalRef.current = window.setInterval(handleCallback, intervalValueRef.current);\n }\n return true;\n });\n }, []);\n\n useEffect(() => {\n active && start();\n return stop;\n }, [active, interval]);\n\n useEffect(() => {\n if (autoInvoke) {\n start();\n }\n }, []);\n\n return { start, stop, toggle, active };\n}\n\nexport namespace useInterval {\n export type Options = UseIntervalOptions;\n export type ReturnValue = UseIntervalReturnValue;\n}\n"],"mappings":";;;;AAsBA,SAAgB,YACd,IACA,UACA,EAAE,aAAa,UAA8B,CAAC,GACtB;CACxB,MAAM,CAAC,QAAQ,aAAa,SAAS,KAAK;CAC1C,MAAM,cAAc,OAAsB,IAAI;CAC9C,MAAM,iBAAiB,eAAe,EAAE;CACxC,MAAM,mBAAmB,OAAO,QAAQ;CACxC,iBAAiB,UAAU;CAE3B,MAAM,QAAQ,kBAAkB;EAC9B,WAAW,QAAQ;GACjB,IAAI,CAAC,OAAO,CAAC,YAAY,SACvB,YAAY,UAAU,OAAO,YAAY,gBAAgB,iBAAiB,OAAO;GAEnF,OAAO;EACT,CAAC;CACH,GAAG,CAAC,CAAC;CAEL,MAAM,OAAO,kBAAkB;EAC7B,UAAU,KAAK;EACf,IAAI,YAAY,SACd,OAAO,cAAc,YAAY,OAAO;EAE1C,YAAY,UAAU;CACxB,GAAG,CAAC,CAAC;CAEL,MAAM,SAAS,kBAAkB;EAC/B,WAAW,YAAY;GACrB,IAAI,SAAS;IACX,IAAI,YAAY,SACd,OAAO,cAAc,YAAY,OAAO;IAE1C,YAAY,UAAU;IACtB,OAAO;GACT;GACA,IAAI,CAAC,YAAY,SACf,YAAY,UAAU,OAAO,YAAY,gBAAgB,iBAAiB,OAAO;GAEnF,OAAO;EACT,CAAC;CACH,GAAG,CAAC,CAAC;CAEL,gBAAgB;EACd,UAAU,MAAM;EAChB,OAAO;CACT,GAAG,CAAC,QAAQ,QAAQ,CAAC;CAErB,gBAAgB;EACd,IAAI,YACF,MAAM;CAEV,GAAG,CAAC,CAAC;CAEL,OAAO;EAAE;EAAO;EAAM;EAAQ;CAAO;AACvC"}
|
|
@@ -244,9 +244,11 @@ function useMask(options) {
|
|
|
244
244
|
const initializeInputValue = useCallback((node) => {
|
|
245
245
|
const opts = optionsRef.current;
|
|
246
246
|
if (!node.value) return false;
|
|
247
|
+
const isOwnValue = node.value === displayValueRef.current;
|
|
248
|
+
const parse = (slots, slotCharOption) => isOwnValue ? applyMaskToRaw(rawValueRef.current, slots, slotCharOption) : processInput(node.value, slots, slotCharOption);
|
|
247
249
|
const { slots: initialSlots, slotChar: initialSlotChar } = getResolvedOptions(opts, "");
|
|
248
|
-
const { slots: resolvedSlots, slotChar } = getResolvedOptions(opts, extractRaw(
|
|
249
|
-
const reprocessed =
|
|
250
|
+
const { slots: resolvedSlots, slotChar } = getResolvedOptions(opts, extractRaw(parse(initialSlots, initialSlotChar), initialSlots));
|
|
251
|
+
const reprocessed = parse(resolvedSlots, slotChar);
|
|
250
252
|
const newRaw = extractRaw(reprocessed, resolvedSlots);
|
|
251
253
|
const showSlots = opts.alwaysShowMask || isFocusedRef.current;
|
|
252
254
|
const showOnFocus = opts.showMaskOnFocus !== false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-mask.mjs","names":[],"sources":["../../src/use-mask/use-mask.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nconst DEFAULT_TOKENS: Record<string, RegExp> = {\n '9': /[0-9]/,\n a: /[A-Za-z]/,\n A: /[A-Z]/,\n '*': /[A-Za-z0-9]/,\n '#': /[-+0-9]/,\n};\n\nexport interface UseMaskOptions {\n /** Mask pattern string or array of string literals and RegExp objects */\n mask: string | Array<string | RegExp>;\n\n /** Override or extend the default token map */\n tokens?: Record<string, RegExp>;\n\n /** Called before masking on each keystroke, can return overrides for mask options */\n modify?: (\n value: string\n ) => Partial<Pick<UseMaskOptions, 'mask' | 'tokens' | 'slotChar' | 'separate'>> | undefined;\n\n /** When true, raw and display values are decoupled */\n separate?: boolean;\n\n /** Character displayed in unfilled slots, `\"_\"` by default */\n slotChar?: string | null;\n\n /** Show mask pattern even when field is empty and unfocused */\n alwaysShowMask?: boolean;\n\n /** Show mask placeholder on focus, `true` by default */\n showMaskOnFocus?: boolean;\n\n /** Transform each character before validation and insertion */\n transform?: (char: string) => string;\n\n /** Clear value on blur when mask is incomplete, `false` by default */\n autoClear?: boolean;\n\n /** Sets aria-invalid on the input */\n invalid?: boolean;\n\n /** Called on every change with raw and masked values */\n onChangeRaw?: (rawValue: string, maskedValue: string) => void;\n\n /** Called when all required mask slots are filled */\n onComplete?: (maskedValue: string, rawValue: string) => void;\n\n /** Escape hatch for advanced cursor/value manipulation */\n beforeMaskedStateChange?: (states: {\n previousState: MaskState;\n currentState: MaskState;\n nextState: MaskState;\n }) => MaskState;\n}\n\nexport interface MaskState {\n value: string;\n selection: { start: number; end: number } | null;\n}\n\nexport interface UseMaskReturnValue {\n /** Ref to attach to the input element */\n ref: React.RefCallback<HTMLInputElement>;\n\n /** Current masked display value */\n value: string;\n\n /** Current raw unmasked value */\n rawValue: string;\n\n /** Whether all required mask slots are filled */\n isComplete: boolean;\n\n /** Clear the input value and reset state */\n reset: () => void;\n}\n\ninterface MaskSlot {\n type: 'token' | 'literal';\n char: string;\n pattern?: RegExp;\n optional?: boolean;\n}\n\ninterface UndoState {\n rawValue: string;\n selectionStart: number;\n}\n\nconst MAX_UNDO_HISTORY = 100;\n\nfunction parseMask(\n mask: string | Array<string | RegExp>,\n tokens: Record<string, RegExp>\n): MaskSlot[] {\n if (Array.isArray(mask)) {\n return mask.map((item) => {\n if (item instanceof RegExp) {\n return { type: 'token', char: '_', pattern: item };\n }\n return { type: 'literal', char: item };\n });\n }\n\n const slots: MaskSlot[] = [];\n let optional = false;\n\n for (let i = 0; i < mask.length; i++) {\n const char = mask[i];\n\n if (char === '\\\\' && i + 1 < mask.length) {\n i++;\n slots.push({ type: 'literal', char: mask[i] });\n continue;\n }\n\n if (char === '?') {\n optional = true;\n continue;\n }\n\n if (tokens[char]) {\n slots.push({ type: 'token', char, pattern: tokens[char], optional });\n } else {\n slots.push({ type: 'literal', char, optional });\n }\n }\n\n return slots;\n}\n\nfunction getSlotChar(slotCharOption: string | null | undefined, index: number): string {\n if (slotCharOption === null || slotCharOption === '' || slotCharOption === undefined) {\n return '';\n }\n if (slotCharOption.length > 1) {\n return slotCharOption[index] || '_';\n }\n return slotCharOption;\n}\n\nfunction applyMaskToRaw(\n raw: string,\n slots: MaskSlot[],\n _slotCharOption: string | null | undefined,\n transform?: (char: string) => string\n): string {\n let result = '';\n let rawIndex = 0;\n let slotIndex = 0;\n\n for (slotIndex = 0; slotIndex < slots.length; slotIndex++) {\n const slot = slots[slotIndex];\n if (slot.type === 'literal') {\n result += slot.char;\n } else if (rawIndex < raw.length) {\n const ch = transform ? transform(raw[rawIndex]) : raw[rawIndex];\n if (slot.pattern && slot.pattern.test(ch)) {\n result += ch;\n rawIndex++;\n } else {\n rawIndex++;\n slotIndex--;\n }\n } else {\n break;\n }\n }\n\n return result;\n}\n\nfunction buildDisplayValue(\n value: string,\n slots: MaskSlot[],\n slotCharOption: string | null | undefined,\n showSlots: boolean\n): string {\n if (!showSlots) {\n return value;\n }\n\n let display = value;\n\n for (let i = value.length; i < slots.length; i++) {\n const slot = slots[i];\n if (slot.type === 'literal') {\n display += slot.char;\n } else {\n const sc = getSlotChar(slotCharOption, i);\n if (!sc) {\n break;\n }\n display += sc;\n }\n }\n\n return display;\n}\n\nfunction extractRaw(masked: string, slots: MaskSlot[]): string {\n let raw = '';\n for (let i = 0; i < masked.length && i < slots.length; i++) {\n if (slots[i].type === 'token') {\n raw += masked[i];\n }\n }\n return raw;\n}\n\nfunction checkComplete(masked: string, slots: MaskSlot[]): boolean {\n for (let i = 0; i < slots.length; i++) {\n if (slots[i].type === 'token' && !slots[i].optional) {\n if (i >= masked.length) {\n return false;\n }\n if (!slots[i].pattern!.test(masked[i])) {\n return false;\n }\n }\n }\n return true;\n}\n\nfunction findNextTokenIndex(slots: MaskSlot[], from: number): number {\n for (let i = from; i < slots.length; i++) {\n if (slots[i].type === 'token') {\n return i;\n }\n }\n return slots.length;\n}\n\nfunction findPrevTokenIndex(slots: MaskSlot[], from: number): number {\n for (let i = from; i >= 0; i--) {\n if (slots[i].type === 'token') {\n return i;\n }\n }\n return -1;\n}\n\nfunction processInput(\n inputValue: string,\n slots: MaskSlot[],\n _slotCharOption: string | null | undefined\n): string {\n let result = '';\n let inputIndex = 0;\n\n for (\n let slotIndex = 0;\n slotIndex < slots.length && inputIndex <= inputValue.length;\n slotIndex++\n ) {\n const slot = slots[slotIndex];\n\n if (slot.type === 'literal') {\n result += slot.char;\n if (inputIndex < inputValue.length && inputValue[inputIndex] === slot.char) {\n inputIndex++;\n }\n continue;\n }\n\n if (inputIndex >= inputValue.length) {\n break;\n }\n\n while (inputIndex < inputValue.length) {\n const ch = inputValue[inputIndex];\n inputIndex++;\n\n if (slot.pattern!.test(ch)) {\n result += ch;\n break;\n }\n }\n\n if (result.length <= slotIndex) {\n break;\n }\n }\n\n return result;\n}\n\nfunction getResolvedOptions(options: UseMaskOptions, rawValue: string) {\n const tokens = { ...DEFAULT_TOKENS, ...options.tokens };\n let mask = options.mask;\n let slotChar: string | null | undefined = options.slotChar === undefined ? '_' : options.slotChar;\n let separate = options.separate ?? false;\n\n if (options.modify) {\n const overrides = options.modify(rawValue);\n if (overrides) {\n if (overrides.mask !== undefined) {\n mask = overrides.mask;\n }\n if (overrides.tokens !== undefined) {\n Object.assign(tokens, overrides.tokens);\n }\n if (overrides.slotChar !== undefined) {\n slotChar = overrides.slotChar;\n }\n if (overrides.separate !== undefined) {\n separate = overrides.separate;\n }\n }\n }\n\n const slots = parseMask(mask, tokens);\n return { slots, slotChar, separate, tokens, transform: options.transform };\n}\n\nexport function formatMask(raw: string, options: UseMaskOptions): string {\n const { slots, slotChar, transform } = getResolvedOptions(options, raw);\n return applyMaskToRaw(raw, slots, slotChar, transform);\n}\n\nexport function unformatMask(masked: string, options: UseMaskOptions): string {\n const { slots } = getResolvedOptions(options, '');\n return extractRaw(masked, slots);\n}\n\nexport function isMaskComplete(masked: string, options: UseMaskOptions): boolean {\n const { slots } = getResolvedOptions(options, '');\n return checkComplete(masked, slots);\n}\n\nexport function generatePattern(mode: 'full' | 'full-inexact', options: UseMaskOptions): string {\n const { slots } = getResolvedOptions(options, '');\n let pattern = '';\n\n for (const slot of slots) {\n if (slot.type === 'literal') {\n pattern += slot.char.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n } else {\n const src = slot.pattern!.source;\n if (mode === 'full-inexact') {\n pattern += slot.optional ? `${src}?` : src;\n } else {\n pattern += slot.optional ? `(${src})?` : `(${src})`;\n }\n }\n }\n\n return pattern;\n}\n\nexport function useMask(options: UseMaskOptions): UseMaskReturnValue {\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const inputRef = useRef<HTMLInputElement | null>(null);\n const [maskedValue, setMaskedValue] = useState('');\n const [rawValue, setRawValue] = useState('');\n const processedRef = useRef('');\n const displayValueRef = useRef('');\n const rawValueRef = useRef('');\n const wasCompleteRef = useRef(false);\n const isFocusedRef = useRef(false);\n const undoStackRef = useRef<UndoState[]>([]);\n const redoStackRef = useRef<UndoState[]>([]);\n\n const getOptions = useCallback(() => {\n const opts = optionsRef.current;\n return getResolvedOptions(opts, rawValue);\n }, [rawValue]);\n\n const applyValue = useCallback(\n ({\n reprocessed,\n newRaw,\n displayValue,\n resolvedSlots,\n cursorPos,\n notifyChange,\n }: {\n reprocessed: string;\n newRaw: string;\n displayValue: string;\n resolvedSlots: MaskSlot[];\n cursorPos?: number;\n notifyChange: boolean;\n }) => {\n const opts = optionsRef.current;\n\n processedRef.current = reprocessed;\n displayValueRef.current = displayValue;\n rawValueRef.current = newRaw;\n setMaskedValue(displayValue);\n setRawValue(newRaw);\n\n if (inputRef.current) {\n inputRef.current.value = displayValue;\n if (cursorPos !== undefined && document.activeElement === inputRef.current) {\n const pos = Math.min(cursorPos, reprocessed.length);\n inputRef.current.setSelectionRange(pos, pos);\n }\n }\n\n if (notifyChange && opts.onChangeRaw) {\n opts.onChangeRaw(newRaw, displayValue);\n }\n\n const complete = checkComplete(reprocessed, resolvedSlots);\n if (notifyChange && complete && !wasCompleteRef.current && opts.onComplete) {\n opts.onComplete(displayValue, newRaw);\n }\n wasCompleteRef.current = complete;\n },\n []\n );\n\n const updateValue = useCallback(\n (newMasked: string, cursorPos?: number) => {\n const opts = optionsRef.current;\n const { slots } = getResolvedOptions(\n opts,\n extractRaw(newMasked, getResolvedOptions(opts, '').slots)\n );\n const raw = extractRaw(newMasked, slots);\n\n const { slots: resolvedSlots, slotChar } = getResolvedOptions(opts, raw);\n\n const reprocessed = processInput(newMasked, resolvedSlots, slotChar);\n const newRaw = extractRaw(reprocessed, resolvedSlots);\n\n const showSlots = opts.alwaysShowMask || isFocusedRef.current;\n const showOnFocus = opts.showMaskOnFocus !== false;\n const shouldShowSlots = showSlots && (showOnFocus || reprocessed.length > 0);\n\n const displayValue = buildDisplayValue(reprocessed, resolvedSlots, slotChar, shouldShowSlots);\n\n applyValue({\n reprocessed,\n newRaw,\n displayValue,\n resolvedSlots,\n cursorPos,\n notifyChange: true,\n });\n\n return { displayValue, newRaw, reprocessed, resolvedSlots };\n },\n [applyValue, getOptions]\n );\n\n const initializeInputValue = useCallback(\n (node: HTMLInputElement) => {\n const opts = optionsRef.current;\n\n if (!node.value) {\n return false;\n }\n\n const { slots: initialSlots, slotChar: initialSlotChar } = getResolvedOptions(opts, '');\n const initialProcessed = processInput(node.value, initialSlots, initialSlotChar);\n const initialRaw = extractRaw(initialProcessed, initialSlots);\n const { slots: resolvedSlots, slotChar } = getResolvedOptions(opts, initialRaw);\n const reprocessed = processInput(node.value, resolvedSlots, slotChar);\n const newRaw = extractRaw(reprocessed, resolvedSlots);\n const showSlots = opts.alwaysShowMask || isFocusedRef.current;\n const showOnFocus = opts.showMaskOnFocus !== false;\n const shouldShowSlots = showSlots && (showOnFocus || reprocessed.length > 0);\n const displayValue = buildDisplayValue(reprocessed, resolvedSlots, slotChar, shouldShowSlots);\n\n applyValue({\n reprocessed,\n newRaw,\n displayValue,\n resolvedSlots,\n notifyChange: false,\n });\n\n return true;\n },\n [applyValue]\n );\n\n const pushUndoState = useCallback(() => {\n const input = inputRef.current;\n const selectionStart = input?.selectionStart ?? rawValueRef.current.length;\n const state: UndoState = {\n rawValue: rawValueRef.current,\n selectionStart,\n };\n const stack = undoStackRef.current;\n const top = stack[stack.length - 1];\n if (top && top.rawValue === state.rawValue && top.selectionStart === state.selectionStart) {\n return;\n }\n stack.push(state);\n if (stack.length > MAX_UNDO_HISTORY) {\n stack.shift();\n }\n redoStackRef.current = [];\n }, []);\n\n const applyHistoryState = useCallback(\n (target: UndoState) => {\n const opts = optionsRef.current;\n const { slots, slotChar, transform } = getResolvedOptions(opts, target.rawValue);\n const newMasked = applyMaskToRaw(target.rawValue, slots, slotChar, transform);\n updateValue(newMasked, target.selectionStart);\n },\n [updateValue]\n );\n\n const handleInput = useCallback(\n (e: Event) => {\n const input = e.target as HTMLInputElement;\n const opts = optionsRef.current;\n\n const { slots: resolvedSlots, slotChar, transform } = getResolvedOptions(opts, '');\n const prev = displayValueRef.current;\n const curr = input.value;\n\n let prefixLen = 0;\n const maxPrefix = Math.min(prev.length, curr.length);\n while (prefixLen < maxPrefix && prev[prefixLen] === curr[prefixLen]) {\n prefixLen++;\n }\n\n let suffixLen = 0;\n const maxSuffix = Math.min(prev.length - prefixLen, curr.length - prefixLen);\n while (\n suffixLen < maxSuffix &&\n prev[prev.length - 1 - suffixLen] === curr[curr.length - 1 - suffixLen]\n ) {\n suffixLen++;\n }\n\n const insertedText = curr.slice(prefixLen, curr.length - suffixLen);\n const removedEnd = prev.length - suffixLen;\n\n const beforeRaw = extractRaw(prev.slice(0, prefixLen), resolvedSlots.slice(0, prefixLen));\n const afterRaw = extractRaw(prev.slice(removedEnd), resolvedSlots.slice(removedEnd));\n const reformatted = applyMaskToRaw(\n beforeRaw + insertedText + afterRaw,\n resolvedSlots,\n slotChar,\n transform\n );\n const maskedPrefix = applyMaskToRaw(\n beforeRaw + insertedText,\n resolvedSlots,\n slotChar,\n transform\n );\n\n if (reformatted !== prev) {\n pushUndoState();\n }\n updateValue(reformatted, maskedPrefix.length);\n },\n [pushUndoState, updateValue]\n );\n\n const clampCursorToProcessed = useCallback((input: HTMLInputElement) => {\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n if (start !== end) {\n return;\n }\n\n const opts = optionsRef.current;\n const { slots } = getResolvedOptions(opts, '');\n const processed = processedRef.current;\n const endPos =\n processed.length > 0\n ? findNextEditablePosition(processed.length, slots, processed)\n : findNextTokenIndex(slots, 0);\n const startPos = findNextTokenIndex(slots, 0);\n\n if (start > endPos || start < startPos) {\n input.setSelectionRange(endPos, endPos);\n }\n }, []);\n\n const handleFocus = useCallback(() => {\n isFocusedRef.current = true;\n const opts = optionsRef.current;\n const input = inputRef.current;\n\n if (!input) {\n return;\n }\n\n const { slots, slotChar } = getResolvedOptions(opts, '');\n const showOnFocus = opts.showMaskOnFocus !== false;\n const processed = processedRef.current;\n\n if (showOnFocus || opts.alwaysShowMask) {\n const display = buildDisplayValue(processed, slots, slotChar, true);\n input.value = display;\n displayValueRef.current = display;\n setMaskedValue(display);\n }\n\n requestAnimationFrame(() => {\n if (input === document.activeElement) {\n clampCursorToProcessed(input);\n }\n });\n }, [clampCursorToProcessed]);\n\n const handleMouseUp = useCallback(() => {\n const input = inputRef.current;\n if (!input || input !== document.activeElement) {\n return;\n }\n\n clampCursorToProcessed(input);\n }, [clampCursorToProcessed]);\n\n const handleMouseDown = useCallback(() => {\n const input = inputRef.current;\n if (!input) {\n return;\n }\n\n requestAnimationFrame(() => {\n if (input !== document.activeElement) {\n return;\n }\n\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n if (start !== end) {\n return;\n }\n\n const opts = optionsRef.current;\n const { slots } = getResolvedOptions(opts, '');\n const processed = processedRef.current;\n const endPos =\n processed.length > 0\n ? findNextEditablePosition(processed.length, slots, processed)\n : findNextTokenIndex(slots, 0);\n\n if (start > endPos) {\n input.setSelectionRange(endPos, endPos);\n }\n });\n }, []);\n\n const handleBlur = useCallback(() => {\n isFocusedRef.current = false;\n const opts = optionsRef.current;\n const input = inputRef.current;\n\n if (!input) {\n return;\n }\n\n const { slots, slotChar } = getResolvedOptions(opts, rawValue);\n const expectedFocusDisplay = buildDisplayValue(processedRef.current, slots, slotChar, true);\n const processed =\n input.value === expectedFocusDisplay\n ? processedRef.current\n : processInput(input.value, slots, slotChar);\n const complete = checkComplete(processed, slots);\n\n if (opts.autoClear && !complete && processed.length > 0) {\n input.value = '';\n processedRef.current = '';\n displayValueRef.current = '';\n rawValueRef.current = '';\n setMaskedValue('');\n setRawValue('');\n wasCompleteRef.current = false;\n\n if (opts.onChangeRaw) {\n opts.onChangeRaw('', '');\n }\n\n if (opts.alwaysShowMask) {\n const emptyDisplay = buildDisplayValue('', slots, slotChar, true);\n input.value = emptyDisplay;\n displayValueRef.current = emptyDisplay;\n setMaskedValue(emptyDisplay);\n }\n return;\n }\n\n if (!opts.alwaysShowMask && !complete) {\n if (extractRaw(processed, slots).length === 0) {\n input.value = '';\n processedRef.current = '';\n displayValueRef.current = '';\n rawValueRef.current = '';\n setMaskedValue('');\n setRawValue('');\n wasCompleteRef.current = false;\n\n if (opts.onChangeRaw) {\n opts.onChangeRaw('', '');\n }\n return;\n }\n\n const display = buildDisplayValue(processed, slots, slotChar, false);\n input.value = display;\n displayValueRef.current = display;\n setMaskedValue(display);\n }\n }, [rawValue]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n const input = e.target as HTMLInputElement;\n const opts = optionsRef.current;\n\n const { slots, slotChar, transform } = getResolvedOptions(opts, rawValue);\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n const processed = processedRef.current;\n\n const modifier = e.metaKey || (e.ctrlKey && !e.altKey);\n const key = e.key.toLowerCase();\n\n if (modifier && key === 'z' && !e.shiftKey) {\n e.preventDefault();\n const prev = undoStackRef.current.pop();\n if (!prev) {\n return;\n }\n redoStackRef.current.push({\n rawValue: rawValueRef.current,\n selectionStart: input.selectionStart ?? 0,\n });\n applyHistoryState(prev);\n return;\n }\n\n if (modifier && ((key === 'z' && e.shiftKey) || (key === 'y' && !e.shiftKey))) {\n e.preventDefault();\n const next = redoStackRef.current.pop();\n if (!next) {\n return;\n }\n undoStackRef.current.push({\n rawValue: rawValueRef.current,\n selectionStart: input.selectionStart ?? 0,\n });\n applyHistoryState(next);\n return;\n }\n\n if (e.key === 'Backspace') {\n e.preventDefault();\n\n if (e.metaKey || (e.ctrlKey && !e.altKey)) {\n const clampedStart = Math.min(start, processed.length);\n const afterRaw = extractRaw(processed.slice(clampedStart), slots.slice(clampedStart));\n const newValue = applyMaskToRaw(afterRaw, slots, slotChar, transform);\n pushUndoState();\n updateValue(newValue, 0);\n return;\n }\n\n if (start !== end) {\n const clampedEnd = Math.min(end, processed.length);\n const before = processed.slice(0, start);\n const afterRaw = extractRaw(processed.slice(clampedEnd), slots.slice(clampedEnd));\n const newValue = applyMaskToRaw(\n extractRaw(before, slots) + afterRaw,\n slots,\n slotChar,\n transform\n );\n pushUndoState();\n updateValue(newValue, start);\n return;\n }\n\n if (start === 0) {\n return;\n }\n\n let deletePos = start - 1;\n while (deletePos >= 0 && slots[deletePos] && slots[deletePos].type === 'literal') {\n deletePos--;\n }\n\n if (deletePos < 0) {\n return;\n }\n\n const beforeRaw = extractRaw(processed.slice(0, deletePos), slots.slice(0, deletePos));\n const afterRaw = extractRaw(processed.slice(deletePos + 1), slots.slice(deletePos + 1));\n const newValue = applyMaskToRaw(beforeRaw + afterRaw, slots, slotChar, transform);\n pushUndoState();\n updateValue(newValue, deletePos);\n } else if (e.key === 'Delete') {\n e.preventDefault();\n\n if (start !== end) {\n const clampedEnd = Math.min(end, processed.length);\n const before = processed.slice(0, start);\n const afterRaw = extractRaw(processed.slice(clampedEnd), slots.slice(clampedEnd));\n const newValue = applyMaskToRaw(\n extractRaw(before, slots) + afterRaw,\n slots,\n slotChar,\n transform\n );\n pushUndoState();\n updateValue(newValue, start);\n return;\n }\n\n let deletePos = start;\n while (\n deletePos < slots.length &&\n slots[deletePos] &&\n slots[deletePos].type === 'literal'\n ) {\n deletePos++;\n }\n\n if (deletePos >= processed.length) {\n return;\n }\n\n const beforeRaw = extractRaw(processed.slice(0, start), slots.slice(0, start));\n const afterRaw = extractRaw(processed.slice(deletePos + 1), slots.slice(deletePos + 1));\n const newValue = applyMaskToRaw(beforeRaw + afterRaw, slots, slotChar, transform);\n pushUndoState();\n updateValue(newValue, start);\n } else if (e.key === 'ArrowRight' && !e.shiftKey) {\n const nextPos = findNextEditablePosition(start + 1, slots, input.value);\n if (nextPos !== start + 1) {\n e.preventDefault();\n input.setSelectionRange(nextPos, nextPos);\n }\n } else if (e.key === 'ArrowLeft' && !e.shiftKey) {\n if (start > 0) {\n const prevToken = findPrevTokenIndex(slots, start - 1);\n if (prevToken >= 0 && prevToken !== start - 1) {\n e.preventDefault();\n input.setSelectionRange(prevToken + 1, prevToken + 1);\n }\n }\n } else if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {\n e.preventDefault();\n\n let insertPos = Math.min(start, processed.length);\n while (\n insertPos < slots.length &&\n slots[insertPos] &&\n slots[insertPos].type === 'literal'\n ) {\n insertPos++;\n }\n\n if (insertPos >= slots.length) {\n return;\n }\n\n const slot = slots[insertPos];\n const ch = transform ? transform(e.key) : e.key;\n if (!slot.pattern!.test(ch)) {\n return;\n }\n\n const beforeRaw = extractRaw(processed.slice(0, insertPos), slots.slice(0, insertPos));\n const afterRaw =\n start < end\n ? extractRaw(\n processed.slice(Math.min(end, processed.length)),\n slots.slice(Math.min(end, processed.length))\n )\n : extractRaw(processed.slice(insertPos), slots.slice(insertPos));\n const newValue = applyMaskToRaw(beforeRaw + ch + afterRaw, slots, slotChar, transform);\n const newCursorPos = findNextEditablePosition(insertPos + 1, slots, newValue);\n pushUndoState();\n updateValue(newValue, newCursorPos);\n }\n },\n [applyHistoryState, pushUndoState, rawValue, updateValue]\n );\n\n const handlePaste = useCallback(\n (e: ClipboardEvent) => {\n e.preventDefault();\n const input = e.target as HTMLInputElement;\n const opts = optionsRef.current;\n\n const pastedText = e.clipboardData?.getData('text') ?? '';\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n const processed = processedRef.current;\n\n const { slots, slotChar, transform } = getResolvedOptions(opts, '');\n const clampedStart = Math.min(start, processed.length);\n const clampedEnd = Math.min(end, processed.length);\n const beforeRaw = extractRaw(processed.slice(0, clampedStart), slots.slice(0, clampedStart));\n const afterRaw = extractRaw(processed.slice(clampedEnd), slots.slice(clampedEnd));\n const newValue = applyMaskToRaw(\n beforeRaw + pastedText + afterRaw,\n slots,\n slotChar,\n transform\n );\n\n pushUndoState();\n updateValue(newValue);\n\n const maskedPrefix = applyMaskToRaw(beforeRaw + pastedText, slots, slotChar, transform);\n const pasteEndPos = Math.min(maskedPrefix.length, slots.length);\n if (input === document.activeElement) {\n input.setSelectionRange(pasteEndPos, pasteEndPos);\n }\n },\n [pushUndoState, updateValue]\n );\n\n const setAriaAttributes = useCallback((input: HTMLInputElement) => {\n const opts = optionsRef.current;\n\n if (opts.invalid) {\n input.setAttribute('aria-invalid', 'true');\n } else {\n input.removeAttribute('aria-invalid');\n }\n }, []);\n\n const refCallback = useCallback(\n (node: HTMLInputElement | null) => {\n const prevInput = inputRef.current;\n\n if (prevInput) {\n prevInput.removeEventListener('input', handleInput);\n prevInput.removeEventListener('focus', handleFocus);\n prevInput.removeEventListener('blur', handleBlur);\n prevInput.removeEventListener('mousedown', handleMouseDown);\n prevInput.removeEventListener('mouseup', handleMouseUp);\n prevInput.removeEventListener('keydown', handleKeyDown as EventListener);\n prevInput.removeEventListener('paste', handlePaste as EventListener);\n }\n\n inputRef.current = node;\n\n if (node) {\n node.addEventListener('input', handleInput);\n node.addEventListener('focus', handleFocus);\n node.addEventListener('blur', handleBlur);\n node.addEventListener('mousedown', handleMouseDown);\n node.addEventListener('mouseup', handleMouseUp);\n node.addEventListener('keydown', handleKeyDown as EventListener);\n node.addEventListener('paste', handlePaste as EventListener);\n\n setAriaAttributes(node);\n\n const hasInitialValue = initializeInputValue(node);\n\n if (options.alwaysShowMask && !hasInitialValue) {\n const { slots, slotChar } = getResolvedOptions(options, '');\n const display = buildDisplayValue('', slots, slotChar, true);\n node.value = display;\n displayValueRef.current = display;\n setMaskedValue(display);\n }\n }\n },\n [\n handleInput,\n handleFocus,\n handleBlur,\n handleMouseDown,\n handleMouseUp,\n handleKeyDown,\n handlePaste,\n initializeInputValue,\n setAriaAttributes,\n options,\n ]\n );\n\n useEffect(() => {\n const input = inputRef.current;\n if (!input) {\n return;\n }\n\n setAriaAttributes(input);\n }, [options.invalid, setAriaAttributes]);\n\n const isComplete = (() => {\n const { slots } = getOptions();\n return checkComplete(processedRef.current, slots);\n })();\n\n const reset = useCallback(() => {\n const opts = optionsRef.current;\n const input = inputRef.current;\n\n processedRef.current = '';\n displayValueRef.current = '';\n rawValueRef.current = '';\n undoStackRef.current = [];\n redoStackRef.current = [];\n setMaskedValue('');\n setRawValue('');\n wasCompleteRef.current = false;\n\n if (input) {\n if (opts.alwaysShowMask) {\n const { slots, slotChar } = getResolvedOptions(opts, '');\n const display = buildDisplayValue('', slots, slotChar, true);\n input.value = display;\n displayValueRef.current = display;\n setMaskedValue(display);\n } else {\n input.value = '';\n }\n }\n\n if (opts.onChangeRaw) {\n opts.onChangeRaw('', '');\n }\n }, []);\n\n return {\n ref: refCallback,\n value: maskedValue,\n rawValue,\n isComplete,\n reset,\n };\n}\n\nfunction findNextEditablePosition(from: number, slots: MaskSlot[], value: string): number {\n let pos = from;\n while (pos < slots.length && pos < value.length && slots[pos] && slots[pos].type === 'literal') {\n pos++;\n }\n return pos;\n}\n\nexport namespace useMask {\n export type Options = UseMaskOptions;\n export type ReturnValue = UseMaskReturnValue;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-mask.mjs","names":[],"sources":["../../src/use-mask/use-mask.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nconst DEFAULT_TOKENS: Record<string, RegExp> = {\n '9': /[0-9]/,\n a: /[A-Za-z]/,\n A: /[A-Z]/,\n '*': /[A-Za-z0-9]/,\n '#': /[-+0-9]/,\n};\n\nexport interface UseMaskOptions {\n /** Mask pattern string or array of string literals and RegExp objects */\n mask: string | Array<string | RegExp>;\n\n /** Override or extend the default token map */\n tokens?: Record<string, RegExp>;\n\n /** Called before masking on each keystroke, can return overrides for mask options */\n modify?: (\n value: string\n ) => Partial<Pick<UseMaskOptions, 'mask' | 'tokens' | 'slotChar' | 'separate'>> | undefined;\n\n /** When true, raw and display values are decoupled */\n separate?: boolean;\n\n /** Character displayed in unfilled slots, `\"_\"` by default */\n slotChar?: string | null;\n\n /** Show mask pattern even when field is empty and unfocused */\n alwaysShowMask?: boolean;\n\n /** Show mask placeholder on focus, `true` by default */\n showMaskOnFocus?: boolean;\n\n /** Transform each character before validation and insertion */\n transform?: (char: string) => string;\n\n /** Clear value on blur when mask is incomplete, `false` by default */\n autoClear?: boolean;\n\n /** Sets aria-invalid on the input */\n invalid?: boolean;\n\n /** Called on every change with raw and masked values */\n onChangeRaw?: (rawValue: string, maskedValue: string) => void;\n\n /** Called when all required mask slots are filled */\n onComplete?: (maskedValue: string, rawValue: string) => void;\n\n /** Escape hatch for advanced cursor/value manipulation */\n beforeMaskedStateChange?: (states: {\n previousState: MaskState;\n currentState: MaskState;\n nextState: MaskState;\n }) => MaskState;\n}\n\nexport interface MaskState {\n value: string;\n selection: { start: number; end: number } | null;\n}\n\nexport interface UseMaskReturnValue {\n /** Ref to attach to the input element */\n ref: React.RefCallback<HTMLInputElement>;\n\n /** Current masked display value */\n value: string;\n\n /** Current raw unmasked value */\n rawValue: string;\n\n /** Whether all required mask slots are filled */\n isComplete: boolean;\n\n /** Clear the input value and reset state */\n reset: () => void;\n}\n\ninterface MaskSlot {\n type: 'token' | 'literal';\n char: string;\n pattern?: RegExp;\n optional?: boolean;\n}\n\ninterface UndoState {\n rawValue: string;\n selectionStart: number;\n}\n\nconst MAX_UNDO_HISTORY = 100;\n\nfunction parseMask(\n mask: string | Array<string | RegExp>,\n tokens: Record<string, RegExp>\n): MaskSlot[] {\n if (Array.isArray(mask)) {\n return mask.map((item) => {\n if (item instanceof RegExp) {\n return { type: 'token', char: '_', pattern: item };\n }\n return { type: 'literal', char: item };\n });\n }\n\n const slots: MaskSlot[] = [];\n let optional = false;\n\n for (let i = 0; i < mask.length; i++) {\n const char = mask[i];\n\n if (char === '\\\\' && i + 1 < mask.length) {\n i++;\n slots.push({ type: 'literal', char: mask[i] });\n continue;\n }\n\n if (char === '?') {\n optional = true;\n continue;\n }\n\n if (tokens[char]) {\n slots.push({ type: 'token', char, pattern: tokens[char], optional });\n } else {\n slots.push({ type: 'literal', char, optional });\n }\n }\n\n return slots;\n}\n\nfunction getSlotChar(slotCharOption: string | null | undefined, index: number): string {\n if (slotCharOption === null || slotCharOption === '' || slotCharOption === undefined) {\n return '';\n }\n if (slotCharOption.length > 1) {\n return slotCharOption[index] || '_';\n }\n return slotCharOption;\n}\n\nfunction applyMaskToRaw(\n raw: string,\n slots: MaskSlot[],\n _slotCharOption: string | null | undefined,\n transform?: (char: string) => string\n): string {\n let result = '';\n let rawIndex = 0;\n let slotIndex = 0;\n\n for (slotIndex = 0; slotIndex < slots.length; slotIndex++) {\n const slot = slots[slotIndex];\n if (slot.type === 'literal') {\n result += slot.char;\n } else if (rawIndex < raw.length) {\n const ch = transform ? transform(raw[rawIndex]) : raw[rawIndex];\n if (slot.pattern && slot.pattern.test(ch)) {\n result += ch;\n rawIndex++;\n } else {\n rawIndex++;\n slotIndex--;\n }\n } else {\n break;\n }\n }\n\n return result;\n}\n\nfunction buildDisplayValue(\n value: string,\n slots: MaskSlot[],\n slotCharOption: string | null | undefined,\n showSlots: boolean\n): string {\n if (!showSlots) {\n return value;\n }\n\n let display = value;\n\n for (let i = value.length; i < slots.length; i++) {\n const slot = slots[i];\n if (slot.type === 'literal') {\n display += slot.char;\n } else {\n const sc = getSlotChar(slotCharOption, i);\n if (!sc) {\n break;\n }\n display += sc;\n }\n }\n\n return display;\n}\n\nfunction extractRaw(masked: string, slots: MaskSlot[]): string {\n let raw = '';\n for (let i = 0; i < masked.length && i < slots.length; i++) {\n if (slots[i].type === 'token') {\n raw += masked[i];\n }\n }\n return raw;\n}\n\nfunction checkComplete(masked: string, slots: MaskSlot[]): boolean {\n for (let i = 0; i < slots.length; i++) {\n if (slots[i].type === 'token' && !slots[i].optional) {\n if (i >= masked.length) {\n return false;\n }\n if (!slots[i].pattern!.test(masked[i])) {\n return false;\n }\n }\n }\n return true;\n}\n\nfunction findNextTokenIndex(slots: MaskSlot[], from: number): number {\n for (let i = from; i < slots.length; i++) {\n if (slots[i].type === 'token') {\n return i;\n }\n }\n return slots.length;\n}\n\nfunction findPrevTokenIndex(slots: MaskSlot[], from: number): number {\n for (let i = from; i >= 0; i--) {\n if (slots[i].type === 'token') {\n return i;\n }\n }\n return -1;\n}\n\nfunction processInput(\n inputValue: string,\n slots: MaskSlot[],\n _slotCharOption: string | null | undefined\n): string {\n let result = '';\n let inputIndex = 0;\n\n for (\n let slotIndex = 0;\n slotIndex < slots.length && inputIndex <= inputValue.length;\n slotIndex++\n ) {\n const slot = slots[slotIndex];\n\n if (slot.type === 'literal') {\n result += slot.char;\n if (inputIndex < inputValue.length && inputValue[inputIndex] === slot.char) {\n inputIndex++;\n }\n continue;\n }\n\n if (inputIndex >= inputValue.length) {\n break;\n }\n\n while (inputIndex < inputValue.length) {\n const ch = inputValue[inputIndex];\n inputIndex++;\n\n if (slot.pattern!.test(ch)) {\n result += ch;\n break;\n }\n }\n\n if (result.length <= slotIndex) {\n break;\n }\n }\n\n return result;\n}\n\nfunction getResolvedOptions(options: UseMaskOptions, rawValue: string) {\n const tokens = { ...DEFAULT_TOKENS, ...options.tokens };\n let mask = options.mask;\n let slotChar: string | null | undefined = options.slotChar === undefined ? '_' : options.slotChar;\n let separate = options.separate ?? false;\n\n if (options.modify) {\n const overrides = options.modify(rawValue);\n if (overrides) {\n if (overrides.mask !== undefined) {\n mask = overrides.mask;\n }\n if (overrides.tokens !== undefined) {\n Object.assign(tokens, overrides.tokens);\n }\n if (overrides.slotChar !== undefined) {\n slotChar = overrides.slotChar;\n }\n if (overrides.separate !== undefined) {\n separate = overrides.separate;\n }\n }\n }\n\n const slots = parseMask(mask, tokens);\n return { slots, slotChar, separate, tokens, transform: options.transform };\n}\n\nexport function formatMask(raw: string, options: UseMaskOptions): string {\n const { slots, slotChar, transform } = getResolvedOptions(options, raw);\n return applyMaskToRaw(raw, slots, slotChar, transform);\n}\n\nexport function unformatMask(masked: string, options: UseMaskOptions): string {\n const { slots } = getResolvedOptions(options, '');\n return extractRaw(masked, slots);\n}\n\nexport function isMaskComplete(masked: string, options: UseMaskOptions): boolean {\n const { slots } = getResolvedOptions(options, '');\n return checkComplete(masked, slots);\n}\n\nexport function generatePattern(mode: 'full' | 'full-inexact', options: UseMaskOptions): string {\n const { slots } = getResolvedOptions(options, '');\n let pattern = '';\n\n for (const slot of slots) {\n if (slot.type === 'literal') {\n pattern += slot.char.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n } else {\n const src = slot.pattern!.source;\n if (mode === 'full-inexact') {\n pattern += slot.optional ? `${src}?` : src;\n } else {\n pattern += slot.optional ? `(${src})?` : `(${src})`;\n }\n }\n }\n\n return pattern;\n}\n\nexport function useMask(options: UseMaskOptions): UseMaskReturnValue {\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const inputRef = useRef<HTMLInputElement | null>(null);\n const [maskedValue, setMaskedValue] = useState('');\n const [rawValue, setRawValue] = useState('');\n const processedRef = useRef('');\n const displayValueRef = useRef('');\n const rawValueRef = useRef('');\n const wasCompleteRef = useRef(false);\n const isFocusedRef = useRef(false);\n const undoStackRef = useRef<UndoState[]>([]);\n const redoStackRef = useRef<UndoState[]>([]);\n\n const getOptions = useCallback(() => {\n const opts = optionsRef.current;\n return getResolvedOptions(opts, rawValue);\n }, [rawValue]);\n\n const applyValue = useCallback(\n ({\n reprocessed,\n newRaw,\n displayValue,\n resolvedSlots,\n cursorPos,\n notifyChange,\n }: {\n reprocessed: string;\n newRaw: string;\n displayValue: string;\n resolvedSlots: MaskSlot[];\n cursorPos?: number;\n notifyChange: boolean;\n }) => {\n const opts = optionsRef.current;\n\n processedRef.current = reprocessed;\n displayValueRef.current = displayValue;\n rawValueRef.current = newRaw;\n setMaskedValue(displayValue);\n setRawValue(newRaw);\n\n if (inputRef.current) {\n inputRef.current.value = displayValue;\n if (cursorPos !== undefined && document.activeElement === inputRef.current) {\n const pos = Math.min(cursorPos, reprocessed.length);\n inputRef.current.setSelectionRange(pos, pos);\n }\n }\n\n if (notifyChange && opts.onChangeRaw) {\n opts.onChangeRaw(newRaw, displayValue);\n }\n\n const complete = checkComplete(reprocessed, resolvedSlots);\n if (notifyChange && complete && !wasCompleteRef.current && opts.onComplete) {\n opts.onComplete(displayValue, newRaw);\n }\n wasCompleteRef.current = complete;\n },\n []\n );\n\n const updateValue = useCallback(\n (newMasked: string, cursorPos?: number) => {\n const opts = optionsRef.current;\n const { slots } = getResolvedOptions(\n opts,\n extractRaw(newMasked, getResolvedOptions(opts, '').slots)\n );\n const raw = extractRaw(newMasked, slots);\n\n const { slots: resolvedSlots, slotChar } = getResolvedOptions(opts, raw);\n\n const reprocessed = processInput(newMasked, resolvedSlots, slotChar);\n const newRaw = extractRaw(reprocessed, resolvedSlots);\n\n const showSlots = opts.alwaysShowMask || isFocusedRef.current;\n const showOnFocus = opts.showMaskOnFocus !== false;\n const shouldShowSlots = showSlots && (showOnFocus || reprocessed.length > 0);\n\n const displayValue = buildDisplayValue(reprocessed, resolvedSlots, slotChar, shouldShowSlots);\n\n applyValue({\n reprocessed,\n newRaw,\n displayValue,\n resolvedSlots,\n cursorPos,\n notifyChange: true,\n });\n\n return { displayValue, newRaw, reprocessed, resolvedSlots };\n },\n [applyValue, getOptions]\n );\n\n const initializeInputValue = useCallback(\n (node: HTMLInputElement) => {\n const opts = optionsRef.current;\n\n if (!node.value) {\n return false;\n }\n\n const isOwnValue = node.value === displayValueRef.current;\n const parse = (slots: MaskSlot[], slotCharOption: string | null | undefined) =>\n isOwnValue\n ? applyMaskToRaw(rawValueRef.current, slots, slotCharOption)\n : processInput(node.value, slots, slotCharOption);\n\n const { slots: initialSlots, slotChar: initialSlotChar } = getResolvedOptions(opts, '');\n const initialProcessed = parse(initialSlots, initialSlotChar);\n const initialRaw = extractRaw(initialProcessed, initialSlots);\n const { slots: resolvedSlots, slotChar } = getResolvedOptions(opts, initialRaw);\n const reprocessed = parse(resolvedSlots, slotChar);\n const newRaw = extractRaw(reprocessed, resolvedSlots);\n const showSlots = opts.alwaysShowMask || isFocusedRef.current;\n const showOnFocus = opts.showMaskOnFocus !== false;\n const shouldShowSlots = showSlots && (showOnFocus || reprocessed.length > 0);\n const displayValue = buildDisplayValue(reprocessed, resolvedSlots, slotChar, shouldShowSlots);\n\n applyValue({\n reprocessed,\n newRaw,\n displayValue,\n resolvedSlots,\n notifyChange: false,\n });\n\n return true;\n },\n [applyValue]\n );\n\n const pushUndoState = useCallback(() => {\n const input = inputRef.current;\n const selectionStart = input?.selectionStart ?? rawValueRef.current.length;\n const state: UndoState = {\n rawValue: rawValueRef.current,\n selectionStart,\n };\n const stack = undoStackRef.current;\n const top = stack[stack.length - 1];\n if (top && top.rawValue === state.rawValue && top.selectionStart === state.selectionStart) {\n return;\n }\n stack.push(state);\n if (stack.length > MAX_UNDO_HISTORY) {\n stack.shift();\n }\n redoStackRef.current = [];\n }, []);\n\n const applyHistoryState = useCallback(\n (target: UndoState) => {\n const opts = optionsRef.current;\n const { slots, slotChar, transform } = getResolvedOptions(opts, target.rawValue);\n const newMasked = applyMaskToRaw(target.rawValue, slots, slotChar, transform);\n updateValue(newMasked, target.selectionStart);\n },\n [updateValue]\n );\n\n const handleInput = useCallback(\n (e: Event) => {\n const input = e.target as HTMLInputElement;\n const opts = optionsRef.current;\n\n const { slots: resolvedSlots, slotChar, transform } = getResolvedOptions(opts, '');\n const prev = displayValueRef.current;\n const curr = input.value;\n\n let prefixLen = 0;\n const maxPrefix = Math.min(prev.length, curr.length);\n while (prefixLen < maxPrefix && prev[prefixLen] === curr[prefixLen]) {\n prefixLen++;\n }\n\n let suffixLen = 0;\n const maxSuffix = Math.min(prev.length - prefixLen, curr.length - prefixLen);\n while (\n suffixLen < maxSuffix &&\n prev[prev.length - 1 - suffixLen] === curr[curr.length - 1 - suffixLen]\n ) {\n suffixLen++;\n }\n\n const insertedText = curr.slice(prefixLen, curr.length - suffixLen);\n const removedEnd = prev.length - suffixLen;\n\n const beforeRaw = extractRaw(prev.slice(0, prefixLen), resolvedSlots.slice(0, prefixLen));\n const afterRaw = extractRaw(prev.slice(removedEnd), resolvedSlots.slice(removedEnd));\n const reformatted = applyMaskToRaw(\n beforeRaw + insertedText + afterRaw,\n resolvedSlots,\n slotChar,\n transform\n );\n const maskedPrefix = applyMaskToRaw(\n beforeRaw + insertedText,\n resolvedSlots,\n slotChar,\n transform\n );\n\n if (reformatted !== prev) {\n pushUndoState();\n }\n updateValue(reformatted, maskedPrefix.length);\n },\n [pushUndoState, updateValue]\n );\n\n const clampCursorToProcessed = useCallback((input: HTMLInputElement) => {\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n if (start !== end) {\n return;\n }\n\n const opts = optionsRef.current;\n const { slots } = getResolvedOptions(opts, '');\n const processed = processedRef.current;\n const endPos =\n processed.length > 0\n ? findNextEditablePosition(processed.length, slots, processed)\n : findNextTokenIndex(slots, 0);\n const startPos = findNextTokenIndex(slots, 0);\n\n if (start > endPos || start < startPos) {\n input.setSelectionRange(endPos, endPos);\n }\n }, []);\n\n const handleFocus = useCallback(() => {\n isFocusedRef.current = true;\n const opts = optionsRef.current;\n const input = inputRef.current;\n\n if (!input) {\n return;\n }\n\n const { slots, slotChar } = getResolvedOptions(opts, '');\n const showOnFocus = opts.showMaskOnFocus !== false;\n const processed = processedRef.current;\n\n if (showOnFocus || opts.alwaysShowMask) {\n const display = buildDisplayValue(processed, slots, slotChar, true);\n input.value = display;\n displayValueRef.current = display;\n setMaskedValue(display);\n }\n\n requestAnimationFrame(() => {\n if (input === document.activeElement) {\n clampCursorToProcessed(input);\n }\n });\n }, [clampCursorToProcessed]);\n\n const handleMouseUp = useCallback(() => {\n const input = inputRef.current;\n if (!input || input !== document.activeElement) {\n return;\n }\n\n clampCursorToProcessed(input);\n }, [clampCursorToProcessed]);\n\n const handleMouseDown = useCallback(() => {\n const input = inputRef.current;\n if (!input) {\n return;\n }\n\n requestAnimationFrame(() => {\n if (input !== document.activeElement) {\n return;\n }\n\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n if (start !== end) {\n return;\n }\n\n const opts = optionsRef.current;\n const { slots } = getResolvedOptions(opts, '');\n const processed = processedRef.current;\n const endPos =\n processed.length > 0\n ? findNextEditablePosition(processed.length, slots, processed)\n : findNextTokenIndex(slots, 0);\n\n if (start > endPos) {\n input.setSelectionRange(endPos, endPos);\n }\n });\n }, []);\n\n const handleBlur = useCallback(() => {\n isFocusedRef.current = false;\n const opts = optionsRef.current;\n const input = inputRef.current;\n\n if (!input) {\n return;\n }\n\n const { slots, slotChar } = getResolvedOptions(opts, rawValue);\n const expectedFocusDisplay = buildDisplayValue(processedRef.current, slots, slotChar, true);\n const processed =\n input.value === expectedFocusDisplay\n ? processedRef.current\n : processInput(input.value, slots, slotChar);\n const complete = checkComplete(processed, slots);\n\n if (opts.autoClear && !complete && processed.length > 0) {\n input.value = '';\n processedRef.current = '';\n displayValueRef.current = '';\n rawValueRef.current = '';\n setMaskedValue('');\n setRawValue('');\n wasCompleteRef.current = false;\n\n if (opts.onChangeRaw) {\n opts.onChangeRaw('', '');\n }\n\n if (opts.alwaysShowMask) {\n const emptyDisplay = buildDisplayValue('', slots, slotChar, true);\n input.value = emptyDisplay;\n displayValueRef.current = emptyDisplay;\n setMaskedValue(emptyDisplay);\n }\n return;\n }\n\n if (!opts.alwaysShowMask && !complete) {\n if (extractRaw(processed, slots).length === 0) {\n input.value = '';\n processedRef.current = '';\n displayValueRef.current = '';\n rawValueRef.current = '';\n setMaskedValue('');\n setRawValue('');\n wasCompleteRef.current = false;\n\n if (opts.onChangeRaw) {\n opts.onChangeRaw('', '');\n }\n return;\n }\n\n const display = buildDisplayValue(processed, slots, slotChar, false);\n input.value = display;\n displayValueRef.current = display;\n setMaskedValue(display);\n }\n }, [rawValue]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n const input = e.target as HTMLInputElement;\n const opts = optionsRef.current;\n\n const { slots, slotChar, transform } = getResolvedOptions(opts, rawValue);\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n const processed = processedRef.current;\n\n const modifier = e.metaKey || (e.ctrlKey && !e.altKey);\n const key = e.key.toLowerCase();\n\n if (modifier && key === 'z' && !e.shiftKey) {\n e.preventDefault();\n const prev = undoStackRef.current.pop();\n if (!prev) {\n return;\n }\n redoStackRef.current.push({\n rawValue: rawValueRef.current,\n selectionStart: input.selectionStart ?? 0,\n });\n applyHistoryState(prev);\n return;\n }\n\n if (modifier && ((key === 'z' && e.shiftKey) || (key === 'y' && !e.shiftKey))) {\n e.preventDefault();\n const next = redoStackRef.current.pop();\n if (!next) {\n return;\n }\n undoStackRef.current.push({\n rawValue: rawValueRef.current,\n selectionStart: input.selectionStart ?? 0,\n });\n applyHistoryState(next);\n return;\n }\n\n if (e.key === 'Backspace') {\n e.preventDefault();\n\n if (e.metaKey || (e.ctrlKey && !e.altKey)) {\n const clampedStart = Math.min(start, processed.length);\n const afterRaw = extractRaw(processed.slice(clampedStart), slots.slice(clampedStart));\n const newValue = applyMaskToRaw(afterRaw, slots, slotChar, transform);\n pushUndoState();\n updateValue(newValue, 0);\n return;\n }\n\n if (start !== end) {\n const clampedEnd = Math.min(end, processed.length);\n const before = processed.slice(0, start);\n const afterRaw = extractRaw(processed.slice(clampedEnd), slots.slice(clampedEnd));\n const newValue = applyMaskToRaw(\n extractRaw(before, slots) + afterRaw,\n slots,\n slotChar,\n transform\n );\n pushUndoState();\n updateValue(newValue, start);\n return;\n }\n\n if (start === 0) {\n return;\n }\n\n let deletePos = start - 1;\n while (deletePos >= 0 && slots[deletePos] && slots[deletePos].type === 'literal') {\n deletePos--;\n }\n\n if (deletePos < 0) {\n return;\n }\n\n const beforeRaw = extractRaw(processed.slice(0, deletePos), slots.slice(0, deletePos));\n const afterRaw = extractRaw(processed.slice(deletePos + 1), slots.slice(deletePos + 1));\n const newValue = applyMaskToRaw(beforeRaw + afterRaw, slots, slotChar, transform);\n pushUndoState();\n updateValue(newValue, deletePos);\n } else if (e.key === 'Delete') {\n e.preventDefault();\n\n if (start !== end) {\n const clampedEnd = Math.min(end, processed.length);\n const before = processed.slice(0, start);\n const afterRaw = extractRaw(processed.slice(clampedEnd), slots.slice(clampedEnd));\n const newValue = applyMaskToRaw(\n extractRaw(before, slots) + afterRaw,\n slots,\n slotChar,\n transform\n );\n pushUndoState();\n updateValue(newValue, start);\n return;\n }\n\n let deletePos = start;\n while (\n deletePos < slots.length &&\n slots[deletePos] &&\n slots[deletePos].type === 'literal'\n ) {\n deletePos++;\n }\n\n if (deletePos >= processed.length) {\n return;\n }\n\n const beforeRaw = extractRaw(processed.slice(0, start), slots.slice(0, start));\n const afterRaw = extractRaw(processed.slice(deletePos + 1), slots.slice(deletePos + 1));\n const newValue = applyMaskToRaw(beforeRaw + afterRaw, slots, slotChar, transform);\n pushUndoState();\n updateValue(newValue, start);\n } else if (e.key === 'ArrowRight' && !e.shiftKey) {\n const nextPos = findNextEditablePosition(start + 1, slots, input.value);\n if (nextPos !== start + 1) {\n e.preventDefault();\n input.setSelectionRange(nextPos, nextPos);\n }\n } else if (e.key === 'ArrowLeft' && !e.shiftKey) {\n if (start > 0) {\n const prevToken = findPrevTokenIndex(slots, start - 1);\n if (prevToken >= 0 && prevToken !== start - 1) {\n e.preventDefault();\n input.setSelectionRange(prevToken + 1, prevToken + 1);\n }\n }\n } else if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {\n e.preventDefault();\n\n let insertPos = Math.min(start, processed.length);\n while (\n insertPos < slots.length &&\n slots[insertPos] &&\n slots[insertPos].type === 'literal'\n ) {\n insertPos++;\n }\n\n if (insertPos >= slots.length) {\n return;\n }\n\n const slot = slots[insertPos];\n const ch = transform ? transform(e.key) : e.key;\n if (!slot.pattern!.test(ch)) {\n return;\n }\n\n const beforeRaw = extractRaw(processed.slice(0, insertPos), slots.slice(0, insertPos));\n const afterRaw =\n start < end\n ? extractRaw(\n processed.slice(Math.min(end, processed.length)),\n slots.slice(Math.min(end, processed.length))\n )\n : extractRaw(processed.slice(insertPos), slots.slice(insertPos));\n const newValue = applyMaskToRaw(beforeRaw + ch + afterRaw, slots, slotChar, transform);\n const newCursorPos = findNextEditablePosition(insertPos + 1, slots, newValue);\n pushUndoState();\n updateValue(newValue, newCursorPos);\n }\n },\n [applyHistoryState, pushUndoState, rawValue, updateValue]\n );\n\n const handlePaste = useCallback(\n (e: ClipboardEvent) => {\n e.preventDefault();\n const input = e.target as HTMLInputElement;\n const opts = optionsRef.current;\n\n const pastedText = e.clipboardData?.getData('text') ?? '';\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n const processed = processedRef.current;\n\n const { slots, slotChar, transform } = getResolvedOptions(opts, '');\n const clampedStart = Math.min(start, processed.length);\n const clampedEnd = Math.min(end, processed.length);\n const beforeRaw = extractRaw(processed.slice(0, clampedStart), slots.slice(0, clampedStart));\n const afterRaw = extractRaw(processed.slice(clampedEnd), slots.slice(clampedEnd));\n const newValue = applyMaskToRaw(\n beforeRaw + pastedText + afterRaw,\n slots,\n slotChar,\n transform\n );\n\n pushUndoState();\n updateValue(newValue);\n\n const maskedPrefix = applyMaskToRaw(beforeRaw + pastedText, slots, slotChar, transform);\n const pasteEndPos = Math.min(maskedPrefix.length, slots.length);\n if (input === document.activeElement) {\n input.setSelectionRange(pasteEndPos, pasteEndPos);\n }\n },\n [pushUndoState, updateValue]\n );\n\n const setAriaAttributes = useCallback((input: HTMLInputElement) => {\n const opts = optionsRef.current;\n\n if (opts.invalid) {\n input.setAttribute('aria-invalid', 'true');\n } else {\n input.removeAttribute('aria-invalid');\n }\n }, []);\n\n const refCallback = useCallback(\n (node: HTMLInputElement | null) => {\n const prevInput = inputRef.current;\n\n if (prevInput) {\n prevInput.removeEventListener('input', handleInput);\n prevInput.removeEventListener('focus', handleFocus);\n prevInput.removeEventListener('blur', handleBlur);\n prevInput.removeEventListener('mousedown', handleMouseDown);\n prevInput.removeEventListener('mouseup', handleMouseUp);\n prevInput.removeEventListener('keydown', handleKeyDown as EventListener);\n prevInput.removeEventListener('paste', handlePaste as EventListener);\n }\n\n inputRef.current = node;\n\n if (node) {\n node.addEventListener('input', handleInput);\n node.addEventListener('focus', handleFocus);\n node.addEventListener('blur', handleBlur);\n node.addEventListener('mousedown', handleMouseDown);\n node.addEventListener('mouseup', handleMouseUp);\n node.addEventListener('keydown', handleKeyDown as EventListener);\n node.addEventListener('paste', handlePaste as EventListener);\n\n setAriaAttributes(node);\n\n const hasInitialValue = initializeInputValue(node);\n\n if (options.alwaysShowMask && !hasInitialValue) {\n const { slots, slotChar } = getResolvedOptions(options, '');\n const display = buildDisplayValue('', slots, slotChar, true);\n node.value = display;\n displayValueRef.current = display;\n setMaskedValue(display);\n }\n }\n },\n [\n handleInput,\n handleFocus,\n handleBlur,\n handleMouseDown,\n handleMouseUp,\n handleKeyDown,\n handlePaste,\n initializeInputValue,\n setAriaAttributes,\n options,\n ]\n );\n\n useEffect(() => {\n const input = inputRef.current;\n if (!input) {\n return;\n }\n\n setAriaAttributes(input);\n }, [options.invalid, setAriaAttributes]);\n\n const isComplete = (() => {\n const { slots } = getOptions();\n return checkComplete(processedRef.current, slots);\n })();\n\n const reset = useCallback(() => {\n const opts = optionsRef.current;\n const input = inputRef.current;\n\n processedRef.current = '';\n displayValueRef.current = '';\n rawValueRef.current = '';\n undoStackRef.current = [];\n redoStackRef.current = [];\n setMaskedValue('');\n setRawValue('');\n wasCompleteRef.current = false;\n\n if (input) {\n if (opts.alwaysShowMask) {\n const { slots, slotChar } = getResolvedOptions(opts, '');\n const display = buildDisplayValue('', slots, slotChar, true);\n input.value = display;\n displayValueRef.current = display;\n setMaskedValue(display);\n } else {\n input.value = '';\n }\n }\n\n if (opts.onChangeRaw) {\n opts.onChangeRaw('', '');\n }\n }, []);\n\n return {\n ref: refCallback,\n value: maskedValue,\n rawValue,\n isComplete,\n reset,\n };\n}\n\nfunction findNextEditablePosition(from: number, slots: MaskSlot[], value: string): number {\n let pos = from;\n while (pos < slots.length && pos < value.length && slots[pos] && slots[pos].type === 'literal') {\n pos++;\n }\n return pos;\n}\n\nexport namespace useMask {\n export type Options = UseMaskOptions;\n export type ReturnValue = UseMaskReturnValue;\n}\n"],"mappings":"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"}
|
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
import { randomId } from "../utils/random-id/random-id.mjs";
|
|
3
3
|
import { useEffect, useEffectEvent, useRef, useState } from "react";
|
|
4
4
|
//#region packages/@mantine/hooks/src/use-scroll-spy/use-scroll-spy.ts
|
|
5
|
-
function
|
|
5
|
+
function resolveHeadingNode(heading, selector, index) {
|
|
6
|
+
if (heading.isConnected) return heading;
|
|
7
|
+
const nodeById = heading.id ? document.getElementById(heading.id) : null;
|
|
8
|
+
if (nodeById) return nodeById;
|
|
9
|
+
return document.querySelectorAll(selector)[index] || heading;
|
|
10
|
+
}
|
|
11
|
+
function getHeadingsData(headings, getDepth, getValue, selector) {
|
|
6
12
|
const result = [];
|
|
7
13
|
for (let i = 0; i < headings.length; i += 1) {
|
|
8
14
|
const heading = headings[i];
|
|
@@ -10,7 +16,7 @@ function getHeadingsData(headings, getDepth, getValue) {
|
|
|
10
16
|
depth: getDepth(heading),
|
|
11
17
|
value: getValue(heading),
|
|
12
18
|
id: heading.id || randomId(),
|
|
13
|
-
getNode: () => heading
|
|
19
|
+
getNode: () => resolveHeadingNode(heading, selector, i)
|
|
14
20
|
});
|
|
15
21
|
}
|
|
16
22
|
return result;
|
|
@@ -48,7 +54,7 @@ function useScrollSpy({ selector = "h1, h2, h3, h4, h5, h6", getDepth = getDefau
|
|
|
48
54
|
setActive(getActiveElement(headingsRef.current.map((d) => d.getNode().getBoundingClientRect()), offset));
|
|
49
55
|
});
|
|
50
56
|
const initialize = () => {
|
|
51
|
-
const headings = getHeadingsData(Array.from(document.querySelectorAll(selector)), getDepth, getValue);
|
|
57
|
+
const headings = getHeadingsData(Array.from(document.querySelectorAll(selector)), getDepth, getValue, selector);
|
|
52
58
|
headingsRef.current = headings;
|
|
53
59
|
setInitialized(true);
|
|
54
60
|
setData(headings);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-scroll-spy.mjs","names":[],"sources":["../../src/use-scroll-spy/use-scroll-spy.ts"],"sourcesContent":["import React, { useEffect, useEffectEvent, useRef, useState } from 'react';\nimport { randomId } from '../utils';\n\nfunction getHeadingsData(\n headings: HTMLElement[],\n getDepth: (element: HTMLElement) => number,\n getValue: (element: HTMLElement) => string\n): UseScrollSpyHeadingData[] {\n const result: UseScrollSpyHeadingData[] = [];\n\n for (let i = 0; i < headings.length; i += 1) {\n const heading = headings[i];\n result.push({\n depth: getDepth(heading),\n value: getValue(heading),\n id: heading.id || randomId(),\n getNode: () => (heading
|
|
1
|
+
{"version":3,"file":"use-scroll-spy.mjs","names":[],"sources":["../../src/use-scroll-spy/use-scroll-spy.ts"],"sourcesContent":["import React, { useEffect, useEffectEvent, useRef, useState } from 'react';\nimport { randomId } from '../utils';\n\nfunction resolveHeadingNode(heading: HTMLElement, selector: string, index: number): HTMLElement {\n if (heading.isConnected) {\n return heading;\n }\n\n const nodeById = heading.id ? document.getElementById(heading.id) : null;\n\n if (nodeById) {\n return nodeById;\n }\n\n return document.querySelectorAll<HTMLElement>(selector)[index] || heading;\n}\n\nfunction getHeadingsData(\n headings: HTMLElement[],\n getDepth: (element: HTMLElement) => number,\n getValue: (element: HTMLElement) => string,\n selector: string\n): UseScrollSpyHeadingData[] {\n const result: UseScrollSpyHeadingData[] = [];\n\n for (let i = 0; i < headings.length; i += 1) {\n const heading = headings[i];\n result.push({\n depth: getDepth(heading),\n value: getValue(heading),\n id: heading.id || randomId(),\n getNode: () => resolveHeadingNode(heading, selector, i),\n });\n }\n\n return result;\n}\n\nfunction getActiveElement(rects: DOMRect[], offset: number = 0) {\n if (rects.length === 0) {\n return -1;\n }\n\n const closest = rects.reduce(\n (acc, item, index) => {\n if (Math.abs(acc.position - offset) < Math.abs(item.y - offset)) {\n return acc;\n }\n\n return {\n index,\n position: item.y,\n };\n },\n { index: 0, position: rects[0].y }\n );\n\n return closest.index;\n}\n\nfunction getDefaultDepth(element: HTMLElement) {\n return Number(element.tagName[1]);\n}\n\nfunction getDefaultValue(element: HTMLElement) {\n return element.textContent || '';\n}\n\nfunction resolveScrollHost(\n scrollHost: HTMLElement | React.RefObject<HTMLElement | null> | undefined\n): HTMLElement | Window {\n if (!scrollHost) {\n return window;\n }\n\n if ('current' in scrollHost) {\n return scrollHost.current || window;\n }\n\n return scrollHost;\n}\n\nexport interface UseScrollSpyHeadingData {\n /** Heading depth, 1-6 */\n depth: number;\n\n /** Heading text content value */\n value: string;\n\n /** Heading id */\n id: string;\n\n /** Function to get heading node */\n getNode: () => HTMLElement;\n}\n\nexport interface UseScrollSpyOptions {\n /** Selector to get headings, `'h1, h2, h3, h4, h5, h6'` by default */\n selector?: string;\n\n /** A function to retrieve depth of heading, by default depth is calculated based on tag name */\n getDepth?: (element: HTMLElement) => number;\n\n /** A function to retrieve heading value, by default `element.textContent` is used */\n getValue?: (element: HTMLElement) => string;\n\n /** Host element or a ref to it to attach scroll event listener, if not provided, `window` is used */\n scrollHost?: HTMLElement | React.RefObject<HTMLElement | null>;\n\n /** Offset from the top of the viewport to use when determining the active heading, `0` by default */\n offset?: number;\n}\n\nexport interface UseScrollSpyReturnValue {\n /** Index of the active heading in the `data` array */\n active: number;\n\n /** Headings data. If not initialize, data is represented by an empty array. */\n data: UseScrollSpyHeadingData[];\n\n /** True if headings value have been retrieved from the DOM. */\n initialized: boolean;\n\n /** Function to update headings values after the parent component has mounted. */\n reinitialize: () => void;\n}\n\nexport function useScrollSpy({\n selector = 'h1, h2, h3, h4, h5, h6',\n getDepth = getDefaultDepth,\n getValue = getDefaultValue,\n offset = 0,\n scrollHost,\n}: UseScrollSpyOptions = {}): UseScrollSpyReturnValue {\n const [active, setActive] = useState(-1);\n const [initialized, setInitialized] = useState(false);\n const [data, setData] = useState<UseScrollSpyHeadingData[]>([]);\n const headingsRef = useRef<UseScrollSpyHeadingData[]>([]);\n\n const handleScroll = useEffectEvent(() => {\n setActive(\n getActiveElement(\n headingsRef.current.map((d) => d.getNode().getBoundingClientRect()),\n offset\n )\n );\n });\n\n const initialize = () => {\n const headings = getHeadingsData(\n Array.from(document.querySelectorAll(selector)),\n getDepth,\n getValue,\n selector\n );\n headingsRef.current = headings;\n setInitialized(true);\n setData(headings);\n setActive(\n getActiveElement(\n headings.map((d) => d.getNode().getBoundingClientRect()),\n offset\n )\n );\n };\n\n useEffect(() => {\n initialize();\n const _scrollHost = resolveScrollHost(scrollHost);\n _scrollHost.addEventListener('scroll', handleScroll);\n return () => _scrollHost.removeEventListener('scroll', handleScroll);\n }, [scrollHost, selector, offset]);\n\n return {\n reinitialize: initialize,\n active,\n initialized,\n data,\n };\n}\n\nexport namespace useScrollSpy {\n export type Options = UseScrollSpyOptions;\n export type ReturnValue = UseScrollSpyReturnValue;\n}\n"],"mappings":";;;;AAGA,SAAS,mBAAmB,SAAsB,UAAkB,OAA4B;CAC9F,IAAI,QAAQ,aACV,OAAO;CAGT,MAAM,WAAW,QAAQ,KAAK,SAAS,eAAe,QAAQ,EAAE,IAAI;CAEpE,IAAI,UACF,OAAO;CAGT,OAAO,SAAS,iBAA8B,QAAQ,CAAC,CAAC,UAAU;AACpE;AAEA,SAAS,gBACP,UACA,UACA,UACA,UAC2B;CAC3B,MAAM,SAAoC,CAAC;CAE3C,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,GAAG;EAC3C,MAAM,UAAU,SAAS;EACzB,OAAO,KAAK;GACV,OAAO,SAAS,OAAO;GACvB,OAAO,SAAS,OAAO;GACvB,IAAI,QAAQ,MAAM,SAAS;GAC3B,eAAe,mBAAmB,SAAS,UAAU,CAAC;EACxD,CAAC;CACH;CAEA,OAAO;AACT;AAEA,SAAS,iBAAiB,OAAkB,SAAiB,GAAG;CAC9D,IAAI,MAAM,WAAW,GACnB,OAAO;CAiBT,OAdgB,MAAM,QACnB,KAAK,MAAM,UAAU;EACpB,IAAI,KAAK,IAAI,IAAI,WAAW,MAAM,IAAI,KAAK,IAAI,KAAK,IAAI,MAAM,GAC5D,OAAO;EAGT,OAAO;GACL;GACA,UAAU,KAAK;EACjB;CACF,GACA;EAAE,OAAO;EAAG,UAAU,MAAM,EAAE,CAAC;CAAE,CAGtB,CAAC,CAAC;AACjB;AAEA,SAAS,gBAAgB,SAAsB;CAC7C,OAAO,OAAO,QAAQ,QAAQ,EAAE;AAClC;AAEA,SAAS,gBAAgB,SAAsB;CAC7C,OAAO,QAAQ,eAAe;AAChC;AAEA,SAAS,kBACP,YACsB;CACtB,IAAI,CAAC,YACH,OAAO;CAGT,IAAI,aAAa,YACf,OAAO,WAAW,WAAW;CAG/B,OAAO;AACT;AA+CA,SAAgB,aAAa,EAC3B,WAAW,0BACX,WAAW,iBACX,WAAW,iBACX,SAAS,GACT,eACuB,CAAC,GAA4B;CACpD,MAAM,CAAC,QAAQ,aAAa,SAAS,EAAE;CACvC,MAAM,CAAC,aAAa,kBAAkB,SAAS,KAAK;CACpD,MAAM,CAAC,MAAM,WAAW,SAAoC,CAAC,CAAC;CAC9D,MAAM,cAAc,OAAkC,CAAC,CAAC;CAExD,MAAM,eAAe,qBAAqB;EACxC,UACE,iBACE,YAAY,QAAQ,KAAK,MAAM,EAAE,QAAQ,CAAC,CAAC,sBAAsB,CAAC,GAClE,MACF,CACF;CACF,CAAC;CAED,MAAM,mBAAmB;EACvB,MAAM,WAAW,gBACf,MAAM,KAAK,SAAS,iBAAiB,QAAQ,CAAC,GAC9C,UACA,UACA,QACF;EACA,YAAY,UAAU;EACtB,eAAe,IAAI;EACnB,QAAQ,QAAQ;EAChB,UACE,iBACE,SAAS,KAAK,MAAM,EAAE,QAAQ,CAAC,CAAC,sBAAsB,CAAC,GACvD,MACF,CACF;CACF;CAEA,gBAAgB;EACd,WAAW;EACX,MAAM,cAAc,kBAAkB,UAAU;EAChD,YAAY,iBAAiB,UAAU,YAAY;EACnD,aAAa,YAAY,oBAAoB,UAAU,YAAY;CACrE,GAAG;EAAC;EAAY;EAAU;CAAM,CAAC;CAEjC,OAAO;EACL,cAAc;EACd;EACA;EACA;CACF;AACF"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { CSSProperties } from 'react';
|
|
2
2
|
export declare function getElementHeight(elementRef: React.RefObject<HTMLElement | null>): number | "auto";
|
|
3
|
+
export declare function isMeasured(size: number | string): size is number;
|
|
3
4
|
export interface UseCollapseInput {
|
|
4
5
|
/** Expanded state */
|
|
5
6
|
expanded: boolean;
|