@mantine/core 9.6.1 → 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.
Files changed (23) hide show
  1. package/cjs/components/Combobox/use-combobox/use-combobox.cjs +1 -4
  2. package/cjs/components/Combobox/use-combobox/use-combobox.cjs.map +1 -1
  3. package/cjs/components/ComboboxPopover/ComboboxPopover.cjs +1 -1
  4. package/cjs/components/ComboboxPopover/ComboboxPopover.cjs.map +1 -1
  5. package/cjs/components/NumberInput/NumberInput.cjs +32 -22
  6. package/cjs/components/NumberInput/NumberInput.cjs.map +1 -1
  7. package/cjs/components/NumberInput/get-caret-position-after-paste/get-caret-position-after-paste.cjs +19 -0
  8. package/cjs/components/NumberInput/get-caret-position-after-paste/get-caret-position-after-paste.cjs.map +1 -0
  9. package/cjs/components/NumberInput/normalize-pasted-value/normalize-pasted-value.cjs +35 -0
  10. package/cjs/components/NumberInput/normalize-pasted-value/normalize-pasted-value.cjs.map +1 -0
  11. package/esm/components/Combobox/use-combobox/use-combobox.mjs +1 -4
  12. package/esm/components/Combobox/use-combobox/use-combobox.mjs.map +1 -1
  13. package/esm/components/ComboboxPopover/ComboboxPopover.mjs +1 -1
  14. package/esm/components/ComboboxPopover/ComboboxPopover.mjs.map +1 -1
  15. package/esm/components/NumberInput/NumberInput.mjs +32 -22
  16. package/esm/components/NumberInput/NumberInput.mjs.map +1 -1
  17. package/esm/components/NumberInput/get-caret-position-after-paste/get-caret-position-after-paste.mjs +19 -0
  18. package/esm/components/NumberInput/get-caret-position-after-paste/get-caret-position-after-paste.mjs.map +1 -0
  19. package/esm/components/NumberInput/normalize-pasted-value/normalize-pasted-value.mjs +35 -0
  20. package/esm/components/NumberInput/normalize-pasted-value/normalize-pasted-value.mjs.map +1 -0
  21. package/lib/components/NumberInput/get-caret-position-after-paste/get-caret-position-after-paste.d.ts +1 -0
  22. package/lib/components/NumberInput/normalize-pasted-value/normalize-pasted-value.d.ts +7 -0
  23. package/package.json +2 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize-pasted-value.cjs","names":[],"sources":["../../../../src/components/NumberInput/normalize-pasted-value/normalize-pasted-value.ts"],"sourcesContent":["export interface NormalizePastedValueOptions {\n decimalSeparator: string;\n thousandSeparator?: string;\n allowedDecimalSeparators: string[];\n thousandsGroupStyle?: 'thousand' | 'lakh' | 'wan' | 'none';\n}\n\nfunction countTrailingDigits(value: string, from: number) {\n let count = 0;\n while (from + count < value.length && /\\d/.test(value[from + count])) {\n count += 1;\n }\n return count;\n}\n\nexport function normalizePastedValue(\n value: string,\n {\n decimalSeparator,\n thousandSeparator,\n allowedDecimalSeparators,\n thousandsGroupStyle,\n }: NormalizePastedValueOptions\n) {\n const candidates = new Set(\n [...allowedDecimalSeparators, decimalSeparator].filter((s) => s.length === 1)\n );\n const chars = value.split('');\n const occurrences = chars.reduce<number[]>((acc, char, index) => {\n if (candidates.has(char)) {\n acc.push(index);\n }\n return acc;\n }, []);\n\n if (occurrences.length === 0) {\n return value;\n }\n\n const lastIndex = occurrences[occurrences.length - 1];\n const lastChar = chars[lastIndex];\n const lastCharCount = occurrences.filter((index) => chars[index] === lastChar).length;\n const lastGroupSize = thousandsGroupStyle === 'wan' ? 4 : 3;\n\n let decimalIndex = -1;\n if (lastCharCount === 1) {\n if (lastChar === decimalSeparator) {\n decimalIndex = lastIndex;\n } else if (lastChar === thousandSeparator) {\n decimalIndex = countTrailingDigits(value, lastIndex + 1) === lastGroupSize ? -1 : lastIndex;\n } else {\n decimalIndex = lastIndex;\n }\n }\n\n return chars\n .map((char, index) => {\n if (index === decimalIndex) {\n return decimalSeparator;\n }\n\n if (candidates.has(char) && char !== thousandSeparator) {\n return '';\n }\n\n return char;\n })\n .join('');\n}\n"],"mappings":";;AAOA,SAAS,oBAAoB,OAAe,MAAc;CACxD,IAAI,QAAQ;CACZ,OAAO,OAAO,QAAQ,MAAM,UAAU,KAAK,KAAK,MAAM,OAAO,MAAM,GACjE,SAAS;CAEX,OAAO;AACT;AAEA,SAAgB,qBACd,OACA,EACE,kBACA,mBACA,0BACA,uBAEF;CACA,MAAM,aAAa,IAAI,IACrB,CAAC,GAAG,0BAA0B,gBAAgB,CAAC,CAAC,QAAQ,MAAM,EAAE,WAAW,CAAC,CAC9E;CACA,MAAM,QAAQ,MAAM,MAAM,EAAE;CAC5B,MAAM,cAAc,MAAM,QAAkB,KAAK,MAAM,UAAU;EAC/D,IAAI,WAAW,IAAI,IAAI,GACrB,IAAI,KAAK,KAAK;EAEhB,OAAO;CACT,GAAG,CAAC,CAAC;CAEL,IAAI,YAAY,WAAW,GACzB,OAAO;CAGT,MAAM,YAAY,YAAY,YAAY,SAAS;CACnD,MAAM,WAAW,MAAM;CACvB,MAAM,gBAAgB,YAAY,QAAQ,UAAU,MAAM,WAAW,QAAQ,CAAC,CAAC;CAC/E,MAAM,gBAAgB,wBAAwB,QAAQ,IAAI;CAE1D,IAAI,eAAe;CACnB,IAAI,kBAAkB,GAAG;EACvB,IAAI,aAAa,kBACf,eAAe;OACV,IAAI,aAAa,mBACtB,eAAe,oBAAoB,OAAO,YAAY,CAAC,MAAM,gBAAgB,KAAK;OAElF,eAAe;CAEnB;CAEA,OAAO,MACJ,KAAK,MAAM,UAAU;EACpB,IAAI,UAAU,cACZ,OAAO;EAGT,IAAI,WAAW,IAAI,IAAI,KAAK,SAAS,mBACnC,OAAO;EAGT,OAAO;CACT,CAAC,CAAC,CACD,KAAK,EAAE;AACZ"}
@@ -48,9 +48,7 @@ function useCombobox({ defaultOpened, opened, onOpenedChange, onDropdownClose, o
48
48
  ]);
49
49
  const clearSelectedItem = useCallback(() => {
50
50
  const root = getRootElement(targetRef.current);
51
- const selected = findElementBySelector(`#${listId.current} [data-combobox-selected]`, root);
52
- selected?.removeAttribute("data-combobox-selected");
53
- selected?.removeAttribute("aria-selected");
51
+ findElementBySelector(`#${listId.current} [data-combobox-selected]`, root)?.removeAttribute("data-combobox-selected");
54
52
  }, []);
