@mantine/core 9.1.1 → 9.2.0

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 (165) hide show
  1. package/cjs/components/Autocomplete/Autocomplete.cjs +5 -1
  2. package/cjs/components/Autocomplete/Autocomplete.cjs.map +1 -1
  3. package/cjs/components/Checkbox/Checkbox.cjs +4 -1
  4. package/cjs/components/Checkbox/Checkbox.cjs.map +1 -1
  5. package/cjs/components/ColorInput/ColorInput.cjs +5 -1
  6. package/cjs/components/ColorInput/ColorInput.cjs.map +1 -1
  7. package/cjs/components/Combobox/use-pills-reorder/move-pill.cjs +17 -0
  8. package/cjs/components/Combobox/use-pills-reorder/move-pill.cjs.map +1 -0
  9. package/cjs/components/Combobox/use-pills-reorder/use-pills-reorder.cjs +170 -0
  10. package/cjs/components/Combobox/use-pills-reorder/use-pills-reorder.cjs.map +1 -0
  11. package/cjs/components/FileInput/FileInput.cjs +5 -1
  12. package/cjs/components/FileInput/FileInput.cjs.map +1 -1
  13. package/cjs/components/Input/use-input-props.cjs +5 -1
  14. package/cjs/components/Input/use-input-props.cjs.map +1 -1
  15. package/cjs/components/JsonInput/JsonInput.cjs +5 -2
  16. package/cjs/components/JsonInput/JsonInput.cjs.map +1 -1
  17. package/cjs/components/MaskInput/MaskInput.cjs +5 -1
  18. package/cjs/components/MaskInput/MaskInput.cjs.map +1 -1
  19. package/cjs/components/MaskInput/use-mask-input-props.cjs +3 -2
  20. package/cjs/components/MaskInput/use-mask-input-props.cjs.map +1 -1
  21. package/cjs/components/MultiSelect/MultiSelect.cjs +19 -3
  22. package/cjs/components/MultiSelect/MultiSelect.cjs.map +1 -1
  23. package/cjs/components/NativeSelect/NativeSelect.cjs +5 -1
  24. package/cjs/components/NativeSelect/NativeSelect.cjs.map +1 -1
  25. package/cjs/components/NumberInput/NumberInput.cjs +5 -1
  26. package/cjs/components/NumberInput/NumberInput.cjs.map +1 -1
  27. package/cjs/components/PasswordInput/PasswordInput.cjs +5 -1
  28. package/cjs/components/PasswordInput/PasswordInput.cjs.map +1 -1
  29. package/cjs/components/Pill/Pill.module.cjs.map +1 -1
  30. package/cjs/components/PillsInput/PillsInput.cjs +5 -1
  31. package/cjs/components/PillsInput/PillsInput.cjs.map +1 -1
  32. package/cjs/components/PinInput/PinInput.cjs +1 -1
  33. package/cjs/components/PinInput/PinInput.cjs.map +1 -1
  34. package/cjs/components/RollingNumber/DigitColumn.cjs +46 -0
  35. package/cjs/components/RollingNumber/DigitColumn.cjs.map +1 -0
  36. package/cjs/components/RollingNumber/RollingNumber.cjs +102 -0
  37. package/cjs/components/RollingNumber/RollingNumber.cjs.map +1 -0
  38. package/cjs/components/RollingNumber/RollingNumber.module.cjs +13 -0
  39. package/cjs/components/RollingNumber/RollingNumber.module.cjs.map +1 -0
  40. package/cjs/components/RollingNumber/build-value.cjs +22 -0
  41. package/cjs/components/RollingNumber/build-value.cjs.map +1 -0
  42. package/cjs/components/RollingNumber/get-digit-parts.cjs +40 -0
  43. package/cjs/components/RollingNumber/get-digit-parts.cjs.map +1 -0
  44. package/cjs/components/RollingNumber/get-render-slots.cjs +78 -0
  45. package/cjs/components/RollingNumber/get-render-slots.cjs.map +1 -0
  46. package/cjs/components/Select/Select.cjs +5 -1
  47. package/cjs/components/Select/Select.cjs.map +1 -1
  48. package/cjs/components/TagsInput/TagsInput.cjs +19 -4
  49. package/cjs/components/TagsInput/TagsInput.cjs.map +1 -1
  50. package/cjs/components/TextInput/TextInput.cjs +5 -1
  51. package/cjs/components/TextInput/TextInput.cjs.map +1 -1
  52. package/cjs/components/Textarea/Textarea.cjs +5 -2
  53. package/cjs/components/Textarea/Textarea.cjs.map +1 -1
  54. package/cjs/components/Tree/is-node-checked/is-node-checked.cjs +1 -0
  55. package/cjs/components/Tree/is-node-indeterminate/is-node-indeterminate.cjs +1 -0
  56. package/cjs/components/TreeSelect/TreeSelect.cjs +601 -0
  57. package/cjs/components/TreeSelect/TreeSelect.cjs.map +1 -0
  58. package/cjs/components/TreeSelect/TreeSelect.module.cjs +16 -0
  59. package/cjs/components/TreeSelect/TreeSelect.module.cjs.map +1 -0
  60. package/cjs/components/TreeSelect/TreeSelectOption.cjs +95 -0
  61. package/cjs/components/TreeSelect/TreeSelectOption.cjs.map +1 -0
  62. package/cjs/components/TreeSelect/flatten-tree-select-data.cjs +34 -0
  63. package/cjs/components/TreeSelect/flatten-tree-select-data.cjs.map +1 -0
  64. package/cjs/components/TreeSelect/get-checked-values-by-strategy.cjs +30 -0
  65. package/cjs/components/TreeSelect/get-checked-values-by-strategy.cjs.map +1 -0
  66. package/cjs/core/MantineProvider/use-props/use-props.cjs +10 -2
  67. package/cjs/core/MantineProvider/use-props/use-props.cjs.map +1 -1
  68. package/cjs/index.cjs +8 -0
  69. package/esm/components/Autocomplete/Autocomplete.mjs +5 -1
  70. package/esm/components/Autocomplete/Autocomplete.mjs.map +1 -1
  71. package/esm/components/Checkbox/Checkbox.mjs +4 -1
  72. package/esm/components/Checkbox/Checkbox.mjs.map +1 -1
  73. package/esm/components/ColorInput/ColorInput.mjs +5 -1
  74. package/esm/components/ColorInput/ColorInput.mjs.map +1 -1
  75. package/esm/components/Combobox/use-pills-reorder/move-pill.mjs +17 -0
  76. package/esm/components/Combobox/use-pills-reorder/move-pill.mjs.map +1 -0
  77. package/esm/components/Combobox/use-pills-reorder/use-pills-reorder.mjs +169 -0
  78. package/esm/components/Combobox/use-pills-reorder/use-pills-reorder.mjs.map +1 -0
  79. package/esm/components/FileInput/FileInput.mjs +5 -1
  80. package/esm/components/FileInput/FileInput.mjs.map +1 -1
  81. package/esm/components/Input/use-input-props.mjs +5 -1
  82. package/esm/components/Input/use-input-props.mjs.map +1 -1
  83. package/esm/components/JsonInput/JsonInput.mjs +5 -2
  84. package/esm/components/JsonInput/JsonInput.mjs.map +1 -1
  85. package/esm/components/MaskInput/MaskInput.mjs +5 -1
  86. package/esm/components/MaskInput/MaskInput.mjs.map +1 -1
  87. package/esm/components/MaskInput/use-mask-input-props.mjs +4 -3
  88. package/esm/components/MaskInput/use-mask-input-props.mjs.map +1 -1
  89. package/esm/components/MultiSelect/MultiSelect.mjs +19 -3
  90. package/esm/components/MultiSelect/MultiSelect.mjs.map +1 -1
  91. package/esm/components/NativeSelect/NativeSelect.mjs +5 -1
  92. package/esm/components/NativeSelect/NativeSelect.mjs.map +1 -1
  93. package/esm/components/NumberInput/NumberInput.mjs +5 -1
  94. package/esm/components/NumberInput/NumberInput.mjs.map +1 -1
  95. package/esm/components/PasswordInput/PasswordInput.mjs +5 -1
  96. package/esm/components/PasswordInput/PasswordInput.mjs.map +1 -1
  97. package/esm/components/Pill/Pill.module.mjs.map +1 -1
  98. package/esm/components/PillsInput/PillsInput.mjs +5 -1
  99. package/esm/components/PillsInput/PillsInput.mjs.map +1 -1
  100. package/esm/components/PinInput/PinInput.mjs +1 -1
  101. package/esm/components/PinInput/PinInput.mjs.map +1 -1
  102. package/esm/components/RollingNumber/DigitColumn.mjs +45 -0
  103. package/esm/components/RollingNumber/DigitColumn.mjs.map +1 -0
  104. package/esm/components/RollingNumber/RollingNumber.mjs +101 -0
  105. package/esm/components/RollingNumber/RollingNumber.mjs.map +1 -0
  106. package/esm/components/RollingNumber/RollingNumber.module.mjs +13 -0
  107. package/esm/components/RollingNumber/RollingNumber.module.mjs.map +1 -0
  108. package/esm/components/RollingNumber/build-value.mjs +22 -0
  109. package/esm/components/RollingNumber/build-value.mjs.map +1 -0
  110. package/esm/components/RollingNumber/get-digit-parts.mjs +40 -0
  111. package/esm/components/RollingNumber/get-digit-parts.mjs.map +1 -0
  112. package/esm/components/RollingNumber/get-render-slots.mjs +78 -0
  113. package/esm/components/RollingNumber/get-render-slots.mjs.map +1 -0
  114. package/esm/components/Select/Select.mjs +5 -1
  115. package/esm/components/Select/Select.mjs.map +1 -1
  116. package/esm/components/TagsInput/TagsInput.mjs +19 -4
  117. package/esm/components/TagsInput/TagsInput.mjs.map +1 -1
  118. package/esm/components/TextInput/TextInput.mjs +5 -1
  119. package/esm/components/TextInput/TextInput.mjs.map +1 -1
  120. package/esm/components/Textarea/Textarea.mjs +5 -2
  121. package/esm/components/Textarea/Textarea.mjs.map +1 -1
  122. package/esm/components/Tree/is-node-checked/is-node-checked.mjs +1 -1
  123. package/esm/components/Tree/is-node-indeterminate/is-node-indeterminate.mjs +1 -1
  124. package/esm/components/TreeSelect/TreeSelect.mjs +600 -0
  125. package/esm/components/TreeSelect/TreeSelect.mjs.map +1 -0
  126. package/esm/components/TreeSelect/TreeSelect.module.mjs +16 -0
  127. package/esm/components/TreeSelect/TreeSelect.module.mjs.map +1 -0
  128. package/esm/components/TreeSelect/TreeSelectOption.mjs +94 -0
  129. package/esm/components/TreeSelect/TreeSelectOption.mjs.map +1 -0
  130. package/esm/components/TreeSelect/flatten-tree-select-data.mjs +34 -0
  131. package/esm/components/TreeSelect/flatten-tree-select-data.mjs.map +1 -0
  132. package/esm/components/TreeSelect/get-checked-values-by-strategy.mjs +29 -0
  133. package/esm/components/TreeSelect/get-checked-values-by-strategy.mjs.map +1 -0
  134. package/esm/core/MantineProvider/use-props/use-props.mjs +10 -2
  135. package/esm/core/MantineProvider/use-props/use-props.mjs.map +1 -1
  136. package/esm/index.mjs +5 -1
  137. package/lib/components/Combobox/Combobox.types.d.ts +3 -0
  138. package/lib/components/Combobox/index.d.ts +2 -0
  139. package/lib/components/Combobox/use-pills-reorder/move-pill.d.ts +2 -0
  140. package/lib/components/Combobox/use-pills-reorder/use-pills-reorder.d.ts +26 -0
  141. package/lib/components/MaskInput/MaskInput.d.ts +2 -0
  142. package/lib/components/MultiSelect/MultiSelect.d.ts +2 -0
  143. package/lib/components/RollingNumber/DigitColumn.d.ts +11 -0
  144. package/lib/components/RollingNumber/RollingNumber.d.ts +41 -0
  145. package/lib/components/RollingNumber/build-value.d.ts +10 -0
  146. package/lib/components/RollingNumber/get-digit-parts.d.ts +12 -0
  147. package/lib/components/RollingNumber/get-render-slots.d.ts +35 -0
  148. package/lib/components/RollingNumber/index.d.ts +9 -0
  149. package/lib/components/TagsInput/TagsInput.d.ts +2 -0
  150. package/lib/components/TreeSelect/TreeSelect.d.ts +124 -0
  151. package/lib/components/TreeSelect/TreeSelectOption.d.ts +36 -0
  152. package/lib/components/TreeSelect/flatten-tree-select-data.d.ts +12 -0
  153. package/lib/components/TreeSelect/get-checked-values-by-strategy.d.ts +4 -0
  154. package/lib/components/TreeSelect/index.d.ts +13 -0
  155. package/lib/components/index.d.ts +2 -0
  156. package/lib/core/MantineProvider/use-props/use-props.d.ts +1 -1
  157. package/package.json +2 -2
  158. package/styles/Pill.css +35 -0
  159. package/styles/Pill.layer.css +35 -0
  160. package/styles/RollingNumber.css +60 -0
  161. package/styles/RollingNumber.layer.css +61 -0
  162. package/styles/TreeSelect.css +113 -0
  163. package/styles/TreeSelect.layer.css +114 -0
  164. package/styles.css +210 -0
  165. package/styles.layer.css +210 -0
