@ahrowe/ui 0.23.0 → 0.24.1

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 (83) hide show
  1. package/dist/esm/common/alert/alert.types.mjs.map +1 -1
  2. package/dist/esm/common/badge/badge.types.mjs.map +1 -1
  3. package/dist/esm/common/button/button.mjs +1 -1
  4. package/dist/esm/common/button/button.mjs.map +1 -1
  5. package/dist/esm/common/button/button.module.mjs +1 -1
  6. package/dist/esm/common/button/button.module.mjs.map +1 -1
  7. package/dist/esm/common/button/button.types.mjs +1 -1
  8. package/dist/esm/common/button/button.types.mjs.map +1 -1
  9. package/dist/esm/common/card/Card.mjs +1 -1
  10. package/dist/esm/common/card/Card.mjs.map +1 -1
  11. package/dist/esm/common/card/card.types.mjs.map +1 -1
  12. package/dist/esm/common/carousel/carousel.mjs +1 -1
  13. package/dist/esm/common/carousel/carousel.mjs.map +1 -1
  14. package/dist/esm/common/chip/chip.mjs +1 -1
  15. package/dist/esm/common/chip/chip.mjs.map +1 -1
  16. package/dist/esm/common/chip/chip.types.mjs.map +1 -1
  17. package/dist/esm/common/dropZone/dropZone.types.mjs.map +1 -1
  18. package/dist/esm/common/floatingMenu/floatingMenu.types.mjs.map +1 -1
  19. package/dist/esm/common/hooks/useCoarsePointer.mjs +2 -0
  20. package/dist/esm/common/hooks/useCoarsePointer.mjs.map +1 -0
  21. package/dist/esm/common/hooks/useSwipeDismiss.mjs +1 -1
  22. package/dist/esm/common/hooks/useSwipeDismiss.mjs.map +1 -1
  23. package/dist/esm/common/iconPicker/iconPicker.mjs +1 -1
  24. package/dist/esm/common/iconPicker/iconPicker.mjs.map +1 -1
  25. package/dist/esm/common/input/input.types.mjs.map +1 -1
  26. package/dist/esm/common/interactableDiv/interactableDiv.mjs +1 -1
  27. package/dist/esm/common/interactableDiv/interactableDiv.mjs.map +1 -1
  28. package/dist/esm/common/numberInput/index.mjs.map +1 -1
  29. package/dist/esm/common/numberInput/numberInput.mjs +1 -1
  30. package/dist/esm/common/numberInput/numberInput.mjs.map +1 -1
  31. package/dist/esm/common/numberInput/numberInput.module.mjs +1 -1
  32. package/dist/esm/common/numberInput/numberInput.module.mjs.map +1 -1
  33. package/dist/esm/common/numberInput/useStepRepeat.mjs +2 -0
  34. package/dist/esm/common/numberInput/useStepRepeat.mjs.map +1 -0
  35. package/dist/esm/common/otpInput/otpInput.types.mjs.map +1 -1
  36. package/dist/esm/common/popover/popover.types.mjs.map +1 -1
  37. package/dist/esm/common/radioGroup/radioGroup.types.mjs.map +1 -1
  38. package/dist/esm/common/sectionHeader/sectionHeader.types.mjs.map +1 -1
  39. package/dist/index.cjs +6 -6
  40. package/dist/index.cjs.map +1 -1
  41. package/dist/style.css +1 -1
  42. package/dist/types/package/common/alert/alert.types.d.ts +1 -1
  43. package/dist/types/package/common/animatedLogo/animatedLogo.types.d.ts +11 -3
  44. package/dist/types/package/common/avatar/avatar.types.d.ts +1 -1
  45. package/dist/types/package/common/badge/badge.types.d.ts +1 -1
  46. package/dist/types/package/common/button/button.types.d.ts +10 -4
  47. package/dist/types/package/common/card/card.types.d.ts +1 -1
  48. package/dist/types/package/common/carousel/carousel.types.d.ts +1 -1
  49. package/dist/types/package/common/checkbox/checkbox.types.d.ts +1 -1
  50. package/dist/types/package/common/chip/chip.types.d.ts +2 -0
  51. package/dist/types/package/common/colorPicker/colorPicker.types.d.ts +1 -1
  52. package/dist/types/package/common/configProvider/configProvider.types.d.ts +1 -1
  53. package/dist/types/package/common/dropZone/dropZone.types.d.ts +1 -1
  54. package/dist/types/package/common/dropdown/dropdown.types.d.ts +1 -1
  55. package/dist/types/package/common/errorBoundary/errorBoundary.types.d.ts +1 -1
  56. package/dist/types/package/common/floatingMenu/floatingMenu.types.d.ts +1 -1
  57. package/dist/types/package/common/hooks/useCoarsePointer.d.ts +10 -0
  58. package/dist/types/package/common/iconPicker/iconPicker.types.d.ts +1 -1
  59. package/dist/types/package/common/input/input.types.d.ts +2 -2
  60. package/dist/types/package/common/inputDropdown/inputDropdown.types.d.ts +1 -1
  61. package/dist/types/package/common/interactableDiv/interactableDiv.d.ts +2 -2
  62. package/dist/types/package/common/kanbanBoard/kanbanBoard.types.d.ts +1 -1
  63. package/dist/types/package/common/numberInput/index.d.ts +1 -0
  64. package/dist/types/package/common/numberInput/numberInput.d.ts +3 -32
  65. package/dist/types/package/common/numberInput/numberInput.types.d.ts +61 -0
  66. package/dist/types/package/common/numberInput/useStepRepeat.d.ts +17 -0
  67. package/dist/types/package/common/optionPicker/optionPicker.types.d.ts +1 -1
  68. package/dist/types/package/common/otpInput/otpInput.types.d.ts +1 -1
  69. package/dist/types/package/common/popover/popover.types.d.ts +1 -1
  70. package/dist/types/package/common/radioGroup/radioGroup.types.d.ts +1 -1
  71. package/dist/types/package/common/rating/rating.types.d.ts +1 -1
  72. package/dist/types/package/common/searchInput/searchInput.types.d.ts +1 -1
  73. package/dist/types/package/common/sectionHeader/sectionHeader.types.d.ts +1 -1
  74. package/dist/types/package/common/slider/slider.types.d.ts +1 -1
  75. package/dist/types/package/common/switch/switch.types.d.ts +1 -1
  76. package/dist/types/package/common/tabHeader/tabHeader.types.d.ts +1 -1
  77. package/dist/types/package/common/timeInput/timeInput.types.d.ts +1 -1
  78. package/dist/types/package/common/types/baseProps.types.d.ts +20 -5
  79. package/dist/types/package/common/types/slots.types.d.ts +1 -1
  80. package/docs/Button.md +23 -2
  81. package/docs/Chip.md +1 -0
  82. package/docs/NumberInput.md +66 -2
  83. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"numberInput.mjs","names":[],"sources":["../../../../package/common/numberInput/numberInput.tsx"],"sourcesContent":["import type { ReactElement } from 'react';\nimport React from 'react';\nimport cx from 'classnames';\nimport { NumericFormat, NumericFormatProps } from 'react-number-format';\nimport type { FormValidator } from 'services/formValidation';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faChevronUp, faChevronDown } from '@fortawesome/free-solid-svg-icons';\n\nimport styles from './numberInput.module.pcss';\nimport Input from '../input';\nimport InteractableDiv from '../interactableDiv';\nimport { useComponentDefaults } from '../configProvider';\n\nexport interface NumberInputProps\n extends Omit<NumericFormatProps, 'onValueChange' | 'value' | 'customInput' | 'onChange' | 'step' | 'onKeyDown'> {\n value?: number | string;\n onChange?: (value: number | undefined) => void;\n formValidator?: FormValidator | null;\n label?: string;\n error?: string;\n className?: string;\n allowNegative?: boolean;\n decimalSeparator?: string;\n thousandSeparator?: string | boolean;\n prefix?: string;\n suffix?: string;\n decimalScale?: number;\n /**\n * Whether to pad the value to exactly `decimalScale` decimals. Default `true`\n * (e.g. with `decimalScale={2}`, `12` displays as `12.00`). Set `false` to make\n * `decimalScale` an upper limit only — the user may type fewer decimals and they\n * are kept as-is (`12` stays `12`, `12.1` stays `12.1`), while anything beyond\n * `decimalScale` is still truncated.\n */\n fixedDecimalScale?: boolean;\n placeholder?: string;\n sign?: '+' | '-';\n showArrows?: boolean;\n step?: number;\n readOnly?: boolean;\n isRequired?: boolean;\n onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void;\n}\n\nfunction NumberInput(props: NumberInputProps): ReactElement {\n const fvRef = React.useRef<FormValidator | null | undefined>(undefined);\n const {\n value,\n onChange,\n formValidator,\n label,\n error,\n className,\n style,\n allowNegative = false,\n decimalSeparator,\n thousandSeparator,\n prefix,\n suffix,\n decimalScale,\n fixedDecimalScale = true,\n placeholder,\n sign,\n showArrows = false,\n step = 1,\n readOnly = false,\n isRequired = false,\n onKeyDown: onKeyDownProp,\n ...rest\n } = useComponentDefaults('NumberInput', props);\n const [, forceUpdate] = React.useState(0);\n React.useEffect(() => {\n fvRef.current = formValidator;\n if (!formValidator) return;\n const listener = () => forceUpdate((n) => n + 1);\n formValidator.registerOnUpdateListener(listener);\n return () => { formValidator.removeOnUpdateListener(listener); };\n }, [formValidator]);\n const computedIsRequired = isRequired || !!formValidator?.validators.find(\n (v) => (v as { validatorId?: string }).validatorId === 'required'\n );\n const rawValue = formValidator != null ? formValidator.value as number | string : value;\n // When a sign is forced, display the absolute value — the prefix character carries the sign visually.\n const displayValue = sign != null && rawValue != null ? Math.abs(Number(rawValue)) : rawValue;\n const controlledValue = displayValue != null ? String(displayValue) : '';\n\n function handleValueChange(floatValue: number | undefined) {\n let out = floatValue;\n if (out !== undefined) {\n if (sign === '-') out = -Math.abs(out);\n if (sign === '+') out = Math.abs(out);\n }\n if (formValidator != null) formValidator.set(out ?? null);\n onChange?.(out);\n }\n\n function handleStep(delta: number) {\n if (readOnly) return;\n const current = rawValue != null && rawValue !== '' ? Number(rawValue) : 0;\n let next = current + delta;\n if (!allowNegative && sign !== '-') next = Math.max(0, next);\n if (sign === '-') next = Math.min(0, next);\n handleValueChange(next);\n }\n\n function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {\n if (readOnly) { onKeyDownProp?.(e); return; }\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n handleStep(e.shiftKey ? step * 10 : step);\n return;\n }\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n handleStep(e.shiftKey ? -step * 10 : -step);\n return;\n }\n onKeyDownProp?.(e);\n }\n\n const resolvedPrefix = sign === '-' ? '-' : sign === '+' ? '+' : prefix;\n\n const arrowSuffix = showArrows && !readOnly ? (\n <div className={styles.arrows}>\n <InteractableDiv\n className={styles.arrowBtn}\n tabIndex={-1}\n onMouseDown={(e) => { e.preventDefault(); handleStep(e.shiftKey ? step * 10 : step); }}\n >\n <FontAwesomeIcon icon={faChevronUp} />\n </InteractableDiv>\n <InteractableDiv\n className={styles.arrowBtn}\n tabIndex={-1}\n onMouseDown={(e) => { e.preventDefault(); handleStep(e.shiftKey ? -step * 10 : -step); }}\n >\n <FontAwesomeIcon icon={faChevronDown} />\n </InteractableDiv>\n </div>\n ) : null;\n\n return (\n <Input\n label={label}\n className={cx(styles.numberInput, className)}\n style={style}\n value={controlledValue}\n onChange={() => {}}\n formValidator={null}\n isRequired={computedIsRequired}\n onBlur={() => { if (fvRef.current) fvRef.current.touched = true; }}\n isValid={formValidator ? (formValidator.touched ? !formValidator.hasError() : true) : !error}\n errorMessage={formValidator ? (formValidator.touched ? (formValidator.getCurrentErrorMessage() ?? '') : '') : (error ?? '')}\n placeholder={placeholder}\n readOnly={readOnly}\n suffix={arrowSuffix}\n inputMode={decimalScale === 0 ? 'numeric' : 'decimal'}\n customInput={\n <NumericFormat\n onValueChange={(vals) => handleValueChange(vals.floatValue)}\n allowNegative={sign != null ? false : allowNegative}\n decimalSeparator={decimalSeparator}\n thousandSeparator={thousandSeparator}\n decimalScale={decimalScale}\n fixedDecimalScale={fixedDecimalScale}\n prefix={resolvedPrefix}\n suffix={suffix}\n onKeyDown={showArrows ? handleKeyDown : onKeyDownProp}\n {...rest}\n />\n }\n />\n );\n}\n\nexport default NumberInput;\n"],"mappings":"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"}