55
53
  const selectOption = useCallback((index) => {
56
54
  const root = getRootElement(targetRef.current);
@@ -62,7 +60,6 @@ function useCombobox({ defaultOpened, opened, onOpenedChange, onDropdownClose, o
62
60
  if (items?.[nextIndex] && !items[nextIndex].hasAttribute("data-combobox-disabled")) {
63
61
  clearSelectedItem();
64
62
  items[nextIndex].setAttribute("data-combobox-selected", "true");
65
- items[nextIndex].setAttribute("aria-selected", "true");
66
63
  items[nextIndex].scrollIntoView({
67
64
  block: "nearest",
68
65
  behavior: scrollBehavior
@@ -1 +1 @@
1
- {"version":3,"file":"use-combobox.mjs","names":[],"sources":["../../../../src/components/Combobox/use-combobox/use-combobox.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from 'react';\nimport { useUncontrolled } from '@mantine/hooks';\nimport { findElementBySelector, findElementsBySelector, getRootElement } from '../../../core/utils';\nimport { getFirstIndex, getNextIndex, getPreviousIndex } from './get-index/get-index';\n\nexport type ComboboxDropdownEventSource = 'keyboard' | 'mouse' | 'unknown';\n\nexport interface ComboboxStore {\n /** Current dropdown opened state */\n dropdownOpened: boolean;\n\n /** Opens dropdown */\n openDropdown: (eventSource?: ComboboxDropdownEventSource) => void;\n\n /** Closes dropdown */\n closeDropdown: (eventSource?: ComboboxDropdownEventSource) => void;\n\n /** Toggles dropdown opened state */\n toggleDropdown: (eventSource?: ComboboxDropdownEventSource) => void;\n\n /** Selected option index ref */\n selectedOptionIndex: number;\n\n /** Returns currently selected option index or `-1` if none of the options is selected */\n getSelectedOptionIndex: () => number;\n\n /** Selects `Combobox.Option` by index */\n selectOption: (index: number) => void;\n\n /** Selects first `Combobox.Option` with `active` prop.\n * If there are no such options, the function does nothing.\n */\n selectActiveOption: () => string | null;\n\n /** Selects first `Combobox.Option` that is not disabled.\n * If there are no such options, the function does nothing.\n * */\n selectFirstOption: () => string | null;\n\n /** Selects next `Combobox.Option` that is not disabled.\n * If the current option is the last one, the function selects first option, if `loop` is true.\n */\n selectNextOption: () => string | null;\n\n /** Selects previous `Combobox.Option` that is not disabled.\n * If the current option is the first one, the function selects last option, if `loop` is true.\n * */\n selectPreviousOption: () => string | null;\n\n /** Resets selected option index to -1, removes `data-combobox-selected` from selected option */\n resetSelectedOption: () => void;\n\n /** Triggers `onClick` event of selected option.\n * If there is no selected option, the function does nothing.\n */\n clickSelectedOption: () => void;\n\n /** Updates selected option index to currently selected or active option.\n * The function is required to be used with searchable components to update selected option index\n * when options list changes based on search query.\n */\n updateSelectedOptionIndex: (\n target?: 'active' | 'selected' | number,\n options?: { scrollIntoView?: boolean }\n ) => void;\n\n /** List id, used for `aria-*` attributes */\n listId: string | null;\n\n /** Sets list id */\n setListId: (id: string) => void;\n\n /** Ref of `Combobox.Search` input */\n searchRef: React.RefObject<HTMLInputElement | null>;\n\n /** Moves focus to `Combobox.Search` input */\n focusSearchInput: () => void;\n\n /** Ref of the target element */\n targetRef: React.RefObject<HTMLElement | null>;\n\n /** Moves focus to the target element */\n focusTarget: () => void;\n}\n\nexport interface UseComboboxOptions {\n /** Default value for `dropdownOpened`, `false` by default. Used when the component is uncontrolled */\n defaultOpened?: boolean;\n\n /** Controlled `dropdownOpened` state. When set, the dropdown opened state is controlled by the parent component */\n opened?: boolean;\n\n /** Called when `dropdownOpened` state changes. Required for controlled mode */\n onOpenedChange?: (opened: boolean) => void;\n\n /** Called when dropdown closes with event source: keyboard, mouse or unknown. Useful for analytics or side effects on dropdown closure */\n onDropdownClose?: (eventSource: ComboboxDropdownEventSource) => void;\n\n /** Called when dropdown opens with event source: keyboard, mouse or unknown. Useful for analytics or side effects on dropdown opening */\n onDropdownOpen?: (eventSource: ComboboxDropdownEventSource) => void;\n\n /** Determines whether arrow key presses should loop through items (first to last and last to first). Defaults to `true` */\n loop?: boolean;\n\n /** `behavior` passed down to `element.scrollIntoView`. Controls the scrolling animation when options are scrolled into view. Defaults to `'instant'` */\n scrollBehavior?: ScrollBehavior;\n}\n\nexport function useCombobox({\n defaultOpened,\n opened,\n onOpenedChange,\n onDropdownClose,\n onDropdownOpen,\n loop = true,\n scrollBehavior = 'instant',\n}: UseComboboxOptions = {}): ComboboxStore {\n const [dropdownOpened, setDropdownOpened] = useUncontrolled({\n value: opened,\n defaultValue: defaultOpened,\n finalValue: false,\n onChange: onOpenedChange,\n });\n\n const listId = useRef<string | null>(null);\n const selectedOptionIndex = useRef<number>(-1);\n const searchRef = useRef<HTMLInputElement | null>(null);\n const targetRef = useRef<HTMLElement | null>(null);\n const focusSearchTimeout = useRef<number>(-1);\n const focusTargetTimeout = useRef<number>(-1);\n const selectedIndexUpdateTimeout = useRef<number>(-1);\n\n const openDropdown: ComboboxStore['openDropdown'] = useCallback(\n (eventSource = 'unknown') => {\n if (!dropdownOpened) {\n setDropdownOpened(true);\n onDropdownOpen?.(eventSource);\n }\n },\n [setDropdownOpened, onDropdownOpen, dropdownOpened]\n );\n\n const closeDropdown: ComboboxStore['closeDropdown'] = useCallback(\n (eventSource = 'unknown') => {\n if (dropdownOpened) {\n setDropdownOpened(false);\n onDropdownClose?.(eventSource);\n }\n },\n [setDropdownOpened, onDropdownClose, dropdownOpened]\n );\n\n const toggleDropdown: ComboboxStore['toggleDropdown'] = useCallback(\n (eventSource = 'unknown') => {\n if (dropdownOpened) {\n closeDropdown(eventSource);\n } else {\n openDropdown(eventSource);\n }\n },\n [closeDropdown, openDropdown, dropdownOpened]\n );\n\n const clearSelectedItem = useCallback(() => {\n const root = getRootElement(targetRef.current);\n const selected = findElementBySelector(`#${listId.current} [data-combobox-selected]`, root);\n selected?.removeAttribute('data-combobox-selected');\n selected?.removeAttribute('aria-selected');\n }, []);\n\n const selectOption = useCallback(\n (index: number) => {\n const root = getRootElement(targetRef.current);\n const list = findElementBySelector(`#${listId.current!}`, root);\n const items = list\n ? findElementsBySelector<HTMLDivElement>('[data-combobox-option]', list)\n : null;\n\n if (!items) {\n return null;\n }\n\n const nextIndex = index >= items!.length ? 0 : index < 0 ? items!.length - 1 : index;\n selectedOptionIndex.current = nextIndex;\n\n if (items?.[nextIndex] && !items[nextIndex].hasAttribute('data-combobox-disabled')) {\n clearSelectedItem();\n items[nextIndex].setAttribute('data-combobox-selected', 'true');\n items[nextIndex].setAttribute('aria-selected', 'true');\n items[nextIndex].scrollIntoView({ block: 'nearest', behavior: scrollBehavior });\n return items[nextIndex].id;\n }\n\n return null;\n },\n [scrollBehavior, clearSelectedItem]\n );\n\n const selectActiveOption = useCallback(() => {\n const root = getRootElement(targetRef.current);\n const activeOption = findElementBySelector<HTMLDivElement>(\n `#${listId.current} [data-combobox-active]`,\n root\n );\n\n if (activeOption) {\n const items = findElementsBySelector<HTMLDivElement>(\n `#${listId.current} [data-combobox-option]`,\n root\n );\n const index = items.findIndex((option) => option === activeOption);\n return selectOption(index);\n }\n\n return selectOption(0);\n }, [selectOption]);\n\n const selectNextOption = useCallback(() => {\n const root = getRootElement(targetRef.current);\n const items = findElementsBySelector<HTMLDivElement>(\n `#${listId.current} [data-combobox-option]`,\n root\n );\n return selectOption(getNextIndex(selectedOptionIndex.current, items, loop));\n }, [selectOption, loop]);\n\n const selectPreviousOption = useCallback(() => {\n const root = getRootElement(targetRef.current);\n const items = findElementsBySelector<HTMLDivElement>(\n `#${listId.current} [data-combobox-option]`,\n root\n );\n return selectOption(getPreviousIndex(selectedOptionIndex.current, items, loop));\n }, [selectOption, loop]);\n\n const selectFirstOption = useCallback(() => {\n const root = getRootElement(targetRef.current);\n const items = findElementsBySelector<HTMLDivElement>(\n `#${listId.current} [data-combobox-option]`,\n root\n );\n return selectOption(getFirstIndex(items));\n }, [selectOption]);\n\n const updateSelectedOptionIndex: ComboboxStore['updateSelectedOptionIndex'] = useCallback(\n (target = 'selected', options) => {\n if (typeof target === 'number') {\n selectedOptionIndex.current = target;\n const root = getRootElement(targetRef.current);\n\n const items = findElementsBySelector<HTMLDivElement>(\n `#${listId.current} [data-combobox-option]`,\n root\n );\n\n if (options?.scrollIntoView) {\n items[target]?.scrollIntoView({ block: 'nearest', behavior: scrollBehavior });\n }\n return;\n }\n\n selectedIndexUpdateTimeout.current = window.setTimeout(() => {\n const root = getRootElement(targetRef.current);\n const items = findElementsBySelector<HTMLDivElement>(\n `#${listId.current} [data-combobox-option]`,\n root\n );\n const index = items.findIndex((option) => option.hasAttribute(`data-combobox-${target}`));\n\n selectedOptionIndex.current = index;\n\n if (options?.scrollIntoView) {\n items[index]?.scrollIntoView({ block: 'nearest', behavior: scrollBehavior });\n }\n }, 0);\n },\n []\n );\n\n const resetSelectedOption = useCallback(() => {\n selectedOptionIndex.current = -1;\n clearSelectedItem();\n }, [clearSelectedItem]);\n\n const clickSelectedOption = useCallback(() => {\n const root = getRootElement(targetRef.current);\n const items = findElementsBySelector<HTMLDivElement>(\n `#${listId.current} [data-combobox-option]`,\n root\n );\n const item = items?.[selectedOptionIndex.current];\n item?.click();\n }, []);\n\n const setListId = useCallback((id: string) => {\n listId.current = id;\n }, []);\n\n const focusSearchInput = useCallback(() => {\n focusSearchTimeout.current = window.setTimeout(() => searchRef.current?.focus(), 0);\n }, []);\n\n const focusTarget = useCallback(() => {\n focusTargetTimeout.current = window.setTimeout(() => targetRef.current?.focus(), 0);\n }, []);\n\n const getSelectedOptionIndex = useCallback(() => selectedOptionIndex.current, []);\n\n useEffect(\n () => () => {\n window.clearTimeout(focusSearchTimeout.current);\n window.clearTimeout(focusTargetTimeout.current);\n window.clearTimeout(selectedIndexUpdateTimeout.current);\n },\n []\n );\n\n return {\n dropdownOpened,\n openDropdown,\n closeDropdown,\n toggleDropdown,\n\n selectedOptionIndex: selectedOptionIndex.current,\n getSelectedOptionIndex,\n selectOption,\n selectFirstOption,\n selectActiveOption,\n selectNextOption,\n selectPreviousOption,\n resetSelectedOption,\n updateSelectedOptionIndex,\n\n listId: listId.current,\n setListId,\n clickSelectedOption,\n\n searchRef,\n focusSearchInput,\n\n targetRef,\n focusTarget,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-combobox.mjs","names":[],"sources":["../../../../src/components/Combobox/use-combobox/use-combobox.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from 'react';\nimport { useUncontrolled } from '@mantine/hooks';\nimport { findElementBySelector, findElementsBySelector, getRootElement } from '../../../core/utils';\nimport { getFirstIndex, getNextIndex, getPreviousIndex } from './get-index/get-index';\n\nexport type ComboboxDropdownEventSource = 'keyboard' | 'mouse' | 'unknown';\n\nexport interface ComboboxStore {\n /** Current dropdown opened state */\n dropdownOpened: boolean;\n\n /** Opens dropdown */\n openDropdown: (eventSource?: ComboboxDropdownEventSource) => void;\n\n /** Closes dropdown */\n closeDropdown: (eventSource?: ComboboxDropdownEventSource) => void;\n\n /** Toggles dropdown opened state */\n toggleDropdown: (eventSource?: ComboboxDropdownEventSource) => void;\n\n /** Selected option index ref */\n selectedOptionIndex: number;\n\n /** Returns currently selected option index or `-1` if none of the options is selected */\n getSelectedOptionIndex: () => number;\n\n /** Selects `Combobox.Option` by index */\n selectOption: (index: number) => void;\n\n /** Selects first `Combobox.Option` with `active` prop.\n * If there are no such options, the function does nothing.\n */\n selectActiveOption: () => string | null;\n\n /** Selects first `Combobox.Option` that is not disabled.\n * If there are no such options, the function does nothing.\n * */\n selectFirstOption: () => string | null;\n\n /** Selects next `Combobox.Option` that is not disabled.\n * If the current option is the last one, the function selects first option, if `loop` is true.\n */\n selectNextOption: () => string | null;\n\n /** Selects previous `Combobox.Option` that is not disabled.\n * If the current option is the first one, the function selects last option, if `loop` is true.\n * */\n selectPreviousOption: () => string | null;\n\n /** Resets selected option index to -1, removes `data-combobox-selected` from selected option */\n resetSelectedOption: () => void;\n\n /** Triggers `onClick` event of selected option.\n * If there is no selected option, the function does nothing.\n */\n clickSelectedOption: () => void;\n\n /** Updates selected option index to currently selected or active option.\n * The function is required to be used with searchable components to update selected option index\n * when options list changes based on search query.\n */\n updateSelectedOptionIndex: (\n target?: 'active' | 'selected' | number,\n options?: { scrollIntoView?: boolean }\n ) => void;\n\n /** List id, used for `aria-*` attributes */\n listId: string | null;\n\n /** Sets list id */\n setListId: (id: string) => void;\n\n /** Ref of `Combobox.Search` input */\n searchRef: React.RefObject<HTMLInputElement | null>;\n\n /** Moves focus to `Combobox.Search` input */\n focusSearchInput: () => void;\n\n /** Ref of the target element */\n targetRef: React.RefObject<HTMLElement | null>;\n\n /** Moves focus to the target element */\n focusTarget: () => void;\n}\n\nexport interface UseComboboxOptions {\n /** Default value for `dropdownOpened`, `false` by default. Used when the component is uncontrolled */\n defaultOpened?: boolean;\n\n /** Controlled `dropdownOpened` state. When set, the dropdown opened state is controlled by the parent component */\n opened?: boolean;\n\n /** Called when `dropdownOpened` state changes. Required for controlled mode */\n onOpenedChange?: (opened: boolean) => void;\n\n /** Called when dropdown closes with event source: keyboard, mouse or unknown. Useful for analytics or side effects on dropdown closure */\n onDropdownClose?: (eventSource: ComboboxDropdownEventSource) => void;\n\n /** Called when dropdown opens with event source: keyboard, mouse or unknown. Useful for analytics or side effects on dropdown opening */\n onDropdownOpen?: (eventSource: ComboboxDropdownEventSource) => void;\n\n /** Determines whether arrow key presses should loop through items (first to last and last to first). Defaults to `true` */\n loop?: boolean;\n\n /** `behavior` passed down to `element.scrollIntoView`. Controls the scrolling animation when options are scrolled into view. Defaults to `'instant'` */\n scrollBehavior?: ScrollBehavior;\n}\n\nexport function useCombobox({\n defaultOpened,\n opened,\n onOpenedChange,\n onDropdownClose,\n onDropdownOpen,\n loop = true,\n scrollBehavior = 'instant',\n}: UseComboboxOptions = {}): ComboboxStore {\n const [dropdownOpened, setDropdownOpened] = useUncontrolled({\n value: opened,\n defaultValue: defaultOpened,\n finalValue: false,\n onChange: onOpenedChange,\n });\n\n const listId = useRef<string | null>(null);\n const selectedOptionIndex = useRef<number>(-1);\n const searchRef = useRef<HTMLInputElement | null>(null);\n const targetRef = useRef<HTMLElement | null>(null);\n const focusSearchTimeout = useRef<number>(-1);\n const focusTargetTimeout = useRef<number>(-1);\n const selectedIndexUpdateTimeout = useRef<number>(-1);\n\n const openDropdown: ComboboxStore['openDropdown'] = useCallback(\n (eventSource = 'unknown') => {\n if (!dropdownOpened) {\n setDropdownOpened(true);\n onDropdownOpen?.(eventSource);\n }\n },\n [setDropdownOpened, onDropdownOpen, dropdownOpened]\n );\n\n const closeDropdown: ComboboxStore['closeDropdown'] = useCallback(\n (eventSource = 'unknown') => {\n if (dropdownOpened) {\n setDropdownOpened(false);\n onDropdownClose?.(eventSource);\n }\n },\n [setDropdownOpened, onDropdownClose, dropdownOpened]\n );\n\n const toggleDropdown: ComboboxStore['toggleDropdown'] = useCallback(\n (eventSource = 'unknown') => {\n if (dropdownOpened) {\n closeDropdown(eventSource);\n } else {\n openDropdown(eventSource);\n }\n },\n [closeDropdown, openDropdown, dropdownOpened]\n );\n\n const clearSelectedItem = useCallback(() => {\n const root = getRootElement(targetRef.current);\n const selected = findElementBySelector(`#${listId.current} [data-combobox-selected]`, root);\n selected?.removeAttribute('data-combobox-selected');\n }, []);\n\n const selectOption = useCallback(\n (index: number) => {\n const root = getRootElement(targetRef.current);\n const list = findElementBySelector(`#${listId.current!}`, root);\n const items = list\n ? findElementsBySelector<HTMLDivElement>('[data-combobox-option]', list)\n : null;\n\n if (!items) {\n return null;\n }\n\n const nextIndex = index >= items!.length ? 0 : index < 0 ? items!.length - 1 : index;\n selectedOptionIndex.current = nextIndex;\n\n if (items?.[nextIndex] && !items[nextIndex].hasAttribute('data-combobox-disabled')) {\n clearSelectedItem();\n items[nextIndex].setAttribute('data-combobox-selected', 'true');\n items[nextIndex].scrollIntoView({ block: 'nearest', behavior: scrollBehavior });\n return items[nextIndex].id;\n }\n\n return null;\n },\n [scrollBehavior, clearSelectedItem]\n );\n\n const selectActiveOption = useCallback(() => {\n const root = getRootElement(targetRef.current);\n const activeOption = findElementBySelector<HTMLDivElement>(\n `#${listId.current} [data-combobox-active]`,\n root\n );\n\n if (activeOption) {\n const items = findElementsBySelector<HTMLDivElement>(\n `#${listId.current} [data-combobox-option]`,\n root\n );\n const index = items.findIndex((option) => option === activeOption);\n return selectOption(index);\n }\n\n return selectOption(0);\n }, [selectOption]);\n\n const selectNextOption = useCallback(() => {\n const root = getRootElement(targetRef.current);\n const items = findElementsBySelector<HTMLDivElement>(\n `#${listId.current} [data-combobox-option]`,\n root\n );\n return selectOption(getNextIndex(selectedOptionIndex.current, items, loop));\n }, [selectOption, loop]);\n\n const selectPreviousOption = useCallback(() => {\n const root = getRootElement(targetRef.current);\n const items = findElementsBySelector<HTMLDivElement>(\n `#${listId.current} [data-combobox-option]`,\n root\n );\n return selectOption(getPreviousIndex(selectedOptionIndex.current, items, loop));\n }, [selectOption, loop]);\n\n const selectFirstOption = useCallback(() => {\n const root = getRootElement(targetRef.current);\n const items = findElementsBySelector<HTMLDivElement>(\n `#${listId.current} [data-combobox-option]`,\n root\n );\n return selectOption(getFirstIndex(items));\n }, [selectOption]);\n\n const updateSelectedOptionIndex: ComboboxStore['updateSelectedOptionIndex'] = useCallback(\n (target = 'selected', options) => {\n if (typeof target === 'number') {\n selectedOptionIndex.current = target;\n const root = getRootElement(targetRef.current);\n\n const items = findElementsBySelector<HTMLDivElement>(\n `#${listId.current} [data-combobox-option]`,\n root\n );\n\n if (options?.scrollIntoView) {\n items[target]?.scrollIntoView({ block: 'nearest', behavior: scrollBehavior });\n }\n return;\n }\n\n selectedIndexUpdateTimeout.current = window.setTimeout(() => {\n const root = getRootElement(targetRef.current);\n const items = findElementsBySelector<HTMLDivElement>(\n `#${listId.current} [data-combobox-option]`,\n root\n );\n const index = items.findIndex((option) => option.hasAttribute(`data-combobox-${target}`));\n\n selectedOptionIndex.current = index;\n\n if (options?.scrollIntoView) {\n items[index]?.scrollIntoView({ block: 'nearest', behavior: scrollBehavior });\n }\n }, 0);\n },\n []\n );\n\n const resetSelectedOption = useCallback(() => {\n selectedOptionIndex.current = -1;\n clearSelectedItem();\n }, [clearSelectedItem]);\n\n const clickSelectedOption = useCallback(() => {\n const root = getRootElement(targetRef.current);\n const items = findElementsBySelector<HTMLDivElement>(\n `#${listId.current} [data-combobox-option]`,\n root\n );\n const item = items?.[selectedOptionIndex.current];\n item?.click();\n }, []);\n\n const setListId = useCallback((id: string) => {\n listId.current = id;\n }, []);\n\n const focusSearchInput = useCallback(() => {\n focusSearchTimeout.current = window.setTimeout(() => searchRef.current?.focus(), 0);\n }, []);\n\n const focusTarget = useCallback(() => {\n focusTargetTimeout.current = window.setTimeout(() => targetRef.current?.focus(), 0);\n }, []);\n\n const getSelectedOptionIndex = useCallback(() => selectedOptionIndex.current, []);\n\n useEffect(\n () => () => {\n window.clearTimeout(focusSearchTimeout.current);\n window.clearTimeout(focusTargetTimeout.current);\n window.clearTimeout(selectedIndexUpdateTimeout.current);\n },\n []\n );\n\n return {\n dropdownOpened,\n openDropdown,\n closeDropdown,\n toggleDropdown,\n\n selectedOptionIndex: selectedOptionIndex.current,\n getSelectedOptionIndex,\n selectOption,\n selectFirstOption,\n selectActiveOption,\n selectNextOption,\n selectPreviousOption,\n resetSelectedOption,\n updateSelectedOptionIndex,\n\n listId: listId.current,\n setListId,\n clickSelectedOption,\n\n searchRef,\n focusSearchInput,\n\n targetRef,\n focusTarget,\n };\n}\n"],"mappings":"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"}
@@ -125,7 +125,6 @@ const ComboboxPopover = genericFactory((_props) => {
125
125
  onDropdownClose: () => {
126
126
  onDropdownClose?.();
127
127
  combobox.resetSelectedOption();
128
- if (searchable) combobox.focusTarget();
129
128
  }
130
129
  });
131
130
  const handleSearchChange = (val) => {
@@ -160,6 +159,7 @@ const ComboboxPopover = genericFactory((_props) => {
160
159
  unstyled,
161
160
  attributes,
162
161
  onOptionSubmit: handleOptionSubmit,
162
+ returnFocus: true,
163
163
  ...comboboxProps,
164
164
  ...others,
165
165
  children: [children, searchable ? /* @__PURE__ */ jsx(SearchableDropdown, {
@@ -1 +1 @@
1
- {"version":3,"file":"ComboboxPopover.mjs","names":["comboboxClasses"],"sources":["../../../src/components/ComboboxPopover/ComboboxPopover.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport cx from 'clsx';\nimport { useUncontrolled } from '@mantine/hooks';\nimport {\n Factory,\n genericFactory,\n Primitive,\n StylesApiProps,\n useProps,\n useResolvedStylesApi,\n} from '../../core';\nimport { CheckIcon } from '../Checkbox';\nimport {\n Combobox,\n ComboboxData,\n ComboboxItem,\n ComboboxLikeRenderOptionInput,\n ComboboxLikeStylesNames,\n ComboboxProps,\n defaultOptionsFilter,\n getOptionsLockup,\n getParsedComboboxData,\n isOptionsGroup,\n OptionsDropdown,\n OptionsFilter,\n useCombobox,\n} from '../Combobox';\nimport { ComboboxParsedItem } from '../Combobox/Combobox.types';\nimport { isEmptyComboboxData } from '../Combobox/OptionsDropdown/is-empty-combobox-data';\nimport { ScrollArea, ScrollAreaProps } from '../ScrollArea';\nimport { ComboboxPopoverValue } from './ComboboxPopover.types';\nimport { ComboboxPopoverTarget } from './ComboboxPopoverTarget';\nimport comboboxClasses from '../Combobox/Combobox.module.css';\n\nfunction isValueChecked(value: Primitive | Primitive[] | undefined | null, optionValue: Primitive) {\n return Array.isArray(value) ? value.includes(optionValue) : value === optionValue;\n}\n\ninterface OptionProps {\n data: ComboboxParsedItem<Primitive>;\n withCheckIcon?: boolean;\n withAlignedLabels?: boolean;\n value?: Primitive | Primitive[] | null;\n checkIconPosition?: 'left' | 'right';\n unstyled: boolean | undefined;\n renderOption?: (input: ComboboxLikeRenderOptionInput<any>) => React.ReactNode;\n}\n\nfunction Option({\n data,\n withCheckIcon,\n withAlignedLabels,\n value,\n checkIconPosition,\n unstyled,\n renderOption,\n}: OptionProps) {\n if (isOptionsGroup(data)) {\n const options = data.items.map((item) => (\n <Option\n data={item}\n value={value}\n key={`${item.value}`}\n unstyled={unstyled}\n withCheckIcon={withCheckIcon}\n withAlignedLabels={withAlignedLabels}\n checkIconPosition={checkIconPosition}\n renderOption={renderOption}\n />\n ));\n return <Combobox.Group label={data.group}>{options}</Combobox.Group>;\n }\n\n const checked = isValueChecked(value, data.value);\n const check =\n withCheckIcon &&\n (checked ? (\n <CheckIcon className={comboboxClasses.optionsDropdownCheckIcon} />\n ) : withAlignedLabels ? (\n <div className={comboboxClasses.optionsDropdownCheckPlaceholder} />\n ) : null);\n\n const defaultContent = (\n <>\n {checkIconPosition === 'left' && check}\n <span>{data.label}</span>\n {checkIconPosition === 'right' && check}\n </>\n );\n\n return (\n <Combobox.Option\n value={data.value}\n disabled={data.disabled}\n className={cx({ [comboboxClasses.optionsDropdownOption]: !unstyled })}\n data-reverse={checkIconPosition === 'right' || undefined}\n data-checked={checked || undefined}\n aria-selected={checked}\n active={checked}\n >\n {typeof renderOption === 'function'\n ? renderOption({ option: data, checked })\n : defaultContent}\n </Combobox.Option>\n );\n}\n\ninterface SearchableDropdownProps {\n data: ComboboxParsedItem<Primitive>[];\n filter: OptionsFilter<Primitive> | undefined;\n search: string;\n limit: number | undefined;\n nothingFoundMessage: React.ReactNode | undefined;\n withScrollArea: boolean | undefined;\n maxDropdownHeight: number | string | undefined;\n value: Primitive | Primitive[] | null;\n checkIconPosition: 'left' | 'right' | undefined;\n withCheckIcon: boolean | undefined;\n withAlignedLabels: boolean | undefined;\n unstyled: boolean | undefined;\n renderOption?: (input: ComboboxLikeRenderOptionInput<any>) => React.ReactNode;\n scrollAreaProps: ScrollAreaProps | undefined;\n onSearchChange: (event: React.ChangeEvent<HTMLInputElement>) => void;\n}\n\nfunction SearchableDropdown({\n data,\n filter,\n search,\n limit,\n nothingFoundMessage,\n withScrollArea = true,\n maxDropdownHeight,\n value,\n checkIconPosition,\n withCheckIcon = false,\n withAlignedLabels = false,\n unstyled,\n renderOption,\n scrollAreaProps,\n onSearchChange,\n}: SearchableDropdownProps) {\n const filteredData = (filter || defaultOptionsFilter)({\n options: data,\n search,\n limit: limit ?? Infinity,\n });\n const isEmpty = isEmptyComboboxData(filteredData);\n\n const options = filteredData.map((item, index) => (\n <Option\n data={item}\n key={\n isOptionsGroup(item)\n ? `group-${typeof item.group === 'string' ? item.group : index}`\n : `${item.value}`\n }\n withCheckIcon={withCheckIcon}\n withAlignedLabels={withAlignedLabels}\n value={value}\n checkIconPosition={checkIconPosition}\n unstyled={unstyled}\n renderOption={renderOption}\n />\n ));\n\n return (\n <Combobox.Dropdown data-composed>\n <Combobox.Search value={search} onChange={onSearchChange} placeholder=\"Search...\" />\n <Combobox.Options>\n {withScrollArea ? (\n <ScrollArea.Autosize\n mah={maxDropdownHeight ?? 220}\n type=\"scroll\"\n scrollbarSize=\"var(--combobox-padding)\"\n offsetScrollbars=\"y\"\n {...scrollAreaProps}\n >\n {options}\n </ScrollArea.Autosize>\n ) : (\n options\n )}\n {isEmpty && nothingFoundMessage && <Combobox.Empty>{nothingFoundMessage}</Combobox.Empty>}\n </Combobox.Options>\n </Combobox.Dropdown>\n );\n}\n\nexport type ComboboxPopoverStylesNames = ComboboxLikeStylesNames | 'search';\n\nexport interface ComboboxPopoverProps<\n Multiple extends boolean = false,\n Value extends Primitive = string,\n> extends StylesApiProps<ComboboxPopoverFactory> {\n /** If set, multiple items can be selected at the same time */\n multiple?: Multiple;\n\n /** Controlled component value */\n value?: ComboboxPopoverValue<Multiple, Value>;\n\n /** Uncontrolled component default value */\n defaultValue?: ComboboxPopoverValue<Multiple, Value>;\n\n /** Called when value changes */\n onChange?: (value: ComboboxPopoverValue<Multiple, Value>) => void;\n\n /** Data used to generate options */\n data?: ComboboxData<Value>;\n\n /** Controlled dropdown opened state */\n dropdownOpened?: boolean;\n\n /** Uncontrolled dropdown initial opened state */\n defaultDropdownOpened?: boolean;\n\n /** Called when dropdown opens */\n onDropdownOpen?: () => void;\n\n /** Called when dropdown closes */\n onDropdownClose?: () => void;\n\n /** Called when option is submitted from dropdown with mouse click or Enter key */\n onOptionSubmit?: (value: Value) => void;\n\n /** Props passed down to Combobox component */\n comboboxProps?: ComboboxProps;\n\n /** Function based on which items are filtered and sorted */\n filter?: OptionsFilter<Value>;\n\n /** Maximum number of options displayed at a time @default Infinity */\n limit?: number;\n\n /** Determines whether the options should be wrapped with ScrollArea.AutoSize @default true */\n withScrollArea?: boolean;\n\n /** max-height of the dropdown @default 250 */\n maxDropdownHeight?: number | string;\n\n /** If set, the first option is selected when dropdown opens @default false */\n selectFirstOptionOnDropdownOpen?: boolean;\n\n /** Displays check icon near the selected option label @default true */\n withCheckIcon?: boolean;\n\n /** Aligns unchecked labels with the checked one @default false */\n withAlignedLabels?: boolean;\n\n /** Position of the check icon relative to the option label @default 'left' */\n checkIconPosition?: 'left' | 'right';\n\n /** Message displayed when no options match the search query or when there is no data */\n nothingFoundMessage?: React.ReactNode;\n\n /** Allows searching through options @default false */\n searchable?: boolean;\n\n /** Controlled search value */\n searchValue?: string;\n\n /** Default search value */\n defaultSearchValue?: string;\n\n /** Called when search changes */\n onSearchChange?: (value: string) => void;\n\n /** Allows deselecting the selected option by clicking it (only for single mode) @default true */\n allowDeselect?: boolean;\n\n /** A function to render content of the option, replaces the default content of the option */\n renderOption?: (item: ComboboxLikeRenderOptionInput<ComboboxItem>) => React.ReactNode;\n\n /** Props passed down to the underlying ScrollArea component in the dropdown */\n scrollAreaProps?: ScrollAreaProps;\n\n /** Props passed down to the hidden input */\n hiddenInputProps?: Omit<React.ComponentProps<'input'>, 'value'>;\n\n /** Hidden input name for form submission */\n name?: string;\n\n /** Hidden input form for form submission */\n form?: string;\n\n /** Content of the component */\n children?: React.ReactNode;\n\n /** Divider used to separate values in the hidden input value attribute @default ',' */\n hiddenInputValuesDivider?: string;\n}\n\nexport type ComboboxPopoverFactory = Factory<{\n props: ComboboxPopoverProps;\n ref: HTMLDivElement;\n stylesNames: ComboboxPopoverStylesNames;\n signature: <Multiple extends boolean = false, Value extends Primitive = string>(\n props: ComboboxPopoverProps<Multiple, Value>\n ) => React.JSX.Element;\n staticComponents: {\n Target: typeof ComboboxPopoverTarget;\n };\n}>;\n\nconst defaultProps = {\n withCheckIcon: true,\n allowDeselect: true,\n checkIconPosition: 'left',\n hiddenInputValuesDivider: ',',\n} satisfies Partial<ComboboxPopoverProps>;\n\nexport const ComboboxPopover = genericFactory<ComboboxPopoverFactory>((_props) => {\n const props = useProps('ComboboxPopover', defaultProps as any, _props);\n const {\n classNames,\n styles,\n unstyled,\n vars,\n children,\n multiple,\n value,\n defaultValue,\n onChange,\n data,\n dropdownOpened,\n defaultDropdownOpened,\n onDropdownOpen,\n onDropdownClose,\n onOptionSubmit,\n comboboxProps,\n filter,\n limit,\n withScrollArea,\n maxDropdownHeight,\n selectFirstOptionOnDropdownOpen,\n withCheckIcon,\n withAlignedLabels,\n checkIconPosition,\n nothingFoundMessage,\n searchable,\n searchValue,\n defaultSearchValue,\n onSearchChange,\n allowDeselect,\n renderOption,\n scrollAreaProps,\n hiddenInputProps,\n name,\n form,\n hiddenInputValuesDivider,\n attributes,\n ...others\n } = props;\n\n const parsedData = useMemo(() => getParsedComboboxData(data), [data]);\n const optionsLockup = useMemo(() => getOptionsLockup(parsedData), [parsedData]);\n\n const [_value, setValue] = useUncontrolled({\n value,\n defaultValue,\n finalValue: multiple ? ([] as any) : null,\n onChange,\n });\n\n const [_searchValue, setSearchValue] = useUncontrolled({\n value: searchValue,\n defaultValue: defaultSearchValue,\n finalValue: '',\n onChange: onSearchChange,\n });\n\n const combobox = useCombobox({\n opened: dropdownOpened,\n defaultOpened: defaultDropdownOpened,\n onDropdownOpen: () => {\n onDropdownOpen?.();\n if (searchable) {\n combobox.focusSearchInput();\n }\n if (selectFirstOptionOnDropdownOpen) {\n combobox.selectFirstOption();\n }\n },\n onDropdownClose: () => {\n onDropdownClose?.();\n combobox.resetSelectedOption();\n if (searchable) {\n combobox.focusTarget();\n }\n },\n });\n\n const handleSearchChange = (val: string) => {\n setSearchValue(val);\n combobox.resetSelectedOption();\n };\n\n const { resolvedClassNames, resolvedStyles } = useResolvedStylesApi<ComboboxPopoverFactory>({\n props,\n styles,\n classNames,\n });\n\n const handleOptionSubmit = (val: string) => {\n onOptionSubmit?.(val as any);\n const option = optionsLockup[val];\n\n if (multiple) {\n const currentValue = Array.isArray(_value) ? _value : [];\n if (currentValue.includes(option.value)) {\n setValue(currentValue.filter((v: any) => v !== option.value) as any);\n } else {\n setValue([...currentValue, option.value] as any);\n }\n combobox.updateSelectedOptionIndex('selected');\n } else {\n const nextValue = allowDeselect && `${option.value}` === `${_value}` ? null : option.value;\n setValue(nextValue as any);\n combobox.closeDropdown();\n }\n\n if (searchable) {\n handleSearchChange('');\n }\n };\n\n return (\n <>\n <Combobox\n store={combobox}\n __staticSelector=\"ComboboxPopover\"\n classNames={resolvedClassNames}\n styles={resolvedStyles}\n unstyled={unstyled}\n attributes={attributes}\n onOptionSubmit={handleOptionSubmit}\n {...comboboxProps}\n {...others}\n >\n {children}\n {searchable ? (\n <SearchableDropdown\n data={parsedData as any}\n filter={filter as OptionsFilter<Primitive> | undefined}\n search={_searchValue}\n limit={limit}\n nothingFoundMessage={nothingFoundMessage}\n withScrollArea={withScrollArea}\n maxDropdownHeight={maxDropdownHeight}\n value={_value}\n checkIconPosition={checkIconPosition}\n withCheckIcon={withCheckIcon}\n withAlignedLabels={withAlignedLabels}\n unstyled={unstyled}\n renderOption={renderOption}\n scrollAreaProps={scrollAreaProps}\n onSearchChange={(event) => {\n handleSearchChange(event.currentTarget.value);\n }}\n />\n ) : (\n <OptionsDropdown\n data={parsedData as any}\n filter={filter as OptionsFilter<Primitive> | undefined}\n search={undefined}\n limit={limit}\n hiddenWhenEmpty={!nothingFoundMessage}\n withScrollArea={withScrollArea}\n maxDropdownHeight={maxDropdownHeight}\n filterOptions={false}\n value={_value}\n checkIconPosition={checkIconPosition}\n withCheckIcon={withCheckIcon}\n withAlignedLabels={withAlignedLabels}\n nothingFoundMessage={nothingFoundMessage}\n unstyled={unstyled}\n renderOption={renderOption}\n scrollAreaProps={scrollAreaProps}\n labelId={undefined}\n aria-label={undefined}\n />\n )}\n </Combobox>\n <Combobox.HiddenInput\n name={name}\n value={_value}\n form={form}\n valuesDivider={hiddenInputValuesDivider}\n {...hiddenInputProps}\n />\n </>\n );\n});\n\nComboboxPopover.classes = Combobox.classes;\nComboboxPopover.displayName = '@mantine/core/ComboboxPopover';\nComboboxPopover.Target = ComboboxPopoverTarget;\n"],"mappings":"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"}
1
+ {"version":3,"file":"ComboboxPopover.mjs","names":["comboboxClasses"],"sources":["../../../src/components/ComboboxPopover/ComboboxPopover.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport cx from 'clsx';\nimport { useUncontrolled } from '@mantine/hooks';\nimport {\n Factory,\n genericFactory,\n Primitive,\n StylesApiProps,\n useProps,\n useResolvedStylesApi,\n} from '../../core';\nimport { CheckIcon } from '../Checkbox';\nimport {\n Combobox,\n ComboboxData,\n ComboboxItem,\n ComboboxLikeRenderOptionInput,\n ComboboxLikeStylesNames,\n ComboboxProps,\n defaultOptionsFilter,\n getOptionsLockup,\n getParsedComboboxData,\n isOptionsGroup,\n OptionsDropdown,\n OptionsFilter,\n useCombobox,\n} from '../Combobox';\nimport { ComboboxParsedItem } from '../Combobox/Combobox.types';\nimport { isEmptyComboboxData } from '../Combobox/OptionsDropdown/is-empty-combobox-data';\nimport { ScrollArea, ScrollAreaProps } from '../ScrollArea';\nimport { ComboboxPopoverValue } from './ComboboxPopover.types';\nimport { ComboboxPopoverTarget } from './ComboboxPopoverTarget';\nimport comboboxClasses from '../Combobox/Combobox.module.css';\n\nfunction isValueChecked(value: Primitive | Primitive[] | undefined | null, optionValue: Primitive) {\n return Array.isArray(value) ? value.includes(optionValue) : value === optionValue;\n}\n\ninterface OptionProps {\n data: ComboboxParsedItem<Primitive>;\n withCheckIcon?: boolean;\n withAlignedLabels?: boolean;\n value?: Primitive | Primitive[] | null;\n checkIconPosition?: 'left' | 'right';\n unstyled: boolean | undefined;\n renderOption?: (input: ComboboxLikeRenderOptionInput<any>) => React.ReactNode;\n}\n\nfunction Option({\n data,\n withCheckIcon,\n withAlignedLabels,\n value,\n checkIconPosition,\n unstyled,\n renderOption,\n}: OptionProps) {\n if (isOptionsGroup(data)) {\n const options = data.items.map((item) => (\n <Option\n data={item}\n value={value}\n key={`${item.value}`}\n unstyled={unstyled}\n withCheckIcon={withCheckIcon}\n withAlignedLabels={withAlignedLabels}\n checkIconPosition={checkIconPosition}\n renderOption={renderOption}\n />\n ));\n return <Combobox.Group label={data.group}>{options}</Combobox.Group>;\n }\n\n const checked = isValueChecked(value, data.value);\n const check =\n withCheckIcon &&\n (checked ? (\n <CheckIcon className={comboboxClasses.optionsDropdownCheckIcon} />\n ) : withAlignedLabels ? (\n <div className={comboboxClasses.optionsDropdownCheckPlaceholder} />\n ) : null);\n\n const defaultContent = (\n <>\n {checkIconPosition === 'left' && check}\n <span>{data.label}</span>\n {checkIconPosition === 'right' && check}\n </>\n );\n\n return (\n <Combobox.Option\n value={data.value}\n disabled={data.disabled}\n className={cx({ [comboboxClasses.optionsDropdownOption]: !unstyled })}\n data-reverse={checkIconPosition === 'right' || undefined}\n data-checked={checked || undefined}\n aria-selected={checked}\n active={checked}\n >\n {typeof renderOption === 'function'\n ? renderOption({ option: data, checked })\n : defaultContent}\n </Combobox.Option>\n );\n}\n\ninterface SearchableDropdownProps {\n data: ComboboxParsedItem<Primitive>[];\n filter: OptionsFilter<Primitive> | undefined;\n search: string;\n limit: number | undefined;\n nothingFoundMessage: React.ReactNode | undefined;\n withScrollArea: boolean | undefined;\n maxDropdownHeight: number | string | undefined;\n value: Primitive | Primitive[] | null;\n checkIconPosition: 'left' | 'right' | undefined;\n withCheckIcon: boolean | undefined;\n withAlignedLabels: boolean | undefined;\n unstyled: boolean | undefined;\n renderOption?: (input: ComboboxLikeRenderOptionInput<any>) => React.ReactNode;\n scrollAreaProps: ScrollAreaProps | undefined;\n onSearchChange: (event: React.ChangeEvent<HTMLInputElement>) => void;\n}\n\nfunction SearchableDropdown({\n data,\n filter,\n search,\n limit,\n nothingFoundMessage,\n withScrollArea = true,\n maxDropdownHeight,\n value,\n checkIconPosition,\n withCheckIcon = false,\n withAlignedLabels = false,\n unstyled,\n renderOption,\n scrollAreaProps,\n onSearchChange,\n}: SearchableDropdownProps) {\n const filteredData = (filter || defaultOptionsFilter)({\n options: data,\n search,\n limit: limit ?? Infinity,\n });\n const isEmpty = isEmptyComboboxData(filteredData);\n\n const options = filteredData.map((item, index) => (\n <Option\n data={item}\n key={\n isOptionsGroup(item)\n ? `group-${typeof item.group === 'string' ? item.group : index}`\n : `${item.value}`\n }\n withCheckIcon={withCheckIcon}\n withAlignedLabels={withAlignedLabels}\n value={value}\n checkIconPosition={checkIconPosition}\n unstyled={unstyled}\n renderOption={renderOption}\n />\n ));\n\n return (\n <Combobox.Dropdown data-composed>\n <Combobox.Search value={search} onChange={onSearchChange} placeholder=\"Search...\" />\n <Combobox.Options>\n {withScrollArea ? (\n <ScrollArea.Autosize\n mah={maxDropdownHeight ?? 220}\n type=\"scroll\"\n scrollbarSize=\"var(--combobox-padding)\"\n offsetScrollbars=\"y\"\n {...scrollAreaProps}\n >\n {options}\n </ScrollArea.Autosize>\n ) : (\n options\n )}\n {isEmpty && nothingFoundMessage && <Combobox.Empty>{nothingFoundMessage}</Combobox.Empty>}\n </Combobox.Options>\n </Combobox.Dropdown>\n );\n}\n\nexport type ComboboxPopoverStylesNames = ComboboxLikeStylesNames | 'search';\n\nexport interface ComboboxPopoverProps<\n Multiple extends boolean = false,\n Value extends Primitive = string,\n> extends StylesApiProps<ComboboxPopoverFactory> {\n /** If set, multiple items can be selected at the same time */\n multiple?: Multiple;\n\n /** Controlled component value */\n value?: ComboboxPopoverValue<Multiple, Value>;\n\n /** Uncontrolled component default value */\n defaultValue?: ComboboxPopoverValue<Multiple, Value>;\n\n /** Called when value changes */\n onChange?: (value: ComboboxPopoverValue<Multiple, Value>) => void;\n\n /** Data used to generate options */\n data?: ComboboxData<Value>;\n\n /** Controlled dropdown opened state */\n dropdownOpened?: boolean;\n\n /** Uncontrolled dropdown initial opened state */\n defaultDropdownOpened?: boolean;\n\n /** Called when dropdown opens */\n onDropdownOpen?: () => void;\n\n /** Called when dropdown closes */\n onDropdownClose?: () => void;\n\n /** Called when option is submitted from dropdown with mouse click or Enter key */\n onOptionSubmit?: (value: Value) => void;\n\n /** Props passed down to Combobox component */\n comboboxProps?: ComboboxProps;\n\n /** Function based on which items are filtered and sorted */\n filter?: OptionsFilter<Value>;\n\n /** Maximum number of options displayed at a time @default Infinity */\n limit?: number;\n\n /** Determines whether the options should be wrapped with ScrollArea.AutoSize @default true */\n withScrollArea?: boolean;\n\n /** max-height of the dropdown @default 250 */\n maxDropdownHeight?: number | string;\n\n /** If set, the first option is selected when dropdown opens @default false */\n selectFirstOptionOnDropdownOpen?: boolean;\n\n /** Displays check icon near the selected option label @default true */\n withCheckIcon?: boolean;\n\n /** Aligns unchecked labels with the checked one @default false */\n withAlignedLabels?: boolean;\n\n /** Position of the check icon relative to the option label @default 'left' */\n checkIconPosition?: 'left' | 'right';\n\n /** Message displayed when no options match the search query or when there is no data */\n nothingFoundMessage?: React.ReactNode;\n\n /** Allows searching through options @default false */\n searchable?: boolean;\n\n /** Controlled search value */\n searchValue?: string;\n\n /** Default search value */\n defaultSearchValue?: string;\n\n /** Called when search changes */\n onSearchChange?: (value: string) => void;\n\n /** Allows deselecting the selected option by clicking it (only for single mode) @default true */\n allowDeselect?: boolean;\n\n /** A function to render content of the option, replaces the default content of the option */\n renderOption?: (item: ComboboxLikeRenderOptionInput<ComboboxItem>) => React.ReactNode;\n\n /** Props passed down to the underlying ScrollArea component in the dropdown */\n scrollAreaProps?: ScrollAreaProps;\n\n /** Props passed down to the hidden input */\n hiddenInputProps?: Omit<React.ComponentProps<'input'>, 'value'>;\n\n /** Hidden input name for form submission */\n name?: string;\n\n /** Hidden input form for form submission */\n form?: string;\n\n /** Content of the component */\n children?: React.ReactNode;\n\n /** Divider used to separate values in the hidden input value attribute @default ',' */\n hiddenInputValuesDivider?: string;\n}\n\nexport type ComboboxPopoverFactory = Factory<{\n props: ComboboxPopoverProps;\n ref: HTMLDivElement;\n stylesNames: ComboboxPopoverStylesNames;\n signature: <Multiple extends boolean = false, Value extends Primitive = string>(\n props: ComboboxPopoverProps<Multiple, Value>\n ) => React.JSX.Element;\n staticComponents: {\n Target: typeof ComboboxPopoverTarget;\n };\n}>;\n\nconst defaultProps = {\n withCheckIcon: true,\n allowDeselect: true,\n checkIconPosition: 'left',\n hiddenInputValuesDivider: ',',\n} satisfies Partial<ComboboxPopoverProps>;\n\nexport const ComboboxPopover = genericFactory<ComboboxPopoverFactory>((_props) => {\n const props = useProps('ComboboxPopover', defaultProps as any, _props);\n const {\n classNames,\n styles,\n unstyled,\n vars,\n children,\n multiple,\n value,\n defaultValue,\n onChange,\n data,\n dropdownOpened,\n defaultDropdownOpened,\n onDropdownOpen,\n onDropdownClose,\n onOptionSubmit,\n comboboxProps,\n filter,\n limit,\n withScrollArea,\n maxDropdownHeight,\n selectFirstOptionOnDropdownOpen,\n withCheckIcon,\n withAlignedLabels,\n checkIconPosition,\n nothingFoundMessage,\n searchable,\n searchValue,\n defaultSearchValue,\n onSearchChange,\n allowDeselect,\n renderOption,\n scrollAreaProps,\n hiddenInputProps,\n name,\n form,\n hiddenInputValuesDivider,\n attributes,\n ...others\n } = props;\n\n const parsedData = useMemo(() => getParsedComboboxData(data), [data]);\n const optionsLockup = useMemo(() => getOptionsLockup(parsedData), [parsedData]);\n\n const [_value, setValue] = useUncontrolled({\n value,\n defaultValue,\n finalValue: multiple ? ([] as any) : null,\n onChange,\n });\n\n const [_searchValue, setSearchValue] = useUncontrolled({\n value: searchValue,\n defaultValue: defaultSearchValue,\n finalValue: '',\n onChange: onSearchChange,\n });\n\n const combobox = useCombobox({\n opened: dropdownOpened,\n defaultOpened: defaultDropdownOpened,\n onDropdownOpen: () => {\n onDropdownOpen?.();\n if (searchable) {\n combobox.focusSearchInput();\n }\n if (selectFirstOptionOnDropdownOpen) {\n combobox.selectFirstOption();\n }\n },\n onDropdownClose: () => {\n onDropdownClose?.();\n combobox.resetSelectedOption();\n },\n });\n\n const handleSearchChange = (val: string) => {\n setSearchValue(val);\n combobox.resetSelectedOption();\n };\n\n const { resolvedClassNames, resolvedStyles } = useResolvedStylesApi<ComboboxPopoverFactory>({\n props,\n styles,\n classNames,\n });\n\n const handleOptionSubmit = (val: string) => {\n onOptionSubmit?.(val as any);\n const option = optionsLockup[val];\n\n if (multiple) {\n const currentValue = Array.isArray(_value) ? _value : [];\n if (currentValue.includes(option.value)) {\n setValue(currentValue.filter((v: any) => v !== option.value) as any);\n } else {\n setValue([...currentValue, option.value] as any);\n }\n combobox.updateSelectedOptionIndex('selected');\n } else {\n const nextValue = allowDeselect && `${option.value}` === `${_value}` ? null : option.value;\n setValue(nextValue as any);\n combobox.closeDropdown();\n }\n\n if (searchable) {\n handleSearchChange('');\n }\n };\n\n return (\n <>\n <Combobox\n store={combobox}\n __staticSelector=\"ComboboxPopover\"\n classNames={resolvedClassNames}\n styles={resolvedStyles}\n unstyled={unstyled}\n attributes={attributes}\n onOptionSubmit={handleOptionSubmit}\n returnFocus\n {...comboboxProps}\n {...others}\n >\n {children}\n {searchable ? (\n <SearchableDropdown\n data={parsedData as any}\n filter={filter as OptionsFilter<Primitive> | undefined}\n search={_searchValue}\n limit={limit}\n nothingFoundMessage={nothingFoundMessage}\n withScrollArea={withScrollArea}\n maxDropdownHeight={maxDropdownHeight}\n value={_value}\n checkIconPosition={checkIconPosition}\n withCheckIcon={withCheckIcon}\n withAlignedLabels={withAlignedLabels}\n unstyled={unstyled}\n renderOption={renderOption}\n scrollAreaProps={scrollAreaProps}\n onSearchChange={(event) => {\n handleSearchChange(event.currentTarget.value);\n }}\n />\n ) : (\n <OptionsDropdown\n data={parsedData as any}\n filter={filter as OptionsFilter<Primitive> | undefined}\n search={undefined}\n limit={limit}\n hiddenWhenEmpty={!nothingFoundMessage}\n withScrollArea={withScrollArea}\n maxDropdownHeight={maxDropdownHeight}\n filterOptions={false}\n value={_value}\n checkIconPosition={checkIconPosition}\n withCheckIcon={withCheckIcon}\n withAlignedLabels={withAlignedLabels}\n nothingFoundMessage={nothingFoundMessage}\n unstyled={unstyled}\n renderOption={renderOption}\n scrollAreaProps={scrollAreaProps}\n labelId={undefined}\n aria-label={undefined}\n />\n )}\n </Combobox>\n <Combobox.HiddenInput\n name={name}\n value={_value}\n form={form}\n valuesDivider={hiddenInputValuesDivider}\n {...hiddenInputProps}\n />\n </>\n );\n});\n\nComboboxPopover.classes = Combobox.classes;\nComboboxPopover.displayName = '@mantine/core/ComboboxPopover';\nComboboxPopover.Target = ComboboxPopoverTarget;\n"],"mappings":"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"}
@@ -8,6 +8,8 @@ import { useStyles } from "../../core/styles-api/use-styles/use-styles.mjs";
8
8
  import { genericFactory } from "../../core/factory/factory.mjs";
9
9
  import { UnstyledButton } from "../UnstyledButton/UnstyledButton.mjs";
10
10
  import { InputBase } from "../InputBase/InputBase.mjs";
11
+ import { getCaretPositionAfterPaste } from "./get-caret-position-after-paste/get-caret-position-after-paste.mjs";
12
+ import { normalizePastedValue } from "./normalize-pasted-value/normalize-pasted-value.mjs";
11
13
  import { NumberInputChevron } from "./NumberInputChevron.mjs";
12
14
  import NumberInput_module_default from "./NumberInput.module.mjs";
13
15
  import { useRef } from "react";
@@ -80,16 +82,18 @@ const defaultProps = {
80
82
  allowedDecimalSeparators: [".", ","]
81
83
  };
82
84
  const varsResolver = createVarsResolver((_, { size }) => ({ controls: { "--ni-chevron-size": getSize(size, "ni-chevron-size") } }));
83
- function clampAndSanitizeInput(sanitizedValue, max, min) {
84
- const stringValue = sanitizedValue.toString();
85
- const hasTrailingDecimalSeparator = trailingDecimalSeparatorPattern.test(stringValue);
86
- const replaced = stringValue.replace(/^0+(?=\d)/, "");
87
- const parsedValue = parseFloat(replaced);
88
- if (Number.isNaN(parsedValue)) return replaced;
89
- if (parsedValue > Number.MAX_SAFE_INTEGER) return max !== void 0 ? max : replaced;
90
- const clamped = clamp(parsedValue, min, max);
91
- if (hasTrailingDecimalSeparator) return `${clamped.toString().replace(/^0+(?=\d)/, "")}.`;
92
- return clamped;
85
+ function withTrailingSeparator(value, hasTrailingDecimalSeparator) {
86
+ return hasTrailingDecimalSeparator ? `${value}.` : value;
87
+ }
88
+ function sanitizeInputOnBlur(value, options) {
89
+ const hasTrailingDecimalSeparator = trailingDecimalSeparatorPattern.test(value);
90
+ const trimmed = options.trim ? value.replace(/^0+(?=\d)/, "") : value;
91
+ const parsedValue = parseFloat(trimmed);
92
+ if (Number.isNaN(parsedValue)) return trimmed;
93
+ if (!options.clamp) return options.trim ? withTrailingSeparator(parsedValue, hasTrailingDecimalSeparator) : value;
94
+ const clamped = parsedValue > Number.MAX_SAFE_INTEGER && options.max !== void 0 ? options.max : clamp(parsedValue, options.min, options.max);
95
+ if (!options.trim && clamped === parsedValue) return value;
96
+ return withTrailingSeparator(clamped, hasTrailingDecimalSeparator);
93
97
  }
94
98
  function clampAndSanitizeBigIntInput(sanitizedValue, options) {
95
99
  if (sanitizedValue === "" || sanitizedValue === "-") return sanitizedValue;
@@ -268,13 +272,15 @@ const NumberInput = genericFactory((_props) => {
268
272
  const handlePaste = (event) => {
269
273
  const pastedText = event.clipboardData.getData("text");
270
274
  const _decimalSeparator = others.decimalSeparator || ".";
271
- const separatorsToReplace = (allowedDecimalSeparators || [".", ","]).filter((s) => s !== _decimalSeparator);
272
- if (separatorsToReplace.some((s) => pastedText.includes(s))) {
275
+ const _thousandSeparator = others.thousandSeparator === true ? "," : others.thousandSeparator === false ? void 0 : others.thousandSeparator;
276
+ const modifiedText = normalizePastedValue(pastedText, {
277
+ decimalSeparator: _decimalSeparator,
278
+ thousandSeparator: _thousandSeparator,
279
+ allowedDecimalSeparators: allowedDecimalSeparators || [".", ","],
280
+ thousandsGroupStyle: others.thousandsGroupStyle
281
+ });
282
+ if (modifiedText !== pastedText) {
273
283
  event.preventDefault();
274
- let modifiedText = pastedText;
275
- separatorsToReplace.forEach((s) => {
276
- modifiedText = modifiedText.split(s).join(_decimalSeparator);
277
- });
278
284
  const input = inputRef.current;
279
285
  if (input) {
280
286
  const start = input.selectionStart ?? 0;
@@ -283,8 +289,8 @@ const NumberInput = genericFactory((_props) => {
283
289
  const newValue = currentValue.substring(0, start) + modifiedText + currentValue.substring(end);
284
290
  (Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value")?.set)?.call(input, newValue);
285
291
  input.dispatchEvent(new Event("change", { bubbles: true }));
286
- const cursorPos = start + modifiedText.length;
287
- setTimeout(() => adjustCursor(cursorPos), 0);
292
+ const rawCaret = start + modifiedText.length;
293
+ setTimeout(() => adjustCursor(getCaretPositionAfterPaste(newValue, rawCaret, input.value, _decimalSeparator)), 0);
288
294
  }
289
295
  }
290
296
  others.onPaste?.(event);
@@ -324,10 +330,14 @@ const NumberInput = genericFactory((_props) => {
324
330
  max: maxBigInt,
325
331
  clampBehavior
326
332
  });
327
- } else {
328
- if (clampBehavior === "blur" && typeof sanitizedValue === "number") sanitizedValue = clamp(sanitizedValue, minNumber, maxNumber);
329
- if (trimLeadingZeroesOnBlur && typeof sanitizedValue === "string" && getDecimalPlaces(sanitizedValue) < 15) sanitizedValue = clampAndSanitizeInput(sanitizedValue, maxNumber, minNumber);
330
- }
333
+ } else if (typeof sanitizedValue === "number") {
334
+ if (clampBehavior === "blur") sanitizedValue = clamp(sanitizedValue, minNumber, maxNumber);
335
+ } else if (typeof sanitizedValue === "string") sanitizedValue = sanitizeInputOnBlur(sanitizedValue, {
336
+ min: minNumber,
337
+ max: maxNumber,
338
+ trim: !!trimLeadingZeroesOnBlur && getDecimalPlaces(sanitizedValue) < 15,
339
+ clamp: clampBehavior === "blur"
340
+ });
331
341
  if (_value !== sanitizedValue) setValue(sanitizedValue);
332
342
  onBlur?.(event);
333
343
  };
@@ -1 +1 @@
1
- {"version":3,"file":"NumberInput.mjs","names":["classes"],"sources":["../../../src/components/NumberInput/NumberInput.tsx"],"sourcesContent":["import React, { useRef } from 'react';\nimport cx from 'clsx';\nimport { NumberFormatValues, NumericFormat, OnValueChange } from 'react-number-format';\nimport { assignRef, clamp, useMergedRef, useUncontrolled } from '@mantine/hooks';\nimport {\n BoxProps,\n createVarsResolver,\n ElementProps,\n Factory,\n genericFactory,\n getSize,\n noop,\n StylesApiProps,\n useProps,\n useResolvedStylesApi,\n useStyles,\n} from '../../core';\nimport { __BaseInputProps, __InputStylesNames, InputVariant } from '../Input';\nimport { InputBase } from '../InputBase';\nimport { UnstyledButton } from '../UnstyledButton';\nimport { NumberInputChevron } from './NumberInputChevron';\nimport classes from './NumberInput.module.css';\n\n// Re for negative -0, -0., -0.0, -0.00, -0.000 ... strings\n// And for positive 0., 0.0, 0.00, 0.000 ... strings\nconst leadingDecimalZeroPattern = /^(0\\.0*|-0(\\.0*)?)$/;\n\n// Re for 01, 006, 00.02, -0010, -000.293 ... and negative counterparts\nconst leadingZerosPattern = /^-?0\\d+(\\.\\d+)?\\.?$/;\n\n// Re for decimal numbers with trailing zeros like 13.0, 13.00, 5.10 ... strings\nconst trailingZerosPattern = /\\.\\d*0$/;\n\n// Re for numbers with trailing decimal separator like 10. or -3.\nconst trailingDecimalSeparatorPattern = /^-?\\d+\\.$/;\n\nexport interface NumberInputHandlers {\n increment: () => void;\n decrement: () => void;\n}\n\nexport type NumberInputMode = 'number' | 'bigint';\nexport type NumberInputNumericType = number | bigint;\nexport type NumberInputValue<T extends NumberInputNumericType = number> = T | string;\ntype NumberInputNumericValue<T extends NumberInputNumericType = number> = T;\ntype InternalNumberInputValue = string | number | bigint;\n\nfunction isNumberString(value: unknown) {\n return typeof value === 'string' && value !== '' && !Number.isNaN(Number(value));\n}\n\nfunction isBigIntValue(value: unknown): value is bigint {\n return typeof value === 'bigint';\n}\n\nfunction canStep(value: number | string) {\n if (typeof value === 'number') {\n return value < Number.MAX_SAFE_INTEGER;\n }\n\n return value === '' || (isNumberString(value) && Number(value) < Number.MAX_SAFE_INTEGER);\n}\n\nfunction isValidBigIntString(value: string, allowNegative: boolean) {\n if (value === '') {\n return false;\n }\n\n if (value === '-') {\n return false;\n }\n\n if (!allowNegative && value.startsWith('-')) {\n return false;\n }\n\n return /^-?\\d+$/.test(value);\n}\n\nfunction canStepBigInt(value: bigint | string, allowNegative: boolean) {\n if (typeof value === 'bigint') {\n return true;\n }\n\n return value === '' || isValidBigIntString(value, allowNegative);\n}\n\nfunction parseBigIntFromString(value: string): bigint | null {\n if (!/^-?\\d+$/.test(value)) {\n return null;\n }\n\n try {\n return BigInt(value);\n } catch {\n return null;\n }\n}\n\nfunction toBigIntOrUndefined(value: unknown): bigint | undefined {\n if (typeof value === 'bigint') {\n return value;\n }\n\n if (typeof value === 'number' && Number.isFinite(value) && Number.isInteger(value)) {\n return BigInt(value);\n }\n\n return undefined;\n}\n\nfunction clampBigInt(value: bigint, min?: bigint, max?: bigint) {\n if (min !== undefined && value < min) {\n return min;\n }\n\n if (max !== undefined && value > max) {\n return max;\n }\n\n return value;\n}\n\nfunction getTotalDigits(inputValue: string | number): number {\n // All digits must be counted, parseFloat precision depends\n // on the number of digits in the input, not only on the decimal scale\n return inputValue.toString().replace('.', '').length;\n}\n\nfunction isValidNumber(floatValue: number | undefined, value: string): floatValue is number {\n return (\n (typeof floatValue === 'number'\n ? floatValue < Number.MAX_SAFE_INTEGER\n : !Number.isNaN(Number(floatValue))) &&\n !Number.isNaN(floatValue) &&\n getTotalDigits(value) < 14 &&\n value !== ''\n );\n}\n\nfunction isInRange(value: number | undefined, min: number | undefined, max: number | undefined) {\n if (value === undefined) {\n return true;\n }\n\n const minValid = min === undefined || value >= min;\n const maxValid = max === undefined || value <= max;\n\n return minValid && maxValid;\n}\n\nexport type NumberInputStylesNames = 'controls' | 'control' | __InputStylesNames;\nexport type NumberInputCssVariables = {\n controls: '--ni-chevron-size';\n};\n\nexport interface NumberInputProps<T extends NumberInputNumericType = number>\n extends\n BoxProps,\n Omit<__BaseInputProps, 'pointer'>,\n StylesApiProps<NumberInputFactory>,\n ElementProps<\n 'input',\n 'size' | 'type' | 'onChange' | 'value' | 'defaultValue' | 'min' | 'max' | 'step'\n > {\n /** Controlled component value */\n value?: NumberInputValue<T>;\n\n /** Uncontrolled component default value */\n defaultValue?: NumberInputValue<T>;\n\n /** Called when value changes */\n onChange?: (value: NumberInputValue<T>) => void;\n\n /** Called when value changes with `react-number-format` payload */\n onValueChange?: OnValueChange;\n\n /** Determines whether leading zeros are allowed during input. If `false`, leading zeros are removed as you type (e.g., typing `007` results in `7`). Works in conjunction with `trimLeadingZeroesOnBlur`. @default true */\n allowLeadingZeros?: boolean;\n\n /** Determines whether negative numbers are allowed. If `false`, the input will not accept negative values, and the decrement button will stop at `0` (when `min` is not set). @default true */\n allowNegative?: boolean;\n\n /** Characters which when pressed result in a decimal separator. These characters will be replaced by the `decimalSeparator` in the input value. @default ['.', ','] */\n allowedDecimalSeparators?: string[];\n\n /** Limits the number of digits that can be entered after the decimal point @default Infinity */\n decimalScale?: number;\n\n /** Character used as a decimal separator. Generally used with `allowedDecimalSeparators` prop. @default '.' */\n decimalSeparator?: string;\n\n /** If `true`, automatically pads the decimal part with zeros to match `decimalScale` (e.g., with `decimalScale={2}`, typing `5.1` displays as `5.10`). Requires `decimalScale` to be set. @default false */\n fixedDecimalScale?: boolean;\n\n /** Prefix added before the input value */\n prefix?: string;\n\n /** Suffix added after the input value */\n suffix?: string;\n\n /** Defines the thousand grouping style. 'thousand' (1,000), 'lakh' (1,00,000), 'wan' (1,0000), 'none'. */\n thousandsGroupStyle?: 'thousand' | 'lakh' | 'wan' | 'none';\n\n /** A function to validate the input value. If this function returns `false`, the `onChange` will not be called and the input value will not change. */\n isAllowed?: (values: NumberFormatValues) => boolean;\n\n /** Advanced: Set to `true` if you're passing numeric strings (e.g., `\"12345\"`) and using formatting props like `prefix` or `suffix`. In most cases, you don't need this prop. See [react-number-format docs](https://www.npmjs.com/package/react-number-format) for details. @default false */\n valueIsNumericString?: boolean;\n\n /** Controls input `type` attribute @default 'text' */\n type?: 'text' | 'tel' | 'password';\n\n /** A character used to separate thousands */\n thousandSeparator?: string | boolean;\n\n /** Minimum possible value */\n min?: NumberInputNumericValue<T>;\n\n /** Maximum possible value */\n max?: NumberInputNumericValue<T>;\n\n /** Number by which value will be incremented/decremented with up/down controls and keyboard arrows @default 1 */\n step?: NumberInputNumericValue<T>;\n\n /** If set, the up/down controls are hidden @default false */\n hideControls?: boolean;\n\n /** Controls how values are clamped to the `min`/`max` range:\n * - `'blur'` (default): User can type any value, but it's clamped when the input loses focus\n * - `'strict'`: User cannot type values outside the range\n * - `'none'`: No clamping; `min`/`max` only apply to increment/decrement controls and arrow keys\n */\n clampBehavior?: 'strict' | 'blur' | 'none';\n\n /** If set, decimal values are allowed @default true */\n allowDecimal?: boolean;\n\n /** Increment/decrement handlers */\n handlersRef?: React.Ref<NumberInputHandlers | undefined>;\n\n /** Value used when incrementing/decrementing an empty input. If `min` is set and `startValue < min`, `min` is used instead. @default 0 */\n startValue?: NumberInputNumericValue<T>;\n\n /** Interval in milliseconds between value steps when increment/decrement button is held down. Can be a number or a function `(stepCount) => number` for dynamic intervals. Requires `stepHoldDelay` to be set. @default undefined */\n stepHoldInterval?: number | ((stepCount: number) => number);\n\n /** Initial delay in milliseconds before stepping the value. */\n stepHoldDelay?: number;\n\n /** If set, up/down keyboard events increment/decrement value @default true */\n withKeyboardEvents?: boolean;\n\n /** If set, leading zeros are removed on blur. For example, `00100` -> `100` @default true */\n trimLeadingZeroesOnBlur?: boolean;\n\n /** If set, all text is selected when the input receives focus @default false */\n selectAllOnFocus?: boolean;\n\n /** Called when the increment button or arrow up key is pressed and the value has reached the maximum */\n onMinReached?: () => void;\n\n /** Called when the decrement button or arrow down key is pressed and the value has reached the minimum */\n onMaxReached?: () => void;\n}\n\nexport type NumberInputFactory = Factory<{\n props: NumberInputProps;\n ref: HTMLInputElement;\n stylesNames: NumberInputStylesNames;\n vars: NumberInputCssVariables;\n variant: InputVariant;\n signature: <T extends NumberInputNumericType = number>(\n props: NumberInputProps<T>\n ) => React.JSX.Element;\n}>;\n\nconst defaultProps = {\n size: 'sm',\n step: 1,\n clampBehavior: 'blur',\n allowDecimal: true,\n allowNegative: true,\n withKeyboardEvents: true,\n allowLeadingZeros: true,\n trimLeadingZeroesOnBlur: true,\n startValue: 0,\n allowedDecimalSeparators: ['.', ','],\n} satisfies Partial<NumberInputProps<number | bigint>>;\n\nconst varsResolver = createVarsResolver<NumberInputFactory>((_, { size }) => ({\n controls: {\n '--ni-chevron-size': getSize(size, 'ni-chevron-size'),\n },\n}));\n\nfunction clampAndSanitizeInput(sanitizedValue: string | number, max?: number, min?: number) {\n const stringValue = sanitizedValue.toString();\n const hasTrailingDecimalSeparator = trailingDecimalSeparatorPattern.test(stringValue);\n\n const replaced = stringValue.replace(/^0+(?=\\d)/, '');\n const parsedValue = parseFloat(replaced);\n\n if (Number.isNaN(parsedValue)) {\n return replaced;\n }\n\n if (parsedValue > Number.MAX_SAFE_INTEGER) {\n return max !== undefined ? max : replaced;\n }\n\n const clamped = clamp(parsedValue, min, max);\n\n if (hasTrailingDecimalSeparator) {\n const clampedString = clamped.toString().replace(/^0+(?=\\d)/, '');\n return `${clampedString}.`;\n }\n\n return clamped;\n}\n\nfunction clampAndSanitizeBigIntInput(\n sanitizedValue: string,\n options: { min?: bigint; max?: bigint; clampBehavior: NumberInputProps['clampBehavior'] }\n) {\n if (sanitizedValue === '' || sanitizedValue === '-') {\n return sanitizedValue;\n }\n\n const parsed = parseBigIntFromString(sanitizedValue);\n\n if (parsed === null) {\n return sanitizedValue;\n }\n\n return options.clampBehavior === 'blur' ? clampBigInt(parsed, options.min, options.max) : parsed;\n}\n\nexport const NumberInput = genericFactory<NumberInputFactory>(\n <T extends NumberInputNumericType = number>(_props: NumberInputProps<T>) => {\n const props = useProps(\n ['Input', 'InputWrapper', 'NumberInput'],\n defaultProps as Partial<NumberInputProps>,\n _props as unknown as NumberInputProps\n );\n const {\n className,\n classNames,\n styles,\n unstyled,\n vars,\n onChange,\n onValueChange,\n value,\n defaultValue,\n max,\n min,\n step,\n hideControls,\n rightSection,\n isAllowed,\n clampBehavior,\n onBlur,\n allowDecimal,\n decimalScale,\n onKeyDown,\n onKeyDownCapture,\n handlersRef,\n startValue,\n disabled,\n rightSectionPointerEvents,\n allowNegative,\n readOnly,\n size,\n rightSectionWidth,\n stepHoldInterval,\n stepHoldDelay,\n allowLeadingZeros,\n withKeyboardEvents,\n trimLeadingZeroesOnBlur,\n allowedDecimalSeparators,\n selectAllOnFocus,\n onMinReached,\n onMaxReached,\n onFocus,\n attributes,\n ref,\n ...others\n } = props;\n const allowNegativeResolved = allowNegative ?? true;\n const allowLeadingZerosResolved = allowLeadingZeros ?? true;\n\n const getStyles = useStyles<NumberInputFactory>({\n name: 'NumberInput',\n classes,\n props: props as NumberInputProps,\n classNames,\n styles,\n unstyled,\n attributes,\n vars,\n varsResolver,\n });\n\n const { resolvedClassNames, resolvedStyles } = useResolvedStylesApi<NumberInputFactory>({\n classNames,\n styles,\n props: props as NumberInputProps,\n });\n\n const valueModeRef = useRef<NumberInputMode>(\n isBigIntValue(value) || isBigIntValue(defaultValue) ? 'bigint' : 'number'\n );\n\n if (isBigIntValue(value)) {\n valueModeRef.current = 'bigint';\n } else if (typeof value === 'number') {\n valueModeRef.current = 'number';\n }\n\n const isBigIntMode = valueModeRef.current === 'bigint';\n\n const [_value, setValue] = useUncontrolled<InternalNumberInputValue>({\n value: value as InternalNumberInputValue | undefined,\n defaultValue: defaultValue as InternalNumberInputValue | undefined,\n finalValue: '',\n onChange: onChange as ((value: InternalNumberInputValue) => void) | undefined,\n });\n\n const shouldUseStepInterval = stepHoldDelay !== undefined && stepHoldInterval !== undefined;\n const inputRef = useRef<HTMLInputElement>(null);\n const onStepTimeoutRef = useRef<number | null>(null);\n const stepCountRef = useRef<number>(0);\n\n const minNumber = typeof min === 'number' ? min : undefined;\n const maxNumber = typeof max === 'number' ? max : undefined;\n const stepNumber = typeof step === 'number' ? step : defaultProps.step;\n const startValueNumber = typeof startValue === 'number' ? startValue : defaultProps.startValue;\n\n const minBigInt = toBigIntOrUndefined(min);\n const maxBigInt = toBigIntOrUndefined(max);\n const stepBigInt = toBigIntOrUndefined(step) ?? BigInt(1);\n const startValueBigInt = toBigIntOrUndefined(startValue) ?? BigInt(0);\n\n const parseBigIntOrString = (inputValue: string): bigint | string => {\n if (\n !isValidBigIntString(inputValue, allowNegativeResolved) ||\n (allowLeadingZerosResolved && leadingZerosPattern.test(inputValue))\n ) {\n return inputValue;\n }\n\n const parsed = parseBigIntFromString(inputValue);\n return parsed ?? inputValue;\n };\n\n const getBigIntFloatValue = (inputValue: bigint) => {\n const numericValue = Number(inputValue);\n return Number.isSafeInteger(numericValue) ? numericValue : undefined;\n };\n\n const handleValueChange: OnValueChange = (payload, event) => {\n if (event.source === 'event') {\n if (isBigIntMode) {\n setValue(parseBigIntOrString(payload.value));\n } else {\n setValue(\n isValidNumber(payload.floatValue, payload.value) &&\n !leadingDecimalZeroPattern.test(payload.value) &&\n !(allowLeadingZerosResolved ? leadingZerosPattern.test(payload.value) : false) &&\n !trailingZerosPattern.test(payload.value) &&\n !trailingDecimalSeparatorPattern.test(payload.value)\n ? payload.floatValue\n : payload.value\n );\n }\n }\n onValueChange?.(payload, event);\n };\n\n const getDecimalPlaces = (inputValue: number | string): number => {\n const match = String(inputValue).match(/(?:\\.(\\d+))?(?:[eE]([+-]?\\d+))?$/);\n if (!match) {\n return 0;\n }\n return Math.max(0, (match[1] ? match[1].length : 0) - (match[2] ? +match[2] : 0));\n };\n\n const adjustCursor = (position?: number) => {\n if (inputRef.current && typeof position !== 'undefined') {\n inputRef.current.setSelectionRange(position, position);\n }\n };\n\n const incrementRef = useRef<() => void>(noop);\n incrementRef.current = () => {\n if (isBigIntMode) {\n if (!canStepBigInt(_value as bigint | string, allowNegativeResolved)) {\n return;\n }\n\n let val: bigint;\n const currentValue = _value;\n\n if (typeof currentValue === 'bigint') {\n const incrementedValue = currentValue + stepBigInt;\n if (maxBigInt !== undefined && incrementedValue > maxBigInt) {\n onMaxReached?.();\n }\n val =\n maxBigInt !== undefined && incrementedValue > maxBigInt ? maxBigInt : incrementedValue;\n } else if (typeof currentValue === 'string' && currentValue !== '') {\n const parsed = parseBigIntFromString(currentValue);\n if (parsed === null) {\n return;\n }\n\n const incrementedValue = parsed + stepBigInt;\n if (maxBigInt !== undefined && incrementedValue > maxBigInt) {\n onMaxReached?.();\n }\n val =\n maxBigInt !== undefined && incrementedValue > maxBigInt ? maxBigInt : incrementedValue;\n } else {\n val = clampBigInt(startValueBigInt, minBigInt, maxBigInt);\n }\n\n const formattedValue = val.toString();\n setValue(val);\n onValueChange?.(\n { floatValue: getBigIntFloatValue(val), formattedValue, value: formattedValue },\n { source: 'increment' as any }\n );\n setTimeout(() => adjustCursor(inputRef.current?.value.length), 0);\n return;\n }\n\n if (!canStep(_value as number | string)) {\n return;\n }\n\n let val: number;\n const currentValuePrecision = getDecimalPlaces(_value as number | string);\n const stepPrecision = getDecimalPlaces(stepNumber);\n const maxPrecision = Math.max(currentValuePrecision, stepPrecision);\n const factor = 10 ** maxPrecision;\n\n if (!isNumberString(_value) && (typeof _value !== 'number' || Number.isNaN(_value))) {\n val = clamp(startValueNumber, minNumber, maxNumber);\n } else if (maxNumber !== undefined) {\n const incrementedValue =\n (Math.round(Number(_value) * factor) + Math.round(stepNumber * factor)) / factor;\n if (incrementedValue > maxNumber) {\n onMaxReached?.();\n }\n val = incrementedValue <= maxNumber ? incrementedValue : maxNumber;\n } else {\n val = (Math.round(Number(_value) * factor) + Math.round(stepNumber * factor)) / factor;\n }\n\n const formattedValue = val.toFixed(maxPrecision);\n setValue(parseFloat(formattedValue));\n onValueChange?.(\n { floatValue: parseFloat(formattedValue), formattedValue, value: formattedValue },\n { source: 'increment' as any }\n );\n setTimeout(() => adjustCursor(inputRef.current?.value.length), 0);\n };\n\n const decrementRef = useRef<() => void>(noop);\n decrementRef.current = () => {\n if (isBigIntMode) {\n if (!canStepBigInt(_value as bigint | string, allowNegativeResolved)) {\n return;\n }\n\n let val: bigint;\n const minValue =\n minBigInt !== undefined ? minBigInt : !allowNegativeResolved ? BigInt(0) : undefined;\n const currentValue = _value;\n\n if (typeof currentValue === 'bigint') {\n const decrementedValue = currentValue - stepBigInt;\n if (minValue !== undefined && decrementedValue < minValue) {\n onMinReached?.();\n }\n val = minValue !== undefined && decrementedValue < minValue ? minValue : decrementedValue;\n } else if (typeof currentValue === 'string' && currentValue !== '') {\n const parsed = parseBigIntFromString(currentValue);\n if (parsed === null) {\n return;\n }\n\n const decrementedValue = parsed - stepBigInt;\n if (minValue !== undefined && decrementedValue < minValue) {\n onMinReached?.();\n }\n val = minValue !== undefined && decrementedValue < minValue ? minValue : decrementedValue;\n } else {\n val = clampBigInt(startValueBigInt, minValue, maxBigInt);\n }\n\n const formattedValue = val.toString();\n setValue(val);\n onValueChange?.(\n { floatValue: getBigIntFloatValue(val), formattedValue, value: formattedValue },\n { source: 'decrement' as any }\n );\n setTimeout(() => adjustCursor(inputRef.current?.value.length), 0);\n return;\n }\n\n if (!canStep(_value as number | string)) {\n return;\n }\n\n let val: number;\n const minValue =\n minNumber !== undefined ? minNumber : !allowNegativeResolved ? 0 : Number.MIN_SAFE_INTEGER;\n const currentValuePrecision = getDecimalPlaces(_value as number | string);\n const stepPrecision = getDecimalPlaces(stepNumber);\n const maxPrecision = Math.max(currentValuePrecision, stepPrecision);\n const factor = 10 ** maxPrecision;\n\n if ((!isNumberString(_value) && typeof _value !== 'number') || Number.isNaN(_value)) {\n val = clamp(startValueNumber, minValue, maxNumber);\n } else {\n const decrementedValue =\n (Math.round(Number(_value) * factor) - Math.round(stepNumber * factor)) / factor;\n if (minValue !== undefined && decrementedValue < minValue) {\n onMinReached?.();\n }\n val = minValue !== undefined && decrementedValue < minValue ? minValue : decrementedValue;\n }\n\n const formattedValue = val.toFixed(maxPrecision);\n setValue(parseFloat(formattedValue));\n onValueChange?.(\n { floatValue: parseFloat(formattedValue), formattedValue, value: formattedValue },\n { source: 'decrement' as any }\n );\n setTimeout(() => adjustCursor(inputRef.current?.value.length), 0);\n };\n\n const handlePaste = (event: React.ClipboardEvent<HTMLInputElement>) => {\n const pastedText = event.clipboardData.getData('text');\n const _decimalSeparator = others.decimalSeparator || '.';\n const separatorsToReplace = (allowedDecimalSeparators || ['.', ',']).filter(\n (s) => s !== _decimalSeparator\n );\n\n if (separatorsToReplace.some((s) => pastedText.includes(s))) {\n event.preventDefault();\n let modifiedText = pastedText;\n separatorsToReplace.forEach((s) => {\n modifiedText = modifiedText.split(s).join(_decimalSeparator);\n });\n\n const input = inputRef.current;\n if (input) {\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n const currentValue = input.value;\n const newValue =\n currentValue.substring(0, start) + modifiedText + currentValue.substring(end);\n\n const nativeInputValueSetter = Object.getOwnPropertyDescriptor(\n window.HTMLInputElement.prototype,\n 'value'\n )?.set;\n nativeInputValueSetter?.call(input, newValue);\n input.dispatchEvent(new Event('change', { bubbles: true }));\n\n const cursorPos = start + modifiedText.length;\n setTimeout(() => adjustCursor(cursorPos), 0);\n }\n }\n\n others.onPaste?.(event as any);\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n onKeyDown?.(event);\n\n if (readOnly || !withKeyboardEvents) {\n return;\n }\n\n if (event.key === 'ArrowUp') {\n event.preventDefault();\n incrementRef.current?.();\n }\n\n if (event.key === 'ArrowDown') {\n event.preventDefault();\n decrementRef.current?.();\n }\n };\n\n const handleKeyDownCapture = (event: React.KeyboardEvent<HTMLInputElement>) => {\n onKeyDownCapture?.(event);\n if (event.key === 'Backspace') {\n const input = inputRef.current;\n if (input && input.selectionStart === 0 && input.selectionStart === input.selectionEnd) {\n event.preventDefault();\n window.setTimeout(() => adjustCursor(0), 0);\n }\n }\n };\n\n const handleFocus = (event: React.FocusEvent<HTMLInputElement>) => {\n if (selectAllOnFocus) {\n window.setTimeout(() => inputRef.current?.select(), 0);\n }\n onFocus?.(event);\n };\n\n const handleBlur = (event: React.FocusEvent<HTMLInputElement>) => {\n let sanitizedValue = _value;\n\n if (isBigIntMode) {\n if (clampBehavior === 'blur' && typeof sanitizedValue === 'bigint') {\n sanitizedValue = clampBigInt(sanitizedValue, minBigInt, maxBigInt);\n }\n\n if (trimLeadingZeroesOnBlur && typeof sanitizedValue === 'string') {\n sanitizedValue = clampAndSanitizeBigIntInput(sanitizedValue, {\n min: minBigInt,\n max: maxBigInt,\n clampBehavior,\n });\n }\n } else {\n if (clampBehavior === 'blur' && typeof sanitizedValue === 'number') {\n sanitizedValue = clamp(sanitizedValue, minNumber, maxNumber);\n }\n\n if (\n trimLeadingZeroesOnBlur &&\n typeof sanitizedValue === 'string' &&\n getDecimalPlaces(sanitizedValue) < 15\n ) {\n sanitizedValue = clampAndSanitizeInput(sanitizedValue, maxNumber, minNumber);\n }\n }\n\n if (_value !== sanitizedValue) {\n setValue(sanitizedValue);\n }\n\n onBlur?.(event);\n };\n\n assignRef(handlersRef, { increment: incrementRef.current, decrement: decrementRef.current });\n\n const onStepHandleChange = (isIncrement: boolean) => {\n if (isIncrement) {\n incrementRef.current?.();\n } else {\n decrementRef.current?.();\n }\n stepCountRef.current += 1;\n };\n\n const onStepLoop = (isIncrement: boolean) => {\n onStepHandleChange(isIncrement);\n\n if (shouldUseStepInterval) {\n const interval =\n typeof stepHoldInterval === 'number'\n ? stepHoldInterval\n : stepHoldInterval(stepCountRef.current);\n onStepTimeoutRef.current = window.setTimeout(() => onStepLoop(isIncrement), interval);\n }\n };\n\n const onStep = (\n event: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>,\n isIncrement: boolean\n ) => {\n event.preventDefault();\n inputRef.current?.focus();\n onStepHandleChange(isIncrement);\n if (shouldUseStepInterval) {\n onStepTimeoutRef.current = window.setTimeout(() => onStepLoop(isIncrement), stepHoldDelay);\n }\n };\n\n const onStepDone = () => {\n if (onStepTimeoutRef.current) {\n window.clearTimeout(onStepTimeoutRef.current);\n }\n onStepTimeoutRef.current = null;\n stepCountRef.current = 0;\n };\n\n const controls = (\n <div {...getStyles('controls')}>\n <UnstyledButton\n {...getStyles('control')}\n tabIndex={-1}\n aria-hidden\n disabled={\n disabled ||\n (typeof _value === 'number' && maxNumber !== undefined && _value >= maxNumber) ||\n (typeof _value === 'bigint' && maxBigInt !== undefined && _value >= maxBigInt)\n }\n mod={{ direction: 'up' }}\n onMouseDown={(event) => event.preventDefault()}\n onPointerDown={(event) => {\n onStep(event, true);\n }}\n onPointerUp={onStepDone}\n onPointerLeave={onStepDone}\n >\n <NumberInputChevron direction=\"up\" />\n </UnstyledButton>\n <UnstyledButton\n {...getStyles('control')}\n tabIndex={-1}\n aria-hidden\n disabled={\n disabled ||\n (typeof _value === 'number' && minNumber !== undefined && _value <= minNumber) ||\n (typeof _value === 'bigint' && minBigInt !== undefined && _value <= minBigInt)\n }\n mod={{ direction: 'down' }}\n onMouseDown={(event) => event.preventDefault()}\n onPointerDown={(event) => {\n onStep(event, false);\n }}\n onPointerUp={onStepDone}\n onPointerLeave={onStepDone}\n >\n <NumberInputChevron direction=\"down\" />\n </UnstyledButton>\n </div>\n );\n\n return (\n <InputBase\n component={NumericFormat}\n allowNegative={allowNegative}\n className={cx(classes.root, className)}\n size={size}\n {...others}\n inputMode={isBigIntMode ? 'numeric' : 'decimal'}\n readOnly={readOnly}\n disabled={disabled}\n value={typeof _value === 'bigint' ? _value.toString() : _value}\n getInputRef={useMergedRef(ref, inputRef)}\n onValueChange={handleValueChange}\n rightSection={\n hideControls ||\n readOnly ||\n !(isBigIntMode\n ? canStepBigInt(_value as bigint | string, allowNegativeResolved)\n : canStep(_value as number | string))\n ? rightSection\n : rightSection || controls\n }\n classNames={resolvedClassNames}\n styles={resolvedStyles}\n unstyled={unstyled}\n __staticSelector=\"NumberInput\"\n decimalScale={isBigIntMode ? 0 : allowDecimal ? decimalScale : 0}\n onPaste={handlePaste}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n onKeyDownCapture={handleKeyDownCapture}\n rightSectionPointerEvents={rightSectionPointerEvents ?? (disabled ? 'none' : undefined)}\n rightSectionWidth={rightSectionWidth ?? `var(--ni-right-section-width-${size || 'sm'})`}\n allowLeadingZeros={allowLeadingZeros}\n allowedDecimalSeparators={allowedDecimalSeparators}\n onBlur={handleBlur}\n attributes={attributes}\n isAllowed={(val) => {\n const userAllowed = isAllowed ? isAllowed(val) : true;\n if (!userAllowed) {\n return false;\n }\n\n if (clampBehavior !== 'strict') {\n return true;\n }\n\n if (!isBigIntMode) {\n return isInRange(val.floatValue, minNumber, maxNumber);\n }\n\n if (val.value === '' || val.value === '-') {\n return true;\n }\n\n const parsed = parseBigIntFromString(val.value);\n\n if (parsed === null) {\n return true;\n }\n\n return (\n (minBigInt === undefined || parsed >= minBigInt) &&\n (maxBigInt === undefined || parsed <= maxBigInt)\n );\n }}\n />\n );\n }\n);\n\nNumberInput.classes = { ...InputBase.classes, ...classes };\nNumberInput.varsResolver = varsResolver;\nNumberInput.displayName = '@mantine/core/NumberInput';\n\nexport namespace NumberInput {\n export type Props<T extends NumberInputNumericType = number> = NumberInputProps<T>;\n export type StylesNames = NumberInputStylesNames;\n export type Factory = NumberInputFactory;\n export type CssVariables = NumberInputCssVariables;\n export type Handlers = NumberInputHandlers;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAyBA,MAAM,4BAA4B;AAGlC,MAAM,sBAAsB;AAG5B,MAAM,uBAAuB;AAG7B,MAAM,kCAAkC;AAaxC,SAAS,eAAe,OAAgB;CACtC,OAAO,OAAO,UAAU,YAAY,UAAU,MAAM,CAAC,OAAO,MAAM,OAAO,KAAK,CAAC;AACjF;AAEA,SAAS,cAAc,OAAiC;CACtD,OAAO,OAAO,UAAU;AAC1B;AAEA,SAAS,QAAQ,OAAwB;CACvC,IAAI,OAAO,UAAU,UACnB,OAAO,QAAQ,OAAO;CAGxB,OAAO,UAAU,MAAO,eAAe,KAAK,KAAK,OAAO,KAAK,IAAI,OAAO;AAC1E;AAEA,SAAS,oBAAoB,OAAe,eAAwB;CAClE,IAAI,UAAU,IACZ,OAAO;CAGT,IAAI,UAAU,KACZ,OAAO;CAGT,IAAI,CAAC,iBAAiB,MAAM,WAAW,GAAG,GACxC,OAAO;CAGT,OAAO,UAAU,KAAK,KAAK;AAC7B;AAEA,SAAS,cAAc,OAAwB,eAAwB;CACrE,IAAI,OAAO,UAAU,UACnB,OAAO;CAGT,OAAO,UAAU,MAAM,oBAAoB,OAAO,aAAa;AACjE;AAEA,SAAS,sBAAsB,OAA8B;CAC3D,IAAI,CAAC,UAAU,KAAK,KAAK,GACvB,OAAO;CAGT,IAAI;EACF,OAAO,OAAO,KAAK;CACrB,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,oBAAoB,OAAoC;CAC/D,IAAI,OAAO,UAAU,UACnB,OAAO;CAGT,IAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,KAAK,OAAO,UAAU,KAAK,GAC/E,OAAO,OAAO,KAAK;AAIvB;AAEA,SAAS,YAAY,OAAe,KAAc,KAAc;CAC9D,IAAI,QAAQ,KAAA,KAAa,QAAQ,KAC/B,OAAO;CAGT,IAAI,QAAQ,KAAA,KAAa,QAAQ,KAC/B,OAAO;CAGT,OAAO;AACT;AAEA,SAAS,eAAe,YAAqC;CAG3D,OAAO,WAAW,SAAS,CAAC,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC;AAChD;AAEA,SAAS,cAAc,YAAgC,OAAqC;CAC1F,QACG,OAAO,eAAe,WACnB,aAAa,OAAO,mBACpB,CAAC,OAAO,MAAM,OAAO,UAAU,CAAC,MACpC,CAAC,OAAO,MAAM,UAAU,KACxB,eAAe,KAAK,IAAI,MACxB,UAAU;AAEd;AAEA,SAAS,UAAU,OAA2B,KAAyB,KAAyB;CAC9F,IAAI,UAAU,KAAA,GACZ,OAAO;CAMT,QAHiB,QAAQ,KAAA,KAAa,SAAS,SAC9B,QAAQ,KAAA,KAAa,SAAS;AAGjD;AAgIA,MAAM,eAAe;CACnB,MAAM;CACN,MAAM;CACN,eAAe;CACf,cAAc;CACd,eAAe;CACf,oBAAoB;CACpB,mBAAmB;CACnB,yBAAyB;CACzB,YAAY;CACZ,0BAA0B,CAAC,KAAK,GAAG;AACrC;AAEA,MAAM,eAAe,oBAAwC,GAAG,EAAE,YAAY,EAC5E,UAAU,EACR,qBAAqB,QAAQ,MAAM,iBAAiB,EACtD,EACF,EAAE;AAEF,SAAS,sBAAsB,gBAAiC,KAAc,KAAc;CAC1F,MAAM,cAAc,eAAe,SAAS;CAC5C,MAAM,8BAA8B,gCAAgC,KAAK,WAAW;CAEpF,MAAM,WAAW,YAAY,QAAQ,aAAa,EAAE;CACpD,MAAM,cAAc,WAAW,QAAQ;CAEvC,IAAI,OAAO,MAAM,WAAW,GAC1B,OAAO;CAGT,IAAI,cAAc,OAAO,kBACvB,OAAO,QAAQ,KAAA,IAAY,MAAM;CAGnC,MAAM,UAAU,MAAM,aAAa,KAAK,GAAG;CAE3C,IAAI,6BAEF,OAAO,GADe,QAAQ,SAAS,CAAC,CAAC,QAAQ,aAAa,EACxC,EAAE;CAG1B,OAAO;AACT;AAEA,SAAS,4BACP,gBACA,SACA;CACA,IAAI,mBAAmB,MAAM,mBAAmB,KAC9C,OAAO;CAGT,MAAM,SAAS,sBAAsB,cAAc;CAEnD,IAAI,WAAW,MACb,OAAO;CAGT,OAAO,QAAQ,kBAAkB,SAAS,YAAY,QAAQ,QAAQ,KAAK,QAAQ,GAAG,IAAI;AAC5F;AAEA,MAAa,cAAc,gBACmB,WAAgC;CAC1E,MAAM,QAAQ,SACZ;EAAC;EAAS;EAAgB;CAAa,GACvC,cACA,MACF;CACA,MAAM,EACJ,WACA,YACA,QACA,UACA,MACA,UACA,eACA,OACA,cACA,KACA,KACA,MACA,cACA,cACA,WACA,eACA,QACA,cACA,cACA,WACA,kBACA,aACA,YACA,UACA,2BACA,eACA,UACA,MACA,mBACA,kBACA,eACA,mBACA,oBACA,yBACA,0BACA,kBACA,cACA,cACA,SACA,YACA,KACA,GAAG,WACD;CACJ,MAAM,wBAAwB,iBAAiB;CAC/C,MAAM,4BAA4B,qBAAqB;CAEvD,MAAM,YAAY,UAA8B;EAC9C,MAAM;EACN,SAAA;EACO;EACP;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,EAAE,oBAAoB,mBAAmB,qBAAyC;EACtF;EACA;EACO;CACT,CAAC;CAED,MAAM,eAAe,OACnB,cAAc,KAAK,KAAK,cAAc,YAAY,IAAI,WAAW,QACnE;CAEA,IAAI,cAAc,KAAK,GACrB,aAAa,UAAU;MAClB,IAAI,OAAO,UAAU,UAC1B,aAAa,UAAU;CAGzB,MAAM,eAAe,aAAa,YAAY;CAE9C,MAAM,CAAC,QAAQ,YAAY,gBAA0C;EAC5D;EACO;EACd,YAAY;EACF;CACZ,CAAC;CAED,MAAM,wBAAwB,kBAAkB,KAAA,KAAa,qBAAqB,KAAA;CAClF,MAAM,WAAW,OAAyB,IAAI;CAC9C,MAAM,mBAAmB,OAAsB,IAAI;CACnD,MAAM,eAAe,OAAe,CAAC;CAErC,MAAM,YAAY,OAAO,QAAQ,WAAW,MAAM,KAAA;CAClD,MAAM,YAAY,OAAO,QAAQ,WAAW,MAAM,KAAA;CAClD,MAAM,aAAa,OAAO,SAAS,WAAW,OAAO,aAAa;CAClE,MAAM,mBAAmB,OAAO,eAAe,WAAW,aAAa,aAAa;CAEpF,MAAM,YAAY,oBAAoB,GAAG;CACzC,MAAM,YAAY,oBAAoB,GAAG;CACzC,MAAM,aAAa,oBAAoB,IAAI,KAAK,OAAO,CAAC;CACxD,MAAM,mBAAmB,oBAAoB,UAAU,KAAK,OAAO,CAAC;CAEpE,MAAM,uBAAuB,eAAwC;EACnE,IACE,CAAC,oBAAoB,YAAY,qBAAqB,KACrD,6BAA6B,oBAAoB,KAAK,UAAU,GAEjE,OAAO;EAIT,OADe,sBAAsB,UACzB,KAAK;CACnB;CAEA,MAAM,uBAAuB,eAAuB;EAClD,MAAM,eAAe,OAAO,UAAU;EACtC,OAAO,OAAO,cAAc,YAAY,IAAI,eAAe,KAAA;CAC7D;CAEA,MAAM,qBAAoC,SAAS,UAAU;EAC3D,IAAI,MAAM,WAAW,SAAS;GAC5B,IAAI,cACF,SAAS,oBAAoB,QAAQ,KAAK,CAAC;QAE3C,SACE,cAAc,QAAQ,YAAY,QAAQ,KAAK,KAC7C,CAAC,0BAA0B,KAAK,QAAQ,KAAK,KAC7C,EAAE,4BAA4B,oBAAoB,KAAK,QAAQ,KAAK,IAAI,UACxE,CAAC,qBAAqB,KAAK,QAAQ,KAAK,KACxC,CAAC,gCAAgC,KAAK,QAAQ,KAAK,IACjD,QAAQ,aACR,QAAQ,KACd;EAEJ;EACA,gBAAgB,SAAS,KAAK;CAChC;CAEA,MAAM,oBAAoB,eAAwC;EAChE,MAAM,QAAQ,OAAO,UAAU,CAAC,CAAC,MAAM,kCAAkC;EACzE,IAAI,CAAC,OACH,OAAO;EAET,OAAO,KAAK,IAAI,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC,SAAS,MAAM,MAAM,KAAK,CAAC,MAAM,KAAK,EAAE;CAClF;CAEA,MAAM,gBAAgB,aAAsB;EAC1C,IAAI,SAAS,WAAW,OAAO,aAAa,aAC1C,SAAS,QAAQ,kBAAkB,UAAU,QAAQ;CAEzD;CAEA,MAAM,eAAe,OAAmB,IAAI;CAC5C,aAAa,gBAAgB;EAC3B,IAAI,cAAc;GAChB,IAAI,CAAC,cAAc,QAA2B,qBAAqB,GACjE;GAGF,IAAI;GACJ,MAAM,eAAe;GAErB,IAAI,OAAO,iBAAiB,UAAU;IACpC,MAAM,mBAAmB,eAAe;IACxC,IAAI,cAAc,KAAA,KAAa,mBAAmB,WAChD,eAAe;IAEjB,MACE,cAAc,KAAA,KAAa,mBAAmB,YAAY,YAAY;GAC1E,OAAO,IAAI,OAAO,iBAAiB,YAAY,iBAAiB,IAAI;IAClE,MAAM,SAAS,sBAAsB,YAAY;IACjD,IAAI,WAAW,MACb;IAGF,MAAM,mBAAmB,SAAS;IAClC,IAAI,cAAc,KAAA,KAAa,mBAAmB,WAChD,eAAe;IAEjB,MACE,cAAc,KAAA,KAAa,mBAAmB,YAAY,YAAY;GAC1E,OACE,MAAM,YAAY,kBAAkB,WAAW,SAAS;GAG1D,MAAM,iBAAiB,IAAI,SAAS;GACpC,SAAS,GAAG;GACZ,gBACE;IAAE,YAAY,oBAAoB,GAAG;IAAG;IAAgB,OAAO;GAAe,GAC9E,EAAE,QAAQ,YAAmB,CAC/B;GACA,iBAAiB,aAAa,SAAS,SAAS,MAAM,MAAM,GAAG,CAAC;GAChE;EACF;EAEA,IAAI,CAAC,QAAQ,MAAyB,GACpC;EAGF,IAAI;EACJ,MAAM,wBAAwB,iBAAiB,MAAyB;EACxE,MAAM,gBAAgB,iBAAiB,UAAU;EACjD,MAAM,eAAe,KAAK,IAAI,uBAAuB,aAAa;EAClE,MAAM,SAAS,MAAM;EAErB,IAAI,CAAC,eAAe,MAAM,MAAM,OAAO,WAAW,YAAY,OAAO,MAAM,MAAM,IAC/E,MAAM,MAAM,kBAAkB,WAAW,SAAS;OAC7C,IAAI,cAAc,KAAA,GAAW;GAClC,MAAM,oBACH,KAAK,MAAM,OAAO,MAAM,IAAI,MAAM,IAAI,KAAK,MAAM,aAAa,MAAM,KAAK;GAC5E,IAAI,mBAAmB,WACrB,eAAe;GAEjB,MAAM,oBAAoB,YAAY,mBAAmB;EAC3D,OACE,OAAO,KAAK,MAAM,OAAO,MAAM,IAAI,MAAM,IAAI,KAAK,MAAM,aAAa,MAAM,KAAK;EAGlF,MAAM,iBAAiB,IAAI,QAAQ,YAAY;EAC/C,SAAS,WAAW,cAAc,CAAC;EACnC,gBACE;GAAE,YAAY,WAAW,cAAc;GAAG;GAAgB,OAAO;EAAe,GAChF,EAAE,QAAQ,YAAmB,CAC/B;EACA,iBAAiB,aAAa,SAAS,SAAS,MAAM,MAAM,GAAG,CAAC;CAClE;CAEA,MAAM,eAAe,OAAmB,IAAI;CAC5C,aAAa,gBAAgB;EAC3B,IAAI,cAAc;GAChB,IAAI,CAAC,cAAc,QAA2B,qBAAqB,GACjE;GAGF,IAAI;GACJ,MAAM,WACJ,cAAc,KAAA,IAAY,YAAY,CAAC,wBAAwB,OAAO,CAAC,IAAI,KAAA;GAC7E,MAAM,eAAe;GAErB,IAAI,OAAO,iBAAiB,UAAU;IACpC,MAAM,mBAAmB,eAAe;IACxC,IAAI,aAAa,KAAA,KAAa,mBAAmB,UAC/C,eAAe;IAEjB,MAAM,aAAa,KAAA,KAAa,mBAAmB,WAAW,WAAW;GAC3E,OAAO,IAAI,OAAO,iBAAiB,YAAY,iBAAiB,IAAI;IAClE,MAAM,SAAS,sBAAsB,YAAY;IACjD,IAAI,WAAW,MACb;IAGF,MAAM,mBAAmB,SAAS;IAClC,IAAI,aAAa,KAAA,KAAa,mBAAmB,UAC/C,eAAe;IAEjB,MAAM,aAAa,KAAA,KAAa,mBAAmB,WAAW,WAAW;GAC3E,OACE,MAAM,YAAY,kBAAkB,UAAU,SAAS;GAGzD,MAAM,iBAAiB,IAAI,SAAS;GACpC,SAAS,GAAG;GACZ,gBACE;IAAE,YAAY,oBAAoB,GAAG;IAAG;IAAgB,OAAO;GAAe,GAC9E,EAAE,QAAQ,YAAmB,CAC/B;GACA,iBAAiB,aAAa,SAAS,SAAS,MAAM,MAAM,GAAG,CAAC;GAChE;EACF;EAEA,IAAI,CAAC,QAAQ,MAAyB,GACpC;EAGF,IAAI;EACJ,MAAM,WACJ,cAAc,KAAA,IAAY,YAAY,CAAC,wBAAwB,IAAI,OAAO;EAC5E,MAAM,wBAAwB,iBAAiB,MAAyB;EACxE,MAAM,gBAAgB,iBAAiB,UAAU;EACjD,MAAM,eAAe,KAAK,IAAI,uBAAuB,aAAa;EAClE,MAAM,SAAS,MAAM;EAErB,IAAK,CAAC,eAAe,MAAM,KAAK,OAAO,WAAW,YAAa,OAAO,MAAM,MAAM,GAChF,MAAM,MAAM,kBAAkB,UAAU,SAAS;OAC5C;GACL,MAAM,oBACH,KAAK,MAAM,OAAO,MAAM,IAAI,MAAM,IAAI,KAAK,MAAM,aAAa,MAAM,KAAK;GAC5E,IAAI,aAAa,KAAA,KAAa,mBAAmB,UAC/C,eAAe;GAEjB,MAAM,aAAa,KAAA,KAAa,mBAAmB,WAAW,WAAW;EAC3E;EAEA,MAAM,iBAAiB,IAAI,QAAQ,YAAY;EAC/C,SAAS,WAAW,cAAc,CAAC;EACnC,gBACE;GAAE,YAAY,WAAW,cAAc;GAAG;GAAgB,OAAO;EAAe,GAChF,EAAE,QAAQ,YAAmB,CAC/B;EACA,iBAAiB,aAAa,SAAS,SAAS,MAAM,MAAM,GAAG,CAAC;CAClE;CAEA,MAAM,eAAe,UAAkD;EACrE,MAAM,aAAa,MAAM,cAAc,QAAQ,MAAM;EACrD,MAAM,oBAAoB,OAAO,oBAAoB;EACrD,MAAM,uBAAuB,4BAA4B,CAAC,KAAK,GAAG,EAAA,CAAG,QAClE,MAAM,MAAM,iBACf;EAEA,IAAI,oBAAoB,MAAM,MAAM,WAAW,SAAS,CAAC,CAAC,GAAG;GAC3D,MAAM,eAAe;GACrB,IAAI,eAAe;GACnB,oBAAoB,SAAS,MAAM;IACjC,eAAe,aAAa,MAAM,CAAC,CAAC,CAAC,KAAK,iBAAiB;GAC7D,CAAC;GAED,MAAM,QAAQ,SAAS;GACvB,IAAI,OAAO;IACT,MAAM,QAAQ,MAAM,kBAAkB;IACtC,MAAM,MAAM,MAAM,gBAAgB;IAClC,MAAM,eAAe,MAAM;IAC3B,MAAM,WACJ,aAAa,UAAU,GAAG,KAAK,IAAI,eAAe,aAAa,UAAU,GAAG;IAM9E,CAJ+B,OAAO,yBACpC,OAAO,iBAAiB,WACxB,OACF,CAAC,EAAE,IAAA,EACqB,KAAK,OAAO,QAAQ;IAC5C,MAAM,cAAc,IAAI,MAAM,UAAU,EAAE,SAAS,KAAK,CAAC,CAAC;IAE1D,MAAM,YAAY,QAAQ,aAAa;IACvC,iBAAiB,aAAa,SAAS,GAAG,CAAC;GAC7C;EACF;EAEA,OAAO,UAAU,KAAY;CAC/B;CAEA,MAAM,iBAAiB,UAAiD;EACtE,YAAY,KAAK;EAEjB,IAAI,YAAY,CAAC,oBACf;EAGF,IAAI,MAAM,QAAQ,WAAW;GAC3B,MAAM,eAAe;GACrB,aAAa,UAAU;EACzB;EAEA,IAAI,MAAM,QAAQ,aAAa;GAC7B,MAAM,eAAe;GACrB,aAAa,UAAU;EACzB;CACF;CAEA,MAAM,wBAAwB,UAAiD;EAC7E,mBAAmB,KAAK;EACxB,IAAI,MAAM,QAAQ,aAAa;GAC7B,MAAM,QAAQ,SAAS;GACvB,IAAI,SAAS,MAAM,mBAAmB,KAAK,MAAM,mBAAmB,MAAM,cAAc;IACtF,MAAM,eAAe;IACrB,OAAO,iBAAiB,aAAa,CAAC,GAAG,CAAC;GAC5C;EACF;CACF;CAEA,MAAM,eAAe,UAA8C;EACjE,IAAI,kBACF,OAAO,iBAAiB,SAAS,SAAS,OAAO,GAAG,CAAC;EAEvD,UAAU,KAAK;CACjB;CAEA,MAAM,cAAc,UAA8C;EAChE,IAAI,iBAAiB;EAErB,IAAI,cAAc;GAChB,IAAI,kBAAkB,UAAU,OAAO,mBAAmB,UACxD,iBAAiB,YAAY,gBAAgB,WAAW,SAAS;GAGnE,IAAI,2BAA2B,OAAO,mBAAmB,UACvD,iBAAiB,4BAA4B,gBAAgB;IAC3D,KAAK;IACL,KAAK;IACL;GACF,CAAC;EAEL,OAAO;GACL,IAAI,kBAAkB,UAAU,OAAO,mBAAmB,UACxD,iBAAiB,MAAM,gBAAgB,WAAW,SAAS;GAG7D,IACE,2BACA,OAAO,mBAAmB,YAC1B,iBAAiB,cAAc,IAAI,IAEnC,iBAAiB,sBAAsB,gBAAgB,WAAW,SAAS;EAE/E;EAEA,IAAI,WAAW,gBACb,SAAS,cAAc;EAGzB,SAAS,KAAK;CAChB;CAEA,UAAU,aAAa;EAAE,WAAW,aAAa;EAAS,WAAW,aAAa;CAAQ,CAAC;CAE3F,MAAM,sBAAsB,gBAAyB;EACnD,IAAI,aACF,aAAa,UAAU;OAEvB,aAAa,UAAU;EAEzB,aAAa,WAAW;CAC1B;CAEA,MAAM,cAAc,gBAAyB;EAC3C,mBAAmB,WAAW;EAE9B,IAAI,uBAAuB;GACzB,MAAM,WACJ,OAAO,qBAAqB,WACxB,mBACA,iBAAiB,aAAa,OAAO;GAC3C,iBAAiB,UAAU,OAAO,iBAAiB,WAAW,WAAW,GAAG,QAAQ;EACtF;CACF;CAEA,MAAM,UACJ,OACA,gBACG;EACH,MAAM,eAAe;EACrB,SAAS,SAAS,MAAM;EACxB,mBAAmB,WAAW;EAC9B,IAAI,uBACF,iBAAiB,UAAU,OAAO,iBAAiB,WAAW,WAAW,GAAG,aAAa;CAE7F;CAEA,MAAM,mBAAmB;EACvB,IAAI,iBAAiB,SACnB,OAAO,aAAa,iBAAiB,OAAO;EAE9C,iBAAiB,UAAU;EAC3B,aAAa,UAAU;CACzB;CAEA,MAAM,WACJ,qBAAC,OAAD;EAAK,GAAI,UAAU,UAAU;EAA7B,UAAA,CACE,oBAAC,gBAAD;GACE,GAAI,UAAU,SAAS;GACvB,UAAU;GACV,eAAA;GACA,UACE,YACC,OAAO,WAAW,YAAY,cAAc,KAAA,KAAa,UAAU,aACnE,OAAO,WAAW,YAAY,cAAc,KAAA,KAAa,UAAU;GAEtE,KAAK,EAAE,WAAW,KAAK;GACvB,cAAc,UAAU,MAAM,eAAe;GAC7C,gBAAgB,UAAU;IACxB,OAAO,OAAO,IAAI;GACpB;GACA,aAAa;GACb,gBAAgB;GAEhB,UAAA,oBAAC,oBAAD,EAAoB,WAAU,KAAM,CAAA;EACtB,CAAA,GAChB,oBAAC,gBAAD;GACE,GAAI,UAAU,SAAS;GACvB,UAAU;GACV,eAAA;GACA,UACE,YACC,OAAO,WAAW,YAAY,cAAc,KAAA,KAAa,UAAU,aACnE,OAAO,WAAW,YAAY,cAAc,KAAA,KAAa,UAAU;GAEtE,KAAK,EAAE,WAAW,OAAO;GACzB,cAAc,UAAU,MAAM,eAAe;GAC7C,gBAAgB,UAAU;IACxB,OAAO,OAAO,KAAK;GACrB;GACA,aAAa;GACb,gBAAgB;GAEhB,UAAA,oBAAC,oBAAD,EAAoB,WAAU,OAAQ,CAAA;EACxB,CAAA,CACb;;CAGP,OACE,oBAAC,WAAD;EACE,WAAW;EACI;EACf,WAAW,GAAGA,2BAAQ,MAAM,SAAS;EAC/B;EACN,GAAI;EACJ,WAAW,eAAe,YAAY;EAC5B;EACA;EACV,OAAO,OAAO,WAAW,WAAW,OAAO,SAAS,IAAI;EACxD,aAAa,aAAa,KAAK,QAAQ;EACvC,eAAe;EACf,cACE,gBACA,YACA,EAAE,eACE,cAAc,QAA2B,qBAAqB,IAC9D,QAAQ,MAAyB,KACjC,eACA,gBAAgB;EAEtB,YAAY;EACZ,QAAQ;EACE;EACV,kBAAiB;EACjB,cAAc,eAAe,IAAI,eAAe,eAAe;EAC/D,SAAS;EACT,SAAS;EACT,WAAW;EACX,kBAAkB;EAClB,2BAA2B,8BAA8B,WAAW,SAAS,KAAA;EAC7E,mBAAmB,qBAAqB,gCAAgC,QAAQ,KAAK;EAClE;EACO;EAC1B,QAAQ;EACI;EACZ,YAAY,QAAQ;GAElB,IAAI,EADgB,YAAY,UAAU,GAAG,IAAI,OAE/C,OAAO;GAGT,IAAI,kBAAkB,UACpB,OAAO;GAGT,IAAI,CAAC,cACH,OAAO,UAAU,IAAI,YAAY,WAAW,SAAS;GAGvD,IAAI,IAAI,UAAU,MAAM,IAAI,UAAU,KACpC,OAAO;GAGT,MAAM,SAAS,sBAAsB,IAAI,KAAK;GAE9C,IAAI,WAAW,MACb,OAAO;GAGT,QACG,cAAc,KAAA,KAAa,UAAU,eACrC,cAAc,KAAA,KAAa,UAAU;EAE1C;CACD,CAAA;AAEL,CACF;AAEA,YAAY,UAAU;CAAE,GAAG,UAAU;CAAS,GAAGA;AAAQ;AACzD,YAAY,eAAe;AAC3B,YAAY,cAAc"}
1
+ {"version":3,"file":"NumberInput.mjs","names":["classes"],"sources":["../../../src/components/NumberInput/NumberInput.tsx"],"sourcesContent":["import React, { useRef } from 'react';\nimport cx from 'clsx';\nimport { NumberFormatValues, NumericFormat, OnValueChange } from 'react-number-format';\nimport { assignRef, clamp, useMergedRef, useUncontrolled } from '@mantine/hooks';\nimport {\n BoxProps,\n createVarsResolver,\n ElementProps,\n Factory,\n genericFactory,\n getSize,\n noop,\n StylesApiProps,\n useProps,\n useResolvedStylesApi,\n useStyles,\n} from '../../core';\nimport { __BaseInputProps, __InputStylesNames, InputVariant } from '../Input';\nimport { InputBase } from '../InputBase';\nimport { UnstyledButton } from '../UnstyledButton';\nimport { getCaretPositionAfterPaste } from './get-caret-position-after-paste/get-caret-position-after-paste';\nimport { normalizePastedValue } from './normalize-pasted-value/normalize-pasted-value';\nimport { NumberInputChevron } from './NumberInputChevron';\nimport classes from './NumberInput.module.css';\n\n// Re for negative -0, -0., -0.0, -0.00, -0.000 ... strings\n// And for positive 0., 0.0, 0.00, 0.000 ... strings\nconst leadingDecimalZeroPattern = /^(0\\.0*|-0(\\.0*)?)$/;\n\n// Re for 01, 006, 00.02, -0010, -000.293 ... and negative counterparts\nconst leadingZerosPattern = /^-?0\\d+(\\.\\d+)?\\.?$/;\n\n// Re for decimal numbers with trailing zeros like 13.0, 13.00, 5.10 ... strings\nconst trailingZerosPattern = /\\.\\d*0$/;\n\n// Re for numbers with trailing decimal separator like 10. or -3.\nconst trailingDecimalSeparatorPattern = /^-?\\d+\\.$/;\n\nexport interface NumberInputHandlers {\n increment: () => void;\n decrement: () => void;\n}\n\nexport type NumberInputMode = 'number' | 'bigint';\nexport type NumberInputNumericType = number | bigint;\nexport type NumberInputValue<T extends NumberInputNumericType = number> = T | string;\ntype NumberInputNumericValue<T extends NumberInputNumericType = number> = T;\ntype InternalNumberInputValue = string | number | bigint;\n\nfunction isNumberString(value: unknown) {\n return typeof value === 'string' && value !== '' && !Number.isNaN(Number(value));\n}\n\nfunction isBigIntValue(value: unknown): value is bigint {\n return typeof value === 'bigint';\n}\n\nfunction canStep(value: number | string) {\n if (typeof value === 'number') {\n return value < Number.MAX_SAFE_INTEGER;\n }\n\n return value === '' || (isNumberString(value) && Number(value) < Number.MAX_SAFE_INTEGER);\n}\n\nfunction isValidBigIntString(value: string, allowNegative: boolean) {\n if (value === '') {\n return false;\n }\n\n if (value === '-') {\n return false;\n }\n\n if (!allowNegative && value.startsWith('-')) {\n return false;\n }\n\n return /^-?\\d+$/.test(value);\n}\n\nfunction canStepBigInt(value: bigint | string, allowNegative: boolean) {\n if (typeof value === 'bigint') {\n return true;\n }\n\n return value === '' || isValidBigIntString(value, allowNegative);\n}\n\nfunction parseBigIntFromString(value: string): bigint | null {\n if (!/^-?\\d+$/.test(value)) {\n return null;\n }\n\n try {\n return BigInt(value);\n } catch {\n return null;\n }\n}\n\nfunction toBigIntOrUndefined(value: unknown): bigint | undefined {\n if (typeof value === 'bigint') {\n return value;\n }\n\n if (typeof value === 'number' && Number.isFinite(value) && Number.isInteger(value)) {\n return BigInt(value);\n }\n\n return undefined;\n}\n\nfunction clampBigInt(value: bigint, min?: bigint, max?: bigint) {\n if (min !== undefined && value < min) {\n return min;\n }\n\n if (max !== undefined && value > max) {\n return max;\n }\n\n return value;\n}\n\nfunction getTotalDigits(inputValue: string | number): number {\n // All digits must be counted, parseFloat precision depends\n // on the number of digits in the input, not only on the decimal scale\n return inputValue.toString().replace('.', '').length;\n}\n\nfunction isValidNumber(floatValue: number | undefined, value: string): floatValue is number {\n return (\n (typeof floatValue === 'number'\n ? floatValue < Number.MAX_SAFE_INTEGER\n : !Number.isNaN(Number(floatValue))) &&\n !Number.isNaN(floatValue) &&\n getTotalDigits(value) < 14 &&\n value !== ''\n );\n}\n\nfunction isInRange(value: number | undefined, min: number | undefined, max: number | undefined) {\n if (value === undefined) {\n return true;\n }\n\n const minValid = min === undefined || value >= min;\n const maxValid = max === undefined || value <= max;\n\n return minValid && maxValid;\n}\n\nexport type NumberInputStylesNames = 'controls' | 'control' | __InputStylesNames;\nexport type NumberInputCssVariables = {\n controls: '--ni-chevron-size';\n};\n\nexport interface NumberInputProps<T extends NumberInputNumericType = number>\n extends\n BoxProps,\n Omit<__BaseInputProps, 'pointer'>,\n StylesApiProps<NumberInputFactory>,\n ElementProps<\n 'input',\n 'size' | 'type' | 'onChange' | 'value' | 'defaultValue' | 'min' | 'max' | 'step'\n > {\n /** Controlled component value */\n value?: NumberInputValue<T>;\n\n /** Uncontrolled component default value */\n defaultValue?: NumberInputValue<T>;\n\n /** Called when value changes */\n onChange?: (value: NumberInputValue<T>) => void;\n\n /** Called when value changes with `react-number-format` payload */\n onValueChange?: OnValueChange;\n\n /** Determines whether leading zeros are allowed during input. If `false`, leading zeros are removed as you type (e.g., typing `007` results in `7`). Works in conjunction with `trimLeadingZeroesOnBlur`. @default true */\n allowLeadingZeros?: boolean;\n\n /** Determines whether negative numbers are allowed. If `false`, the input will not accept negative values, and the decrement button will stop at `0` (when `min` is not set). @default true */\n allowNegative?: boolean;\n\n /** Characters which when pressed result in a decimal separator. These characters will be replaced by the `decimalSeparator` in the input value. @default ['.', ','] */\n allowedDecimalSeparators?: string[];\n\n /** Limits the number of digits that can be entered after the decimal point @default Infinity */\n decimalScale?: number;\n\n /** Character used as a decimal separator. Generally used with `allowedDecimalSeparators` prop. @default '.' */\n decimalSeparator?: string;\n\n /** If `true`, automatically pads the decimal part with zeros to match `decimalScale` (e.g., with `decimalScale={2}`, typing `5.1` displays as `5.10`). Requires `decimalScale` to be set. @default false */\n fixedDecimalScale?: boolean;\n\n /** Prefix added before the input value */\n prefix?: string;\n\n /** Suffix added after the input value */\n suffix?: string;\n\n /** Defines the thousand grouping style. 'thousand' (1,000), 'lakh' (1,00,000), 'wan' (1,0000), 'none'. */\n thousandsGroupStyle?: 'thousand' | 'lakh' | 'wan' | 'none';\n\n /** A function to validate the input value. If this function returns `false`, the `onChange` will not be called and the input value will not change. */\n isAllowed?: (values: NumberFormatValues) => boolean;\n\n /** Advanced: Set to `true` if you're passing numeric strings (e.g., `\"12345\"`) and using formatting props like `prefix` or `suffix`. In most cases, you don't need this prop. See [react-number-format docs](https://www.npmjs.com/package/react-number-format) for details. @default false */\n valueIsNumericString?: boolean;\n\n /** Controls input `type` attribute @default 'text' */\n type?: 'text' | 'tel' | 'password';\n\n /** A character used to separate thousands */\n thousandSeparator?: string | boolean;\n\n /** Minimum possible value */\n min?: NumberInputNumericValue<T>;\n\n /** Maximum possible value */\n max?: NumberInputNumericValue<T>;\n\n /** Number by which value will be incremented/decremented with up/down controls and keyboard arrows @default 1 */\n step?: NumberInputNumericValue<T>;\n\n /** If set, the up/down controls are hidden @default false */\n hideControls?: boolean;\n\n /** Controls how values are clamped to the `min`/`max` range:\n * - `'blur'` (default): User can type any value, but it's clamped when the input loses focus\n * - `'strict'`: User cannot type values outside the range\n * - `'none'`: No clamping; `min`/`max` only apply to increment/decrement controls and arrow keys\n */\n clampBehavior?: 'strict' | 'blur' | 'none';\n\n /** If set, decimal values are allowed @default true */\n allowDecimal?: boolean;\n\n /** Increment/decrement handlers */\n handlersRef?: React.Ref<NumberInputHandlers | undefined>;\n\n /** Value used when incrementing/decrementing an empty input. If `min` is set and `startValue < min`, `min` is used instead. @default 0 */\n startValue?: NumberInputNumericValue<T>;\n\n /** Interval in milliseconds between value steps when increment/decrement button is held down. Can be a number or a function `(stepCount) => number` for dynamic intervals. Requires `stepHoldDelay` to be set. @default undefined */\n stepHoldInterval?: number | ((stepCount: number) => number);\n\n /** Initial delay in milliseconds before stepping the value. */\n stepHoldDelay?: number;\n\n /** If set, up/down keyboard events increment/decrement value @default true */\n withKeyboardEvents?: boolean;\n\n /** If set, leading zeros are removed on blur. For example, `00100` -> `100` @default true */\n trimLeadingZeroesOnBlur?: boolean;\n\n /** If set, all text is selected when the input receives focus @default false */\n selectAllOnFocus?: boolean;\n\n /** Called when the increment button or arrow up key is pressed and the value has reached the maximum */\n onMinReached?: () => void;\n\n /** Called when the decrement button or arrow down key is pressed and the value has reached the minimum */\n onMaxReached?: () => void;\n}\n\nexport type NumberInputFactory = Factory<{\n props: NumberInputProps;\n ref: HTMLInputElement;\n stylesNames: NumberInputStylesNames;\n vars: NumberInputCssVariables;\n variant: InputVariant;\n signature: <T extends NumberInputNumericType = number>(\n props: NumberInputProps<T>\n ) => React.JSX.Element;\n}>;\n\nconst defaultProps = {\n size: 'sm',\n step: 1,\n clampBehavior: 'blur',\n allowDecimal: true,\n allowNegative: true,\n withKeyboardEvents: true,\n allowLeadingZeros: true,\n trimLeadingZeroesOnBlur: true,\n startValue: 0,\n allowedDecimalSeparators: ['.', ','],\n} satisfies Partial<NumberInputProps<number | bigint>>;\n\nconst varsResolver = createVarsResolver<NumberInputFactory>((_, { size }) => ({\n controls: {\n '--ni-chevron-size': getSize(size, 'ni-chevron-size'),\n },\n}));\n\nfunction withTrailingSeparator(value: number, hasTrailingDecimalSeparator: boolean) {\n return hasTrailingDecimalSeparator ? `${value}.` : value;\n}\n\ninterface SanitizeInputOnBlurOptions {\n min: number | undefined;\n max: number | undefined;\n trim: boolean;\n clamp: boolean;\n}\n\nfunction sanitizeInputOnBlur(value: string, options: SanitizeInputOnBlurOptions) {\n const hasTrailingDecimalSeparator = trailingDecimalSeparatorPattern.test(value);\n const trimmed = options.trim ? value.replace(/^0+(?=\\d)/, '') : value;\n const parsedValue = parseFloat(trimmed);\n\n if (Number.isNaN(parsedValue)) {\n return trimmed;\n }\n\n if (!options.clamp) {\n return options.trim ? withTrailingSeparator(parsedValue, hasTrailingDecimalSeparator) : value;\n }\n\n const clamped =\n parsedValue > Number.MAX_SAFE_INTEGER && options.max !== undefined\n ? options.max\n : clamp(parsedValue, options.min, options.max);\n\n if (!options.trim && clamped === parsedValue) {\n return value;\n }\n\n return withTrailingSeparator(clamped, hasTrailingDecimalSeparator);\n}\n\nfunction clampAndSanitizeBigIntInput(\n sanitizedValue: string,\n options: { min?: bigint; max?: bigint; clampBehavior: NumberInputProps['clampBehavior'] }\n) {\n if (sanitizedValue === '' || sanitizedValue === '-') {\n return sanitizedValue;\n }\n\n const parsed = parseBigIntFromString(sanitizedValue);\n\n if (parsed === null) {\n return sanitizedValue;\n }\n\n return options.clampBehavior === 'blur' ? clampBigInt(parsed, options.min, options.max) : parsed;\n}\n\nexport const NumberInput = genericFactory<NumberInputFactory>(\n <T extends NumberInputNumericType = number>(_props: NumberInputProps<T>) => {\n const props = useProps(\n ['Input', 'InputWrapper', 'NumberInput'],\n defaultProps as Partial<NumberInputProps>,\n _props as unknown as NumberInputProps\n );\n const {\n className,\n classNames,\n styles,\n unstyled,\n vars,\n onChange,\n onValueChange,\n value,\n defaultValue,\n max,\n min,\n step,\n hideControls,\n rightSection,\n isAllowed,\n clampBehavior,\n onBlur,\n allowDecimal,\n decimalScale,\n onKeyDown,\n onKeyDownCapture,\n handlersRef,\n startValue,\n disabled,\n rightSectionPointerEvents,\n allowNegative,\n readOnly,\n size,\n rightSectionWidth,\n stepHoldInterval,\n stepHoldDelay,\n allowLeadingZeros,\n withKeyboardEvents,\n trimLeadingZeroesOnBlur,\n allowedDecimalSeparators,\n selectAllOnFocus,\n onMinReached,\n onMaxReached,\n onFocus,\n attributes,\n ref,\n ...others\n } = props;\n const allowNegativeResolved = allowNegative ?? true;\n const allowLeadingZerosResolved = allowLeadingZeros ?? true;\n\n const getStyles = useStyles<NumberInputFactory>({\n name: 'NumberInput',\n classes,\n props: props as NumberInputProps,\n classNames,\n styles,\n unstyled,\n attributes,\n vars,\n varsResolver,\n });\n\n const { resolvedClassNames, resolvedStyles } = useResolvedStylesApi<NumberInputFactory>({\n classNames,\n styles,\n props: props as NumberInputProps,\n });\n\n const valueModeRef = useRef<NumberInputMode>(\n isBigIntValue(value) || isBigIntValue(defaultValue) ? 'bigint' : 'number'\n );\n\n if (isBigIntValue(value)) {\n valueModeRef.current = 'bigint';\n } else if (typeof value === 'number') {\n valueModeRef.current = 'number';\n }\n\n const isBigIntMode = valueModeRef.current === 'bigint';\n\n const [_value, setValue] = useUncontrolled<InternalNumberInputValue>({\n value: value as InternalNumberInputValue | undefined,\n defaultValue: defaultValue as InternalNumberInputValue | undefined,\n finalValue: '',\n onChange: onChange as ((value: InternalNumberInputValue) => void) | undefined,\n });\n\n const shouldUseStepInterval = stepHoldDelay !== undefined && stepHoldInterval !== undefined;\n const inputRef = useRef<HTMLInputElement>(null);\n const onStepTimeoutRef = useRef<number | null>(null);\n const stepCountRef = useRef<number>(0);\n\n const minNumber = typeof min === 'number' ? min : undefined;\n const maxNumber = typeof max === 'number' ? max : undefined;\n const stepNumber = typeof step === 'number' ? step : defaultProps.step;\n const startValueNumber = typeof startValue === 'number' ? startValue : defaultProps.startValue;\n\n const minBigInt = toBigIntOrUndefined(min);\n const maxBigInt = toBigIntOrUndefined(max);\n const stepBigInt = toBigIntOrUndefined(step) ?? BigInt(1);\n const startValueBigInt = toBigIntOrUndefined(startValue) ?? BigInt(0);\n\n const parseBigIntOrString = (inputValue: string): bigint | string => {\n if (\n !isValidBigIntString(inputValue, allowNegativeResolved) ||\n (allowLeadingZerosResolved && leadingZerosPattern.test(inputValue))\n ) {\n return inputValue;\n }\n\n const parsed = parseBigIntFromString(inputValue);\n return parsed ?? inputValue;\n };\n\n const getBigIntFloatValue = (inputValue: bigint) => {\n const numericValue = Number(inputValue);\n return Number.isSafeInteger(numericValue) ? numericValue : undefined;\n };\n\n const handleValueChange: OnValueChange = (payload, event) => {\n if (event.source === 'event') {\n if (isBigIntMode) {\n setValue(parseBigIntOrString(payload.value));\n } else {\n setValue(\n isValidNumber(payload.floatValue, payload.value) &&\n !leadingDecimalZeroPattern.test(payload.value) &&\n !(allowLeadingZerosResolved ? leadingZerosPattern.test(payload.value) : false) &&\n !trailingZerosPattern.test(payload.value) &&\n !trailingDecimalSeparatorPattern.test(payload.value)\n ? payload.floatValue\n : payload.value\n );\n }\n }\n onValueChange?.(payload, event);\n };\n\n const getDecimalPlaces = (inputValue: number | string): number => {\n const match = String(inputValue).match(/(?:\\.(\\d+))?(?:[eE]([+-]?\\d+))?$/);\n if (!match) {\n return 0;\n }\n return Math.max(0, (match[1] ? match[1].length : 0) - (match[2] ? +match[2] : 0));\n };\n\n const adjustCursor = (position?: number) => {\n if (inputRef.current && typeof position !== 'undefined') {\n inputRef.current.setSelectionRange(position, position);\n }\n };\n\n const incrementRef = useRef<() => void>(noop);\n incrementRef.current = () => {\n if (isBigIntMode) {\n if (!canStepBigInt(_value as bigint | string, allowNegativeResolved)) {\n return;\n }\n\n let val: bigint;\n const currentValue = _value;\n\n if (typeof currentValue === 'bigint') {\n const incrementedValue = currentValue + stepBigInt;\n if (maxBigInt !== undefined && incrementedValue > maxBigInt) {\n onMaxReached?.();\n }\n val =\n maxBigInt !== undefined && incrementedValue > maxBigInt ? maxBigInt : incrementedValue;\n } else if (typeof currentValue === 'string' && currentValue !== '') {\n const parsed = parseBigIntFromString(currentValue);\n if (parsed === null) {\n return;\n }\n\n const incrementedValue = parsed + stepBigInt;\n if (maxBigInt !== undefined && incrementedValue > maxBigInt) {\n onMaxReached?.();\n }\n val =\n maxBigInt !== undefined && incrementedValue > maxBigInt ? maxBigInt : incrementedValue;\n } else {\n val = clampBigInt(startValueBigInt, minBigInt, maxBigInt);\n }\n\n const formattedValue = val.toString();\n setValue(val);\n onValueChange?.(\n { floatValue: getBigIntFloatValue(val), formattedValue, value: formattedValue },\n { source: 'increment' as any }\n );\n setTimeout(() => adjustCursor(inputRef.current?.value.length), 0);\n return;\n }\n\n if (!canStep(_value as number | string)) {\n return;\n }\n\n let val: number;\n const currentValuePrecision = getDecimalPlaces(_value as number | string);\n const stepPrecision = getDecimalPlaces(stepNumber);\n const maxPrecision = Math.max(currentValuePrecision, stepPrecision);\n const factor = 10 ** maxPrecision;\n\n if (!isNumberString(_value) && (typeof _value !== 'number' || Number.isNaN(_value))) {\n val = clamp(startValueNumber, minNumber, maxNumber);\n } else if (maxNumber !== undefined) {\n const incrementedValue =\n (Math.round(Number(_value) * factor) + Math.round(stepNumber * factor)) / factor;\n if (incrementedValue > maxNumber) {\n onMaxReached?.();\n }\n val = incrementedValue <= maxNumber ? incrementedValue : maxNumber;\n } else {\n val = (Math.round(Number(_value) * factor) + Math.round(stepNumber * factor)) / factor;\n }\n\n const formattedValue = val.toFixed(maxPrecision);\n setValue(parseFloat(formattedValue));\n onValueChange?.(\n { floatValue: parseFloat(formattedValue), formattedValue, value: formattedValue },\n { source: 'increment' as any }\n );\n setTimeout(() => adjustCursor(inputRef.current?.value.length), 0);\n };\n\n const decrementRef = useRef<() => void>(noop);\n decrementRef.current = () => {\n if (isBigIntMode) {\n if (!canStepBigInt(_value as bigint | string, allowNegativeResolved)) {\n return;\n }\n\n let val: bigint;\n const minValue =\n minBigInt !== undefined ? minBigInt : !allowNegativeResolved ? BigInt(0) : undefined;\n const currentValue = _value;\n\n if (typeof currentValue === 'bigint') {\n const decrementedValue = currentValue - stepBigInt;\n if (minValue !== undefined && decrementedValue < minValue) {\n onMinReached?.();\n }\n val = minValue !== undefined && decrementedValue < minValue ? minValue : decrementedValue;\n } else if (typeof currentValue === 'string' && currentValue !== '') {\n const parsed = parseBigIntFromString(currentValue);\n if (parsed === null) {\n return;\n }\n\n const decrementedValue = parsed - stepBigInt;\n if (minValue !== undefined && decrementedValue < minValue) {\n onMinReached?.();\n }\n val = minValue !== undefined && decrementedValue < minValue ? minValue : decrementedValue;\n } else {\n val = clampBigInt(startValueBigInt, minValue, maxBigInt);\n }\n\n const formattedValue = val.toString();\n setValue(val);\n onValueChange?.(\n { floatValue: getBigIntFloatValue(val), formattedValue, value: formattedValue },\n { source: 'decrement' as any }\n );\n setTimeout(() => adjustCursor(inputRef.current?.value.length), 0);\n return;\n }\n\n if (!canStep(_value as number | string)) {\n return;\n }\n\n let val: number;\n const minValue =\n minNumber !== undefined ? minNumber : !allowNegativeResolved ? 0 : Number.MIN_SAFE_INTEGER;\n const currentValuePrecision = getDecimalPlaces(_value as number | string);\n const stepPrecision = getDecimalPlaces(stepNumber);\n const maxPrecision = Math.max(currentValuePrecision, stepPrecision);\n const factor = 10 ** maxPrecision;\n\n if ((!isNumberString(_value) && typeof _value !== 'number') || Number.isNaN(_value)) {\n val = clamp(startValueNumber, minValue, maxNumber);\n } else {\n const decrementedValue =\n (Math.round(Number(_value) * factor) - Math.round(stepNumber * factor)) / factor;\n if (minValue !== undefined && decrementedValue < minValue) {\n onMinReached?.();\n }\n val = minValue !== undefined && decrementedValue < minValue ? minValue : decrementedValue;\n }\n\n const formattedValue = val.toFixed(maxPrecision);\n setValue(parseFloat(formattedValue));\n onValueChange?.(\n { floatValue: parseFloat(formattedValue), formattedValue, value: formattedValue },\n { source: 'decrement' as any }\n );\n setTimeout(() => adjustCursor(inputRef.current?.value.length), 0);\n };\n\n const handlePaste = (event: React.ClipboardEvent<HTMLInputElement>) => {\n const pastedText = event.clipboardData.getData('text');\n const _decimalSeparator = others.decimalSeparator || '.';\n const _thousandSeparator =\n others.thousandSeparator === true\n ? ','\n : others.thousandSeparator === false\n ? undefined\n : others.thousandSeparator;\n const modifiedText = normalizePastedValue(pastedText, {\n decimalSeparator: _decimalSeparator,\n thousandSeparator: _thousandSeparator,\n allowedDecimalSeparators: allowedDecimalSeparators || ['.', ','],\n thousandsGroupStyle: others.thousandsGroupStyle,\n });\n\n if (modifiedText !== pastedText) {\n event.preventDefault();\n\n const input = inputRef.current;\n if (input) {\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n const currentValue = input.value;\n const newValue =\n currentValue.substring(0, start) + modifiedText + currentValue.substring(end);\n\n const nativeInputValueSetter = Object.getOwnPropertyDescriptor(\n window.HTMLInputElement.prototype,\n 'value'\n )?.set;\n nativeInputValueSetter?.call(input, newValue);\n input.dispatchEvent(new Event('change', { bubbles: true }));\n\n const rawCaret = start + modifiedText.length;\n setTimeout(\n () =>\n adjustCursor(\n getCaretPositionAfterPaste(newValue, rawCaret, input.value, _decimalSeparator)\n ),\n 0\n );\n }\n }\n\n others.onPaste?.(event as any);\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n onKeyDown?.(event);\n\n if (readOnly || !withKeyboardEvents) {\n return;\n }\n\n if (event.key === 'ArrowUp') {\n event.preventDefault();\n incrementRef.current?.();\n }\n\n if (event.key === 'ArrowDown') {\n event.preventDefault();\n decrementRef.current?.();\n }\n };\n\n const handleKeyDownCapture = (event: React.KeyboardEvent<HTMLInputElement>) => {\n onKeyDownCapture?.(event);\n if (event.key === 'Backspace') {\n const input = inputRef.current;\n if (input && input.selectionStart === 0 && input.selectionStart === input.selectionEnd) {\n event.preventDefault();\n window.setTimeout(() => adjustCursor(0), 0);\n }\n }\n };\n\n const handleFocus = (event: React.FocusEvent<HTMLInputElement>) => {\n if (selectAllOnFocus) {\n window.setTimeout(() => inputRef.current?.select(), 0);\n }\n onFocus?.(event);\n };\n\n const handleBlur = (event: React.FocusEvent<HTMLInputElement>) => {\n let sanitizedValue = _value;\n\n if (isBigIntMode) {\n if (clampBehavior === 'blur' && typeof sanitizedValue === 'bigint') {\n sanitizedValue = clampBigInt(sanitizedValue, minBigInt, maxBigInt);\n }\n\n if (trimLeadingZeroesOnBlur && typeof sanitizedValue === 'string') {\n sanitizedValue = clampAndSanitizeBigIntInput(sanitizedValue, {\n min: minBigInt,\n max: maxBigInt,\n clampBehavior,\n });\n }\n } else if (typeof sanitizedValue === 'number') {\n if (clampBehavior === 'blur') {\n sanitizedValue = clamp(sanitizedValue, minNumber, maxNumber);\n }\n } else if (typeof sanitizedValue === 'string') {\n sanitizedValue = sanitizeInputOnBlur(sanitizedValue, {\n min: minNumber,\n max: maxNumber,\n trim: !!trimLeadingZeroesOnBlur && getDecimalPlaces(sanitizedValue) < 15,\n clamp: clampBehavior === 'blur',\n });\n }\n\n if (_value !== sanitizedValue) {\n setValue(sanitizedValue);\n }\n\n onBlur?.(event);\n };\n\n assignRef(handlersRef, { increment: incrementRef.current, decrement: decrementRef.current });\n\n const onStepHandleChange = (isIncrement: boolean) => {\n if (isIncrement) {\n incrementRef.current?.();\n } else {\n decrementRef.current?.();\n }\n stepCountRef.current += 1;\n };\n\n const onStepLoop = (isIncrement: boolean) => {\n onStepHandleChange(isIncrement);\n\n if (shouldUseStepInterval) {\n const interval =\n typeof stepHoldInterval === 'number'\n ? stepHoldInterval\n : stepHoldInterval(stepCountRef.current);\n onStepTimeoutRef.current = window.setTimeout(() => onStepLoop(isIncrement), interval);\n }\n };\n\n const onStep = (\n event: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>,\n isIncrement: boolean\n ) => {\n event.preventDefault();\n inputRef.current?.focus();\n onStepHandleChange(isIncrement);\n if (shouldUseStepInterval) {\n onStepTimeoutRef.current = window.setTimeout(() => onStepLoop(isIncrement), stepHoldDelay);\n }\n };\n\n const onStepDone = () => {\n if (onStepTimeoutRef.current) {\n window.clearTimeout(onStepTimeoutRef.current);\n }\n onStepTimeoutRef.current = null;\n stepCountRef.current = 0;\n };\n\n const controls = (\n <div {...getStyles('controls')}>\n <UnstyledButton\n {...getStyles('control')}\n tabIndex={-1}\n aria-hidden\n disabled={\n disabled ||\n (typeof _value === 'number' && maxNumber !== undefined && _value >= maxNumber) ||\n (typeof _value === 'bigint' && maxBigInt !== undefined && _value >= maxBigInt)\n }\n mod={{ direction: 'up' }}\n onMouseDown={(event) => event.preventDefault()}\n onPointerDown={(event) => {\n onStep(event, true);\n }}\n onPointerUp={onStepDone}\n onPointerLeave={onStepDone}\n >\n <NumberInputChevron direction=\"up\" />\n </UnstyledButton>\n <UnstyledButton\n {...getStyles('control')}\n tabIndex={-1}\n aria-hidden\n disabled={\n disabled ||\n (typeof _value === 'number' && minNumber !== undefined && _value <= minNumber) ||\n (typeof _value === 'bigint' && minBigInt !== undefined && _value <= minBigInt)\n }\n mod={{ direction: 'down' }}\n onMouseDown={(event) => event.preventDefault()}\n onPointerDown={(event) => {\n onStep(event, false);\n }}\n onPointerUp={onStepDone}\n onPointerLeave={onStepDone}\n >\n <NumberInputChevron direction=\"down\" />\n </UnstyledButton>\n </div>\n );\n\n return (\n <InputBase\n component={NumericFormat}\n allowNegative={allowNegative}\n className={cx(classes.root, className)}\n size={size}\n {...others}\n inputMode={isBigIntMode ? 'numeric' : 'decimal'}\n readOnly={readOnly}\n disabled={disabled}\n value={typeof _value === 'bigint' ? _value.toString() : _value}\n getInputRef={useMergedRef(ref, inputRef)}\n onValueChange={handleValueChange}\n rightSection={\n hideControls ||\n readOnly ||\n !(isBigIntMode\n ? canStepBigInt(_value as bigint | string, allowNegativeResolved)\n : canStep(_value as number | string))\n ? rightSection\n : rightSection || controls\n }\n classNames={resolvedClassNames}\n styles={resolvedStyles}\n unstyled={unstyled}\n __staticSelector=\"NumberInput\"\n decimalScale={isBigIntMode ? 0 : allowDecimal ? decimalScale : 0}\n onPaste={handlePaste}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n onKeyDownCapture={handleKeyDownCapture}\n rightSectionPointerEvents={rightSectionPointerEvents ?? (disabled ? 'none' : undefined)}\n rightSectionWidth={rightSectionWidth ?? `var(--ni-right-section-width-${size || 'sm'})`}\n allowLeadingZeros={allowLeadingZeros}\n allowedDecimalSeparators={allowedDecimalSeparators}\n onBlur={handleBlur}\n attributes={attributes}\n isAllowed={(val) => {\n const userAllowed = isAllowed ? isAllowed(val) : true;\n if (!userAllowed) {\n return false;\n }\n\n if (clampBehavior !== 'strict') {\n return true;\n }\n\n if (!isBigIntMode) {\n return isInRange(val.floatValue, minNumber, maxNumber);\n }\n\n if (val.value === '' || val.value === '-') {\n return true;\n }\n\n const parsed = parseBigIntFromString(val.value);\n\n if (parsed === null) {\n return true;\n }\n\n return (\n (minBigInt === undefined || parsed >= minBigInt) &&\n (maxBigInt === undefined || parsed <= maxBigInt)\n );\n }}\n />\n );\n }\n);\n\nNumberInput.classes = { ...InputBase.classes, ...classes };\nNumberInput.varsResolver = varsResolver;\nNumberInput.displayName = '@mantine/core/NumberInput';\n\nexport namespace NumberInput {\n export type Props<T extends NumberInputNumericType = number> = NumberInputProps<T>;\n export type StylesNames = NumberInputStylesNames;\n export type Factory = NumberInputFactory;\n export type CssVariables = NumberInputCssVariables;\n export type Handlers = NumberInputHandlers;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA2BA,MAAM,4BAA4B;AAGlC,MAAM,sBAAsB;AAG5B,MAAM,uBAAuB;AAG7B,MAAM,kCAAkC;AAaxC,SAAS,eAAe,OAAgB;CACtC,OAAO,OAAO,UAAU,YAAY,UAAU,MAAM,CAAC,OAAO,MAAM,OAAO,KAAK,CAAC;AACjF;AAEA,SAAS,cAAc,OAAiC;CACtD,OAAO,OAAO,UAAU;AAC1B;AAEA,SAAS,QAAQ,OAAwB;CACvC,IAAI,OAAO,UAAU,UACnB,OAAO,QAAQ,OAAO;CAGxB,OAAO,UAAU,MAAO,eAAe,KAAK,KAAK,OAAO,KAAK,IAAI,OAAO;AAC1E;AAEA,SAAS,oBAAoB,OAAe,eAAwB;CAClE,IAAI,UAAU,IACZ,OAAO;CAGT,IAAI,UAAU,KACZ,OAAO;CAGT,IAAI,CAAC,iBAAiB,MAAM,WAAW,GAAG,GACxC,OAAO;CAGT,OAAO,UAAU,KAAK,KAAK;AAC7B;AAEA,SAAS,cAAc,OAAwB,eAAwB;CACrE,IAAI,OAAO,UAAU,UACnB,OAAO;CAGT,OAAO,UAAU,MAAM,oBAAoB,OAAO,aAAa;AACjE;AAEA,SAAS,sBAAsB,OAA8B;CAC3D,IAAI,CAAC,UAAU,KAAK,KAAK,GACvB,OAAO;CAGT,IAAI;EACF,OAAO,OAAO,KAAK;CACrB,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,oBAAoB,OAAoC;CAC/D,IAAI,OAAO,UAAU,UACnB,OAAO;CAGT,IAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,KAAK,OAAO,UAAU,KAAK,GAC/E,OAAO,OAAO,KAAK;AAIvB;AAEA,SAAS,YAAY,OAAe,KAAc,KAAc;CAC9D,IAAI,QAAQ,KAAA,KAAa,QAAQ,KAC/B,OAAO;CAGT,IAAI,QAAQ,KAAA,KAAa,QAAQ,KAC/B,OAAO;CAGT,OAAO;AACT;AAEA,SAAS,eAAe,YAAqC;CAG3D,OAAO,WAAW,SAAS,CAAC,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC;AAChD;AAEA,SAAS,cAAc,YAAgC,OAAqC;CAC1F,QACG,OAAO,eAAe,WACnB,aAAa,OAAO,mBACpB,CAAC,OAAO,MAAM,OAAO,UAAU,CAAC,MACpC,CAAC,OAAO,MAAM,UAAU,KACxB,eAAe,KAAK,IAAI,MACxB,UAAU;AAEd;AAEA,SAAS,UAAU,OAA2B,KAAyB,KAAyB;CAC9F,IAAI,UAAU,KAAA,GACZ,OAAO;CAMT,QAHiB,QAAQ,KAAA,KAAa,SAAS,SAC9B,QAAQ,KAAA,KAAa,SAAS;AAGjD;AAgIA,MAAM,eAAe;CACnB,MAAM;CACN,MAAM;CACN,eAAe;CACf,cAAc;CACd,eAAe;CACf,oBAAoB;CACpB,mBAAmB;CACnB,yBAAyB;CACzB,YAAY;CACZ,0BAA0B,CAAC,KAAK,GAAG;AACrC;AAEA,MAAM,eAAe,oBAAwC,GAAG,EAAE,YAAY,EAC5E,UAAU,EACR,qBAAqB,QAAQ,MAAM,iBAAiB,EACtD,EACF,EAAE;AAEF,SAAS,sBAAsB,OAAe,6BAAsC;CAClF,OAAO,8BAA8B,GAAG,MAAM,KAAK;AACrD;AASA,SAAS,oBAAoB,OAAe,SAAqC;CAC/E,MAAM,8BAA8B,gCAAgC,KAAK,KAAK;CAC9E,MAAM,UAAU,QAAQ,OAAO,MAAM,QAAQ,aAAa,EAAE,IAAI;CAChE,MAAM,cAAc,WAAW,OAAO;CAEtC,IAAI,OAAO,MAAM,WAAW,GAC1B,OAAO;CAGT,IAAI,CAAC,QAAQ,OACX,OAAO,QAAQ,OAAO,sBAAsB,aAAa,2BAA2B,IAAI;CAG1F,MAAM,UACJ,cAAc,OAAO,oBAAoB,QAAQ,QAAQ,KAAA,IACrD,QAAQ,MACR,MAAM,aAAa,QAAQ,KAAK,QAAQ,GAAG;CAEjD,IAAI,CAAC,QAAQ,QAAQ,YAAY,aAC/B,OAAO;CAGT,OAAO,sBAAsB,SAAS,2BAA2B;AACnE;AAEA,SAAS,4BACP,gBACA,SACA;CACA,IAAI,mBAAmB,MAAM,mBAAmB,KAC9C,OAAO;CAGT,MAAM,SAAS,sBAAsB,cAAc;CAEnD,IAAI,WAAW,MACb,OAAO;CAGT,OAAO,QAAQ,kBAAkB,SAAS,YAAY,QAAQ,QAAQ,KAAK,QAAQ,GAAG,IAAI;AAC5F;AAEA,MAAa,cAAc,gBACmB,WAAgC;CAC1E,MAAM,QAAQ,SACZ;EAAC;EAAS;EAAgB;CAAa,GACvC,cACA,MACF;CACA,MAAM,EACJ,WACA,YACA,QACA,UACA,MACA,UACA,eACA,OACA,cACA,KACA,KACA,MACA,cACA,cACA,WACA,eACA,QACA,cACA,cACA,WACA,kBACA,aACA,YACA,UACA,2BACA,eACA,UACA,MACA,mBACA,kBACA,eACA,mBACA,oBACA,yBACA,0BACA,kBACA,cACA,cACA,SACA,YACA,KACA,GAAG,WACD;CACJ,MAAM,wBAAwB,iBAAiB;CAC/C,MAAM,4BAA4B,qBAAqB;CAEvD,MAAM,YAAY,UAA8B;EAC9C,MAAM;EACN,SAAA;EACO;EACP;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,EAAE,oBAAoB,mBAAmB,qBAAyC;EACtF;EACA;EACO;CACT,CAAC;CAED,MAAM,eAAe,OACnB,cAAc,KAAK,KAAK,cAAc,YAAY,IAAI,WAAW,QACnE;CAEA,IAAI,cAAc,KAAK,GACrB,aAAa,UAAU;MAClB,IAAI,OAAO,UAAU,UAC1B,aAAa,UAAU;CAGzB,MAAM,eAAe,aAAa,YAAY;CAE9C,MAAM,CAAC,QAAQ,YAAY,gBAA0C;EAC5D;EACO;EACd,YAAY;EACF;CACZ,CAAC;CAED,MAAM,wBAAwB,kBAAkB,KAAA,KAAa,qBAAqB,KAAA;CAClF,MAAM,WAAW,OAAyB,IAAI;CAC9C,MAAM,mBAAmB,OAAsB,IAAI;CACnD,MAAM,eAAe,OAAe,CAAC;CAErC,MAAM,YAAY,OAAO,QAAQ,WAAW,MAAM,KAAA;CAClD,MAAM,YAAY,OAAO,QAAQ,WAAW,MAAM,KAAA;CAClD,MAAM,aAAa,OAAO,SAAS,WAAW,OAAO,aAAa;CAClE,MAAM,mBAAmB,OAAO,eAAe,WAAW,aAAa,aAAa;CAEpF,MAAM,YAAY,oBAAoB,GAAG;CACzC,MAAM,YAAY,oBAAoB,GAAG;CACzC,MAAM,aAAa,oBAAoB,IAAI,KAAK,OAAO,CAAC;CACxD,MAAM,mBAAmB,oBAAoB,UAAU,KAAK,OAAO,CAAC;CAEpE,MAAM,uBAAuB,eAAwC;EACnE,IACE,CAAC,oBAAoB,YAAY,qBAAqB,KACrD,6BAA6B,oBAAoB,KAAK,UAAU,GAEjE,OAAO;EAIT,OADe,sBAAsB,UACzB,KAAK;CACnB;CAEA,MAAM,uBAAuB,eAAuB;EAClD,MAAM,eAAe,OAAO,UAAU;EACtC,OAAO,OAAO,cAAc,YAAY,IAAI,eAAe,KAAA;CAC7D;CAEA,MAAM,qBAAoC,SAAS,UAAU;EAC3D,IAAI,MAAM,WAAW,SAAS;GAC5B,IAAI,cACF,SAAS,oBAAoB,QAAQ,KAAK,CAAC;QAE3C,SACE,cAAc,QAAQ,YAAY,QAAQ,KAAK,KAC7C,CAAC,0BAA0B,KAAK,QAAQ,KAAK,KAC7C,EAAE,4BAA4B,oBAAoB,KAAK,QAAQ,KAAK,IAAI,UACxE,CAAC,qBAAqB,KAAK,QAAQ,KAAK,KACxC,CAAC,gCAAgC,KAAK,QAAQ,KAAK,IACjD,QAAQ,aACR,QAAQ,KACd;EAEJ;EACA,gBAAgB,SAAS,KAAK;CAChC;CAEA,MAAM,oBAAoB,eAAwC;EAChE,MAAM,QAAQ,OAAO,UAAU,CAAC,CAAC,MAAM,kCAAkC;EACzE,IAAI,CAAC,OACH,OAAO;EAET,OAAO,KAAK,IAAI,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC,SAAS,MAAM,MAAM,KAAK,CAAC,MAAM,KAAK,EAAE;CAClF;CAEA,MAAM,gBAAgB,aAAsB;EAC1C,IAAI,SAAS,WAAW,OAAO,aAAa,aAC1C,SAAS,QAAQ,kBAAkB,UAAU,QAAQ;CAEzD;CAEA,MAAM,eAAe,OAAmB,IAAI;CAC5C,aAAa,gBAAgB;EAC3B,IAAI,cAAc;GAChB,IAAI,CAAC,cAAc,QAA2B,qBAAqB,GACjE;GAGF,IAAI;GACJ,MAAM,eAAe;GAErB,IAAI,OAAO,iBAAiB,UAAU;IACpC,MAAM,mBAAmB,eAAe;IACxC,IAAI,cAAc,KAAA,KAAa,mBAAmB,WAChD,eAAe;IAEjB,MACE,cAAc,KAAA,KAAa,mBAAmB,YAAY,YAAY;GAC1E,OAAO,IAAI,OAAO,iBAAiB,YAAY,iBAAiB,IAAI;IAClE,MAAM,SAAS,sBAAsB,YAAY;IACjD,IAAI,WAAW,MACb;IAGF,MAAM,mBAAmB,SAAS;IAClC,IAAI,cAAc,KAAA,KAAa,mBAAmB,WAChD,eAAe;IAEjB,MACE,cAAc,KAAA,KAAa,mBAAmB,YAAY,YAAY;GAC1E,OACE,MAAM,YAAY,kBAAkB,WAAW,SAAS;GAG1D,MAAM,iBAAiB,IAAI,SAAS;GACpC,SAAS,GAAG;GACZ,gBACE;IAAE,YAAY,oBAAoB,GAAG;IAAG;IAAgB,OAAO;GAAe,GAC9E,EAAE,QAAQ,YAAmB,CAC/B;GACA,iBAAiB,aAAa,SAAS,SAAS,MAAM,MAAM,GAAG,CAAC;GAChE;EACF;EAEA,IAAI,CAAC,QAAQ,MAAyB,GACpC;EAGF,IAAI;EACJ,MAAM,wBAAwB,iBAAiB,MAAyB;EACxE,MAAM,gBAAgB,iBAAiB,UAAU;EACjD,MAAM,eAAe,KAAK,IAAI,uBAAuB,aAAa;EAClE,MAAM,SAAS,MAAM;EAErB,IAAI,CAAC,eAAe,MAAM,MAAM,OAAO,WAAW,YAAY,OAAO,MAAM,MAAM,IAC/E,MAAM,MAAM,kBAAkB,WAAW,SAAS;OAC7C,IAAI,cAAc,KAAA,GAAW;GAClC,MAAM,oBACH,KAAK,MAAM,OAAO,MAAM,IAAI,MAAM,IAAI,KAAK,MAAM,aAAa,MAAM,KAAK;GAC5E,IAAI,mBAAmB,WACrB,eAAe;GAEjB,MAAM,oBAAoB,YAAY,mBAAmB;EAC3D,OACE,OAAO,KAAK,MAAM,OAAO,MAAM,IAAI,MAAM,IAAI,KAAK,MAAM,aAAa,MAAM,KAAK;EAGlF,MAAM,iBAAiB,IAAI,QAAQ,YAAY;EAC/C,SAAS,WAAW,cAAc,CAAC;EACnC,gBACE;GAAE,YAAY,WAAW,cAAc;GAAG;GAAgB,OAAO;EAAe,GAChF,EAAE,QAAQ,YAAmB,CAC/B;EACA,iBAAiB,aAAa,SAAS,SAAS,MAAM,MAAM,GAAG,CAAC;CAClE;CAEA,MAAM,eAAe,OAAmB,IAAI;CAC5C,aAAa,gBAAgB;EAC3B,IAAI,cAAc;GAChB,IAAI,CAAC,cAAc,QAA2B,qBAAqB,GACjE;GAGF,IAAI;GACJ,MAAM,WACJ,cAAc,KAAA,IAAY,YAAY,CAAC,wBAAwB,OAAO,CAAC,IAAI,KAAA;GAC7E,MAAM,eAAe;GAErB,IAAI,OAAO,iBAAiB,UAAU;IACpC,MAAM,mBAAmB,eAAe;IACxC,IAAI,aAAa,KAAA,KAAa,mBAAmB,UAC/C,eAAe;IAEjB,MAAM,aAAa,KAAA,KAAa,mBAAmB,WAAW,WAAW;GAC3E,OAAO,IAAI,OAAO,iBAAiB,YAAY,iBAAiB,IAAI;IAClE,MAAM,SAAS,sBAAsB,YAAY;IACjD,IAAI,WAAW,MACb;IAGF,MAAM,mBAAmB,SAAS;IAClC,IAAI,aAAa,KAAA,KAAa,mBAAmB,UAC/C,eAAe;IAEjB,MAAM,aAAa,KAAA,KAAa,mBAAmB,WAAW,WAAW;GAC3E,OACE,MAAM,YAAY,kBAAkB,UAAU,SAAS;GAGzD,MAAM,iBAAiB,IAAI,SAAS;GACpC,SAAS,GAAG;GACZ,gBACE;IAAE,YAAY,oBAAoB,GAAG;IAAG;IAAgB,OAAO;GAAe,GAC9E,EAAE,QAAQ,YAAmB,CAC/B;GACA,iBAAiB,aAAa,SAAS,SAAS,MAAM,MAAM,GAAG,CAAC;GAChE;EACF;EAEA,IAAI,CAAC,QAAQ,MAAyB,GACpC;EAGF,IAAI;EACJ,MAAM,WACJ,cAAc,KAAA,IAAY,YAAY,CAAC,wBAAwB,IAAI,OAAO;EAC5E,MAAM,wBAAwB,iBAAiB,MAAyB;EACxE,MAAM,gBAAgB,iBAAiB,UAAU;EACjD,MAAM,eAAe,KAAK,IAAI,uBAAuB,aAAa;EAClE,MAAM,SAAS,MAAM;EAErB,IAAK,CAAC,eAAe,MAAM,KAAK,OAAO,WAAW,YAAa,OAAO,MAAM,MAAM,GAChF,MAAM,MAAM,kBAAkB,UAAU,SAAS;OAC5C;GACL,MAAM,oBACH,KAAK,MAAM,OAAO,MAAM,IAAI,MAAM,IAAI,KAAK,MAAM,aAAa,MAAM,KAAK;GAC5E,IAAI,aAAa,KAAA,KAAa,mBAAmB,UAC/C,eAAe;GAEjB,MAAM,aAAa,KAAA,KAAa,mBAAmB,WAAW,WAAW;EAC3E;EAEA,MAAM,iBAAiB,IAAI,QAAQ,YAAY;EAC/C,SAAS,WAAW,cAAc,CAAC;EACnC,gBACE;GAAE,YAAY,WAAW,cAAc;GAAG;GAAgB,OAAO;EAAe,GAChF,EAAE,QAAQ,YAAmB,CAC/B;EACA,iBAAiB,aAAa,SAAS,SAAS,MAAM,MAAM,GAAG,CAAC;CAClE;CAEA,MAAM,eAAe,UAAkD;EACrE,MAAM,aAAa,MAAM,cAAc,QAAQ,MAAM;EACrD,MAAM,oBAAoB,OAAO,oBAAoB;EACrD,MAAM,qBACJ,OAAO,sBAAsB,OACzB,MACA,OAAO,sBAAsB,QAC3B,KAAA,IACA,OAAO;EACf,MAAM,eAAe,qBAAqB,YAAY;GACpD,kBAAkB;GAClB,mBAAmB;GACnB,0BAA0B,4BAA4B,CAAC,KAAK,GAAG;GAC/D,qBAAqB,OAAO;EAC9B,CAAC;EAED,IAAI,iBAAiB,YAAY;GAC/B,MAAM,eAAe;GAErB,MAAM,QAAQ,SAAS;GACvB,IAAI,OAAO;IACT,MAAM,QAAQ,MAAM,kBAAkB;IACtC,MAAM,MAAM,MAAM,gBAAgB;IAClC,MAAM,eAAe,MAAM;IAC3B,MAAM,WACJ,aAAa,UAAU,GAAG,KAAK,IAAI,eAAe,aAAa,UAAU,GAAG;IAM9E,CAJ+B,OAAO,yBACpC,OAAO,iBAAiB,WACxB,OACF,CAAC,EAAE,IAAA,EACqB,KAAK,OAAO,QAAQ;IAC5C,MAAM,cAAc,IAAI,MAAM,UAAU,EAAE,SAAS,KAAK,CAAC,CAAC;IAE1D,MAAM,WAAW,QAAQ,aAAa;IACtC,iBAEI,aACE,2BAA2B,UAAU,UAAU,MAAM,OAAO,iBAAiB,CAC/E,GACF,CACF;GACF;EACF;EAEA,OAAO,UAAU,KAAY;CAC/B;CAEA,MAAM,iBAAiB,UAAiD;EACtE,YAAY,KAAK;EAEjB,IAAI,YAAY,CAAC,oBACf;EAGF,IAAI,MAAM,QAAQ,WAAW;GAC3B,MAAM,eAAe;GACrB,aAAa,UAAU;EACzB;EAEA,IAAI,MAAM,QAAQ,aAAa;GAC7B,MAAM,eAAe;GACrB,aAAa,UAAU;EACzB;CACF;CAEA,MAAM,wBAAwB,UAAiD;EAC7E,mBAAmB,KAAK;EACxB,IAAI,MAAM,QAAQ,aAAa;GAC7B,MAAM,QAAQ,SAAS;GACvB,IAAI,SAAS,MAAM,mBAAmB,KAAK,MAAM,mBAAmB,MAAM,cAAc;IACtF,MAAM,eAAe;IACrB,OAAO,iBAAiB,aAAa,CAAC,GAAG,CAAC;GAC5C;EACF;CACF;CAEA,MAAM,eAAe,UAA8C;EACjE,IAAI,kBACF,OAAO,iBAAiB,SAAS,SAAS,OAAO,GAAG,CAAC;EAEvD,UAAU,KAAK;CACjB;CAEA,MAAM,cAAc,UAA8C;EAChE,IAAI,iBAAiB;EAErB,IAAI,cAAc;GAChB,IAAI,kBAAkB,UAAU,OAAO,mBAAmB,UACxD,iBAAiB,YAAY,gBAAgB,WAAW,SAAS;GAGnE,IAAI,2BAA2B,OAAO,mBAAmB,UACvD,iBAAiB,4BAA4B,gBAAgB;IAC3D,KAAK;IACL,KAAK;IACL;GACF,CAAC;EAEL,OAAO,IAAI,OAAO,mBAAmB,UAC/B;OAAA,kBAAkB,QACpB,iBAAiB,MAAM,gBAAgB,WAAW,SAAS;EAAA,OAExD,IAAI,OAAO,mBAAmB,UACnC,iBAAiB,oBAAoB,gBAAgB;GACnD,KAAK;GACL,KAAK;GACL,MAAM,CAAC,CAAC,2BAA2B,iBAAiB,cAAc,IAAI;GACtE,OAAO,kBAAkB;EAC3B,CAAC;EAGH,IAAI,WAAW,gBACb,SAAS,cAAc;EAGzB,SAAS,KAAK;CAChB;CAEA,UAAU,aAAa;EAAE,WAAW,aAAa;EAAS,WAAW,aAAa;CAAQ,CAAC;CAE3F,MAAM,sBAAsB,gBAAyB;EACnD,IAAI,aACF,aAAa,UAAU;OAEvB,aAAa,UAAU;EAEzB,aAAa,WAAW;CAC1B;CAEA,MAAM,cAAc,gBAAyB;EAC3C,mBAAmB,WAAW;EAE9B,IAAI,uBAAuB;GACzB,MAAM,WACJ,OAAO,qBAAqB,WACxB,mBACA,iBAAiB,aAAa,OAAO;GAC3C,iBAAiB,UAAU,OAAO,iBAAiB,WAAW,WAAW,GAAG,QAAQ;EACtF;CACF;CAEA,MAAM,UACJ,OACA,gBACG;EACH,MAAM,eAAe;EACrB,SAAS,SAAS,MAAM;EACxB,mBAAmB,WAAW;EAC9B,IAAI,uBACF,iBAAiB,UAAU,OAAO,iBAAiB,WAAW,WAAW,GAAG,aAAa;CAE7F;CAEA,MAAM,mBAAmB;EACvB,IAAI,iBAAiB,SACnB,OAAO,aAAa,iBAAiB,OAAO;EAE9C,iBAAiB,UAAU;EAC3B,aAAa,UAAU;CACzB;CAEA,MAAM,WACJ,qBAAC,OAAD;EAAK,GAAI,UAAU,UAAU;EAA7B,UAAA,CACE,oBAAC,gBAAD;GACE,GAAI,UAAU,SAAS;GACvB,UAAU;GACV,eAAA;GACA,UACE,YACC,OAAO,WAAW,YAAY,cAAc,KAAA,KAAa,UAAU,aACnE,OAAO,WAAW,YAAY,cAAc,KAAA,KAAa,UAAU;GAEtE,KAAK,EAAE,WAAW,KAAK;GACvB,cAAc,UAAU,MAAM,eAAe;GAC7C,gBAAgB,UAAU;IACxB,OAAO,OAAO,IAAI;GACpB;GACA,aAAa;GACb,gBAAgB;GAEhB,UAAA,oBAAC,oBAAD,EAAoB,WAAU,KAAM,CAAA;EACtB,CAAA,GAChB,oBAAC,gBAAD;GACE,GAAI,UAAU,SAAS;GACvB,UAAU;GACV,eAAA;GACA,UACE,YACC,OAAO,WAAW,YAAY,cAAc,KAAA,KAAa,UAAU,aACnE,OAAO,WAAW,YAAY,cAAc,KAAA,KAAa,UAAU;GAEtE,KAAK,EAAE,WAAW,OAAO;GACzB,cAAc,UAAU,MAAM,eAAe;GAC7C,gBAAgB,UAAU;IACxB,OAAO,OAAO,KAAK;GACrB;GACA,aAAa;GACb,gBAAgB;GAEhB,UAAA,oBAAC,oBAAD,EAAoB,WAAU,OAAQ,CAAA;EACxB,CAAA,CACb;;CAGP,OACE,oBAAC,WAAD;EACE,WAAW;EACI;EACf,WAAW,GAAGA,2BAAQ,MAAM,SAAS;EAC/B;EACN,GAAI;EACJ,WAAW,eAAe,YAAY;EAC5B;EACA;EACV,OAAO,OAAO,WAAW,WAAW,OAAO,SAAS,IAAI;EACxD,aAAa,aAAa,KAAK,QAAQ;EACvC,eAAe;EACf,cACE,gBACA,YACA,EAAE,eACE,cAAc,QAA2B,qBAAqB,IAC9D,QAAQ,MAAyB,KACjC,eACA,gBAAgB;EAEtB,YAAY;EACZ,QAAQ;EACE;EACV,kBAAiB;EACjB,cAAc,eAAe,IAAI,eAAe,eAAe;EAC/D,SAAS;EACT,SAAS;EACT,WAAW;EACX,kBAAkB;EAClB,2BAA2B,8BAA8B,WAAW,SAAS,KAAA;EAC7E,mBAAmB,qBAAqB,gCAAgC,QAAQ,KAAK;EAClE;EACO;EAC1B,QAAQ;EACI;EACZ,YAAY,QAAQ;GAElB,IAAI,EADgB,YAAY,UAAU,GAAG,IAAI,OAE/C,OAAO;GAGT,IAAI,kBAAkB,UACpB,OAAO;GAGT,IAAI,CAAC,cACH,OAAO,UAAU,IAAI,YAAY,WAAW,SAAS;GAGvD,IAAI,IAAI,UAAU,MAAM,IAAI,UAAU,KACpC,OAAO;GAGT,MAAM,SAAS,sBAAsB,IAAI,KAAK;GAE9C,IAAI,WAAW,MACb,OAAO;GAGT,QACG,cAAc,KAAA,KAAa,UAAU,eACrC,cAAc,KAAA,KAAa,UAAU;EAE1C;CACD,CAAA;AAEL,CACF;AAEA,YAAY,UAAU;CAAE,GAAG,UAAU;CAAS,GAAGA;AAAQ;AACzD,YAAY,eAAe;AAC3B,YAAY,cAAc"}
@@ -0,0 +1,19 @@
1
+ "use client";
2
+ //#region packages/@mantine/core/src/components/NumberInput/get-caret-position-after-paste/get-caret-position-after-paste.ts
3
+ function isSignificant(char, decimalSeparator) {
4
+ return /\d/.test(char) || char === decimalSeparator;
5
+ }
6
+ function getCaretPositionAfterPaste(rawValue, rawCaret, formattedValue, decimalSeparator) {
7
+ let remaining = 0;
8
+ for (let i = 0; i < rawCaret && i < rawValue.length; i += 1) if (isSignificant(rawValue[i], decimalSeparator)) remaining += 1;
9
+ if (remaining === 0) return Math.min(rawCaret, formattedValue.length);
10
+ for (let i = 0; i < formattedValue.length; i += 1) if (isSignificant(formattedValue[i], decimalSeparator)) {
11
+ remaining -= 1;
12
+ if (remaining === 0) return i + 1;
13
+ }
14
+ return formattedValue.length;
15
+ }
16
+ //#endregion
17
+ export { getCaretPositionAfterPaste };
18
+
19
+ //# sourceMappingURL=get-caret-position-after-paste.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-caret-position-after-paste.mjs","names":[],"sources":["../../../../src/components/NumberInput/get-caret-position-after-paste/get-caret-position-after-paste.ts"],"sourcesContent":["function isSignificant(char: string, decimalSeparator: string) {\n return /\\d/.test(char) || char === decimalSeparator;\n}\n\nexport function getCaretPositionAfterPaste(\n rawValue: string,\n rawCaret: number,\n formattedValue: string,\n decimalSeparator: string\n) {\n let remaining = 0;\n for (let i = 0; i < rawCaret && i < rawValue.length; i += 1) {\n if (isSignificant(rawValue[i], decimalSeparator)) {\n remaining += 1;\n }\n }\n\n if (remaining === 0) {\n return Math.min(rawCaret, formattedValue.length);\n }\n\n for (let i = 0; i < formattedValue.length; i += 1) {\n if (isSignificant(formattedValue[i], decimalSeparator)) {\n remaining -= 1;\n if (remaining === 0) {\n return i + 1;\n }\n }\n }\n\n return formattedValue.length;\n}\n"],"mappings":";;AAAA,SAAS,cAAc,MAAc,kBAA0B;CAC7D,OAAO,KAAK,KAAK,IAAI,KAAK,SAAS;AACrC;AAEA,SAAgB,2BACd,UACA,UACA,gBACA,kBACA;CACA,IAAI,YAAY;CAChB,KAAK,IAAI,IAAI,GAAG,IAAI,YAAY,IAAI,SAAS,QAAQ,KAAK,GACxD,IAAI,cAAc,SAAS,IAAI,gBAAgB,GAC7C,aAAa;CAIjB,IAAI,cAAc,GAChB,OAAO,KAAK,IAAI,UAAU,eAAe,MAAM;CAGjD,KAAK,IAAI,IAAI,GAAG,IAAI,eAAe,QAAQ,KAAK,GAC9C,IAAI,cAAc,eAAe,IAAI,gBAAgB,GAAG;EACtD,aAAa;EACb,IAAI,cAAc,GAChB,OAAO,IAAI;CAEf;CAGF,OAAO,eAAe;AACxB"}
@@ -0,0 +1,35 @@
1
+ "use client";
2
+ //#region packages/@mantine/core/src/components/NumberInput/normalize-pasted-value/normalize-pasted-value.ts
3
+ function countTrailingDigits(value, from) {
4
+ let count = 0;
5
+ while (from + count < value.length && /\d/.test(value[from + count])) count += 1;
6
+ return count;
7
+ }
8
+ function normalizePastedValue(value, { decimalSeparator, thousandSeparator, allowedDecimalSeparators, thousandsGroupStyle }) {
9
+ const candidates = new Set([...allowedDecimalSeparators, decimalSeparator].filter((s) => s.length === 1));
10
+ const chars = value.split("");
11
+ const occurrences = chars.reduce((acc, char, index) => {
12
+ if (candidates.has(char)) acc.push(index);
13
+ return acc;
14
+ }, []);
15
+ if (occurrences.length === 0) return value;
16
+ const lastIndex = occurrences[occurrences.length - 1];
17
+ const lastChar = chars[lastIndex];
18
+ const lastCharCount = occurrences.filter((index) => chars[index] === lastChar).length;
19
+ const lastGroupSize = thousandsGroupStyle === "wan" ? 4 : 3;
20
+ let decimalIndex = -1;
21
+ if (lastCharCount === 1) {
22
+ if (lastChar === decimalSeparator) decimalIndex = lastIndex;
23
+ else if (lastChar === thousandSeparator) decimalIndex = countTrailingDigits(value, lastIndex + 1) === lastGroupSize ? -1 : lastIndex;
24
+ else decimalIndex = lastIndex;
25
+ }
26
+ return chars.map((char, index) => {
27
+ if (index === decimalIndex) return decimalSeparator;
28
+ if (candidates.has(char) && char !== thousandSeparator) return "";
29
+ return char;
30
+ }).join("");
31
+ }
32
+ //#endregion
33
+ export { normalizePastedValue };
34
+
35
+ //# sourceMappingURL=normalize-pasted-value.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize-pasted-value.mjs","names":[],"sources":["../../../../src/components/NumberInput/normalize-pasted-value/normalize-pasted-value.ts"],"sourcesContent":["export interface NormalizePastedValueOptions {\n decimalSeparator: string;\n thousandSeparator?: string;\n allowedDecimalSeparators: string[];\n thousandsGroupStyle?: 'thousand' | 'lakh' | 'wan' | 'none';\n}\n\nfunction countTrailingDigits(value: string, from: number) {\n let count = 0;\n while (from + count < value.length && /\\d/.test(value[from + count])) {\n count += 1;\n }\n return count;\n}\n\nexport function normalizePastedValue(\n value: string,\n {\n decimalSeparator,\n thousandSeparator,\n allowedDecimalSeparators,\n thousandsGroupStyle,\n }: NormalizePastedValueOptions\n) {\n const candidates = new Set(\n [...allowedDecimalSeparators, decimalSeparator].filter((s) => s.length === 1)\n );\n const chars = value.split('');\n const occurrences = chars.reduce<number[]>((acc, char, index) => {\n if (candidates.has(char)) {\n acc.push(index);\n }\n return acc;\n }, []);\n\n if (occurrences.length === 0) {\n return value;\n }\n\n const lastIndex = occurrences[occurrences.length - 1];\n const lastChar = chars[lastIndex];\n const lastCharCount = occurrences.filter((index) => chars[index] === lastChar).length;\n const lastGroupSize = thousandsGroupStyle === 'wan' ? 4 : 3;\n\n let decimalIndex = -1;\n if (lastCharCount === 1) {\n if (lastChar === decimalSeparator) {\n decimalIndex = lastIndex;\n } else if (lastChar === thousandSeparator) {\n decimalIndex = countTrailingDigits(value, lastIndex + 1) === lastGroupSize ? -1 : lastIndex;\n } else {\n decimalIndex = lastIndex;\n }\n }\n\n return chars\n .map((char, index) => {\n if (index === decimalIndex) {\n return decimalSeparator;\n }\n\n if (candidates.has(char) && char !== thousandSeparator) {\n return '';\n }\n\n return char;\n })\n .join('');\n}\n"],"mappings":";;AAOA,SAAS,oBAAoB,OAAe,MAAc;CACxD,IAAI,QAAQ;CACZ,OAAO,OAAO,QAAQ,MAAM,UAAU,KAAK,KAAK,MAAM,OAAO,MAAM,GACjE,SAAS;CAEX,OAAO;AACT;AAEA,SAAgB,qBACd,OACA,EACE,kBACA,mBACA,0BACA,uBAEF;CACA,MAAM,aAAa,IAAI,IACrB,CAAC,GAAG,0BAA0B,gBAAgB,CAAC,CAAC,QAAQ,MAAM,EAAE,WAAW,CAAC,CAC9E;CACA,MAAM,QAAQ,MAAM,MAAM,EAAE;CAC5B,MAAM,cAAc,MAAM,QAAkB,KAAK,MAAM,UAAU;EAC/D,IAAI,WAAW,IAAI,IAAI,GACrB,IAAI,KAAK,KAAK;EAEhB,OAAO;CACT,GAAG,CAAC,CAAC;CAEL,IAAI,YAAY,WAAW,GACzB,OAAO;CAGT,MAAM,YAAY,YAAY,YAAY,SAAS;CACnD,MAAM,WAAW,MAAM;CACvB,MAAM,gBAAgB,YAAY,QAAQ,UAAU,MAAM,WAAW,QAAQ,CAAC,CAAC;CAC/E,MAAM,gBAAgB,wBAAwB,QAAQ,IAAI;CAE1D,IAAI,eAAe;CACnB,IAAI,kBAAkB,GAAG;EACvB,IAAI,aAAa,kBACf,eAAe;OACV,IAAI,aAAa,mBACtB,eAAe,oBAAoB,OAAO,YAAY,CAAC,MAAM,gBAAgB,KAAK;OAElF,eAAe;CAEnB;CAEA,OAAO,MACJ,KAAK,MAAM,UAAU;EACpB,IAAI,UAAU,cACZ,OAAO;EAGT,IAAI,WAAW,IAAI,IAAI,KAAK,SAAS,mBACnC,OAAO;EAGT,OAAO;CACT,CAAC,CAAC,CACD,KAAK,EAAE;AACZ"}
@@ -0,0 +1 @@
1
+ export declare function getCaretPositionAfterPaste(rawValue: string, rawCaret: number, formattedValue: string, decimalSeparator: string): number;