@@ -1 +1 @@
1
- {"version":3,"file":"PinInput.mjs","names":["useId","classes"],"sources":["../../../src/components/PinInput/PinInput.tsx"],"sourcesContent":["import { useRef, useState } from 'react';\nimport { assignRef, useId, useUncontrolled } from '@mantine/hooks';\nimport {\n BoxProps,\n createVarsResolver,\n DataAttributes,\n ElementProps,\n Factory,\n factory,\n getSize,\n MantineRadius,\n MantineSize,\n MantineSpacing,\n StylesApiProps,\n useProps,\n useResolvedStylesApi,\n useStyles,\n} from '../../core';\nimport { Group } from '../Group';\nimport { Input, InputProps } from '../Input';\nimport { InputBase } from '../InputBase';\nimport { createPinArray } from './create-pin-array/create-pin-array';\nimport classes from './PinInput.module.css';\n\nconst regex = {\n number: /^[0-9]+$/,\n alphanumeric: /^[a-zA-Z0-9]+$/i,\n};\n\nexport type PinInputStylesNames = 'root' | 'pinInput' | 'input';\n\nexport type PinInputCssVariables = {\n root: '--pin-input-size';\n};\n\nexport interface PinInputProps\n extends BoxProps, StylesApiProps<PinInputFactory>, ElementProps<'div', 'onChange' | 'ref'> {\n ref?: React.Ref<HTMLInputElement>;\n\n /** Hidden input `name` attribute */\n name?: string;\n\n /** Hidden input `form` attribute */\n form?: string;\n\n /** Key of `theme.spacing` or any valid CSS value to set `gap` between inputs, numbers are converted to rem @default 'md' */\n gap?: MantineSpacing;\n\n /** Key of `theme.radius` or any valid CSS value to set `border-radius`, numbers are converted to rem @default theme.defaultRadius */\n radius?: MantineRadius;\n\n /** Controls inputs `width` and `height` @default 'sm' */\n size?: MantineSize;\n\n /** If set, the first input is focused when component is mounted @default false */\n autoFocus?: boolean;\n\n /** Controlled component value */\n value?: string;\n\n /** Uncontrolled component default value */\n defaultValue?: string;\n\n /** Called when value changes */\n onChange?: (value: string) => void;\n\n /** Called when all inputs have value */\n onComplete?: (value: string) => void;\n\n /** Inputs placeholder @default '○' */\n placeholder?: string;\n\n /** Determines whether focus should be moved automatically to the next input once filled @default true */\n manageFocus?: boolean;\n\n /** Determines whether `autocomplete=\"one-time-code\"` attribute should be set on all inputs @default true */\n oneTimeCode?: boolean;\n\n /** Base id used to generate unique ids for inputs */\n id?: string;\n\n /** Adds disabled attribute to all inputs */\n disabled?: boolean;\n\n /** Sets `aria-invalid` attribute and applies error styles to all inputs */\n error?: boolean;\n\n /** Determines which values can be entered @default 'alphanumeric' */\n type?: 'alphanumeric' | 'number' | RegExp;\n\n /** Changes input type to `\"password\"` @default false */\n mask?: boolean;\n\n /** Number of inputs @default 4 */\n length?: number;\n\n /** If set, the user cannot edit the value */\n readOnly?: boolean;\n\n /** Inputs `type` attribute, inferred from the `type` prop if not specified */\n inputType?: React.HTMLInputTypeAttribute;\n\n /** `inputmode` attribute, inferred from the `type` prop if not specified */\n inputMode?:\n | 'none'\n | 'text'\n | 'tel'\n | 'url'\n | 'email'\n | 'numeric'\n | 'decimal'\n | 'search'\n | undefined;\n\n /** `aria-label` attribute */\n ariaLabel?: string;\n\n /** Props passed down to the hidden input */\n hiddenInputProps?: React.ComponentProps<'input'>;\n\n /** Assigns ref of the root element */\n rootRef?: React.Ref<HTMLDivElement>;\n\n /** Props added to the input element depending on its index */\n getInputProps?: (index: number) => InputProps & ElementProps<'input', 'size'> & DataAttributes;\n}\n\nexport type PinInputFactory = Factory<{\n props: PinInputProps;\n ref: HTMLDivElement;\n stylesNames: PinInputStylesNames;\n vars: PinInputCssVariables;\n}>;\n\nconst defaultProps = {\n gap: 'sm',\n length: 4,\n manageFocus: true,\n oneTimeCode: true,\n placeholder: '○',\n type: 'alphanumeric',\n ariaLabel: 'PinInput',\n size: 'sm',\n} satisfies Partial<PinInputProps>;\n\nconst varsResolver = createVarsResolver<PinInputFactory>((_, { size }) => ({\n root: {\n '--pin-input-size': getSize(size ?? 'sm', 'pin-input-size'),\n },\n}));\n\nexport const PinInput = factory<PinInputFactory>((props) => {\n const {\n name,\n form,\n className,\n value,\n defaultValue,\n variant,\n gap,\n style,\n size,\n classNames,\n styles,\n unstyled,\n length,\n onChange,\n onComplete,\n manageFocus,\n autoFocus,\n error,\n radius,\n disabled,\n oneTimeCode,\n placeholder,\n type,\n mask,\n readOnly,\n inputType,\n inputMode,\n ariaLabel,\n vars,\n id,\n hiddenInputProps,\n rootRef,\n getInputProps,\n attributes,\n ref,\n ...others\n } = useProps('PinInput', defaultProps, props);\n\n const uuid = useId(id);\n\n const getStyles = useStyles<PinInputFactory>({\n name: 'PinInput',\n classes,\n props,\n className,\n style,\n classNames,\n styles,\n unstyled,\n attributes,\n vars,\n varsResolver,\n });\n\n const { resolvedClassNames, resolvedStyles } = useResolvedStylesApi<PinInputFactory>({\n classNames,\n styles,\n props,\n });\n\n const [focusedIndex, setFocusedIndex] = useState(-1);\n const inputsRef = useRef<Array<HTMLInputElement>>([]);\n const currentLength = length ?? 4;\n\n const completedRef = useRef(false);\n\n const [_value, setValues] = useUncontrolled<string[]>({\n value: value !== undefined ? createPinArray(currentLength, value) : undefined,\n defaultValue: defaultValue?.split('').slice(0, currentLength),\n finalValue: createPinArray(currentLength, ''),\n onChange: (val) => {\n const stringValue = val.join('').trim();\n onChange?.(stringValue);\n if (stringValue.length === currentLength && !completedRef.current) {\n completedRef.current = true;\n onComplete?.(stringValue);\n } else if (stringValue.length < currentLength) {\n completedRef.current = false;\n }\n },\n });\n\n const currentValue =\n _value.length !== currentLength ? createPinArray(currentLength, _value.join('')) : _value;\n\n const _valueToString = currentValue.join('').trim();\n\n const validate = (code: string) => {\n const re = type instanceof RegExp ? type : type && type in regex ? regex[type] : null;\n return re?.test(code);\n };\n\n const focusInputField = (dir: 'next' | 'prev', index: number) => {\n if (!manageFocus) {\n return;\n }\n\n if (dir === 'next') {\n const nextIndex = index + 1;\n if (nextIndex < currentLength) {\n inputsRef.current[nextIndex]?.focus();\n }\n } else if (dir === 'prev') {\n const prevIndex = index - 1;\n if (prevIndex >= 0) {\n inputsRef.current[prevIndex]?.focus();\n }\n }\n };\n\n const setFieldValue = (val: string, index: number) => {\n const values = [...currentValue];\n values[index] = val;\n setValues(values);\n return values;\n };\n\n const handleChange = (event: React.ChangeEvent<HTMLInputElement>, index: number) => {\n const inputValue = event.target.value;\n\n if (inputValue.length > 1) {\n const isPaste = inputValue.length > 2;\n if (isPaste) {\n const isValid = validate(inputValue);\n if (isValid) {\n setValues(createPinArray(currentLength, inputValue));\n const filledCount = Math.min(inputValue.length, currentLength);\n if (filledCount < currentLength) {\n focusInputField('next', filledCount - 1);\n }\n }\n return;\n }\n\n const newChar = inputValue.split('')[inputValue.length - 1];\n if (validate(newChar)) {\n setFieldValue(newChar, index);\n focusInputField('next', index);\n }\n return;\n }\n\n if (inputValue.length === 1) {\n if (validate(inputValue)) {\n setFieldValue(inputValue, index);\n focusInputField('next', index);\n } else {\n setFieldValue('', index);\n }\n } else if (inputValue.length === 0) {\n setFieldValue('', index);\n }\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>, index: number) => {\n const { ctrlKey, metaKey, key, shiftKey, target } = event;\n const inputValue = (target as HTMLInputElement).value;\n\n if (inputMode === 'numeric') {\n const allowedKeys = ['Backspace', 'Tab', 'Control', 'Delete', 'ArrowLeft', 'ArrowRight'];\n const isPasteShortcut = (ctrlKey || metaKey) && key === 'v';\n const isAllowedKey =\n allowedKeys.includes(key) || isPasteShortcut || !Number.isNaN(Number(key));\n\n if (!isAllowedKey) {\n event.preventDefault();\n return;\n }\n }\n\n switch (key) {\n case 'ArrowLeft':\n event.preventDefault();\n focusInputField('prev', index);\n break;\n\n case 'ArrowRight':\n event.preventDefault();\n focusInputField('next', index);\n break;\n\n case 'Tab':\n if (shiftKey) {\n if (index > 0 && manageFocus) {\n event.preventDefault();\n focusInputField('prev', index);\n }\n }\n break;\n\n case ' ':\n event.preventDefault();\n focusInputField('next', index);\n break;\n\n case 'Delete':\n event.preventDefault();\n setFieldValue('', index);\n break;\n\n case 'Backspace':\n if (inputValue === '') {\n event.preventDefault();\n focusInputField('prev', index);\n } else {\n setFieldValue('', index);\n if (index < currentLength - 1) {\n event.preventDefault();\n focusInputField('prev', index);\n }\n }\n break;\n\n default:\n if (inputValue.length > 0 && key === currentValue[index]) {\n event.preventDefault();\n focusInputField('next', index);\n }\n }\n };\n\n const handleFocus = (event: React.FocusEvent<HTMLInputElement>, index: number) => {\n event.target.select();\n setFocusedIndex(index);\n };\n\n const handleBlur = () => {\n setFocusedIndex(-1);\n };\n\n const handlePaste = (event: React.ClipboardEvent<HTMLInputElement>) => {\n event.preventDefault();\n const pasteData = event.clipboardData.getData('text/plain').replace(/[\\n\\r\\s]+/g, '');\n const isValid = validate(pasteData.trim());\n\n if (isValid) {\n const pasteArray = createPinArray(currentLength, pasteData);\n setValues(pasteArray);\n const filledCount = pasteArray.filter((val) => val !== '').length;\n if (filledCount >= currentLength) {\n inputsRef.current[currentLength - 1]?.focus();\n } else {\n inputsRef.current[filledCount]?.focus();\n }\n }\n };\n\n return (\n <>\n <Group\n {...others}\n {...getStyles('root')}\n ref={rootRef}\n role=\"group\"\n id={uuid}\n gap={gap}\n unstyled={unstyled}\n wrap=\"nowrap\"\n variant={variant}\n __size={size}\n dir=\"ltr\"\n >\n {currentValue.map((char: string, index: number) => (\n <Input\n component=\"input\"\n {...getStyles('pinInput', {\n style: {\n '--input-padding': '0',\n '--input-text-align': 'center',\n } as React.CSSProperties,\n })}\n classNames={resolvedClassNames}\n styles={resolvedStyles}\n size={size}\n __staticSelector=\"PinInput\"\n id={`${uuid}-${index + 1}`}\n key={`${uuid}-${index}`}\n inputMode={inputMode || (type === 'number' ? 'numeric' : 'text')}\n onChange={(event) => handleChange(event, index)}\n onKeyDown={(event) => handleKeyDown(event, index)}\n onFocus={(event) => handleFocus(event, index)}\n onBlur={handleBlur}\n onPaste={handlePaste}\n type={inputType || (mask ? 'password' : type === 'number' ? 'tel' : 'text')}\n radius={radius}\n error={error}\n variant={variant}\n disabled={disabled}\n ref={(node) => {\n if (node) {\n index === 0 && assignRef(ref, node);\n inputsRef.current[index] = node;\n }\n }}\n autoComplete={oneTimeCode ? 'one-time-code' : 'off'}\n placeholder={focusedIndex === index ? '' : placeholder}\n value={char}\n autoFocus={autoFocus && index === 0}\n unstyled={unstyled}\n aria-label={ariaLabel}\n readOnly={readOnly}\n {...getInputProps?.(index)}\n />\n ))}\n </Group>\n\n <input type=\"hidden\" name={name} form={form} value={_valueToString} {...hiddenInputProps} />\n </>\n );\n});\n\nPinInput.classes = { ...classes, ...InputBase.classes };\nPinInput.varsResolver = varsResolver;\nPinInput.displayName = '@mantine/core/PinInput';\n\nexport namespace PinInput {\n export type Props = PinInputProps;\n export type StylesNames = PinInputStylesNames;\n export type Factory = PinInputFactory;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"PinInput.mjs","names":["useId","classes"],"sources":["../../../src/components/PinInput/PinInput.tsx"],"sourcesContent":["import { useRef, useState } from 'react';\nimport { assignRef, useId, useUncontrolled } from '@mantine/hooks';\nimport {\n BoxProps,\n createVarsResolver,\n DataAttributes,\n ElementProps,\n Factory,\n factory,\n getSize,\n MantineRadius,\n MantineSize,\n MantineSpacing,\n StylesApiProps,\n useProps,\n useResolvedStylesApi,\n useStyles,\n} from '../../core';\nimport { Group } from '../Group';\nimport { Input, InputProps } from '../Input';\nimport { InputBase } from '../InputBase';\nimport { createPinArray } from './create-pin-array/create-pin-array';\nimport classes from './PinInput.module.css';\n\nconst regex = {\n number: /^[0-9]+$/,\n alphanumeric: /^[a-zA-Z0-9]+$/i,\n};\n\nexport type PinInputStylesNames = 'root' | 'pinInput' | 'input';\n\nexport type PinInputCssVariables = {\n root: '--pin-input-size';\n};\n\nexport interface PinInputProps\n extends BoxProps, StylesApiProps<PinInputFactory>, ElementProps<'div', 'onChange' | 'ref'> {\n ref?: React.Ref<HTMLInputElement>;\n\n /** Hidden input `name` attribute */\n name?: string;\n\n /** Hidden input `form` attribute */\n form?: string;\n\n /** Key of `theme.spacing` or any valid CSS value to set `gap` between inputs, numbers are converted to rem @default 'md' */\n gap?: MantineSpacing;\n\n /** Key of `theme.radius` or any valid CSS value to set `border-radius`, numbers are converted to rem @default theme.defaultRadius */\n radius?: MantineRadius;\n\n /** Controls inputs `width` and `height` @default 'sm' */\n size?: MantineSize;\n\n /** If set, the first input is focused when component is mounted @default false */\n autoFocus?: boolean;\n\n /** Controlled component value */\n value?: string;\n\n /** Uncontrolled component default value */\n defaultValue?: string;\n\n /** Called when value changes */\n onChange?: (value: string) => void;\n\n /** Called when all inputs have value */\n onComplete?: (value: string) => void;\n\n /** Inputs placeholder @default '○' */\n placeholder?: string;\n\n /** Determines whether focus should be moved automatically to the next input once filled @default true */\n manageFocus?: boolean;\n\n /** Determines whether `autocomplete=\"one-time-code\"` attribute should be set on all inputs @default true */\n oneTimeCode?: boolean;\n\n /** Base id used to generate unique ids for inputs */\n id?: string;\n\n /** Adds disabled attribute to all inputs */\n disabled?: boolean;\n\n /** Sets `aria-invalid` attribute and applies error styles to all inputs */\n error?: boolean;\n\n /** Determines which values can be entered @default 'alphanumeric' */\n type?: 'alphanumeric' | 'number' | RegExp;\n\n /** Changes input type to `\"password\"` @default false */\n mask?: boolean;\n\n /** Number of inputs @default 4 */\n length?: number;\n\n /** If set, the user cannot edit the value */\n readOnly?: boolean;\n\n /** Inputs `type` attribute, inferred from the `type` prop if not specified */\n inputType?: React.HTMLInputTypeAttribute;\n\n /** `inputmode` attribute, inferred from the `type` prop if not specified */\n inputMode?:\n | 'none'\n | 'text'\n | 'tel'\n | 'url'\n | 'email'\n | 'numeric'\n | 'decimal'\n | 'search'\n | undefined;\n\n /** `aria-label` attribute */\n ariaLabel?: string;\n\n /** Props passed down to the hidden input */\n hiddenInputProps?: React.ComponentProps<'input'>;\n\n /** Assigns ref of the root element */\n rootRef?: React.Ref<HTMLDivElement>;\n\n /** Props added to the input element depending on its index */\n getInputProps?: (index: number) => InputProps & ElementProps<'input', 'size'> & DataAttributes;\n}\n\nexport type PinInputFactory = Factory<{\n props: PinInputProps;\n ref: HTMLDivElement;\n stylesNames: PinInputStylesNames;\n vars: PinInputCssVariables;\n}>;\n\nconst defaultProps = {\n gap: 'sm',\n length: 4,\n manageFocus: true,\n oneTimeCode: true,\n placeholder: '○',\n type: 'alphanumeric',\n ariaLabel: 'PinInput',\n size: 'sm',\n} satisfies Partial<PinInputProps>;\n\nconst varsResolver = createVarsResolver<PinInputFactory>((_, { size }) => ({\n root: {\n '--pin-input-size': getSize(size ?? 'sm', 'pin-input-size'),\n },\n}));\n\nexport const PinInput = factory<PinInputFactory>((props) => {\n const {\n name,\n form,\n className,\n value,\n defaultValue,\n variant,\n gap,\n style,\n size,\n classNames,\n styles,\n unstyled,\n length,\n onChange,\n onComplete,\n manageFocus,\n autoFocus,\n error,\n radius,\n disabled,\n oneTimeCode,\n placeholder,\n type,\n mask,\n readOnly,\n inputType,\n inputMode,\n ariaLabel,\n vars,\n id,\n hiddenInputProps,\n rootRef,\n getInputProps,\n attributes,\n ref,\n ...others\n } = useProps(['Input', 'PinInput'], defaultProps, props);\n\n const uuid = useId(id);\n\n const getStyles = useStyles<PinInputFactory>({\n name: 'PinInput',\n classes,\n props,\n className,\n style,\n classNames,\n styles,\n unstyled,\n attributes,\n vars,\n varsResolver,\n });\n\n const { resolvedClassNames, resolvedStyles } = useResolvedStylesApi<PinInputFactory>({\n classNames,\n styles,\n props,\n });\n\n const [focusedIndex, setFocusedIndex] = useState(-1);\n const inputsRef = useRef<Array<HTMLInputElement>>([]);\n const currentLength = length ?? 4;\n\n const completedRef = useRef(false);\n\n const [_value, setValues] = useUncontrolled<string[]>({\n value: value !== undefined ? createPinArray(currentLength, value) : undefined,\n defaultValue: defaultValue?.split('').slice(0, currentLength),\n finalValue: createPinArray(currentLength, ''),\n onChange: (val) => {\n const stringValue = val.join('').trim();\n onChange?.(stringValue);\n if (stringValue.length === currentLength && !completedRef.current) {\n completedRef.current = true;\n onComplete?.(stringValue);\n } else if (stringValue.length < currentLength) {\n completedRef.current = false;\n }\n },\n });\n\n const currentValue =\n _value.length !== currentLength ? createPinArray(currentLength, _value.join('')) : _value;\n\n const _valueToString = currentValue.join('').trim();\n\n const validate = (code: string) => {\n const re = type instanceof RegExp ? type : type && type in regex ? regex[type] : null;\n return re?.test(code);\n };\n\n const focusInputField = (dir: 'next' | 'prev', index: number) => {\n if (!manageFocus) {\n return;\n }\n\n if (dir === 'next') {\n const nextIndex = index + 1;\n if (nextIndex < currentLength) {\n inputsRef.current[nextIndex]?.focus();\n }\n } else if (dir === 'prev') {\n const prevIndex = index - 1;\n if (prevIndex >= 0) {\n inputsRef.current[prevIndex]?.focus();\n }\n }\n };\n\n const setFieldValue = (val: string, index: number) => {\n const values = [...currentValue];\n values[index] = val;\n setValues(values);\n return values;\n };\n\n const handleChange = (event: React.ChangeEvent<HTMLInputElement>, index: number) => {\n const inputValue = event.target.value;\n\n if (inputValue.length > 1) {\n const isPaste = inputValue.length > 2;\n if (isPaste) {\n const isValid = validate(inputValue);\n if (isValid) {\n setValues(createPinArray(currentLength, inputValue));\n const filledCount = Math.min(inputValue.length, currentLength);\n if (filledCount < currentLength) {\n focusInputField('next', filledCount - 1);\n }\n }\n return;\n }\n\n const newChar = inputValue.split('')[inputValue.length - 1];\n if (validate(newChar)) {\n setFieldValue(newChar, index);\n focusInputField('next', index);\n }\n return;\n }\n\n if (inputValue.length === 1) {\n if (validate(inputValue)) {\n setFieldValue(inputValue, index);\n focusInputField('next', index);\n } else {\n setFieldValue('', index);\n }\n } else if (inputValue.length === 0) {\n setFieldValue('', index);\n }\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>, index: number) => {\n const { ctrlKey, metaKey, key, shiftKey, target } = event;\n const inputValue = (target as HTMLInputElement).value;\n\n if (inputMode === 'numeric') {\n const allowedKeys = ['Backspace', 'Tab', 'Control', 'Delete', 'ArrowLeft', 'ArrowRight'];\n const isPasteShortcut = (ctrlKey || metaKey) && key === 'v';\n const isAllowedKey =\n allowedKeys.includes(key) || isPasteShortcut || !Number.isNaN(Number(key));\n\n if (!isAllowedKey) {\n event.preventDefault();\n return;\n }\n }\n\n switch (key) {\n case 'ArrowLeft':\n event.preventDefault();\n focusInputField('prev', index);\n break;\n\n case 'ArrowRight':\n event.preventDefault();\n focusInputField('next', index);\n break;\n\n case 'Tab':\n if (shiftKey) {\n if (index > 0 && manageFocus) {\n event.preventDefault();\n focusInputField('prev', index);\n }\n }\n break;\n\n case ' ':\n event.preventDefault();\n focusInputField('next', index);\n break;\n\n case 'Delete':\n event.preventDefault();\n setFieldValue('', index);\n break;\n\n case 'Backspace':\n if (inputValue === '') {\n event.preventDefault();\n focusInputField('prev', index);\n } else {\n setFieldValue('', index);\n if (index < currentLength - 1) {\n event.preventDefault();\n focusInputField('prev', index);\n }\n }\n break;\n\n default:\n if (inputValue.length > 0 && key === currentValue[index]) {\n event.preventDefault();\n focusInputField('next', index);\n }\n }\n };\n\n const handleFocus = (event: React.FocusEvent<HTMLInputElement>, index: number) => {\n event.target.select();\n setFocusedIndex(index);\n };\n\n const handleBlur = () => {\n setFocusedIndex(-1);\n };\n\n const handlePaste = (event: React.ClipboardEvent<HTMLInputElement>) => {\n event.preventDefault();\n const pasteData = event.clipboardData.getData('text/plain').replace(/[\\n\\r\\s]+/g, '');\n const isValid = validate(pasteData.trim());\n\n if (isValid) {\n const pasteArray = createPinArray(currentLength, pasteData);\n setValues(pasteArray);\n const filledCount = pasteArray.filter((val) => val !== '').length;\n if (filledCount >= currentLength) {\n inputsRef.current[currentLength - 1]?.focus();\n } else {\n inputsRef.current[filledCount]?.focus();\n }\n }\n };\n\n return (\n <>\n <Group\n {...others}\n {...getStyles('root')}\n ref={rootRef}\n role=\"group\"\n id={uuid}\n gap={gap}\n unstyled={unstyled}\n wrap=\"nowrap\"\n variant={variant}\n __size={size}\n dir=\"ltr\"\n >\n {currentValue.map((char: string, index: number) => (\n <Input\n component=\"input\"\n {...getStyles('pinInput', {\n style: {\n '--input-padding': '0',\n '--input-text-align': 'center',\n } as React.CSSProperties,\n })}\n classNames={resolvedClassNames}\n styles={resolvedStyles}\n size={size}\n __staticSelector=\"PinInput\"\n id={`${uuid}-${index + 1}`}\n key={`${uuid}-${index}`}\n inputMode={inputMode || (type === 'number' ? 'numeric' : 'text')}\n onChange={(event) => handleChange(event, index)}\n onKeyDown={(event) => handleKeyDown(event, index)}\n onFocus={(event) => handleFocus(event, index)}\n onBlur={handleBlur}\n onPaste={handlePaste}\n type={inputType || (mask ? 'password' : type === 'number' ? 'tel' : 'text')}\n radius={radius}\n error={error}\n variant={variant}\n disabled={disabled}\n ref={(node) => {\n if (node) {\n index === 0 && assignRef(ref, node);\n inputsRef.current[index] = node;\n }\n }}\n autoComplete={oneTimeCode ? 'one-time-code' : 'off'}\n placeholder={focusedIndex === index ? '' : placeholder}\n value={char}\n autoFocus={autoFocus && index === 0}\n unstyled={unstyled}\n aria-label={ariaLabel}\n readOnly={readOnly}\n {...getInputProps?.(index)}\n />\n ))}\n </Group>\n\n <input type=\"hidden\" name={name} form={form} value={_valueToString} {...hiddenInputProps} />\n </>\n );\n});\n\nPinInput.classes = { ...classes, ...InputBase.classes };\nPinInput.varsResolver = varsResolver;\nPinInput.displayName = '@mantine/core/PinInput';\n\nexport namespace PinInput {\n export type Props = PinInputProps;\n export type StylesNames = PinInputStylesNames;\n export type Factory = PinInputFactory;\n}\n"],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region packages/@mantine/core/src/components/RollingNumber/DigitColumn.tsx
4
+ const STRIP_CELLS = [
5
+ "0",
6
+ "1",
7
+ "2",
8
+ "3",
9
+ "4",
10
+ "5",
11
+ "6",
12
+ "7",
13
+ "8",
14
+ "9",
15
+ "0",
16
+ "1"
17
+ ];
18
+ function DigitColumn({ digit, getStyles, previousDigit, empty, valueDirection }) {
19
+ const digitIndex = parseInt(digit, 10);
20
+ const previousDigitIndex = previousDigit !== null ? parseInt(previousDigit, 10) : digitIndex;
21
+ const animateToIndex = valueDirection === "up" && previousDigit !== null && digitIndex < previousDigitIndex && digitIndex <= 1 ? digitIndex + 10 : digitIndex;
22
+ const direction = digitIndex >= previousDigitIndex ? "up" : "down";
23
+ const digitStyles = getStyles("digit");
24
+ const columnStyles = getStyles("digitColumn");
25
+ return /* @__PURE__ */ jsx("span", {
26
+ ...digitStyles,
27
+ "data-empty": empty || void 0,
28
+ "aria-hidden": "true",
29
+ children: /* @__PURE__ */ jsx("span", {
30
+ ...columnStyles,
31
+ style: {
32
+ ...columnStyles.style,
33
+ transform: `translateY(${-digitIndex}em)`,
34
+ ["--rn-roll-from"]: `translateY(${-previousDigitIndex}em)`,
35
+ ["--rn-roll-to"]: `translateY(${-animateToIndex}em)`
36
+ },
37
+ "data-direction": direction,
38
+ children: STRIP_CELLS.map((d, i) => /* @__PURE__ */ jsx("span", { children: d }, i))
39
+ }, digit)
40
+ });
41
+ }
42
+ //#endregion
43
+ export { DigitColumn };
44
+
45
+ //# sourceMappingURL=DigitColumn.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DigitColumn.mjs","names":[],"sources":["../../../src/components/RollingNumber/DigitColumn.tsx"],"sourcesContent":["import { useStyles } from '../../core';\nimport type { RollingNumberFactory } from './RollingNumber';\n\nconst STRIP_CELLS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1'];\n\ninterface DigitColumnProps {\n digit: string;\n getStyles: ReturnType<typeof useStyles<RollingNumberFactory>>;\n previousDigit: string | null;\n empty?: boolean;\n valueDirection: 'up' | 'down';\n}\n\nexport function DigitColumn({\n digit,\n getStyles,\n previousDigit,\n empty,\n valueDirection,\n}: DigitColumnProps) {\n const digitIndex = parseInt(digit, 10);\n const previousDigitIndex = previousDigit !== null ? parseInt(previousDigit, 10) : digitIndex;\n\n const wrapsForward =\n valueDirection === 'up' &&\n previousDigit !== null &&\n digitIndex < previousDigitIndex &&\n digitIndex <= 1;\n\n const animateToIndex = wrapsForward ? digitIndex + 10 : digitIndex;\n const direction = digitIndex >= previousDigitIndex ? 'up' : 'down';\n\n const digitStyles = getStyles('digit');\n const columnStyles = getStyles('digitColumn');\n\n return (\n <span {...digitStyles} data-empty={empty || undefined} aria-hidden=\"true\">\n <span\n key={digit}\n {...columnStyles}\n style={{\n ...columnStyles.style,\n transform: `translateY(${-digitIndex}em)`,\n ['--rn-roll-from' as any]: `translateY(${-previousDigitIndex}em)`,\n ['--rn-roll-to' as any]: `translateY(${-animateToIndex}em)`,\n }}\n data-direction={direction}\n >\n {STRIP_CELLS.map((d, i) => (\n <span key={i}>{d}</span>\n ))}\n </span>\n </span>\n );\n}\n"],"mappings":";;;AAGA,MAAM,cAAc;CAAC;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAI;AAUhF,SAAgB,YAAY,EAC1B,OACA,WACA,eACA,OACA,kBACmB;CACnB,MAAM,aAAa,SAAS,OAAO,GAAG;CACtC,MAAM,qBAAqB,kBAAkB,OAAO,SAAS,eAAe,GAAG,GAAG;CAQlF,MAAM,iBALJ,mBAAmB,QACnB,kBAAkB,QAClB,aAAa,sBACb,cAAc,IAEsB,aAAa,KAAK;CACxD,MAAM,YAAY,cAAc,qBAAqB,OAAO;CAE5D,MAAM,cAAc,UAAU,QAAQ;CACtC,MAAM,eAAe,UAAU,cAAc;AAE7C,QACE,oBAAC,QAAD;EAAM,GAAI;EAAa,cAAY,SAAS,KAAA;EAAW,eAAY;YACjE,oBAAC,QAAD;GAEE,GAAI;GACJ,OAAO;IACL,GAAG,aAAa;IAChB,WAAW,cAAc,CAAC,WAAW;KACpC,mBAA0B,cAAc,CAAC,mBAAmB;KAC5D,iBAAwB,cAAc,CAAC,eAAe;IACxD;GACD,kBAAgB;aAEf,YAAY,KAAK,GAAG,MACnB,oBAAC,QAAD,EAAA,UAAe,GAAS,EAAb,EAAa,CACxB;GACG,EAbA,MAaA;EACF,CAAA"}
@@ -0,0 +1,101 @@
1
+ "use client";
2
+ import { createVarsResolver } from "../../core/styles-api/create-vars-resolver/create-vars-resolver.mjs";
3
+ import { useProps } from "../../core/MantineProvider/use-props/use-props.mjs";
4
+ import { useStyles } from "../../core/styles-api/use-styles/use-styles.mjs";
5
+ import { factory } from "../../core/factory/factory.mjs";
6
+ import { Box } from "../../core/Box/Box.mjs";
7
+ import { getDigitParts } from "./get-digit-parts.mjs";
8
+ import { buildValue } from "./build-value.mjs";
9
+ import { DigitColumn } from "./DigitColumn.mjs";
10
+ import { getRenderSlots } from "./get-render-slots.mjs";
11
+ import RollingNumber_module_default from "./RollingNumber.module.mjs";
12
+ import { useEffect, useRef } from "react";
13
+ import { jsx } from "react/jsx-runtime";
14
+ //#region packages/@mantine/core/src/components/RollingNumber/RollingNumber.tsx
15
+ const defaultProps = {
16
+ animationDuration: 600,
17
+ timingFunction: "ease",
18
+ decimalSeparator: ".",
19
+ tabularNumbers: true
20
+ };
21
+ const varsResolver = createVarsResolver((_, { animationDuration, timingFunction }) => ({ root: {
22
+ "--rn-duration": `${animationDuration}ms`,
23
+ "--rn-timing-function": timingFunction
24
+ } }));
25
+ const RollingNumber = factory((_props) => {
26
+ const props = useProps("RollingNumber", defaultProps, _props);
27
+ const { classNames, className, style, styles, unstyled, vars, value, prefix, suffix, decimalSeparator, thousandSeparator, decimalScale, fixedDecimalScale, animationDuration, timingFunction, tabularNumbers, withLiveRegion, mod, attributes, ...others } = props;
28
+ const getStyles = useStyles({
29
+ name: "RollingNumber",
30
+ classes: RollingNumber_module_default,
31
+ props,
32
+ className,
33
+ style,
34
+ classNames,
35
+ styles,
36
+ unstyled,
37
+ attributes,
38
+ vars,
39
+ varsResolver
40
+ });
41
+ const previousValueRef = useRef(value);
42
+ const previousValue = previousValueRef.current;
43
+ useEffect(() => {
44
+ previousValueRef.current = value;
45
+ });
46
+ const valueDirection = value >= previousValue ? "up" : "down";
47
+ const slots = getRenderSlots({
48
+ current: getDigitParts({
49
+ value,
50
+ decimalScale,
51
+ fixedDecimalScale
52
+ }),
53
+ previous: getDigitParts({
54
+ value: previousValue,
55
+ decimalScale,
56
+ fixedDecimalScale
57
+ }),
58
+ prefix,
59
+ suffix,
60
+ decimalSeparator,
61
+ thousandSeparator
62
+ });
63
+ const accessibleValue = buildValue({
64
+ value,
65
+ prefix,
66
+ suffix,
67
+ decimalSeparator,
68
+ thousandSeparator,
69
+ decimalScale,
70
+ fixedDecimalScale
71
+ });
72
+ return /* @__PURE__ */ jsx(Box, {
73
+ ...getStyles("root"),
74
+ mod: [{ "tabular-numbers": tabularNumbers }, mod],
75
+ role: withLiveRegion ? "status" : "img",
76
+ "aria-label": accessibleValue,
77
+ ...others,
78
+ children: slots.map((slot) => {
79
+ if (slot.type === "digit") return /* @__PURE__ */ jsx(DigitColumn, {
80
+ digit: slot.digit,
81
+ previousDigit: slot.previousDigit,
82
+ getStyles,
83
+ empty: slot.empty,
84
+ valueDirection
85
+ }, slot.key);
86
+ return /* @__PURE__ */ jsx("span", {
87
+ ...getStyles("char"),
88
+ "data-empty": slot.empty || void 0,
89
+ "aria-hidden": "true",
90
+ children: slot.char
91
+ }, slot.key);
92
+ })
93
+ });
94
+ });
95
+ RollingNumber.classes = RollingNumber_module_default;
96
+ RollingNumber.varsResolver = varsResolver;
97
+ RollingNumber.displayName = "@mantine/core/RollingNumber";
98
+ //#endregion
99
+ export { RollingNumber };
100
+
101
+ //# sourceMappingURL=RollingNumber.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RollingNumber.mjs","names":["classes"],"sources":["../../../src/components/RollingNumber/RollingNumber.tsx"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport {\n Box,\n BoxProps,\n createVarsResolver,\n ElementProps,\n factory,\n Factory,\n StylesApiProps,\n useProps,\n useStyles,\n} from '../../core';\nimport { buildValue } from './build-value';\nimport { DigitColumn } from './DigitColumn';\nimport { getDigitParts } from './get-digit-parts';\nimport { getRenderSlots } from './get-render-slots';\nimport classes from './RollingNumber.module.css';\n\nexport type RollingNumberStylesNames = 'root' | 'digit' | 'digitColumn' | 'char';\nexport type RollingNumberCssVariables = {\n root: '--rn-duration' | '--rn-timing-function';\n};\n\nexport interface RollingNumberProps\n extends BoxProps, StylesApiProps<RollingNumberFactory>, ElementProps<'div'> {\n /** Number value to display */\n value: number;\n\n /** Prefix added before the value */\n prefix?: string;\n\n /** Suffix added after the value */\n suffix?: string;\n\n /** Character used as a decimal separator @default '.' */\n decimalSeparator?: string;\n\n /** Character used to separate thousands, set to `true` for `,` @default false */\n thousandSeparator?: string | boolean;\n\n /** Number of decimal places to display */\n decimalScale?: number;\n\n /** If set, trailing zeros are added to match `decimalScale` @default false */\n fixedDecimalScale?: boolean;\n\n /** Animation duration in milliseconds @default 600 */\n animationDuration?: number;\n\n /** CSS timing function for animation @default 'ease' */\n timingFunction?: string;\n\n /** If set, use tabular (monospace) numbers @default true */\n tabularNumbers?: boolean;\n\n /** If set, the root element acts as an `aria-live=\"polite\"` region (`role=\"status\"`) and screen readers announce every value change. When `false`, the root uses `role=\"img\"` so the current value is still accessible but updates are not announced. @default false */\n withLiveRegion?: boolean;\n}\n\nexport type RollingNumberFactory = Factory<{\n props: RollingNumberProps;\n ref: HTMLDivElement;\n stylesNames: RollingNumberStylesNames;\n vars: RollingNumberCssVariables;\n}>;\n\nconst defaultProps = {\n animationDuration: 600,\n timingFunction: 'ease',\n decimalSeparator: '.',\n tabularNumbers: true,\n} satisfies Partial<RollingNumberProps>;\n\nconst varsResolver = createVarsResolver<RollingNumberFactory>(\n (_, { animationDuration, timingFunction }) => ({\n root: {\n '--rn-duration': `${animationDuration}ms`,\n '--rn-timing-function': timingFunction,\n },\n })\n);\n\nexport const RollingNumber = factory<RollingNumberFactory>((_props) => {\n const props = useProps('RollingNumber', defaultProps, _props);\n const {\n classNames,\n className,\n style,\n styles,\n unstyled,\n vars,\n value,\n prefix,\n suffix,\n decimalSeparator,\n thousandSeparator,\n decimalScale,\n fixedDecimalScale,\n animationDuration,\n timingFunction,\n tabularNumbers,\n withLiveRegion,\n mod,\n attributes,\n ...others\n } = props;\n\n const getStyles = useStyles<RollingNumberFactory>({\n name: 'RollingNumber',\n classes,\n props,\n className,\n style,\n classNames,\n styles,\n unstyled,\n attributes,\n vars,\n varsResolver,\n });\n\n const previousValueRef = useRef(value);\n const previousValue = previousValueRef.current;\n\n useEffect(() => {\n previousValueRef.current = value;\n });\n\n const valueDirection: 'up' | 'down' = value >= previousValue ? 'up' : 'down';\n\n const current = getDigitParts({ value, decimalScale, fixedDecimalScale });\n const prev = getDigitParts({ value: previousValue, decimalScale, fixedDecimalScale });\n\n const slots = getRenderSlots({\n current,\n previous: prev,\n prefix,\n suffix,\n decimalSeparator,\n thousandSeparator,\n });\n\n const accessibleValue = buildValue({\n value,\n prefix,\n suffix,\n decimalSeparator,\n thousandSeparator,\n decimalScale,\n fixedDecimalScale,\n });\n\n return (\n <Box\n {...getStyles('root')}\n mod={[{ 'tabular-numbers': tabularNumbers }, mod]}\n role={withLiveRegion ? 'status' : 'img'}\n aria-label={accessibleValue}\n {...others}\n >\n {slots.map((slot) => {\n if (slot.type === 'digit') {\n return (\n <DigitColumn\n key={slot.key}\n digit={slot.digit}\n previousDigit={slot.previousDigit}\n getStyles={getStyles}\n empty={slot.empty}\n valueDirection={valueDirection}\n />\n );\n }\n\n return (\n <span\n key={slot.key}\n {...getStyles('char')}\n data-empty={slot.empty || undefined}\n aria-hidden=\"true\"\n >\n {slot.char}\n </span>\n );\n })}\n </Box>\n );\n});\n\nRollingNumber.classes = classes;\nRollingNumber.varsResolver = varsResolver;\nRollingNumber.displayName = '@mantine/core/RollingNumber';\n"],"mappings":";;;;;;;;;;;;;;AAkEA,MAAM,eAAe;CACnB,mBAAmB;CACnB,gBAAgB;CAChB,kBAAkB;CAClB,gBAAgB;CACjB;AAED,MAAM,eAAe,oBAClB,GAAG,EAAE,mBAAmB,sBAAsB,EAC7C,MAAM;CACJ,iBAAiB,GAAG,kBAAkB;CACtC,wBAAwB;CACzB,EACF,EACF;AAED,MAAa,gBAAgB,SAA+B,WAAW;CACrE,MAAM,QAAQ,SAAS,iBAAiB,cAAc,OAAO;CAC7D,MAAM,EACJ,YACA,WACA,OACA,QACA,UACA,MACA,OACA,QACA,QACA,kBACA,mBACA,cACA,mBACA,mBACA,gBACA,gBACA,gBACA,KACA,YACA,GAAG,WACD;CAEJ,MAAM,YAAY,UAAgC;EAChD,MAAM;EACN,SAAA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;CAEF,MAAM,mBAAmB,OAAO,MAAM;CACtC,MAAM,gBAAgB,iBAAiB;AAEvC,iBAAgB;AACd,mBAAiB,UAAU;GAC3B;CAEF,MAAM,iBAAgC,SAAS,gBAAgB,OAAO;CAKtE,MAAM,QAAQ,eAAe;EAC3B,SAJc,cAAc;GAAE;GAAO;GAAc;GAAmB,CAAC;EAKvE,UAJW,cAAc;GAAE,OAAO;GAAe;GAAc;GAAmB,CAAC;EAKnF;EACA;EACA;EACA;EACD,CAAC;CAEF,MAAM,kBAAkB,WAAW;EACjC;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;AAEF,QACE,oBAAC,KAAD;EACE,GAAI,UAAU,OAAO;EACrB,KAAK,CAAC,EAAE,mBAAmB,gBAAgB,EAAE,IAAI;EACjD,MAAM,iBAAiB,WAAW;EAClC,cAAY;EACZ,GAAI;YAEH,MAAM,KAAK,SAAS;AACnB,OAAI,KAAK,SAAS,QAChB,QACE,oBAAC,aAAD;IAEE,OAAO,KAAK;IACZ,eAAe,KAAK;IACT;IACX,OAAO,KAAK;IACI;IAChB,EANK,KAAK,IAMV;AAIN,UACE,oBAAC,QAAD;IAEE,GAAI,UAAU,OAAO;IACrB,cAAY,KAAK,SAAS,KAAA;IAC1B,eAAY;cAEX,KAAK;IACD,EANA,KAAK,IAML;IAET;EACE,CAAA;EAER;AAEF,cAAc,UAAUA;AACxB,cAAc,eAAe;AAC7B,cAAc,cAAc"}
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ //#region packages/@mantine/core/src/components/RollingNumber/RollingNumber.module.css
3
+ var RollingNumber_module_default = {
4
+ "root": "m_47dd3981",
5
+ "digit": "m_b301d46e",
6
+ "digitColumn": "m_8ae40964",
7
+ "mantine-rolling-number-roll": "m_18d73873",
8
+ "char": "m_47d64bf5"
9
+ };
10
+ //#endregion
11
+ export { RollingNumber_module_default as default };
12
+
13
+ //# sourceMappingURL=RollingNumber.module.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RollingNumber.module.mjs","names":[],"sources":["../../../src/components/RollingNumber/RollingNumber.module.css"],"sourcesContent":[".root {\n display: inline-flex;\n align-items: baseline;\n overflow: hidden;\n\n &[data-tabular-numbers] {\n font-variant-numeric: tabular-nums;\n }\n}\n\n.digit {\n display: inline-block;\n width: 1ch;\n height: 1em;\n overflow: hidden;\n line-height: 1;\n transition:\n width var(--rn-duration) var(--rn-timing-function),\n opacity var(--rn-duration) var(--rn-timing-function);\n\n &[data-empty] {\n width: 0;\n opacity: 0;\n }\n}\n\n.digitColumn {\n display: flex;\n flex-direction: column;\n animation: mantine-rolling-number-roll var(--rn-duration) var(--rn-timing-function);\n\n & > span {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 1em;\n }\n}\n\n.char {\n display: inline-block;\n overflow: hidden;\n white-space: pre;\n transition: opacity var(--rn-duration) var(--rn-timing-function);\n\n &[data-empty] {\n width: 0;\n opacity: 0;\n }\n}\n\n@keyframes mantine-rolling-number-roll {\n from {\n transform: var(--rn-roll-from);\n }\n\n to {\n transform: var(--rn-roll-to);\n }\n}\n"],"mappings":""}
@@ -0,0 +1,22 @@
1
+ "use client";
2
+ import { getDigitParts } from "./get-digit-parts.mjs";
3
+ //#region packages/@mantine/core/src/components/RollingNumber/build-value.ts
4
+ function buildValue({ value, prefix, suffix, decimalSeparator = ".", thousandSeparator, decimalScale, fixedDecimalScale }) {
5
+ const parts = getDigitParts({
6
+ value,
7
+ decimalScale,
8
+ fixedDecimalScale
9
+ });
10
+ let intStr = parts.intDigits.join("");
11
+ if (thousandSeparator) {
12
+ const sep = typeof thousandSeparator === "string" ? thousandSeparator : ",";
13
+ intStr = intStr.replace(/\B(?=(\d{3})+(?!\d))/g, sep);
14
+ }
15
+ let result = parts.negative ? `-${intStr}` : intStr;
16
+ if (parts.fracDigits.length > 0) result += `${decimalSeparator}${parts.fracDigits.join("")}`;
17
+ return `${prefix || ""}${result}${suffix || ""}`;
18
+ }
19
+ //#endregion
20
+ export { buildValue };
21
+
22
+ //# sourceMappingURL=build-value.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-value.mjs","names":[],"sources":["../../../src/components/RollingNumber/build-value.ts"],"sourcesContent":["import { getDigitParts } from './get-digit-parts';\n\nexport interface BuildValueInput {\n value: number;\n prefix?: string;\n suffix?: string;\n decimalSeparator?: string;\n thousandSeparator?: string | boolean;\n decimalScale?: number;\n fixedDecimalScale?: boolean;\n}\n\nexport function buildValue({\n value,\n prefix,\n suffix,\n decimalSeparator = '.',\n thousandSeparator,\n decimalScale,\n fixedDecimalScale,\n}: BuildValueInput): string {\n const parts = getDigitParts({ value, decimalScale, fixedDecimalScale });\n let intStr = parts.intDigits.join('');\n\n if (thousandSeparator) {\n const sep = typeof thousandSeparator === 'string' ? thousandSeparator : ',';\n intStr = intStr.replace(/\\B(?=(\\d{3})+(?!\\d))/g, sep);\n }\n\n let result = parts.negative ? `-${intStr}` : intStr;\n if (parts.fracDigits.length > 0) {\n result += `${decimalSeparator}${parts.fracDigits.join('')}`;\n }\n\n return `${prefix || ''}${result}${suffix || ''}`;\n}\n"],"mappings":";;;AAYA,SAAgB,WAAW,EACzB,OACA,QACA,QACA,mBAAmB,KACnB,mBACA,cACA,qBAC0B;CAC1B,MAAM,QAAQ,cAAc;EAAE;EAAO;EAAc;EAAmB,CAAC;CACvE,IAAI,SAAS,MAAM,UAAU,KAAK,GAAG;AAErC,KAAI,mBAAmB;EACrB,MAAM,MAAM,OAAO,sBAAsB,WAAW,oBAAoB;AACxE,WAAS,OAAO,QAAQ,yBAAyB,IAAI;;CAGvD,IAAI,SAAS,MAAM,WAAW,IAAI,WAAW;AAC7C,KAAI,MAAM,WAAW,SAAS,EAC5B,WAAU,GAAG,mBAAmB,MAAM,WAAW,KAAK,GAAG;AAG3D,QAAO,GAAG,UAAU,KAAK,SAAS,UAAU"}
@@ -0,0 +1,40 @@
1
+ "use client";
2
+ //#region packages/@mantine/core/src/components/RollingNumber/get-digit-parts.ts
3
+ const PLAIN_FORMAT = new Intl.NumberFormat("en-US", {
4
+ useGrouping: false,
5
+ maximumFractionDigits: 20
6
+ });
7
+ function toPlainString(num, decimalScale) {
8
+ if (!Number.isFinite(num)) return "0";
9
+ if (decimalScale !== void 0) return new Intl.NumberFormat("en-US", {
10
+ useGrouping: false,
11
+ minimumFractionDigits: decimalScale,
12
+ maximumFractionDigits: decimalScale
13
+ }).format(num);
14
+ const str = String(num);
15
+ if (!str.includes("e") && !str.includes("E")) return str;
16
+ return PLAIN_FORMAT.format(num);
17
+ }
18
+ function getDigitParts({ value, decimalScale, fixedDecimalScale }) {
19
+ let str = toPlainString(Math.abs(value), decimalScale);
20
+ if (!fixedDecimalScale && decimalScale !== void 0) {
21
+ const parts = str.split(".");
22
+ if (parts[1]) {
23
+ const trimmed = parts[1].replace(/0+$/, "");
24
+ str = trimmed ? `${parts[0]}.${trimmed}` : parts[0];
25
+ }
26
+ }
27
+ const dotIdx = str.indexOf(".");
28
+ const intStr = dotIdx >= 0 ? str.slice(0, dotIdx) : str;
29
+ const fracStr = dotIdx >= 0 ? str.slice(dotIdx + 1) : "";
30
+ return {
31
+ negative: value < 0,
32
+ intDigits: intStr.split(""),
33
+ fracDigits: fracStr ? fracStr.split("") : [],
34
+ hasDecimal: dotIdx >= 0
35
+ };
36
+ }
37
+ //#endregion
38
+ export { getDigitParts };
39
+
40
+ //# sourceMappingURL=get-digit-parts.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-digit-parts.mjs","names":[],"sources":["../../../src/components/RollingNumber/get-digit-parts.ts"],"sourcesContent":["export interface DigitParts {\n negative: boolean;\n intDigits: string[];\n fracDigits: string[];\n hasDecimal: boolean;\n}\n\nexport interface GetDigitPartsInput {\n value: number;\n decimalScale?: number;\n fixedDecimalScale?: boolean;\n}\n\nconst PLAIN_FORMAT = new Intl.NumberFormat('en-US', {\n useGrouping: false,\n maximumFractionDigits: 20,\n});\n\nfunction toPlainString(num: number, decimalScale?: number): string {\n if (!Number.isFinite(num)) {\n return '0';\n }\n\n if (decimalScale !== undefined) {\n return new Intl.NumberFormat('en-US', {\n useGrouping: false,\n minimumFractionDigits: decimalScale,\n maximumFractionDigits: decimalScale,\n }).format(num);\n }\n\n const str = String(num);\n if (!str.includes('e') && !str.includes('E')) {\n return str;\n }\n\n return PLAIN_FORMAT.format(num);\n}\n\nexport function getDigitParts({\n value,\n decimalScale,\n fixedDecimalScale,\n}: GetDigitPartsInput): DigitParts {\n const abs = Math.abs(value);\n let str = toPlainString(abs, decimalScale);\n\n if (!fixedDecimalScale && decimalScale !== undefined) {\n const parts = str.split('.');\n if (parts[1]) {\n const trimmed = parts[1].replace(/0+$/, '');\n str = trimmed ? `${parts[0]}.${trimmed}` : parts[0];\n }\n }\n\n const dotIdx = str.indexOf('.');\n const intStr = dotIdx >= 0 ? str.slice(0, dotIdx) : str;\n const fracStr = dotIdx >= 0 ? str.slice(dotIdx + 1) : '';\n\n return {\n negative: value < 0,\n intDigits: intStr.split(''),\n fracDigits: fracStr ? fracStr.split('') : [],\n hasDecimal: dotIdx >= 0,\n };\n}\n"],"mappings":";;AAaA,MAAM,eAAe,IAAI,KAAK,aAAa,SAAS;CAClD,aAAa;CACb,uBAAuB;CACxB,CAAC;AAEF,SAAS,cAAc,KAAa,cAA+B;AACjE,KAAI,CAAC,OAAO,SAAS,IAAI,CACvB,QAAO;AAGT,KAAI,iBAAiB,KAAA,EACnB,QAAO,IAAI,KAAK,aAAa,SAAS;EACpC,aAAa;EACb,uBAAuB;EACvB,uBAAuB;EACxB,CAAC,CAAC,OAAO,IAAI;CAGhB,MAAM,MAAM,OAAO,IAAI;AACvB,KAAI,CAAC,IAAI,SAAS,IAAI,IAAI,CAAC,IAAI,SAAS,IAAI,CAC1C,QAAO;AAGT,QAAO,aAAa,OAAO,IAAI;;AAGjC,SAAgB,cAAc,EAC5B,OACA,cACA,qBACiC;CAEjC,IAAI,MAAM,cADE,KAAK,IAAI,MAAM,EACE,aAAa;AAE1C,KAAI,CAAC,qBAAqB,iBAAiB,KAAA,GAAW;EACpD,MAAM,QAAQ,IAAI,MAAM,IAAI;AAC5B,MAAI,MAAM,IAAI;GACZ,MAAM,UAAU,MAAM,GAAG,QAAQ,OAAO,GAAG;AAC3C,SAAM,UAAU,GAAG,MAAM,GAAG,GAAG,YAAY,MAAM;;;CAIrD,MAAM,SAAS,IAAI,QAAQ,IAAI;CAC/B,MAAM,SAAS,UAAU,IAAI,IAAI,MAAM,GAAG,OAAO,GAAG;CACpD,MAAM,UAAU,UAAU,IAAI,IAAI,MAAM,SAAS,EAAE,GAAG;AAEtD,QAAO;EACL,UAAU,QAAQ;EAClB,WAAW,OAAO,MAAM,GAAG;EAC3B,YAAY,UAAU,QAAQ,MAAM,GAAG,GAAG,EAAE;EAC5C,YAAY,UAAU;EACvB"}
@@ -0,0 +1,78 @@
1
+ "use client";
2
+ //#region packages/@mantine/core/src/components/RollingNumber/get-render-slots.ts
3
+ function padLeft(arr, length) {
4
+ return [...Array(length - arr.length).fill(null), ...arr];
5
+ }
6
+ function padRight(arr, length) {
7
+ return [...arr, ...Array(length - arr.length).fill(null)];
8
+ }
9
+ function getRenderSlots({ current, previous, prefix, suffix, decimalSeparator = ".", thousandSeparator }) {
10
+ const maxIntLen = Math.max(current.intDigits.length, previous.intDigits.length);
11
+ const maxFracLen = Math.max(current.fracDigits.length, previous.fracDigits.length);
12
+ const currIntPadded = padLeft(current.intDigits, maxIntLen);
13
+ const prevIntPadded = padLeft(previous.intDigits, maxIntLen);
14
+ const currFracPadded = padRight(current.fracDigits, maxFracLen);
15
+ const prevFracPadded = padRight(previous.fracDigits, maxFracLen);
16
+ const sep = thousandSeparator ? typeof thousandSeparator === "string" ? thousandSeparator : "," : null;
17
+ const slots = [];
18
+ if (prefix) for (let i = 0; i < prefix.length; i++) slots.push({
19
+ type: "char",
20
+ key: `prefix-${i}`,
21
+ char: prefix[i],
22
+ empty: false
23
+ });
24
+ if (current.negative || previous.negative) slots.push({
25
+ type: "char",
26
+ key: "sign",
27
+ char: "-",
28
+ empty: !current.negative
29
+ });
30
+ for (let i = 0; i < maxIntLen; i++) {
31
+ const posFromRight = maxIntLen - 1 - i;
32
+ const currDigit = currIntPadded[i];
33
+ const prevDigit = prevIntPadded[i];
34
+ const isEmpty = currDigit === null;
35
+ slots.push({
36
+ type: "digit",
37
+ key: `int-${posFromRight}`,
38
+ digit: currDigit ?? "0",
39
+ previousDigit: prevDigit,
40
+ empty: isEmpty
41
+ });
42
+ if (sep && posFromRight > 0 && posFromRight % 3 === 0) slots.push({
43
+ type: "char",
44
+ key: `sep-${posFromRight}`,
45
+ char: sep,
46
+ empty: isEmpty
47
+ });
48
+ }
49
+ if (current.hasDecimal || previous.hasDecimal) slots.push({
50
+ type: "char",
51
+ key: "dec",
52
+ char: decimalSeparator,
53
+ empty: !current.hasDecimal
54
+ });
55
+ for (let i = 0; i < maxFracLen; i++) {
56
+ const currDigit = currFracPadded[i];
57
+ const prevDigit = prevFracPadded[i];
58
+ const isEmpty = currDigit === null;
59
+ slots.push({
60
+ type: "digit",
61
+ key: `frac-${i}`,
62
+ digit: currDigit ?? "0",
63
+ previousDigit: prevDigit,
64
+ empty: isEmpty
65
+ });
66
+ }
67
+ if (suffix) for (let i = 0; i < suffix.length; i++) slots.push({
68
+ type: "char",
69
+ key: `suffix-${i}`,
70
+ char: suffix[i],
71
+ empty: false
72
+ });
73
+ return slots;
74
+ }
75
+ //#endregion
76
+ export { getRenderSlots };
77
+
78
+ //# sourceMappingURL=get-render-slots.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-render-slots.mjs","names":[],"sources":["../../../src/components/RollingNumber/get-render-slots.ts"],"sourcesContent":["import { getDigitParts, type DigitParts } from './get-digit-parts';\n\nexport interface DigitSlot {\n type: 'digit';\n key: string;\n digit: string;\n previousDigit: string | null;\n empty: boolean;\n}\n\nexport interface CharSlot {\n type: 'char';\n key: string;\n char: string;\n empty: boolean;\n}\n\nexport type RenderSlot = DigitSlot | CharSlot;\n\nexport interface GetRenderSlotsInput {\n current: DigitParts;\n previous: DigitParts;\n prefix?: string;\n suffix?: string;\n decimalSeparator?: string;\n thousandSeparator?: string | boolean;\n}\n\nfunction padLeft(arr: string[], length: number): (string | null)[] {\n return [...Array(length - arr.length).fill(null), ...arr];\n}\n\nfunction padRight(arr: string[], length: number): (string | null)[] {\n return [...arr, ...Array(length - arr.length).fill(null)];\n}\n\nexport function getRenderSlots({\n current,\n previous,\n prefix,\n suffix,\n decimalSeparator = '.',\n thousandSeparator,\n}: GetRenderSlotsInput): RenderSlot[] {\n const maxIntLen = Math.max(current.intDigits.length, previous.intDigits.length);\n const maxFracLen = Math.max(current.fracDigits.length, previous.fracDigits.length);\n\n const currIntPadded = padLeft(current.intDigits, maxIntLen);\n const prevIntPadded = padLeft(previous.intDigits, maxIntLen);\n const currFracPadded = padRight(current.fracDigits, maxFracLen);\n const prevFracPadded = padRight(previous.fracDigits, maxFracLen);\n\n const sep = thousandSeparator\n ? typeof thousandSeparator === 'string'\n ? thousandSeparator\n : ','\n : null;\n\n const slots: RenderSlot[] = [];\n\n if (prefix) {\n for (let i = 0; i < prefix.length; i++) {\n slots.push({ type: 'char', key: `prefix-${i}`, char: prefix[i], empty: false });\n }\n }\n\n if (current.negative || previous.negative) {\n slots.push({ type: 'char', key: 'sign', char: '-', empty: !current.negative });\n }\n\n for (let i = 0; i < maxIntLen; i++) {\n const posFromRight = maxIntLen - 1 - i;\n const currDigit = currIntPadded[i];\n const prevDigit = prevIntPadded[i];\n const isEmpty = currDigit === null;\n\n slots.push({\n type: 'digit',\n key: `int-${posFromRight}`,\n digit: currDigit ?? '0',\n previousDigit: prevDigit,\n empty: isEmpty,\n });\n\n if (sep && posFromRight > 0 && posFromRight % 3 === 0) {\n slots.push({ type: 'char', key: `sep-${posFromRight}`, char: sep, empty: isEmpty });\n }\n }\n\n if (current.hasDecimal || previous.hasDecimal) {\n slots.push({\n type: 'char',\n key: 'dec',\n char: decimalSeparator,\n empty: !current.hasDecimal,\n });\n }\n\n for (let i = 0; i < maxFracLen; i++) {\n const currDigit = currFracPadded[i];\n const prevDigit = prevFracPadded[i];\n const isEmpty = currDigit === null;\n\n slots.push({\n type: 'digit',\n key: `frac-${i}`,\n digit: currDigit ?? '0',\n previousDigit: prevDigit,\n empty: isEmpty,\n });\n }\n\n if (suffix) {\n for (let i = 0; i < suffix.length; i++) {\n slots.push({ type: 'char', key: `suffix-${i}`, char: suffix[i], empty: false });\n }\n }\n\n return slots;\n}\n\nexport interface GetRenderSlotsFromValuesInput {\n value: number;\n previousValue: number;\n prefix?: string;\n suffix?: string;\n decimalSeparator?: string;\n thousandSeparator?: string | boolean;\n decimalScale?: number;\n fixedDecimalScale?: boolean;\n}\n\nexport function getRenderSlotsFromValues({\n value,\n previousValue,\n prefix,\n suffix,\n decimalSeparator,\n thousandSeparator,\n decimalScale,\n fixedDecimalScale,\n}: GetRenderSlotsFromValuesInput): RenderSlot[] {\n const current = getDigitParts({ value, decimalScale, fixedDecimalScale });\n const prev = getDigitParts({ value: previousValue, decimalScale, fixedDecimalScale });\n\n return getRenderSlots({\n current,\n previous: prev,\n prefix,\n suffix,\n decimalSeparator,\n thousandSeparator,\n });\n}\n"],"mappings":";;AA4BA,SAAS,QAAQ,KAAe,QAAmC;AACjE,QAAO,CAAC,GAAG,MAAM,SAAS,IAAI,OAAO,CAAC,KAAK,KAAK,EAAE,GAAG,IAAI;;AAG3D,SAAS,SAAS,KAAe,QAAmC;AAClE,QAAO,CAAC,GAAG,KAAK,GAAG,MAAM,SAAS,IAAI,OAAO,CAAC,KAAK,KAAK,CAAC;;AAG3D,SAAgB,eAAe,EAC7B,SACA,UACA,QACA,QACA,mBAAmB,KACnB,qBACoC;CACpC,MAAM,YAAY,KAAK,IAAI,QAAQ,UAAU,QAAQ,SAAS,UAAU,OAAO;CAC/E,MAAM,aAAa,KAAK,IAAI,QAAQ,WAAW,QAAQ,SAAS,WAAW,OAAO;CAElF,MAAM,gBAAgB,QAAQ,QAAQ,WAAW,UAAU;CAC3D,MAAM,gBAAgB,QAAQ,SAAS,WAAW,UAAU;CAC5D,MAAM,iBAAiB,SAAS,QAAQ,YAAY,WAAW;CAC/D,MAAM,iBAAiB,SAAS,SAAS,YAAY,WAAW;CAEhE,MAAM,MAAM,oBACR,OAAO,sBAAsB,WAC3B,oBACA,MACF;CAEJ,MAAM,QAAsB,EAAE;AAE9B,KAAI,OACF,MAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,IACjC,OAAM,KAAK;EAAE,MAAM;EAAQ,KAAK,UAAU;EAAK,MAAM,OAAO;EAAI,OAAO;EAAO,CAAC;AAInF,KAAI,QAAQ,YAAY,SAAS,SAC/B,OAAM,KAAK;EAAE,MAAM;EAAQ,KAAK;EAAQ,MAAM;EAAK,OAAO,CAAC,QAAQ;EAAU,CAAC;AAGhF,MAAK,IAAI,IAAI,GAAG,IAAI,WAAW,KAAK;EAClC,MAAM,eAAe,YAAY,IAAI;EACrC,MAAM,YAAY,cAAc;EAChC,MAAM,YAAY,cAAc;EAChC,MAAM,UAAU,cAAc;AAE9B,QAAM,KAAK;GACT,MAAM;GACN,KAAK,OAAO;GACZ,OAAO,aAAa;GACpB,eAAe;GACf,OAAO;GACR,CAAC;AAEF,MAAI,OAAO,eAAe,KAAK,eAAe,MAAM,EAClD,OAAM,KAAK;GAAE,MAAM;GAAQ,KAAK,OAAO;GAAgB,MAAM;GAAK,OAAO;GAAS,CAAC;;AAIvF,KAAI,QAAQ,cAAc,SAAS,WACjC,OAAM,KAAK;EACT,MAAM;EACN,KAAK;EACL,MAAM;EACN,OAAO,CAAC,QAAQ;EACjB,CAAC;AAGJ,MAAK,IAAI,IAAI,GAAG,IAAI,YAAY,KAAK;EACnC,MAAM,YAAY,eAAe;EACjC,MAAM,YAAY,eAAe;EACjC,MAAM,UAAU,cAAc;AAE9B,QAAM,KAAK;GACT,MAAM;GACN,KAAK,QAAQ;GACb,OAAO,aAAa;GACpB,eAAe;GACf,OAAO;GACR,CAAC;;AAGJ,KAAI,OACF,MAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,IACjC,OAAM,KAAK;EAAE,MAAM;EAAQ,KAAK,UAAU;EAAK,MAAM,OAAO;EAAI,OAAO;EAAO,CAAC;AAInF,QAAO"}
@@ -20,7 +20,11 @@ const defaultProps = {
20
20
  openOnFocus: true
21
21
  };
22
22
  const Select = genericFactory((_props) => {
23
- const props = useProps("Select", defaultProps, _props);
23
+ const props = useProps([
24
+ "Input",
25
+ "InputWrapper",
26
+ "Select"
27
+ ], defaultProps, _props);
24
28
  const { classNames, styles, unstyled, vars, dropdownOpened, defaultDropdownOpened, onDropdownClose, onDropdownOpen, onFocus, onBlur, onClick, onChange, data, value, defaultValue, selectFirstOptionOnChange, selectFirstOptionOnDropdownOpen, onOptionSubmit, comboboxProps, readOnly, disabled, filter, limit, withScrollArea, maxDropdownHeight, size, searchable, rightSection, checkIconPosition, withCheckIcon, withAlignedLabels, nothingFoundMessage, name, form, searchValue, defaultSearchValue, onSearchChange, allowDeselect, error, rightSectionPointerEvents, id, clearable, clearSectionMode, clearButtonProps, hiddenInputProps, renderOption, onClear, autoComplete, scrollAreaProps, __defaultRightSection, __clearSection, __clearable, chevronColor, autoSelectOnBlur, openOnFocus, attributes, ...others } = props;
25
29
  const parsedData = useMemo(() => getParsedComboboxData(data), [data]);
26
30
  const retainedSelectedOptions = useRef({});
@@ -1 +1 @@
1
- {"version":3,"file":"Select.mjs","names":["useId"],"sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef } from 'react';\nimport { useId, usePrevious, useUncontrolled } from '@mantine/hooks';\nimport {\n BoxProps,\n ElementProps,\n Factory,\n genericFactory,\n MantineColor,\n Primitive,\n StylesApiProps,\n useProps,\n useResolvedStylesApi,\n} from '../../core';\nimport {\n Combobox,\n ComboboxItem,\n ComboboxLikeProps,\n ComboboxLikeRenderOptionInput,\n ComboboxLikeStylesNames,\n getOptionsLockup,\n getParsedComboboxData,\n OptionsDropdown,\n OptionsFilter,\n useCombobox,\n} from '../Combobox';\nimport {\n __BaseInputProps,\n __InputStylesNames,\n ClearSectionMode,\n InputClearButtonProps,\n InputVariant,\n} from '../Input';\nimport { InputBase } from '../InputBase';\nimport { ScrollAreaProps } from '../ScrollArea';\n\nexport type SelectStylesNames = __InputStylesNames | ComboboxLikeStylesNames;\n\nexport interface SelectProps<Value extends Primitive = string>\n extends\n BoxProps,\n __BaseInputProps,\n ComboboxLikeProps<Value>,\n StylesApiProps<SelectFactory>,\n ElementProps<'input', 'onChange' | 'size' | 'value' | 'defaultValue'> {\n /** Controlled component value */\n value?: Value | null;\n\n /** Uncontrolled component default value */\n defaultValue?: Value | null;\n\n /** Called when value changes */\n onChange?: (value: Value | null, option: ComboboxItem<Value>) => void;\n\n /** Called when the clear button is clicked */\n onClear?: () => void;\n\n /** Determines whether the select should be searchable @default false */\n searchable?: 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 /** 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 @default true */\n allowDeselect?: boolean;\n\n /** Displays clear button in the right section when component has value @default false */\n clearable?: boolean;\n\n /** Determines how the clear button and rightSection are rendered @default 'both' */\n clearSectionMode?: ClearSectionMode;\n\n /** Props passed down to the clear button */\n clearButtonProps?: InputClearButtonProps;\n\n /** Props passed down to the hidden input */\n hiddenInputProps?: Omit<React.ComponentProps<'input'>, 'value'>;\n\n /** A function to render content of the option, replaces the default content of the option */\n renderOption?: (item: ComboboxLikeRenderOptionInput<ComboboxItem<Value>>) => React.ReactNode;\n\n /** Props passed down to the underlying `ScrollArea` component in the dropdown */\n scrollAreaProps?: ScrollAreaProps;\n\n /** Controls color of the default chevron, by default depends on the color scheme */\n chevronColor?: MantineColor;\n\n /** Automatically selects the highlighted option when input loses focus @default false */\n autoSelectOnBlur?: boolean;\n\n /** Opens dropdown when input receives focus (requires searchable={true}) @default true */\n openOnFocus?: boolean;\n}\n\nexport type SelectFactory = Factory<{\n props: SelectProps;\n ref: HTMLInputElement;\n stylesNames: SelectStylesNames;\n variant: InputVariant;\n signature: <Value extends Primitive = string>(props: SelectProps<Value>) => React.JSX.Element;\n}>;\n\nconst defaultProps = {\n size: 'sm',\n withCheckIcon: true,\n allowDeselect: true,\n checkIconPosition: 'left',\n openOnFocus: true,\n} satisfies Partial<SelectProps>;\n\nexport const Select = genericFactory<SelectFactory>((_props) => {\n const props = useProps('Select', defaultProps, _props);\n const {\n classNames,\n styles,\n unstyled,\n vars,\n dropdownOpened,\n defaultDropdownOpened,\n onDropdownClose,\n onDropdownOpen,\n onFocus,\n onBlur,\n onClick,\n onChange,\n data,\n value,\n defaultValue,\n selectFirstOptionOnChange,\n selectFirstOptionOnDropdownOpen,\n onOptionSubmit,\n comboboxProps,\n readOnly,\n disabled,\n filter,\n limit,\n withScrollArea,\n maxDropdownHeight,\n size,\n searchable,\n rightSection,\n checkIconPosition,\n withCheckIcon,\n withAlignedLabels,\n nothingFoundMessage,\n name,\n form,\n searchValue,\n defaultSearchValue,\n onSearchChange,\n allowDeselect,\n error,\n rightSectionPointerEvents,\n id,\n clearable,\n clearSectionMode,\n clearButtonProps,\n hiddenInputProps,\n renderOption,\n onClear,\n autoComplete,\n scrollAreaProps,\n __defaultRightSection,\n __clearSection,\n __clearable,\n chevronColor,\n autoSelectOnBlur,\n openOnFocus,\n attributes,\n ...others\n } = props;\n\n const parsedData = useMemo(() => getParsedComboboxData(data), [data]);\n const retainedSelectedOptions = useRef<Record<string, ComboboxItem<Primitive>>>({});\n const optionsLockup = useMemo(() => getOptionsLockup(parsedData), [parsedData]);\n const _id = useId(id);\n\n const [_value, setValue, controlled] = useUncontrolled({\n value,\n defaultValue,\n finalValue: null,\n onChange,\n });\n\n const selectedOption =\n _value != null\n ? `${_value}` in optionsLockup\n ? optionsLockup[`${_value}`]\n : retainedSelectedOptions.current[`${_value}`]\n : undefined;\n const previousSelectedOption = usePrevious(selectedOption);\n\n const [search, setSearch, searchControlled] = useUncontrolled({\n value: searchValue,\n defaultValue: defaultSearchValue,\n finalValue: selectedOption ? selectedOption.label : '',\n onChange: onSearchChange,\n });\n\n const combobox = useCombobox({\n opened: dropdownOpened,\n defaultOpened: defaultDropdownOpened,\n onDropdownOpen: () => {\n onDropdownOpen?.();\n if (selectFirstOptionOnDropdownOpen) {\n combobox.selectFirstOption();\n } else {\n combobox.updateSelectedOptionIndex('active', { scrollIntoView: true });\n }\n },\n onDropdownClose: () => {\n onDropdownClose?.();\n // Required for autoSelectOnBlur to work correctly\n setTimeout(combobox.resetSelectedOption, 0);\n },\n });\n\n const handleSearchChange = (value: string) => {\n setSearch(value);\n combobox.resetSelectedOption();\n };\n\n const { resolvedClassNames, resolvedStyles } = useResolvedStylesApi<SelectFactory>({\n props,\n styles,\n classNames,\n });\n\n useEffect(() => {\n if (selectFirstOptionOnChange) {\n combobox.selectFirstOption();\n }\n }, [selectFirstOptionOnChange, search]);\n\n useEffect(() => {\n if (value === null) {\n handleSearchChange('');\n }\n\n if (\n value != null &&\n selectedOption &&\n (previousSelectedOption?.value !== selectedOption.value ||\n previousSelectedOption?.label !== selectedOption.label)\n ) {\n handleSearchChange(selectedOption.label);\n }\n }, [value, selectedOption]);\n\n useEffect(() => {\n if (!controlled && !searchControlled) {\n handleSearchChange(\n _value != null\n ? `${_value}` in optionsLockup\n ? optionsLockup[`${_value}`]?.label\n : retainedSelectedOptions.current[`${_value}`]?.label || ''\n : ''\n );\n }\n }, [optionsLockup, _value]);\n\n useEffect(() => {\n if (_value) {\n if (`${_value}` in optionsLockup) {\n retainedSelectedOptions.current[`${_value}`] = optionsLockup[`${_value}`];\n }\n }\n }, [optionsLockup, _value]);\n\n const clearButton = (\n <Combobox.ClearButton\n {...clearButtonProps}\n onClear={() => {\n setValue(null, null);\n handleSearchChange('');\n onClear?.();\n }}\n />\n );\n\n const _clearable = clearable && !!_value && !disabled && !readOnly;\n\n return (\n <>\n <Combobox\n store={combobox}\n __staticSelector=\"Select\"\n classNames={resolvedClassNames}\n styles={resolvedStyles}\n unstyled={unstyled}\n readOnly={readOnly}\n size={size}\n attributes={attributes}\n keepMounted={autoSelectOnBlur}\n onOptionSubmit={(val) => {\n onOptionSubmit?.(val as any);\n const optionLockup = allowDeselect\n ? `${optionsLockup[val].value}` === `${_value}`\n ? null\n : optionsLockup[val]\n : optionsLockup[val];\n\n const nextValue = optionLockup ? optionLockup.value : null;\n\n nextValue !== _value && setValue(nextValue as any, optionLockup);\n !controlled && handleSearchChange(nextValue != null ? optionLockup?.label || '' : '');\n combobox.closeDropdown();\n }}\n {...comboboxProps}\n >\n <Combobox.Target\n targetType={searchable ? 'input' : 'button'}\n autoComplete={autoComplete}\n withExpandedAttribute\n >\n <InputBase\n id={_id}\n __defaultRightSection={\n <Combobox.Chevron\n size={size}\n error={error}\n unstyled={unstyled}\n color={chevronColor}\n />\n }\n __clearSection={clearButton}\n __clearable={_clearable}\n __clearSectionMode={clearSectionMode}\n rightSection={rightSection}\n rightSectionPointerEvents={rightSectionPointerEvents || 'none'}\n {...others}\n size={size}\n __staticSelector=\"Select\"\n disabled={disabled}\n readOnly={readOnly || !searchable}\n value={search}\n onChange={(event) => {\n handleSearchChange(event.currentTarget.value);\n combobox.openDropdown();\n selectFirstOptionOnChange && combobox.selectFirstOption();\n }}\n onFocus={(event) => {\n openOnFocus && !!searchable && combobox.openDropdown();\n onFocus?.(event);\n }}\n onBlur={(event) => {\n if (autoSelectOnBlur) {\n combobox.clickSelectedOption();\n }\n\n !!searchable && combobox.closeDropdown();\n const optionLockup =\n _value != null &&\n (`${_value}` in optionsLockup\n ? optionsLockup[`${_value}`]\n : retainedSelectedOptions.current[`${_value}`]);\n handleSearchChange(optionLockup ? optionLockup.label || '' : '');\n onBlur?.(event);\n }}\n onClick={(event) => {\n searchable ? combobox.openDropdown() : combobox.toggleDropdown();\n onClick?.(event);\n }}\n classNames={resolvedClassNames}\n styles={resolvedStyles}\n unstyled={unstyled}\n pointer={!searchable}\n error={error}\n attributes={attributes}\n />\n </Combobox.Target>\n <OptionsDropdown\n data={parsedData as any}\n hidden={readOnly || disabled}\n filter={filter as OptionsFilter<Primitive> | undefined}\n search={search}\n limit={limit}\n hiddenWhenEmpty={!nothingFoundMessage}\n withScrollArea={withScrollArea}\n maxDropdownHeight={maxDropdownHeight}\n filterOptions={!!searchable && selectedOption?.label !== search}\n value={_value}\n checkIconPosition={checkIconPosition}\n withCheckIcon={withCheckIcon}\n withAlignedLabels={withAlignedLabels}\n nothingFoundMessage={nothingFoundMessage}\n unstyled={unstyled}\n labelId={others.label ? `${_id}-label` : undefined}\n aria-label={others.label ? undefined : others['aria-label']}\n renderOption={renderOption}\n scrollAreaProps={scrollAreaProps}\n />\n </Combobox>\n <Combobox.HiddenInput\n value={_value}\n name={name}\n form={form}\n disabled={disabled}\n {...hiddenInputProps}\n />\n </>\n );\n});\n\nSelect.classes = { ...InputBase.classes, ...Combobox.classes };\nSelect.displayName = '@mantine/core/Select';\n\nexport namespace Select {\n export type Props<Value extends Primitive = string> = SelectProps<Value>;\n export type StylesNames = SelectStylesNames;\n export type Factory = SelectFactory;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Select.mjs","names":["useId"],"sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef } from 'react';\nimport { useId, usePrevious, useUncontrolled } from '@mantine/hooks';\nimport {\n BoxProps,\n ElementProps,\n Factory,\n genericFactory,\n MantineColor,\n Primitive,\n StylesApiProps,\n useProps,\n useResolvedStylesApi,\n} from '../../core';\nimport {\n Combobox,\n ComboboxItem,\n ComboboxLikeProps,\n ComboboxLikeRenderOptionInput,\n ComboboxLikeStylesNames,\n getOptionsLockup,\n getParsedComboboxData,\n OptionsDropdown,\n OptionsFilter,\n useCombobox,\n} from '../Combobox';\nimport {\n __BaseInputProps,\n __InputStylesNames,\n ClearSectionMode,\n InputClearButtonProps,\n InputVariant,\n} from '../Input';\nimport { InputBase } from '../InputBase';\nimport { ScrollAreaProps } from '../ScrollArea';\n\nexport type SelectStylesNames = __InputStylesNames | ComboboxLikeStylesNames;\n\nexport interface SelectProps<Value extends Primitive = string>\n extends\n BoxProps,\n __BaseInputProps,\n ComboboxLikeProps<Value>,\n StylesApiProps<SelectFactory>,\n ElementProps<'input', 'onChange' | 'size' | 'value' | 'defaultValue'> {\n /** Controlled component value */\n value?: Value | null;\n\n /** Uncontrolled component default value */\n defaultValue?: Value | null;\n\n /** Called when value changes */\n onChange?: (value: Value | null, option: ComboboxItem<Value>) => void;\n\n /** Called when the clear button is clicked */\n onClear?: () => void;\n\n /** Determines whether the select should be searchable @default false */\n searchable?: 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 /** 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 @default true */\n allowDeselect?: boolean;\n\n /** Displays clear button in the right section when component has value @default false */\n clearable?: boolean;\n\n /** Determines how the clear button and rightSection are rendered @default 'both' */\n clearSectionMode?: ClearSectionMode;\n\n /** Props passed down to the clear button */\n clearButtonProps?: InputClearButtonProps;\n\n /** Props passed down to the hidden input */\n hiddenInputProps?: Omit<React.ComponentProps<'input'>, 'value'>;\n\n /** A function to render content of the option, replaces the default content of the option */\n renderOption?: (item: ComboboxLikeRenderOptionInput<ComboboxItem<Value>>) => React.ReactNode;\n\n /** Props passed down to the underlying `ScrollArea` component in the dropdown */\n scrollAreaProps?: ScrollAreaProps;\n\n /** Controls color of the default chevron, by default depends on the color scheme */\n chevronColor?: MantineColor;\n\n /** Automatically selects the highlighted option when input loses focus @default false */\n autoSelectOnBlur?: boolean;\n\n /** Opens dropdown when input receives focus (requires searchable={true}) @default true */\n openOnFocus?: boolean;\n}\n\nexport type SelectFactory = Factory<{\n props: SelectProps;\n ref: HTMLInputElement;\n stylesNames: SelectStylesNames;\n variant: InputVariant;\n signature: <Value extends Primitive = string>(props: SelectProps<Value>) => React.JSX.Element;\n}>;\n\nconst defaultProps = {\n size: 'sm',\n withCheckIcon: true,\n allowDeselect: true,\n checkIconPosition: 'left',\n openOnFocus: true,\n} satisfies Partial<SelectProps>;\n\nexport const Select = genericFactory<SelectFactory>((_props) => {\n const props = useProps(['Input', 'InputWrapper', 'Select'], defaultProps, _props);\n const {\n classNames,\n styles,\n unstyled,\n vars,\n dropdownOpened,\n defaultDropdownOpened,\n onDropdownClose,\n onDropdownOpen,\n onFocus,\n onBlur,\n onClick,\n onChange,\n data,\n value,\n defaultValue,\n selectFirstOptionOnChange,\n selectFirstOptionOnDropdownOpen,\n onOptionSubmit,\n comboboxProps,\n readOnly,\n disabled,\n filter,\n limit,\n withScrollArea,\n maxDropdownHeight,\n size,\n searchable,\n rightSection,\n checkIconPosition,\n withCheckIcon,\n withAlignedLabels,\n nothingFoundMessage,\n name,\n form,\n searchValue,\n defaultSearchValue,\n onSearchChange,\n allowDeselect,\n error,\n rightSectionPointerEvents,\n id,\n clearable,\n clearSectionMode,\n clearButtonProps,\n hiddenInputProps,\n renderOption,\n onClear,\n autoComplete,\n scrollAreaProps,\n __defaultRightSection,\n __clearSection,\n __clearable,\n chevronColor,\n autoSelectOnBlur,\n openOnFocus,\n attributes,\n ...others\n } = props;\n\n const parsedData = useMemo(() => getParsedComboboxData(data), [data]);\n const retainedSelectedOptions = useRef<Record<string, ComboboxItem<Primitive>>>({});\n const optionsLockup = useMemo(() => getOptionsLockup(parsedData), [parsedData]);\n const _id = useId(id);\n\n const [_value, setValue, controlled] = useUncontrolled({\n value,\n defaultValue,\n finalValue: null,\n onChange,\n });\n\n const selectedOption =\n _value != null\n ? `${_value}` in optionsLockup\n ? optionsLockup[`${_value}`]\n : retainedSelectedOptions.current[`${_value}`]\n : undefined;\n const previousSelectedOption = usePrevious(selectedOption);\n\n const [search, setSearch, searchControlled] = useUncontrolled({\n value: searchValue,\n defaultValue: defaultSearchValue,\n finalValue: selectedOption ? selectedOption.label : '',\n onChange: onSearchChange,\n });\n\n const combobox = useCombobox({\n opened: dropdownOpened,\n defaultOpened: defaultDropdownOpened,\n onDropdownOpen: () => {\n onDropdownOpen?.();\n if (selectFirstOptionOnDropdownOpen) {\n combobox.selectFirstOption();\n } else {\n combobox.updateSelectedOptionIndex('active', { scrollIntoView: true });\n }\n },\n onDropdownClose: () => {\n onDropdownClose?.();\n // Required for autoSelectOnBlur to work correctly\n setTimeout(combobox.resetSelectedOption, 0);\n },\n });\n\n const handleSearchChange = (value: string) => {\n setSearch(value);\n combobox.resetSelectedOption();\n };\n\n const { resolvedClassNames, resolvedStyles } = useResolvedStylesApi<SelectFactory>({\n props,\n styles,\n classNames,\n });\n\n useEffect(() => {\n if (selectFirstOptionOnChange) {\n combobox.selectFirstOption();\n }\n }, [selectFirstOptionOnChange, search]);\n\n useEffect(() => {\n if (value === null) {\n handleSearchChange('');\n }\n\n if (\n value != null &&\n selectedOption &&\n (previousSelectedOption?.value !== selectedOption.value ||\n previousSelectedOption?.label !== selectedOption.label)\n ) {\n handleSearchChange(selectedOption.label);\n }\n }, [value, selectedOption]);\n\n useEffect(() => {\n if (!controlled && !searchControlled) {\n handleSearchChange(\n _value != null\n ? `${_value}` in optionsLockup\n ? optionsLockup[`${_value}`]?.label\n : retainedSelectedOptions.current[`${_value}`]?.label || ''\n : ''\n );\n }\n }, [optionsLockup, _value]);\n\n useEffect(() => {\n if (_value) {\n if (`${_value}` in optionsLockup) {\n retainedSelectedOptions.current[`${_value}`] = optionsLockup[`${_value}`];\n }\n }\n }, [optionsLockup, _value]);\n\n const clearButton = (\n <Combobox.ClearButton\n {...clearButtonProps}\n onClear={() => {\n setValue(null, null);\n handleSearchChange('');\n onClear?.();\n }}\n />\n );\n\n const _clearable = clearable && !!_value && !disabled && !readOnly;\n\n return (\n <>\n <Combobox\n store={combobox}\n __staticSelector=\"Select\"\n classNames={resolvedClassNames}\n styles={resolvedStyles}\n unstyled={unstyled}\n readOnly={readOnly}\n size={size}\n attributes={attributes}\n keepMounted={autoSelectOnBlur}\n onOptionSubmit={(val) => {\n onOptionSubmit?.(val as any);\n const optionLockup = allowDeselect\n ? `${optionsLockup[val].value}` === `${_value}`\n ? null\n : optionsLockup[val]\n : optionsLockup[val];\n\n const nextValue = optionLockup ? optionLockup.value : null;\n\n nextValue !== _value && setValue(nextValue as any, optionLockup);\n !controlled && handleSearchChange(nextValue != null ? optionLockup?.label || '' : '');\n combobox.closeDropdown();\n }}\n {...comboboxProps}\n >\n <Combobox.Target\n targetType={searchable ? 'input' : 'button'}\n autoComplete={autoComplete}\n withExpandedAttribute\n >\n <InputBase\n id={_id}\n __defaultRightSection={\n <Combobox.Chevron\n size={size}\n error={error}\n unstyled={unstyled}\n color={chevronColor}\n />\n }\n __clearSection={clearButton}\n __clearable={_clearable}\n __clearSectionMode={clearSectionMode}\n rightSection={rightSection}\n rightSectionPointerEvents={rightSectionPointerEvents || 'none'}\n {...others}\n size={size}\n __staticSelector=\"Select\"\n disabled={disabled}\n readOnly={readOnly || !searchable}\n value={search}\n onChange={(event) => {\n handleSearchChange(event.currentTarget.value);\n combobox.openDropdown();\n selectFirstOptionOnChange && combobox.selectFirstOption();\n }}\n onFocus={(event) => {\n openOnFocus && !!searchable && combobox.openDropdown();\n onFocus?.(event);\n }}\n onBlur={(event) => {\n if (autoSelectOnBlur) {\n combobox.clickSelectedOption();\n }\n\n !!searchable && combobox.closeDropdown();\n const optionLockup =\n _value != null &&\n (`${_value}` in optionsLockup\n ? optionsLockup[`${_value}`]\n : retainedSelectedOptions.current[`${_value}`]);\n handleSearchChange(optionLockup ? optionLockup.label || '' : '');\n onBlur?.(event);\n }}\n onClick={(event) => {\n searchable ? combobox.openDropdown() : combobox.toggleDropdown();\n onClick?.(event);\n }}\n classNames={resolvedClassNames}\n styles={resolvedStyles}\n unstyled={unstyled}\n pointer={!searchable}\n error={error}\n attributes={attributes}\n />\n </Combobox.Target>\n <OptionsDropdown\n data={parsedData as any}\n hidden={readOnly || disabled}\n filter={filter as OptionsFilter<Primitive> | undefined}\n search={search}\n limit={limit}\n hiddenWhenEmpty={!nothingFoundMessage}\n withScrollArea={withScrollArea}\n maxDropdownHeight={maxDropdownHeight}\n filterOptions={!!searchable && selectedOption?.label !== search}\n value={_value}\n checkIconPosition={checkIconPosition}\n withCheckIcon={withCheckIcon}\n withAlignedLabels={withAlignedLabels}\n nothingFoundMessage={nothingFoundMessage}\n unstyled={unstyled}\n labelId={others.label ? `${_id}-label` : undefined}\n aria-label={others.label ? undefined : others['aria-label']}\n renderOption={renderOption}\n scrollAreaProps={scrollAreaProps}\n />\n </Combobox>\n <Combobox.HiddenInput\n value={_value}\n name={name}\n form={form}\n disabled={disabled}\n {...hiddenInputProps}\n />\n </>\n );\n});\n\nSelect.classes = { ...InputBase.classes, ...Combobox.classes };\nSelect.displayName = '@mantine/core/Select';\n\nexport namespace Select {\n export type Props<Value extends Primitive = string> = SelectProps<Value>;\n export type StylesNames = SelectStylesNames;\n export type Factory = SelectFactory;\n}\n"],"mappings":"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"}