1
+ {"version":3,"file":"numberInput.mjs","names":[],"sources":["../../../../package/common/numberInput/numberInput.tsx"],"sourcesContent":["import type { ReactElement } from 'react';\nimport React from 'react';\nimport cx from 'classnames';\nimport { NumericFormat } from 'react-number-format';\nimport type { FormValidator } from 'services/formValidation';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faChevronUp, faChevronDown, faMinus, faPlus } from '@fortawesome/free-solid-svg-icons';\n\nimport styles from './numberInput.module.pcss';\nimport Input from '../input';\nimport Button from '../button';\nimport ButtonGroup from '../buttonGroup';\nimport { ButtonSize } from '../button/button.types';\nimport { useComponentDefaults } from '../configProvider';\nimport { useCoarsePointer } from '../hooks/useCoarsePointer';\nimport { useStepRepeat } from './useStepRepeat';\nimport type { NumberInputProps } from './numberInput.types';\n\nexport type { NumberInputProps, NumberInputArrowsLayout } from './numberInput.types';\n\ninterface StepButtonProps {\n label: string;\n icon: typeof faPlus;\n disabled: boolean;\n direction: 1 | -1;\n onStart: (direction: 1 | -1, multiplier: number) => void;\n onStop: () => void;\n}\n\n/** Press-and-hold behaviour shared by both stepper layouts. */\nfunction stepButtonProps({ label, disabled, direction, onStart, onStop }: StepButtonProps) {\n return {\n // The input keeps the tab stop — it carries role=\"spinbutton\", which announces the value\n // and the arrow-key affordance, so two more tab stops per field would be noise.\n tabIndex: -1,\n disabled,\n 'aria-label': label,\n // pointerdown (not click) keeps focus in the field and responds immediately on touch.\n // Deliberately no setPointerCapture: capturing retargets the following click to the captured\n // element, past the node Button's ripple listens on. useStepRepeat watches the window for\n // the release instead.\n onPointerDown: (e: React.PointerEvent<HTMLElement>) => {\n if (e.button !== 0 && e.pointerType === 'mouse') return;\n e.preventDefault();\n onStart(direction, e.shiftKey ? 10 : 1);\n },\n onPointerUp: onStop,\n onPointerCancel: onStop,\n onContextMenu: (e: React.SyntheticEvent) => e.preventDefault(),\n };\n}\n\n/** Stacked-layout chevron: borderless, sits inside the field's border. */\nfunction ChevronStepButton(props: StepButtonProps): ReactElement {\n return (\n <button type=\"button\" {...stepButtonProps(props)} className={styles.arrowBtn}>\n <FontAwesomeIcon icon={props.icon} aria-hidden=\"true\" />\n </button>\n );\n}\n\n/** Split-layout stepper: a standalone control, so a real Button. */\nfunction SplitStepButton(props: StepButtonProps): ReactElement {\n const { disabled, ...handlers } = stepButtonProps(props);\n return (\n <Button\n {...handlers}\n className={styles.splitBtn}\n size={ButtonSize.Icon}\n disabled={disabled}\n icon={props.icon}\n />\n );\n}\n\nfunction NumberInput(props: NumberInputProps): ReactElement {\n const fvRef = React.useRef<FormValidator | null | undefined>(undefined);\n const {\n value,\n onChange,\n formValidator,\n label,\n error,\n className,\n style,\n allowNegative = false,\n decimalSeparator,\n thousandSeparator,\n prefix,\n suffix,\n decimalScale,\n fixedDecimalScale = true,\n placeholder,\n sign,\n showArrows = false,\n step = 1,\n min,\n max,\n arrowsLayout = 'auto',\n increaseLabel = 'Increase',\n decreaseLabel = 'Decrease',\n readOnly = false,\n disabled = false,\n isRequired = false,\n onKeyDown: onKeyDownProp,\n ...rest\n } = useComponentDefaults('NumberInput', props);\n const [, forceUpdate] = React.useState(0);\n React.useEffect(() => {\n fvRef.current = formValidator;\n if (!formValidator) return;\n const listener = () => forceUpdate((n) => n + 1);\n formValidator.registerOnUpdateListener(listener);\n return () => { formValidator.removeOnUpdateListener(listener); };\n }, [formValidator]);\n const computedIsRequired = isRequired || !!formValidator?.validators.find(\n (v) => (v as { validatorId?: string }).validatorId === 'required'\n );\n const rawValue = formValidator != null ? formValidator.value as number | string : value;\n // When a sign is forced, display the absolute value — the prefix character carries the sign visually.\n const displayValue = sign != null && rawValue != null ? Math.abs(Number(rawValue)) : rawValue;\n const controlledValue = displayValue != null ? String(displayValue) : '';\n\n function handleValueChange(floatValue: number | undefined) {\n let out = floatValue;\n if (out !== undefined) {\n if (sign === '-') out = -Math.abs(out);\n if (sign === '+') out = Math.abs(out);\n }\n if (formValidator != null) formValidator.set(out ?? null);\n onChange?.(out);\n }\n\n function clamp(next: number): number {\n let out = next;\n if (!allowNegative && sign !== '-') out = Math.max(0, out);\n if (sign === '-') out = Math.min(0, out);\n if (min !== undefined) out = Math.max(min, out);\n if (max !== undefined) out = Math.min(max, out);\n return out;\n }\n\n const currentNumber = rawValue != null && rawValue !== '' ? Number(rawValue) : 0;\n\n /**\n * Called on blur and Enter, never per keystroke: rejecting an out-of-bounds edit as it is\n * typed swallows keystrokes on their way somewhere valid (with `max: 10`, typing `1` in front\n * of `8` to reach `18`). An empty field is skipped so a `min` is never typed in for the user.\n */\n function clampToBounds() {\n if (readOnly || disabled) return;\n if (rawValue == null || rawValue === '') return;\n const n = Number(rawValue);\n if (!Number.isFinite(n)) return;\n const next = clamp(n);\n if (next !== n) handleValueChange(next);\n }\n\n /** Returns whether the value moved, which is how useStepRepeat knows to end a hold at a bound. */\n function handleStep(delta: number): boolean {\n if (readOnly || disabled) return false;\n const next = clamp(currentNumber + delta);\n if (next === currentNumber) return false;\n handleValueChange(next);\n return true;\n }\n\n const { start: startRepeat, stop: stopRepeat } = useStepRepeat((delta) => handleStep(delta * step));\n\n function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {\n // Enter submits the surrounding form without ever blurring, so the blur clamp would not run.\n // Before the stepper guard, since the bounds apply with or without steppers.\n if (e.key === 'Enter') {\n clampToBounds();\n onKeyDownProp?.(e);\n return;\n }\n if (!showStepper) { onKeyDownProp?.(e); return; }\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n handleStep(e.shiftKey ? step * 10 : step);\n return;\n }\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n handleStep(e.shiftKey ? -step * 10 : -step);\n return;\n }\n onKeyDownProp?.(e);\n }\n\n const resolvedPrefix = sign === '-' ? '-' : sign === '+' ? '+' : prefix;\n\n const isCoarsePointer = useCoarsePointer();\n const showStepper = showArrows && !readOnly && !disabled;\n const isSplit = arrowsLayout === 'split' || (arrowsLayout === 'auto' && isCoarsePointer);\n\n const canIncrease = clamp(currentNumber + step) !== currentNumber;\n const canDecrease = clamp(currentNumber - step) !== currentNumber;\n\n const stepperProps = { onStart: startRepeat, onStop: stopRepeat };\n\n const stackedArrows = showStepper && !isSplit ? (\n <div className={styles.arrows}>\n <ChevronStepButton\n label={increaseLabel}\n icon={faChevronUp}\n disabled={!canIncrease}\n direction={1}\n {...stepperProps}\n />\n <ChevronStepButton\n label={decreaseLabel}\n icon={faChevronDown}\n disabled={!canDecrease}\n direction={-1}\n {...stepperProps}\n />\n </div>\n ) : null;\n\n // aria-* is spread onto NumericFormat, which forwards unknown props to the DOM input.\n // Input's own cloneElement doesn't set these keys, so they survive the clone.\n const spinButtonProps = showStepper\n ? {\n role: 'spinbutton',\n 'aria-valuenow': Number.isFinite(currentNumber) ? currentNumber : undefined,\n 'aria-valuemin': min,\n 'aria-valuemax': max,\n 'aria-valuetext': controlledValue || undefined,\n }\n : {};\n\n // Shared with the split group, whose buttons have to mirror the field's invalid state — they\n // form one continuous border.\n const isValid = formValidator ? (formValidator.touched ? !formValidator.hasError() : true) : !error;\n\n // In the split layout the ButtonGroup is the root, so the consumer's className and style\n // belong there rather than on the Input.\n const isSplitGroup = showStepper && isSplit;\n\n const input = (\n <Input\n label={label}\n className={cx(styles.numberInput, { [styles.numberInputSplit]: isSplitGroup }, isSplitGroup ? undefined : className)}\n style={isSplitGroup ? undefined : style}\n value={controlledValue}\n onChange={() => {}}\n formValidator={null}\n isRequired={computedIsRequired}\n onBlur={() => { clampToBounds(); if (fvRef.current) fvRef.current.touched = true; }}\n isValid={isValid}\n errorMessage={formValidator ? (formValidator.touched ? (formValidator.getCurrentErrorMessage() ?? '') : '') : (error ?? '')}\n placeholder={placeholder}\n readOnly={readOnly}\n disabled={disabled}\n suffix={stackedArrows}\n // Input centres its suffix wrapper; this lets the chevrons claim the field's full height.\n classNames={stackedArrows ? { suffix: styles.arrowSuffix } : undefined}\n inputMode={decimalScale === 0 ? 'numeric' : 'decimal'}\n customInput={\n <NumericFormat\n onValueChange={(vals) => handleValueChange(vals.floatValue)}\n allowNegative={sign != null ? false : allowNegative}\n decimalSeparator={decimalSeparator}\n thousandSeparator={thousandSeparator}\n decimalScale={decimalScale}\n fixedDecimalScale={fixedDecimalScale}\n prefix={resolvedPrefix}\n suffix={suffix}\n onKeyDown={handleKeyDown}\n {...spinButtonProps}\n {...rest}\n />\n }\n />\n );\n\n if (!isSplitGroup) return input;\n\n return (\n // ButtonGroup collapses the doubled borders and flattens the inner corners, so the three\n // read as one control.\n <ButtonGroup className={cx(styles.split, { [styles.splitInvalid]: !isValid }, className)} style={style}>\n <SplitStepButton\n label={decreaseLabel}\n icon={faMinus}\n disabled={!canDecrease}\n direction={-1}\n {...stepperProps}\n />\n {input}\n <SplitStepButton\n label={increaseLabel}\n icon={faPlus}\n disabled={!canIncrease}\n direction={1}\n {...stepperProps}\n />\n </ButtonGroup>\n );\n}\n\nexport default NumberInput;\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- var e={numberInput:`numberInput_7p2O3`,arrows:`arrows_yjRlc`,arrowBtn:`arrowBtn_DbJoa`};export{e as default};
1
+ var e={"numberInput-split":`numberInput-split_1kFLr`,numberInputSplit:`numberInput-split_1kFLr`,arrowSuffix:`arrowSuffix_QECPG`,arrows:`arrows_yjRlc`,arrowBtn:`arrowBtn_DbJoa`,split:`split_FYvfQ`,splitBtn:`splitBtn_MquuB`,"split-invalid":`split-invalid_F94dA`,splitInvalid:`split-invalid_F94dA`};export{e as default};
2
2
  //# sourceMappingURL=numberInput.module.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"numberInput.module.mjs","names":[],"sources":["../../../../package/common/numberInput/numberInput.module.pcss"],"sourcesContent":[".numberInput {}\n\n.arrows {\n display: flex;\n flex-direction: column;\n align-self: stretch;\n border-left: 1px solid var(--border-color);\n margin: 4px 0;\n}\n\n.arrowBtn {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n background: none;\n border: none;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n color: var(--text-dark);\n padding: 0 6px;\n font-size: 0.55rem;\n line-height: 1;\n transition: color 0.15s, background 0.15s;\n\n &:hover {\n color: var(--primary-color);\n background: var(--background-accent-light);\n }\n\n &:active {\n color: var(--primary-lighter);\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"numberInput.module.mjs","names":[],"sources":["../../../../package/common/numberInput/numberInput.module.pcss"],"sourcesContent":[".numberInput {\n /* Only set when the split layout wraps this input in a flex row. */\n &-split {\n flex: 1;\n min-width: 0;\n }\n}\n\n/* ── Stacked layout: chevrons inside the field's right edge (mouse-oriented) ───────── */\n\n/* Input's `suffix` slot: stretch to the field so the chevrons get its full height. */\n.arrowSuffix {\n align-self: stretch;\n display: flex;\n padding-right: 0;\n}\n\n.arrows {\n display: flex;\n flex-direction: column;\n align-self: stretch;\n border-left: 1px solid var(--border-color);\n /* Sitting flush against the field's edge, the chevrons' background would square off its\n rounded corner, so it is clipped. Read from --group-radius-* like Input's own border, so it\n still flattens inside a ButtonGroup. */\n overflow: hidden;\n border-top-right-radius: var(--group-radius-tr, var(--default-border-radius));\n border-bottom-right-radius: var(--group-radius-br, var(--default-border-radius));\n}\n\n.arrowBtn {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n background: none;\n border: none;\n padding: 0 0.5em;\n /* No min-height: the two halves divide the field's own height, so a stepper never makes a\n NumberInput taller than a plain Input. In em, so it tracks the field's text size. */\n min-width: 1.75em;\n font-size: 0.75em;\n line-height: 1;\n color: var(--text-dark);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n /* So a long press reads as a hold, not a text gesture. */\n touch-action: manipulation;\n user-select: none;\n -webkit-user-select: none;\n -webkit-touch-callout: none;\n transition: color 0.15s, background 0.15s, opacity 0.15s;\n\n &:disabled {\n cursor: default;\n opacity: 0.35;\n }\n\n &:focus-visible {\n outline: 2px solid var(--focus-border-color, var(--primary-color));\n outline-offset: -2px;\n }\n\n /* (hover: hover) only — on touch a :hover state latches after a tap until you tap elsewhere. */\n @media (hover: hover) {\n &:hover:not(:disabled) {\n color: var(--primary-color);\n background: var(--background-accent-light);\n }\n }\n\n &:active:not(:disabled) {\n color: var(--primary-color);\n }\n}\n\n/* ── Split layout: full-height − / + flanking the field (touch-oriented) ───────────── */\n\n/* ButtonGroup is inline-flex; a form field fills its row instead, with the Input taking the\n slack (see .numberInput-split). The class is repeated to beat `.buttonGroup`'s own `display`\n without depending on which CSS module the bundler emits first. */\n.split.split {\n display: flex;\n width: 100%;\n}\n\n.splitBtn {\n /* Set through Button's own theme hooks: custom properties cascade, so no specificity fight.\n Same surface and border as the field, so the three read as one control.\n\n Resting state only, deliberately — Button has no :hover or :active anywhere, and press\n feedback across the library is the Ripple. */\n --button-default-background: var(--input-background);\n --button-default-color: var(--text-dark);\n --button-default-border: 1px solid var(--border-color);\n\n flex: 0 0 auto;\n /* No fixed height — ButtonGroup stretches these to the field.\n\n The width repeats Input's own height formula (`line-height: 1.25` plus the 8px/6px padding\n of `.input-field-default`) to come out square at any text size, and must follow it if that\n padding changes. `aspect-ratio: 1` cannot do this: a flex item's main size is resolved from\n its content before the stretched cross size exists. */\n align-self: stretch;\n width: calc(1.25em + 14px);\n touch-action: manipulation;\n user-select: none;\n -webkit-user-select: none;\n -webkit-touch-callout: none;\n transition: opacity 0.15s;\n\n &:disabled {\n opacity: 0.35;\n }\n\n &:focus-visible {\n outline: 2px solid var(--focus-border-color, var(--primary-color));\n outline-offset: 2px;\n }\n}\n\n/* One continuous border, so the buttons follow the field's focus and error colours — left grey,\n the group reads as a box inside a box. */\n.split:focus-within .splitBtn {\n --button-default-border: 1px solid var(--focus-border-color, var(--primary-color));\n}\n\n.split-invalid .splitBtn {\n --button-default-border: 1px solid var(--error-border-color);\n}\n"],"mappings":""}
@@ -0,0 +1,2 @@
1
+ import{useCallback as e,useEffect as t,useRef as n}from"react";var r=400,i=120,a=50,o=1e3;function s(s){let c=n(null),l=n(null),u=n(s);u.current=s;let d=n(null),f=e(()=>{if(c.current!==null&&(clearTimeout(c.current),c.current=null),l.current!==null&&(clearInterval(l.current),l.current=null),typeof window>`u`)return;let{onEndEvent:e}=d.current;window.removeEventListener(`pointerup`,e),window.removeEventListener(`pointercancel`,e),window.removeEventListener(`pointermove`,e),window.removeEventListener(`blur`,e),document.removeEventListener(`visibilitychange`,e)},[]);d.current={stop:f,onEndEvent:e=>{e.type===`pointermove`&&e.buttons!==0||e.type===`visibilitychange`&&!document.hidden||d.current.stop()}};let p=e((e,t)=>{f();let{onEndEvent:n}=d.current;window.addEventListener(`pointerup`,n),window.addEventListener(`pointercancel`,n),window.addEventListener(`pointermove`,n),window.addEventListener(`blur`,n),document.addEventListener(`visibilitychange`,n);let s=()=>{u.current(e*t)||f()};s(),c.current=setTimeout(()=>{c.current=null;let e=Date.now(),t=!1,n=()=>{s(),l.current!==null&&!t&&Date.now()-e>=o&&(t=!0,l.current!==null&&clearInterval(l.current),l.current=setInterval(n,a))};l.current=setInterval(n,i)},r)},[f]);return t(()=>f,[f]),{start:p,stop:f}}export{s as default};
2
+ //# sourceMappingURL=useStepRepeat.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStepRepeat.mjs","names":[],"sources":["../../../../package/common/numberInput/useStepRepeat.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from 'react';\n\n/** Time a button must be held before the value starts repeating. */\nconst INITIAL_DELAY_MS = 400;\n/** Interval between repeats right after the hold kicks in. */\nconst SLOW_INTERVAL_MS = 120;\n/** Interval the repeat accelerates to once the hold has been going a while. */\nconst FAST_INTERVAL_MS = 50;\n/** How long the slow phase lasts before switching to `FAST_INTERVAL_MS`. */\nconst ACCELERATE_AFTER_MS = 1000;\n\nexport interface UseStepRepeatResult {\n /** Fires one step immediately, then starts the hold-to-repeat timer. */\n start: (direction: 1 | -1, multiplier: number) => void;\n /** Cancels a running repeat. Safe to call when nothing is running. */\n stop: () => void;\n}\n\n/**\n * Hold-to-repeat for the stepper buttons: one step on press, then an accelerating repeat.\n *\n * The release is watched on `window` rather than by capturing the pointer, which would retarget\n * the following click past the node Button's ripple listens on. Capture would have guaranteed a\n * `pointerup`, so the extra listeners cover the ways a press can end without one.\n *\n * `onStep` returns whether anything changed; `false` ends the repeat, so a hold at a bound stops.\n */\nexport function useStepRepeat(onStep: (delta: number) => boolean): UseStepRepeatResult {\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n // Read at repeat time, so a repeat always steps from the latest value.\n const onStepRef = useRef(onStep);\n onStepRef.current = onStep;\n\n // One stable reference to attach and detach with; `stop` and `onEndEvent` also refer to each\n // other, so both go through the ref.\n const handlersRef = useRef<{ stop: () => void; onEndEvent: (e: Event) => void }>(null!);\n\n const stop = useCallback(() => {\n if (timeoutRef.current !== null) { clearTimeout(timeoutRef.current); timeoutRef.current = null; }\n if (intervalRef.current !== null) { clearInterval(intervalRef.current); intervalRef.current = null; }\n if (typeof window === 'undefined') return;\n const { onEndEvent } = handlersRef.current;\n window.removeEventListener('pointerup', onEndEvent);\n window.removeEventListener('pointercancel', onEndEvent);\n window.removeEventListener('pointermove', onEndEvent);\n window.removeEventListener('blur', onEndEvent);\n document.removeEventListener('visibilitychange', onEndEvent);\n }, []);\n\n handlersRef.current = {\n stop,\n onEndEvent: (e: Event) => {\n // A move ends the hold only if nothing is pressed — how a mouse released outside the\n // window reports itself on re-entry.\n if (e.type === 'pointermove' && (e as PointerEvent).buttons !== 0) return;\n if (e.type === 'visibilitychange' && !document.hidden) return;\n handlersRef.current.stop();\n },\n };\n\n const start = useCallback((direction: 1 | -1, multiplier: number) => {\n stop();\n const { onEndEvent } = handlersRef.current;\n window.addEventListener('pointerup', onEndEvent);\n window.addEventListener('pointercancel', onEndEvent);\n window.addEventListener('pointermove', onEndEvent);\n window.addEventListener('blur', onEndEvent);\n document.addEventListener('visibilitychange', onEndEvent);\n\n const fire = () => { if (!onStepRef.current(direction * multiplier)) stop(); };\n fire();\n\n timeoutRef.current = setTimeout(() => {\n timeoutRef.current = null;\n const startedAt = Date.now();\n let isFast = false;\n const tick = () => {\n fire();\n if (intervalRef.current === null) return;\n if (!isFast && Date.now() - startedAt >= ACCELERATE_AFTER_MS) {\n isFast = true;\n if (intervalRef.current !== null) clearInterval(intervalRef.current);\n intervalRef.current = setInterval(tick, FAST_INTERVAL_MS);\n }\n };\n intervalRef.current = setInterval(tick, SLOW_INTERVAL_MS);\n }, INITIAL_DELAY_MS);\n }, [stop]);\n\n useEffect(() => stop, [stop]);\n\n return { start, stop };\n}\n\nexport default useStepRepeat;\n"],"mappings":"+DAGA,IAAM,EAAmB,IAEnB,EAAmB,IAEnB,EAAmB,GAEnB,EAAsB,IAkB5B,SAAgB,EAAc,EAAyD,CACrF,IAAM,EAAa,EAA6C,IAAI,EAC9D,EAAc,EAA8C,IAAI,EAEhE,EAAY,EAAO,CAAM,EAC/B,EAAU,QAAU,EAIpB,IAAM,EAAc,EAA6D,IAAK,EAEhF,EAAO,MAAkB,CAG7B,GAFI,EAAW,UAAY,OAAQ,aAAa,EAAW,OAAO,EAAG,EAAW,QAAU,MACtF,EAAY,UAAY,OAAQ,cAAc,EAAY,OAAO,EAAG,EAAY,QAAU,MAC1F,OAAO,OAAW,IAAa,OACnC,GAAM,CAAE,cAAe,EAAY,QACnC,OAAO,oBAAoB,YAAa,CAAU,EAClD,OAAO,oBAAoB,gBAAiB,CAAU,EACtD,OAAO,oBAAoB,cAAe,CAAU,EACpD,OAAO,oBAAoB,OAAQ,CAAU,EAC7C,SAAS,oBAAoB,mBAAoB,CAAU,CAC7D,EAAG,CAAC,CAAC,EAEL,EAAY,QAAU,CACpB,OACA,WAAa,GAAa,CAGpB,EAAE,OAAS,eAAkB,EAAmB,UAAY,GAC5D,EAAE,OAAS,oBAAsB,CAAC,SAAS,QAC/C,EAAY,QAAQ,KAAK,CAC3B,CACF,EAEA,IAAM,EAAQ,GAAa,EAAmB,IAAuB,CACnE,EAAK,EACL,GAAM,CAAE,cAAe,EAAY,QACnC,OAAO,iBAAiB,YAAa,CAAU,EAC/C,OAAO,iBAAiB,gBAAiB,CAAU,EACnD,OAAO,iBAAiB,cAAe,CAAU,EACjD,OAAO,iBAAiB,OAAQ,CAAU,EAC1C,SAAS,iBAAiB,mBAAoB,CAAU,EAExD,IAAM,MAAa,CAAO,EAAU,QAAQ,EAAY,CAAU,GAAG,EAAK,CAAG,EAC7E,EAAK,EAEL,EAAW,QAAU,eAAiB,CACpC,EAAW,QAAU,KACrB,IAAM,EAAY,KAAK,IAAI,EACvB,EAAS,GACP,MAAa,CACjB,EAAK,EACD,EAAY,UAAY,MACxB,CAAC,GAAU,KAAK,IAAI,EAAI,GAAa,IACvC,EAAS,GACL,EAAY,UAAY,MAAM,cAAc,EAAY,OAAO,EACnE,EAAY,QAAU,YAAY,EAAM,CAAgB,EAE5D,EACA,EAAY,QAAU,YAAY,EAAM,CAAgB,CAC1D,EAAG,CAAgB,CACrB,EAAG,CAAC,CAAI,CAAC,EAIT,OAFA,MAAgB,EAAM,CAAC,CAAI,CAAC,EAErB,CAAE,QAAO,MAAK,CACvB"}
@@ -1 +1 @@
1
- {"version":3,"file":"otpInput.types.mjs","names":[],"sources":["../../../../package/common/otpInput/otpInput.types.ts"],"sourcesContent":["import type React from 'react';\nimport type { FormValidator } from 'services/formValidation';\nimport type { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';\n\nexport type OtpInputSlots = 'root' | 'label' | 'inputs' | 'input' | 'separator';\n\nexport enum OtpInputCharset {\n /** Digits only (0-9). Shows a numeric mobile keyboard. */\n Numeric = 'numeric',\n /** Letters and digits. */\n Alphanumeric = 'alphanumeric',\n}\n\nexport interface OtpInputProps extends HtmlProps {\n /** Number of character boxes. Default 6. */\n length?: number;\n /** Current code as a plain string, e.g. \"123456\". */\n value?: string;\n /** Fired on every change with the full current code (may be shorter than `length`). */\n onChange?: ((value: string) => void) | null;\n /** Fired once, when the code reaches `length` characters. */\n onComplete?: ((value: string) => void) | null;\n formValidator?: FormValidator | null;\n\n /** Restricts which characters can be typed and picks the mobile keyboard. Default `numeric`. */\n charset?: OtpInputCharset;\n /** Render each box's value as a dot, like a password field. */\n masked?: boolean;\n /** Draw a small gap after these 1-based box indices, e.g. `[3]` to split 6 boxes into 3+3. */\n groupAfter?: number[];\n\n label?: string;\n isValid?: boolean;\n /** Shown in an error Tooltip on focus/hover once `isValid` is `false` (or, with a\n * `formValidator`, once it's touched and has an error). Persists until the value changes\n * `isValid`/`formValidator`'s error state itself — see `clearOnError` to auto-dismiss it. */\n errorMessage?: string;\n isRequired?: boolean;\n /** When an error newly appears (`isValid`/`formValidator` turning invalid), clear every box and\n * refocus the first one after `clearErrorDelay`, so the next attempt starts clean instead of the\n * user editing individual wrong digits (and re-triggering `onComplete` on every keystroke while\n * the code stays at full length). Default `false`. */\n clearOnError?: boolean;\n /** Delay in ms before `clearOnError` clears the boxes, so the wrong code and error message are\n * still visible for a moment first. Default `900`. */\n clearErrorDelay?: number;\n disabled?: boolean;\n /** Focuses the first empty box (or the first box) on mount. */\n autoFocus?: boolean;\n\n className?: string;\n style?: React.CSSProperties;\n classNames?: SlotClassNames<OtpInputSlots>;\n styles?: SlotStyles<OtpInputSlots>;\n}\n"],"mappings":"AAMA,IAAY,EAAL,SAAA,EAAA,OAEL,GAAA,QAAA,UAEA,EAAA,aAAA,gBACF,EAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"otpInput.types.mjs","names":[],"sources":["../../../../package/common/otpInput/otpInput.types.ts"],"sourcesContent":["import type React from 'react';\nimport type { FormValidator } from 'services/formValidation';\nimport type { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';\n\nexport type OtpInputSlots = 'root' | 'label' | 'inputs' | 'input' | 'separator';\n\nexport enum OtpInputCharset {\n /** Digits only (0-9). Shows a numeric mobile keyboard. */\n Numeric = 'numeric',\n /** Letters and digits. */\n Alphanumeric = 'alphanumeric',\n}\n\nexport interface OtpInputProps extends Omit<HtmlProps, 'onChange'> {\n /** Number of character boxes. Default 6. */\n length?: number;\n /** Current code as a plain string, e.g. \"123456\". */\n value?: string;\n /** Fired on every change with the full current code (may be shorter than `length`). */\n onChange?: ((value: string) => void) | null;\n /** Fired once, when the code reaches `length` characters. */\n onComplete?: ((value: string) => void) | null;\n formValidator?: FormValidator | null;\n\n /** Restricts which characters can be typed and picks the mobile keyboard. Default `numeric`. */\n charset?: OtpInputCharset;\n /** Render each box's value as a dot, like a password field. */\n masked?: boolean;\n /** Draw a small gap after these 1-based box indices, e.g. `[3]` to split 6 boxes into 3+3. */\n groupAfter?: number[];\n\n label?: string;\n isValid?: boolean;\n /** Shown in an error Tooltip on focus/hover once `isValid` is `false` (or, with a\n * `formValidator`, once it's touched and has an error). Persists until the value changes\n * `isValid`/`formValidator`'s error state itself — see `clearOnError` to auto-dismiss it. */\n errorMessage?: string;\n isRequired?: boolean;\n /** When an error newly appears (`isValid`/`formValidator` turning invalid), clear every box and\n * refocus the first one after `clearErrorDelay`, so the next attempt starts clean instead of the\n * user editing individual wrong digits (and re-triggering `onComplete` on every keystroke while\n * the code stays at full length). Default `false`. */\n clearOnError?: boolean;\n /** Delay in ms before `clearOnError` clears the boxes, so the wrong code and error message are\n * still visible for a moment first. Default `900`. */\n clearErrorDelay?: number;\n disabled?: boolean;\n /** Focuses the first empty box (or the first box) on mount. */\n autoFocus?: boolean;\n\n className?: string;\n style?: React.CSSProperties;\n classNames?: SlotClassNames<OtpInputSlots>;\n styles?: SlotStyles<OtpInputSlots>;\n}\n"],"mappings":"AAMA,IAAY,EAAL,SAAA,EAAA,OAEL,GAAA,QAAA,UAEA,EAAA,aAAA,gBACF,EAAA,CAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"popover.types.mjs","names":[],"sources":["../../../../package/common/popover/popover.types.ts"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react';\nimport type { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';\n\n/** Preferred side of the trigger the panel opens on. Flips to the opposite side when there's no room. */\nexport enum PopoverPlacement {\n Top = 'top',\n Bottom = 'bottom',\n Left = 'left',\n Right = 'right',\n}\n\n/** Alignment along the trigger's cross axis (horizontal for top/bottom, vertical for left/right). */\nexport enum PopoverAlign {\n Start = 'start',\n Center = 'center',\n End = 'end',\n}\n\n/** What opens the popover. */\nexport enum PopoverTrigger {\n Click = 'click',\n Hover = 'hover',\n Focus = 'focus',\n}\n\nexport type PopoverSlots = 'root' | 'trigger' | 'floating' | 'panel' | 'arrow';\n\nexport interface PopoverProps extends HtmlProps {\n /** The trigger element. */\n children?: ReactNode;\n /** The popover body. */\n content?: ReactNode;\n /** Preferred side (default `Bottom`). */\n placement?: PopoverPlacement;\n /** Cross-axis alignment (default `Center`). */\n align?: PopoverAlign;\n /** What opens the popover (default `Click`). */\n trigger?: PopoverTrigger;\n /** Controlled open state. Omit for uncontrolled. */\n isOpen?: boolean;\n /** Initial open state when uncontrolled (default `false`). */\n defaultOpen?: boolean;\n /** Fires whenever the popover wants to open or close. */\n onOpenChange?: (isOpen: boolean) => void;\n /** Gap in px between trigger and panel (default `10`). */\n offset?: number;\n /** Render the arrow pointing at the trigger (default `true`). */\n withArrow?: boolean;\n /** Close when clicking outside the panel (default `true`). */\n closeOnOutsideClick?: boolean;\n /** Close when pressing Escape (default `true`). */\n closeOnEscape?: boolean;\n /** Delay in ms before a hover-triggered popover opens (default `100`). */\n openDelay?: number;\n /** Delay in ms before a hover-triggered popover closes (default `120`). */\n closeDelay?: number;\n /** Prevent the popover from opening. */\n disabled?: boolean;\n\n className?: string;\n style?: CSSProperties;\n classNames?: SlotClassNames<PopoverSlots>;\n styles?: SlotStyles<PopoverSlots>;\n}\n"],"mappings":"AAIA,IAAY,EAAL,SAAA,EAAA,OACL,GAAA,IAAA,MACA,EAAA,OAAA,SACA,EAAA,KAAA,OACA,EAAA,MAAA,SACF,EAAA,CAAA,CAAA,EAGY,EAAL,SAAA,EAAA,OACL,GAAA,MAAA,QACA,EAAA,OAAA,SACA,EAAA,IAAA,OACF,EAAA,CAAA,CAAA,EAGY,EAAL,SAAA,EAAA,OACL,GAAA,MAAA,QACA,EAAA,MAAA,QACA,EAAA,MAAA,SACF,EAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"popover.types.mjs","names":[],"sources":["../../../../package/common/popover/popover.types.ts"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react';\nimport type { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';\n\n/** Preferred side of the trigger the panel opens on. Flips to the opposite side when there's no room. */\nexport enum PopoverPlacement {\n Top = 'top',\n Bottom = 'bottom',\n Left = 'left',\n Right = 'right',\n}\n\n/** Alignment along the trigger's cross axis (horizontal for top/bottom, vertical for left/right). */\nexport enum PopoverAlign {\n Start = 'start',\n Center = 'center',\n End = 'end',\n}\n\n/** What opens the popover. */\nexport enum PopoverTrigger {\n Click = 'click',\n Hover = 'hover',\n Focus = 'focus',\n}\n\nexport type PopoverSlots = 'root' | 'trigger' | 'floating' | 'panel' | 'arrow';\n\nexport interface PopoverProps extends Omit<HtmlProps, 'content'> {\n /** The trigger element. */\n children?: ReactNode;\n /** The popover body. */\n content?: ReactNode;\n /** Preferred side (default `Bottom`). */\n placement?: PopoverPlacement;\n /** Cross-axis alignment (default `Center`). */\n align?: PopoverAlign;\n /** What opens the popover (default `Click`). */\n trigger?: PopoverTrigger;\n /** Controlled open state. Omit for uncontrolled. */\n isOpen?: boolean;\n /** Initial open state when uncontrolled (default `false`). */\n defaultOpen?: boolean;\n /** Fires whenever the popover wants to open or close. */\n onOpenChange?: (isOpen: boolean) => void;\n /** Gap in px between trigger and panel (default `10`). */\n offset?: number;\n /** Render the arrow pointing at the trigger (default `true`). */\n withArrow?: boolean;\n /** Close when clicking outside the panel (default `true`). */\n closeOnOutsideClick?: boolean;\n /** Close when pressing Escape (default `true`). */\n closeOnEscape?: boolean;\n /** Delay in ms before a hover-triggered popover opens (default `100`). */\n openDelay?: number;\n /** Delay in ms before a hover-triggered popover closes (default `120`). */\n closeDelay?: number;\n /** Prevent the popover from opening. */\n disabled?: boolean;\n\n className?: string;\n style?: CSSProperties;\n classNames?: SlotClassNames<PopoverSlots>;\n styles?: SlotStyles<PopoverSlots>;\n}\n"],"mappings":"AAIA,IAAY,EAAL,SAAA,EAAA,OACL,GAAA,IAAA,MACA,EAAA,OAAA,SACA,EAAA,KAAA,OACA,EAAA,MAAA,SACF,EAAA,CAAA,CAAA,EAGY,EAAL,SAAA,EAAA,OACL,GAAA,MAAA,QACA,EAAA,OAAA,SACA,EAAA,IAAA,OACF,EAAA,CAAA,CAAA,EAGY,EAAL,SAAA,EAAA,OACL,GAAA,MAAA,QACA,EAAA,MAAA,QACA,EAAA,MAAA,SACF,EAAA,CAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"radioGroup.types.mjs","names":[],"sources":["../../../../package/common/radioGroup/radioGroup.types.ts"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react';\nimport type { FormValidator } from 'services/formValidation';\nimport type { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';\n\nexport type RadioValue = string | number;\n\nexport enum RadioGroupOrientation {\n Vertical = 'vertical',\n Horizontal = 'horizontal',\n}\n\nexport interface RadioOption {\n value: RadioValue;\n /** Visible label; falls back to `value` when omitted. */\n label?: ReactNode;\n /** Secondary description shown under the label. */\n description?: ReactNode;\n /** Disable just this option. */\n disabled?: boolean;\n}\n\nexport type RadioGroupSlots = 'root' | 'option' | 'radio' | 'dot' | 'label' | 'description';\n\nexport interface RadioGroupProps extends HtmlProps {\n /** The selectable options. */\n options: RadioOption[];\n /** Controlled selected value. Omit for uncontrolled. */\n value?: RadioValue;\n /** Initial value when uncontrolled. */\n defaultValue?: RadioValue;\n /** Fires with the newly selected value. */\n onChange?: (value: RadioValue, event?: React.MouseEvent | React.KeyboardEvent) => void;\n /** Layout direction (default `Vertical`). */\n orientation?: RadioGroupOrientation;\n /** Disable the whole group. */\n disabled?: boolean;\n /** Diameter of the radio circle (default `'18px'`). */\n size?: string;\n /** Tab index of the active (roving) option. */\n tabIndex?: number;\n formValidator?: FormValidator | null;\n /** Manual error message shown in a tooltip (used when there's no `formValidator`, or to force one). */\n errorMessage?: string;\n /** Manual valid state when not using a `formValidator` (default `true`). */\n isValid?: boolean;\n\n className?: string;\n style?: CSSProperties;\n classNames?: SlotClassNames<RadioGroupSlots>;\n styles?: SlotStyles<RadioGroupSlots>;\n}\n"],"mappings":"AAMA,IAAY,EAAL,SAAA,EAAA,OACL,GAAA,SAAA,WACA,EAAA,WAAA,cACF,EAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"radioGroup.types.mjs","names":[],"sources":["../../../../package/common/radioGroup/radioGroup.types.ts"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react';\nimport type { FormValidator } from 'services/formValidation';\nimport type { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';\n\nexport type RadioValue = string | number;\n\nexport enum RadioGroupOrientation {\n Vertical = 'vertical',\n Horizontal = 'horizontal',\n}\n\nexport interface RadioOption {\n value: RadioValue;\n /** Visible label; falls back to `value` when omitted. */\n label?: ReactNode;\n /** Secondary description shown under the label. */\n description?: ReactNode;\n /** Disable just this option. */\n disabled?: boolean;\n}\n\nexport type RadioGroupSlots = 'root' | 'option' | 'radio' | 'dot' | 'label' | 'description';\n\nexport interface RadioGroupProps extends Omit<HtmlProps, 'onChange'> {\n /** The selectable options. */\n options: RadioOption[];\n /** Controlled selected value. Omit for uncontrolled. */\n value?: RadioValue;\n /** Initial value when uncontrolled. */\n defaultValue?: RadioValue;\n /** Fires with the newly selected value. */\n onChange?: (value: RadioValue, event?: React.MouseEvent | React.KeyboardEvent) => void;\n /** Layout direction (default `Vertical`). */\n orientation?: RadioGroupOrientation;\n /** Disable the whole group. */\n disabled?: boolean;\n /** Diameter of the radio circle (default `'18px'`). */\n size?: string;\n /** Tab index of the active (roving) option. */\n tabIndex?: number;\n formValidator?: FormValidator | null;\n /** Manual error message shown in a tooltip (used when there's no `formValidator`, or to force one). */\n errorMessage?: string;\n /** Manual valid state when not using a `formValidator` (default `true`). */\n isValid?: boolean;\n\n className?: string;\n style?: CSSProperties;\n classNames?: SlotClassNames<RadioGroupSlots>;\n styles?: SlotStyles<RadioGroupSlots>;\n}\n"],"mappings":"AAMA,IAAY,EAAL,SAAA,EAAA,OACL,GAAA,SAAA,WACA,EAAA,WAAA,cACF,EAAA,CAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"sectionHeader.types.mjs","names":[],"sources":["../../../../package/common/sectionHeader/sectionHeader.types.ts"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react';\nimport type { IconContent } from '../types/icon.types';\nimport type { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';\nimport type { IconAction } from '../types/actions.types';\n\nexport enum SectionHeaderSize {\n Small = 'small',\n Medium = 'medium',\n Large = 'large',\n}\n\nexport type SectionHeaderAction = IconAction;\n\nexport type SectionHeaderSlots =\n | 'root'\n | 'identity'\n | 'leading'\n | 'titles'\n | 'title'\n | 'subtitle'\n | 'trailing'\n | 'left'\n | 'center'\n | 'actions';\n\nexport interface SectionHeaderProps extends HtmlProps {\n title?: ReactNode;\n subtitle?: ReactNode;\n icon?: IconContent;\n thumbnail?: string | ReactNode;\n left?: ReactNode;\n center?: ReactNode;\n actions?: SectionHeaderAction[] | ReactNode;\n level?: 1 | 2 | 3 | 4 | 5 | 6;\n size?: SectionHeaderSize;\n divider?: boolean;\n className?: string;\n style?: CSSProperties;\n classNames?: SlotClassNames<SectionHeaderSlots>;\n styles?: SlotStyles<SectionHeaderSlots>;\n}\n"],"mappings":"AAKA,IAAY,EAAL,SAAA,EAAA,OACL,GAAA,MAAA,QACA,EAAA,OAAA,SACA,EAAA,MAAA,SACF,EAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"sectionHeader.types.mjs","names":[],"sources":["../../../../package/common/sectionHeader/sectionHeader.types.ts"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react';\nimport type { IconContent } from '../types/icon.types';\nimport type { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';\nimport type { IconAction } from '../types/actions.types';\n\nexport enum SectionHeaderSize {\n Small = 'small',\n Medium = 'medium',\n Large = 'large',\n}\n\nexport type SectionHeaderAction = IconAction;\n\nexport type SectionHeaderSlots =\n | 'root'\n | 'identity'\n | 'leading'\n | 'titles'\n | 'title'\n | 'subtitle'\n | 'trailing'\n | 'left'\n | 'center'\n | 'actions';\n\nexport interface SectionHeaderProps extends Omit<HtmlProps, 'title'> {\n title?: ReactNode;\n subtitle?: ReactNode;\n icon?: IconContent;\n thumbnail?: string | ReactNode;\n left?: ReactNode;\n center?: ReactNode;\n actions?: SectionHeaderAction[] | ReactNode;\n level?: 1 | 2 | 3 | 4 | 5 | 6;\n size?: SectionHeaderSize;\n divider?: boolean;\n className?: string;\n style?: CSSProperties;\n classNames?: SlotClassNames<SectionHeaderSlots>;\n styles?: SlotStyles<SectionHeaderSlots>;\n}\n"],"mappings":"AAKA,IAAY,EAAL,SAAA,EAAA,OACL,GAAA,MAAA,QACA,EAAA,OAAA,SACA,EAAA,MAAA,SACF,EAAA,CAAA,CAAA"}