@spark-ui/components 17.4.1 → 17.5.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 (203) hide show
  1. package/dist/accordion/index.js.map +1 -1
  2. package/dist/accordion/index.mjs.map +1 -1
  3. package/dist/alert-dialog/index.js.map +1 -1
  4. package/dist/alert-dialog/index.mjs.map +1 -1
  5. package/dist/avatar/index.js +1 -1
  6. package/dist/avatar/index.js.map +1 -1
  7. package/dist/avatar/index.mjs +8 -2
  8. package/dist/avatar/index.mjs.map +1 -1
  9. package/dist/badge/index.js.map +1 -1
  10. package/dist/badge/index.mjs.map +1 -1
  11. package/dist/breadcrumb/index.js.map +1 -1
  12. package/dist/breadcrumb/index.mjs.map +1 -1
  13. package/dist/button-B-sMnDc_.js.map +1 -1
  14. package/dist/button-C6nlNPdv.mjs.map +1 -1
  15. package/dist/card/index.js.map +1 -1
  16. package/dist/card/index.mjs.map +1 -1
  17. package/dist/carousel/index.js.map +1 -1
  18. package/dist/carousel/index.mjs.map +1 -1
  19. package/dist/checkbox-DjwbAH09.js.map +1 -1
  20. package/dist/checkbox-xsURzANi.mjs.map +1 -1
  21. package/dist/chip/index.js.map +1 -1
  22. package/dist/chip/index.mjs.map +1 -1
  23. package/dist/circular-meter/index.js.map +1 -1
  24. package/dist/circular-meter/index.mjs.map +1 -1
  25. package/dist/collapsible/index.js.map +1 -1
  26. package/dist/collapsible/index.mjs.map +1 -1
  27. package/dist/combobox/index.js.map +1 -1
  28. package/dist/combobox/index.mjs.map +1 -1
  29. package/dist/dialog/index.js.map +1 -1
  30. package/dist/dialog/index.mjs.map +1 -1
  31. package/dist/divider/index.js.map +1 -1
  32. package/dist/divider/index.mjs.map +1 -1
  33. package/dist/drawer/index.js.map +1 -1
  34. package/dist/drawer/index.mjs.map +1 -1
  35. package/dist/dropdown/index.js.map +1 -1
  36. package/dist/dropdown/index.mjs.map +1 -1
  37. package/dist/file-upload/index.js.map +1 -1
  38. package/dist/file-upload/index.mjs.map +1 -1
  39. package/dist/form-field-81wzFxM0.js.map +1 -1
  40. package/dist/form-field-GTAuK_nO.mjs.map +1 -1
  41. package/dist/icon-CRPcdgYp.js.map +1 -1
  42. package/dist/icon-D05Uqh8_.mjs.map +1 -1
  43. package/dist/icon-button-CYz_Fitz.js.map +1 -1
  44. package/dist/icon-button-DpucUC_L.mjs.map +1 -1
  45. package/dist/input-BUSYZ_VO.js.map +1 -1
  46. package/dist/input-CiWFuTs_.mjs.map +1 -1
  47. package/dist/input-otp/index.js.map +1 -1
  48. package/dist/input-otp/index.mjs.map +1 -1
  49. package/dist/kbd/index.js.map +1 -1
  50. package/dist/kbd/index.mjs.map +1 -1
  51. package/dist/label-BCSEss4U.js.map +1 -1
  52. package/dist/label-DDBRKLUX.mjs.map +1 -1
  53. package/dist/link-box/index.js.map +1 -1
  54. package/dist/link-box/index.mjs.map +1 -1
  55. package/dist/meter/index.js.map +1 -1
  56. package/dist/meter/index.mjs.map +1 -1
  57. package/dist/pagination/index.js.map +1 -1
  58. package/dist/pagination/index.mjs.map +1 -1
  59. package/dist/popover-CrKp_TKk.js.map +1 -1
  60. package/dist/popover-DsBY8eYl.mjs.map +1 -1
  61. package/dist/portal/index.js.map +1 -1
  62. package/dist/portal/index.mjs.map +1 -1
  63. package/dist/progress-BjqJSRnK.js.map +1 -1
  64. package/dist/progress-C3w4PmxY.mjs.map +1 -1
  65. package/dist/progress-tracker/index.js.map +1 -1
  66. package/dist/progress-tracker/index.mjs.map +1 -1
  67. package/dist/radio-group/index.js.map +1 -1
  68. package/dist/radio-group/index.mjs.map +1 -1
  69. package/dist/rating/index.js.map +1 -1
  70. package/dist/rating/index.mjs.map +1 -1
  71. package/dist/rating-display/index.js.map +1 -1
  72. package/dist/rating-display/index.mjs.map +1 -1
  73. package/dist/scrolling-list/index.js.map +1 -1
  74. package/dist/scrolling-list/index.mjs.map +1 -1
  75. package/dist/segmented-control/index.js.map +1 -1
  76. package/dist/segmented-control/index.mjs.map +1 -1
  77. package/dist/segmented-gauge/index.js.map +1 -1
  78. package/dist/segmented-gauge/index.mjs.map +1 -1
  79. package/dist/select/index.js.map +1 -1
  80. package/dist/select/index.mjs.map +1 -1
  81. package/dist/skeleton/index.js.map +1 -1
  82. package/dist/skeleton/index.mjs.map +1 -1
  83. package/dist/slider/index.js.map +1 -1
  84. package/dist/slider/index.mjs.map +1 -1
  85. package/dist/slot/index.js.map +1 -1
  86. package/dist/slot/index.mjs.map +1 -1
  87. package/dist/spinner-DFUoYvmm.js.map +1 -1
  88. package/dist/spinner-DULLiM6a.mjs.map +1 -1
  89. package/dist/src/accordion/index.d.mts +3 -0
  90. package/dist/src/accordion/index.d.ts +3 -0
  91. package/dist/src/alert-dialog/index.d.mts +3 -0
  92. package/dist/src/alert-dialog/index.d.ts +3 -0
  93. package/dist/src/avatar/index.d.mts +7 -5
  94. package/dist/src/avatar/index.d.ts +7 -5
  95. package/dist/src/badge/Badge.d.ts +3 -0
  96. package/dist/src/breadcrumb/index.d.mts +3 -0
  97. package/dist/src/breadcrumb/index.d.ts +3 -0
  98. package/dist/src/button/Button.d.ts +3 -0
  99. package/dist/src/card/index.d.mts +3 -0
  100. package/dist/src/card/index.d.ts +3 -0
  101. package/dist/src/carousel/index.d.mts +3 -0
  102. package/dist/src/carousel/index.d.ts +3 -0
  103. package/dist/src/checkbox/Checkbox.d.ts +3 -0
  104. package/dist/src/checkbox/CheckboxGroup.d.ts +4 -0
  105. package/dist/src/chip/index.d.mts +3 -0
  106. package/dist/src/chip/index.d.ts +3 -0
  107. package/dist/src/circular-meter/index.d.mts +3 -0
  108. package/dist/src/circular-meter/index.d.ts +3 -0
  109. package/dist/src/collapsible/index.d.mts +3 -0
  110. package/dist/src/collapsible/index.d.ts +3 -0
  111. package/dist/src/combobox/index.d.mts +3 -0
  112. package/dist/src/combobox/index.d.ts +3 -0
  113. package/dist/src/dialog/index.d.mts +3 -0
  114. package/dist/src/dialog/index.d.ts +3 -0
  115. package/dist/src/divider/index.d.mts +3 -0
  116. package/dist/src/divider/index.d.ts +3 -0
  117. package/dist/src/drawer/index.d.mts +3 -0
  118. package/dist/src/drawer/index.d.ts +3 -0
  119. package/dist/src/dropdown/index.d.mts +3 -0
  120. package/dist/src/dropdown/index.d.ts +3 -0
  121. package/dist/src/file-upload/index.d.mts +3 -0
  122. package/dist/src/file-upload/index.d.ts +3 -0
  123. package/dist/src/form-field/index.d.mts +3 -0
  124. package/dist/src/form-field/index.d.ts +3 -0
  125. package/dist/src/icon/Icon.d.ts +3 -0
  126. package/dist/src/icon-button/IconButton.d.ts +3 -0
  127. package/dist/src/input/Input.d.ts +3 -0
  128. package/dist/src/input/index.d.mts +4 -0
  129. package/dist/src/input/index.d.ts +4 -0
  130. package/dist/src/input-otp/index.d.mts +3 -0
  131. package/dist/src/input-otp/index.d.ts +3 -0
  132. package/dist/src/kbd/Kbd.d.ts +3 -0
  133. package/dist/src/label/index.d.mts +3 -0
  134. package/dist/src/label/index.d.ts +3 -0
  135. package/dist/src/link-box/index.d.mts +3 -0
  136. package/dist/src/link-box/index.d.ts +3 -0
  137. package/dist/src/meter/index.d.mts +3 -0
  138. package/dist/src/meter/index.d.ts +3 -0
  139. package/dist/src/pagination/index.d.mts +3 -0
  140. package/dist/src/pagination/index.d.ts +3 -0
  141. package/dist/src/popover/index.d.mts +3 -0
  142. package/dist/src/popover/index.d.ts +3 -0
  143. package/dist/src/portal/Portal.d.ts +3 -0
  144. package/dist/src/progress/index.d.mts +3 -0
  145. package/dist/src/progress/index.d.ts +3 -0
  146. package/dist/src/progress-tracker/index.d.mts +3 -0
  147. package/dist/src/progress-tracker/index.d.ts +3 -0
  148. package/dist/src/radio-group/index.d.mts +3 -0
  149. package/dist/src/radio-group/index.d.ts +3 -0
  150. package/dist/src/rating/Rating.d.ts +3 -0
  151. package/dist/src/rating-display/index.d.mts +3 -0
  152. package/dist/src/rating-display/index.d.ts +3 -0
  153. package/dist/src/scrolling-list/index.d.mts +3 -0
  154. package/dist/src/scrolling-list/index.d.ts +3 -0
  155. package/dist/src/segmented-control/index.d.mts +3 -0
  156. package/dist/src/segmented-control/index.d.ts +3 -0
  157. package/dist/src/segmented-gauge/index.d.mts +3 -0
  158. package/dist/src/segmented-gauge/index.d.ts +3 -0
  159. package/dist/src/select/index.d.mts +3 -0
  160. package/dist/src/select/index.d.ts +3 -0
  161. package/dist/src/skeleton/index.d.mts +3 -0
  162. package/dist/src/skeleton/index.d.ts +3 -0
  163. package/dist/src/slider/index.d.mts +3 -0
  164. package/dist/src/slider/index.d.ts +3 -0
  165. package/dist/src/slot/Slot.d.ts +4 -0
  166. package/dist/src/spinner/Spinner.d.ts +3 -0
  167. package/dist/src/stepper/index.d.mts +3 -0
  168. package/dist/src/stepper/index.d.ts +3 -0
  169. package/dist/src/switch/Switch.d.ts +3 -0
  170. package/dist/src/table/index.d.mts +6 -2
  171. package/dist/src/table/index.d.ts +6 -2
  172. package/dist/src/table/internal/TableRootWrapper.d.ts +3 -0
  173. package/dist/src/tabs/index.d.mts +3 -0
  174. package/dist/src/tabs/index.d.ts +3 -0
  175. package/dist/src/tag/Tag.d.ts +3 -0
  176. package/dist/src/text-link/TextLink.d.ts +3 -0
  177. package/dist/src/textarea/Textarea.d.ts +3 -0
  178. package/dist/src/textarea/index.d.mts +4 -0
  179. package/dist/src/textarea/index.d.ts +4 -0
  180. package/dist/src/toast/index.d.mts +3 -0
  181. package/dist/src/toast/index.d.ts +3 -0
  182. package/dist/src/visually-hidden/VisuallyHidden.d.ts +3 -0
  183. package/dist/stepper/index.js.map +1 -1
  184. package/dist/stepper/index.mjs.map +1 -1
  185. package/dist/switch/index.js.map +1 -1
  186. package/dist/switch/index.mjs.map +1 -1
  187. package/dist/table/index.js +1 -1
  188. package/dist/table/index.js.map +1 -1
  189. package/dist/table/index.mjs +1 -1
  190. package/dist/table/index.mjs.map +1 -1
  191. package/dist/tabs/index.js.map +1 -1
  192. package/dist/tabs/index.mjs.map +1 -1
  193. package/dist/tag/index.js.map +1 -1
  194. package/dist/tag/index.mjs.map +1 -1
  195. package/dist/text-link/index.js.map +1 -1
  196. package/dist/text-link/index.mjs.map +1 -1
  197. package/dist/textarea/index.js.map +1 -1
  198. package/dist/textarea/index.mjs.map +1 -1
  199. package/dist/toast/index.js.map +1 -1
  200. package/dist/toast/index.mjs.map +1 -1
  201. package/dist/visually-hidden/index.js.map +1 -1
  202. package/dist/visually-hidden/index.mjs.map +1 -1
  203. package/package.json +16 -18
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/input-otp/InputOTPContext.tsx","../../src/input-otp/InputOTP.styles.ts","../../src/input-otp/InputOTPSlot.tsx","../../src/input-otp/useInputOTP.ts","../../src/input-otp/InputOTP.tsx","../../src/input-otp/InputOTPGroup.tsx","../../src/input-otp/InputOTPSeparator.tsx","../../src/input-otp/index.ts"],"sourcesContent":["import { createContext, useContext } from 'react'\n\nexport interface InputOTPContextValue {\n value: string\n maxLength: number\n slots: {\n char: string\n isActive: boolean\n hasFakeCaret: boolean\n }[]\n activeIndex: number\n intent: 'neutral' | 'success' | 'alert' | 'error'\n disabled: boolean\n readOnly: boolean\n placeholder?: string\n type: 'text' | 'number' | 'password' | 'tel'\n}\n\nexport const InputOTPContext = createContext<InputOTPContextValue | null>(null)\n\nexport const useInputOTPContext = () => {\n const context = useContext(InputOTPContext)\n if (!context) {\n throw new Error('InputOTP components must be used within InputOTP')\n }\n\n return context\n}\n","import { cva, VariantProps } from 'class-variance-authority'\n\nexport const inputOTPContainerStyles = cva(['relative', 'inline-flex', 'items-center', 'gap-sm'])\n\nexport const inputOTPSlotStyles = cva(\n [\n // Base slot styles\n 'relative h-[50px] w-sz-40',\n 'border-sm rounded-md',\n 'text-center text-display-3 text-on-surface',\n 'outline-hidden',\n 'transition-colors',\n 'flex items-center justify-center',\n // Slot that receives focus when clicking the group (first empty or last slot)\n // Use data-[focus-target=true]:... for distinct styles\n // Active state (when focused)\n 'data-[active=true]:ring-1',\n 'data-[active=true]:ring-inset',\n 'data-[active=true]:ring-l-2',\n 'data-[active=true]:border-focus',\n 'data-[active=true]:z-raised ring-focus',\n // Disabled state\n 'data-[disabled=true]:cursor-not-allowed',\n 'data-[disabled=true]:border-outline',\n 'data-[disabled=true]:bg-on-surface/dim-5',\n 'data-[disabled=true]:text-on-surface/dim-3',\n // Read-only state (same as disabled but text stays normal)\n 'data-[readonly=true]:cursor-default',\n 'data-[readonly=true]:data-[active=false]:border-outline',\n 'data-[readonly=true]:bg-on-surface/dim-5',\n 'group-hover:data-[focus-target=true]:data-[disabled=false]:border-outline-high',\n ],\n {\n variants: {\n /**\n * Color scheme of the slot\n */\n intent: {\n neutral: ['data-[filled=true]:bg-neutral-container bg-surface border-outline'],\n success: ['border-success bg-success-container text-on-success-container'],\n alert: ['border-alert bg-alert-container text-on-alert-container'],\n error: ['border-error bg-error-container text-on-error-container'],\n },\n },\n defaultVariants: {\n intent: 'neutral',\n },\n }\n)\n\nexport type InputOTPSlotStylesProps = VariantProps<typeof inputOTPSlotStyles>\n\n// Keep for backward compatibility\nexport const inputOTPStyles = inputOTPSlotStyles\nexport type InputOTPStylesProps = InputOTPSlotStylesProps\n","import { ComponentPropsWithoutRef } from 'react'\n\nimport { inputOTPSlotStyles } from './InputOTP.styles'\nimport { useInputOTPContext } from './InputOTPContext'\n\nexport interface InputOTPSlotProps extends ComponentPropsWithoutRef<'div'> {\n /**\n * Index of the slot (0-based).\n * If not provided, will be automatically assigned based on position in children.\n */\n index?: number\n}\n\nexport const InputOTPSlot = ({ index: indexProp, className, ...props }: InputOTPSlotProps) => {\n const context = useInputOTPContext()\n\n // Use provided index or fallback to 0 (should not happen if auto-assignment works)\n const index = indexProp ?? 0\n const slot = context.slots[index]\n\n if (!slot) {\n return null\n }\n\n const { char, isActive, hasFakeCaret } = slot\n const isEmpty = !char\n const isPlaceholder = isEmpty && !hasFakeCaret && context.placeholder\n\n const isFocusTarget = index === context.activeIndex\n\n return (\n <div\n className={inputOTPSlotStyles({\n intent: context.intent,\n className,\n })}\n data-active={isActive}\n data-disabled={context.disabled}\n data-readonly={context.readOnly}\n data-filled={!isEmpty}\n data-focus-target={isFocusTarget}\n data-valid={context.intent !== 'error'}\n {...props}\n >\n <span className={isPlaceholder ? 'text-on-surface/dim-3' : ''}>\n {context.type === 'password' && char\n ? '•'\n : char || (!hasFakeCaret && context.placeholder ? context.placeholder : '')}\n </span>\n {hasFakeCaret && (\n <span\n className=\"pointer-events-none absolute inset-0 flex items-center justify-center\"\n aria-hidden=\"true\"\n >\n <span className=\"bg-on-surface animate-standalone-caret-blink h-sz-24 w-sz-2\" />\n </span>\n )}\n </div>\n )\n}\n\nInputOTPSlot.displayName = 'InputOTP.Slot'\n","/* eslint-disable max-lines-per-function */\nimport { useFormFieldControl } from '@spark-ui/components/form-field'\nimport {\n ChangeEventHandler,\n ClipboardEventHandler,\n KeyboardEventHandler,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react'\n\nimport type { InputOTPContextValue } from './InputOTPContext'\n\nconst BACKSPACE_KEY = 'Backspace'\nconst LEFT_ARROW_KEY = 'ArrowLeft'\nconst UP_ARROW_KEY = 'ArrowUp'\nconst RIGHT_ARROW_KEY = 'ArrowRight'\nconst DOWN_ARROW_KEY = 'ArrowDown'\nconst E_KEY = 'e'\n\nexport interface UseInputOTPProps {\n maxLength: number\n type: 'text' | 'number' | 'password' | 'tel'\n value?: string\n defaultValue: string\n onValueChange?: (value: string) => void\n isValid: boolean\n disabledProp: boolean\n readOnlyProp: boolean\n autoFocus: boolean\n forceUppercase: boolean\n filterKeys: string[]\n pattern?: string\n placeholder: string\n nameProp?: string\n}\n\nexport interface UseInputOTPReturn {\n uuid: string\n inputRef: React.RefObject<HTMLInputElement | null>\n containerRef: React.RefObject<HTMLDivElement | null>\n name: string | undefined\n disabled: boolean\n readOnly: boolean\n isInvalid: boolean\n isRequired: boolean\n description: string | undefined\n maxLength: number\n intent: 'neutral' | 'success' | 'alert' | 'error'\n currentValue: string\n activeIndex: number\n slots: {\n char: string\n isActive: boolean\n hasFakeCaret: boolean\n }[]\n contextValue: InputOTPContextValue\n handleChange: ChangeEventHandler<HTMLInputElement>\n handleKeyDown: KeyboardEventHandler<HTMLInputElement>\n handleCopy: ClipboardEventHandler<HTMLInputElement>\n handlePaste: ClipboardEventHandler<HTMLInputElement>\n handleFocus: () => void\n handleBlur: () => void\n handleClick: () => void\n labelId: string | undefined\n}\n\nexport const useInputOTP = ({\n maxLength,\n type,\n value: controlledValue,\n defaultValue,\n onValueChange,\n isValid,\n disabledProp,\n readOnlyProp,\n autoFocus,\n forceUppercase,\n filterKeys,\n pattern,\n placeholder,\n nameProp,\n}: UseInputOTPProps): UseInputOTPReturn => {\n const uuid = useId()\n const inputRef = useRef<HTMLInputElement>(null)\n const containerRef = useRef<HTMLDivElement>(null)\n\n // Get FormField context (optional, falls back gracefully if not present)\n const field = useFormFieldControl()\n\n // Use FormField values if available, otherwise fall back to props\n // Use FormField id when available so label htmlFor works correctly\n const id = field.id ?? uuid\n const name = nameProp ?? field.name\n const disabled = field.disabled ?? disabledProp\n const readOnly = field.readOnly ?? readOnlyProp\n const isInvalid = field.isInvalid ?? !isValid\n const isRequired = field.isRequired ?? false\n const labelId = field.labelId\n const description = field.description\n const fieldState = field.state\n\n // Determine intent based on FormField state or isValid prop\n const getIntent = (): 'neutral' | 'success' | 'alert' | 'error' => {\n // FormField state takes priority\n if (['success', 'alert', 'error'].includes(fieldState ?? '')) {\n return fieldState as 'success' | 'alert' | 'error'\n }\n\n // Fallback to isValid prop for backward compatibility\n if (isInvalid) {\n return 'error'\n }\n\n return 'neutral'\n }\n\n const intent = getIntent()\n\n // Initialize value\n const initialValue = controlledValue !== undefined ? controlledValue : defaultValue\n const processedValue = forceUppercase ? initialValue.toUpperCase() : initialValue\n\n const [internalValue, setInternalValue] = useState<string>(processedValue)\n const [isFocused, setIsFocused] = useState<boolean>(false)\n\n // Use controlled value if provided, otherwise use internal state\n const currentValue = controlledValue !== undefined ? controlledValue : internalValue\n\n // Calculate active index: last empty slot, or last slot if all are filled\n const activeIndex = Math.min(currentValue.length, maxLength - 1)\n\n // Sync cursor position with active index\n useEffect(() => {\n if (inputRef.current) {\n inputRef.current.setSelectionRange(activeIndex, activeIndex)\n }\n }, [activeIndex, currentValue.length, maxLength])\n\n // Create slots array\n const slots = useMemo(\n () =>\n Array.from({ length: maxLength }, (_, i) => ({\n char: currentValue[i] || '',\n isActive: i === activeIndex && isFocused,\n hasFakeCaret: i === activeIndex && !currentValue[i] && !disabled && !readOnly && isFocused,\n })),\n [maxLength, currentValue, activeIndex, isFocused, disabled, readOnly]\n )\n\n // Sync controlled value with input ref\n useEffect(() => {\n if (inputRef.current && controlledValue !== undefined) {\n inputRef.current.value = controlledValue\n }\n }, [controlledValue])\n\n // Focus management\n useEffect(() => {\n if (autoFocus && inputRef.current) {\n inputRef.current.focus()\n }\n }, [autoFocus])\n\n const processInputValue = (inputValue: string): string => {\n let processed = inputValue\n\n if (forceUppercase) {\n processed = processed.toUpperCase()\n }\n\n if (type === 'number') {\n processed = processed.replace(/[^\\d]/g, '')\n }\n\n // Filter characters using pattern if provided\n if (pattern) {\n try {\n // Convert HTML pattern (string) to RegExp\n // HTML patterns validate the entire string, but we need to test each character\n // We create a regex that tests if a single character matches the pattern\n // For example: [0-9]* becomes ^[0-9]$ to test a single digit\n // We wrap the pattern in ^...$ to ensure it matches a single character\n let regexPattern = pattern\n // If pattern doesn't start with ^, wrap it to test single character\n if (!pattern.startsWith('^')) {\n regexPattern = `^${pattern}$`\n }\n const regex = new RegExp(regexPattern)\n processed = processed\n .split('')\n .filter(currChar => {\n // Test if the character matches the pattern\n return regex.test(currChar)\n })\n .join('')\n } catch (error) {\n // If pattern is invalid, ignore it and continue with other filters\n console.error('Invalid pattern provided to InputOTP:', pattern, error)\n }\n }\n\n return processed\n }\n\n const handleChange: ChangeEventHandler<HTMLInputElement> = e => {\n if (disabled || readOnly) return\n\n const inputValue = e.target.value\n const processedValue = processInputValue(inputValue)\n\n // Limit to maxLength\n const newValue = processedValue.slice(0, maxLength)\n\n // Call onValueChange callback first (before updating state)\n if (onValueChange) {\n onValueChange(newValue)\n }\n\n // Update state only in uncontrolled mode\n if (controlledValue === undefined) {\n setInternalValue(newValue)\n }\n\n // Active index is automatically calculated based on value length\n // Sync cursor position\n const newActiveIndex = Math.min(newValue.length, maxLength - 1)\n if (inputRef.current) {\n inputRef.current.setSelectionRange(newActiveIndex, newActiveIndex)\n }\n }\n\n const handleKeyDown: KeyboardEventHandler<HTMLInputElement> = e => {\n if (disabled || readOnly) return\n\n // Allow copy/cut/paste/selectAll shortcuts even when key is in filterKeys\n const isShortcut =\n (e.ctrlKey || e.metaKey) && ['a', 'c', 'v', 'x'].includes(e.key.toLowerCase())\n\n // Filter keys\n if (filterKeys.length > 0 && filterKeys.includes(e.key) && !isShortcut) {\n e.preventDefault()\n\n return\n }\n\n switch (e.key) {\n case BACKSPACE_KEY:\n e.preventDefault()\n const currentLength = currentValue.length\n if (currentLength > 0) {\n const newValue = currentValue.slice(0, currentLength - 1)\n\n // Call onValueChange first\n if (onValueChange) {\n onValueChange(newValue)\n }\n\n // Update state only in uncontrolled mode\n if (controlledValue === undefined) {\n setInternalValue(newValue)\n }\n\n // Active index is automatically calculated based on value length\n // Sync cursor position\n const newActiveIndex = Math.max(0, newValue.length)\n if (inputRef.current) {\n inputRef.current.setSelectionRange(newActiveIndex, newActiveIndex)\n }\n }\n break\n\n case LEFT_ARROW_KEY:\n case RIGHT_ARROW_KEY:\n // Prevent navigation with arrow keys - focus stays on last empty slot\n e.preventDefault()\n break\n\n case UP_ARROW_KEY:\n case DOWN_ARROW_KEY:\n e.preventDefault()\n break\n\n case E_KEY:\n case 'E':\n // Prevent 'e' or 'E' in number inputs\n if (type === 'number') {\n e.preventDefault()\n }\n break\n\n default:\n break\n }\n }\n\n const handleCopy: ClipboardEventHandler<HTMLInputElement> = e => {\n if (disabled) return\n\n e.preventDefault()\n if (currentValue.length > 0) {\n e.clipboardData.setData('text/plain', currentValue)\n }\n }\n\n const handlePaste: ClipboardEventHandler<HTMLInputElement> = e => {\n if (disabled || readOnly) return\n\n e.preventDefault()\n\n const pastedText = e.clipboardData.getData('text')\n\n if (!pastedText) return\n\n const processedText = processInputValue(pastedText)\n const newValue = processedText.slice(0, maxLength)\n\n // Call onValueChange callback first (before updating state)\n if (onValueChange) {\n onValueChange(newValue)\n }\n\n // Update state only in uncontrolled mode\n if (controlledValue === undefined) {\n setInternalValue(newValue)\n }\n\n // Active index is automatically calculated based on value length\n // Move cursor to end\n const newActiveIndex = Math.min(newValue.length, maxLength - 1)\n if (inputRef.current) {\n inputRef.current.setSelectionRange(newActiveIndex, newActiveIndex)\n }\n }\n\n const handleFocus = () => {\n setIsFocused(true)\n if (inputRef.current) {\n // Focus on last empty slot, or last slot if all are filled\n const cursorPosition = Math.min(currentValue.length, maxLength - 1)\n inputRef.current.setSelectionRange(cursorPosition, cursorPosition)\n }\n }\n\n const handleBlur = () => {\n setIsFocused(false)\n }\n\n const handleClick = () => {\n if (inputRef.current) {\n inputRef.current.focus()\n }\n }\n\n const contextValue: InputOTPContextValue = {\n value: currentValue,\n maxLength,\n slots,\n activeIndex,\n intent,\n disabled,\n readOnly,\n placeholder,\n type,\n }\n\n const returnValue: UseInputOTPReturn = {\n uuid: id,\n inputRef,\n containerRef,\n name,\n disabled,\n readOnly,\n isInvalid,\n isRequired,\n description,\n maxLength,\n intent,\n currentValue,\n activeIndex,\n slots,\n contextValue,\n handleChange,\n handleKeyDown,\n handleCopy,\n handlePaste,\n handleFocus,\n handleBlur,\n handleClick,\n labelId,\n }\n\n return returnValue\n}\n","/* eslint-disable max-lines-per-function */\nimport { cx } from 'class-variance-authority'\nimport {\n Children,\n cloneElement,\n ComponentPropsWithoutRef,\n isValidElement,\n ReactElement,\n ReactNode,\n Ref,\n useMemo,\n} from 'react'\n\nimport { InputOTPContext } from './InputOTPContext'\nimport { InputOTPSlot } from './InputOTPSlot'\nimport { useInputOTP } from './useInputOTP'\n\n/**\n * Counts the number of InputOTPSlot components in the children tree\n */\nconst countSlots = (children: ReactNode): number => {\n let count = 0\n\n Children.forEach(children, child => {\n if (isValidElement(child)) {\n const props = child.props as { children?: ReactNode }\n // Check if it's an InputOTPSlot by checking displayName\n if (\n child.type === InputOTPSlot ||\n (child.type as { displayName?: string })?.displayName === 'InputOTP.Slot'\n ) {\n count++\n } else if (props.children) {\n // Recursively count slots in nested children (e.g., inside InputOTPGroup)\n count += countSlots(props.children)\n }\n }\n })\n\n return count\n}\n\n/**\n * Recursively assigns index to InputOTPSlot components\n * Returns a tuple of [processedChildren, nextIndex]\n */\nconst assignSlotIndexes = (children: ReactNode, startIndex: number = 0): [ReactNode, number] => {\n let currentIndex = startIndex\n\n const processed = Children.map(children, child => {\n if (isValidElement(child)) {\n const props = child.props as { index?: number; children?: ReactNode }\n // Check if it's an InputOTPSlot\n if (\n child.type === InputOTPSlot ||\n (child.type as { displayName?: string })?.displayName === 'InputOTP.Slot'\n ) {\n // Only assign index if not already provided\n const slotIndex = typeof props.index === 'number' ? props.index : currentIndex++\n\n return cloneElement(child as ReactElement<{ index?: number }>, {\n ...props,\n index: slotIndex,\n })\n } else if (props.children) {\n // Recursively process nested children\n const [processedChildren, nextIndex] = assignSlotIndexes(props.children, currentIndex)\n currentIndex = nextIndex\n\n return cloneElement(child, {\n ...(child.props as Record<string, unknown>),\n children: processedChildren,\n } as Parameters<typeof cloneElement>[1])\n }\n }\n\n return child\n })\n\n return [processed, currentIndex]\n}\n\nexport interface InputOTPProps extends Omit<\n ComponentPropsWithoutRef<'div'>,\n 'onChange' | 'inputMode'\n> {\n /**\n * Maximum length of the input value.\n * If not provided, will be automatically detected from the number of InputOTP.Slot children.\n */\n maxLength?: number\n /**\n * Type of input\n * @default 'text'\n */\n type?: 'text' | 'number' | 'password' | 'tel'\n /**\n * Current value (controlled mode)\n */\n value?: string\n /**\n * Default value (uncontrolled mode)\n */\n defaultValue?: string\n /**\n * Callback fired when the value changes\n */\n onValueChange?: (value: string) => void\n /**\n * Whether the input is valid\n * @default true\n */\n isValid?: boolean\n /**\n * Whether the input is disabled\n * @default false\n */\n disabled?: boolean\n /**\n * Whether the input is read-only (value visible but not editable)\n * @default false\n */\n readOnly?: boolean\n /**\n * Whether to auto-focus the input\n * @default false\n */\n autoFocus?: boolean\n /**\n * Auto-complete attribute\n * @default 'off'\n */\n autoComplete?: string\n /**\n * Whether to force uppercase\n * @default false\n */\n forceUppercase?: boolean\n /**\n * Array of keys to filter out (using KeyboardEvent.key values)\n * @default ['-', '.']\n */\n filterKeys?: string[]\n /**\n * Pattern attribute for input validation and character filtering.\n * Uses a regular expression to filter allowed characters in real-time.\n * For example: \"[0-9]\" for digits only, \"[a-c]\" for letters a, b, c only.\n */\n pattern?: string\n /**\n * Input mode attribute\n */\n inputMode?: string\n /**\n * Placeholder text\n */\n placeholder?: string\n /**\n * Name attribute for form integration\n */\n name?: string\n /**\n * Children components (InputOTPGroup, InputOTPSlot, InputOTPSeparator)\n */\n children: ReactNode\n /**\n * Ref callback for the container\n */\n ref?: Ref<HTMLDivElement>\n}\n\nexport const InputOTP = ({\n maxLength: maxLengthProp,\n type = 'text',\n value: controlledValue,\n defaultValue = '',\n onValueChange,\n isValid = true,\n disabled: disabledProp = false,\n readOnly: readOnlyProp = false,\n autoFocus = false,\n autoComplete = 'off',\n forceUppercase = false,\n filterKeys = ['-', '.'],\n pattern,\n inputMode,\n placeholder = '-',\n name: nameProp,\n className,\n children,\n ...others\n}: InputOTPProps) => {\n // Auto-detect maxLength from children if not provided\n const maxLength = useMemo(() => {\n if (maxLengthProp !== undefined) {\n return maxLengthProp\n }\n\n const detectedLength = countSlots(children)\n const DEFAULT_MAX_LENGTH = 4\n\n return detectedLength > 0 ? detectedLength : DEFAULT_MAX_LENGTH // fallback to 4 if no slots found\n }, [maxLengthProp, children])\n\n // Assign indexes to slots automatically\n const processedChildren = useMemo(() => {\n const [processed] = assignSlotIndexes(children)\n\n return processed\n }, [children])\n\n // Use the hook for all business logic\n const {\n uuid,\n inputRef,\n containerRef,\n name,\n disabled,\n readOnly,\n isInvalid,\n isRequired,\n description,\n currentValue,\n contextValue,\n handleChange,\n handleKeyDown,\n handleCopy,\n handlePaste,\n handleFocus,\n handleBlur,\n handleClick,\n labelId,\n } = useInputOTP({\n maxLength,\n type,\n value: controlledValue,\n defaultValue,\n onValueChange,\n isValid,\n disabledProp,\n readOnlyProp,\n autoFocus,\n forceUppercase,\n filterKeys,\n pattern,\n placeholder,\n nameProp,\n })\n\n // Extract aria-label from others if provided (for cases without FormField)\n const ariaLabel =\n 'aria-label' in others ? (others['aria-label'] as string | undefined) : undefined\n const { 'aria-label': _, ...restOthers } = others\n\n const getAccessibleNameProps = (): Record<string, string | undefined> => {\n if (labelId) {\n return { 'aria-labelledby': labelId }\n }\n\n if (ariaLabel) {\n return { 'aria-label': ariaLabel }\n }\n\n return {}\n }\n\n const accessibleNameProps = getAccessibleNameProps()\n\n return (\n <InputOTPContext.Provider value={contextValue}>\n <div\n ref={containerRef}\n data-spark-component=\"input-otp\"\n role=\"group\"\n {...accessibleNameProps}\n {...(description ? { 'aria-describedby': description } : {})}\n className={cx(\n 'group gap-md relative inline-flex w-fit items-center default:cursor-text',\n {\n 'cursor-not-allowed': disabled,\n 'cursor-default': readOnly,\n },\n className\n )}\n onClick={handleClick}\n {...restOthers}\n >\n {/* Hidden input for form submission with complete value */}\n {name && (\n <input\n type=\"hidden\"\n name={name}\n value={currentValue}\n required={isRequired}\n aria-required={isRequired}\n aria-invalid={isInvalid}\n {...accessibleNameProps}\n />\n )}\n {/* Actual input that handles all interactions */}\n <input\n ref={inputRef}\n id={uuid}\n type={type === 'password' ? 'password' : 'text'}\n value={currentValue}\n maxLength={maxLength}\n autoFocus={autoFocus}\n autoComplete={autoComplete}\n disabled={disabled}\n readOnly={readOnly}\n pattern={pattern}\n inputMode={inputMode as React.InputHTMLAttributes<HTMLInputElement>['inputMode']}\n {...accessibleNameProps}\n {...(description ? { 'aria-describedby': description } : {})}\n aria-invalid={isInvalid}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n onCopy={handleCopy}\n onPaste={handlePaste}\n onFocus={handleFocus}\n onBlur={handleBlur}\n className=\"bg-success z-raised absolute inset-0 m-0 p-0 opacity-0 read-only:cursor-default disabled:cursor-not-allowed\"\n tabIndex={0}\n />\n {/* Children render slots with auto-assigned indexes */}\n {processedChildren}\n </div>\n </InputOTPContext.Provider>\n )\n}\n\nInputOTP.displayName = 'InputOTP'\n","import { ComponentPropsWithoutRef } from 'react'\n\nexport interface InputOTPGroupProps extends ComponentPropsWithoutRef<'div'> {}\n\nexport const InputOTPGroup = ({ children, className, ...props }: InputOTPGroupProps) => {\n return (\n <div className={`gap-md flex ${className}`} {...props}>\n {children}\n </div>\n )\n}\n\nInputOTPGroup.displayName = 'InputOTP.Group'\n","import { ComponentPropsWithoutRef } from 'react'\n\nexport interface InputOTPSeparatorProps extends ComponentPropsWithoutRef<'div'> {}\n\nexport const InputOTPSeparator = ({ className, ...props }: InputOTPSeparatorProps) => {\n return (\n <div\n className={`text-on-surface/dim-3 flex items-center justify-center ${className || ''}`}\n {...props}\n >\n <div className=\"h-sz-4 w-sz-8 bg-outline rounded-full\" />\n </div>\n )\n}\n\nInputOTPSeparator.displayName = 'InputOTP.Separator'\n","import { InputOTP as Root } from './InputOTP'\nimport { InputOTPGroup } from './InputOTPGroup'\nimport { InputOTPSeparator } from './InputOTPSeparator'\nimport { InputOTPSlot } from './InputOTPSlot'\n\nexport const InputOTP: typeof Root & {\n Group: typeof InputOTPGroup\n Slot: typeof InputOTPSlot\n Separator: typeof InputOTPSeparator\n} = Object.assign(Root, {\n Group: InputOTPGroup,\n Slot: InputOTPSlot,\n Separator: InputOTPSeparator,\n})\n\nInputOTP.displayName = 'InputOTP'\nInputOTPGroup.displayName = 'InputOTP.Group'\nInputOTPSlot.displayName = 'InputOTP.Slot'\nInputOTPSeparator.displayName = 'InputOTP.Separator'\n\nexport { type InputOTPProps } from './InputOTP'\nexport { type InputOTPGroupProps } from './InputOTPGroup'\nexport { type InputOTPSlotProps } from './InputOTPSlot'\nexport { type InputOTPSeparatorProps } from './InputOTPSeparator'\nexport {\n inputOTPSlotStyles,\n inputOTPStyles,\n type InputOTPSlotStylesProps,\n type InputOTPStylesProps,\n} from './InputOTP.styles'\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/input-otp/InputOTPContext.tsx","../../src/input-otp/InputOTP.styles.ts","../../src/input-otp/InputOTPSlot.tsx","../../src/input-otp/useInputOTP.ts","../../src/input-otp/InputOTP.tsx","../../src/input-otp/InputOTPGroup.tsx","../../src/input-otp/InputOTPSeparator.tsx","../../src/input-otp/index.ts"],"sourcesContent":["import { createContext, useContext } from 'react'\n\nexport interface InputOTPContextValue {\n value: string\n maxLength: number\n slots: {\n char: string\n isActive: boolean\n hasFakeCaret: boolean\n }[]\n activeIndex: number\n intent: 'neutral' | 'success' | 'alert' | 'error'\n disabled: boolean\n readOnly: boolean\n placeholder?: string\n type: 'text' | 'number' | 'password' | 'tel'\n}\n\nexport const InputOTPContext = createContext<InputOTPContextValue | null>(null)\n\nexport const useInputOTPContext = () => {\n const context = useContext(InputOTPContext)\n if (!context) {\n throw new Error('InputOTP components must be used within InputOTP')\n }\n\n return context\n}\n","import { cva, VariantProps } from 'class-variance-authority'\n\nexport const inputOTPContainerStyles = cva(['relative', 'inline-flex', 'items-center', 'gap-sm'])\n\nexport const inputOTPSlotStyles = cva(\n [\n // Base slot styles\n 'relative h-[50px] w-sz-40',\n 'border-sm rounded-md',\n 'text-center text-display-3 text-on-surface',\n 'outline-hidden',\n 'transition-colors',\n 'flex items-center justify-center',\n // Slot that receives focus when clicking the group (first empty or last slot)\n // Use data-[focus-target=true]:... for distinct styles\n // Active state (when focused)\n 'data-[active=true]:ring-1',\n 'data-[active=true]:ring-inset',\n 'data-[active=true]:ring-l-2',\n 'data-[active=true]:border-focus',\n 'data-[active=true]:z-raised ring-focus',\n // Disabled state\n 'data-[disabled=true]:cursor-not-allowed',\n 'data-[disabled=true]:border-outline',\n 'data-[disabled=true]:bg-on-surface/dim-5',\n 'data-[disabled=true]:text-on-surface/dim-3',\n // Read-only state (same as disabled but text stays normal)\n 'data-[readonly=true]:cursor-default',\n 'data-[readonly=true]:data-[active=false]:border-outline',\n 'data-[readonly=true]:bg-on-surface/dim-5',\n 'group-hover:data-[focus-target=true]:data-[disabled=false]:border-outline-high',\n ],\n {\n variants: {\n /**\n * Color scheme of the slot\n */\n intent: {\n neutral: ['data-[filled=true]:bg-neutral-container bg-surface border-outline'],\n success: ['border-success bg-success-container text-on-success-container'],\n alert: ['border-alert bg-alert-container text-on-alert-container'],\n error: ['border-error bg-error-container text-on-error-container'],\n },\n },\n defaultVariants: {\n intent: 'neutral',\n },\n }\n)\n\nexport type InputOTPSlotStylesProps = VariantProps<typeof inputOTPSlotStyles>\n\n// Keep for backward compatibility\nexport const inputOTPStyles = inputOTPSlotStyles\nexport type InputOTPStylesProps = InputOTPSlotStylesProps\n","import { ComponentPropsWithoutRef } from 'react'\n\nimport { inputOTPSlotStyles } from './InputOTP.styles'\nimport { useInputOTPContext } from './InputOTPContext'\n\nexport interface InputOTPSlotProps extends ComponentPropsWithoutRef<'div'> {\n /**\n * Index of the slot (0-based).\n * If not provided, will be automatically assigned based on position in children.\n */\n index?: number\n}\n\nexport const InputOTPSlot = ({ index: indexProp, className, ...props }: InputOTPSlotProps) => {\n const context = useInputOTPContext()\n\n // Use provided index or fallback to 0 (should not happen if auto-assignment works)\n const index = indexProp ?? 0\n const slot = context.slots[index]\n\n if (!slot) {\n return null\n }\n\n const { char, isActive, hasFakeCaret } = slot\n const isEmpty = !char\n const isPlaceholder = isEmpty && !hasFakeCaret && context.placeholder\n\n const isFocusTarget = index === context.activeIndex\n\n return (\n <div\n className={inputOTPSlotStyles({\n intent: context.intent,\n className,\n })}\n data-active={isActive}\n data-disabled={context.disabled}\n data-readonly={context.readOnly}\n data-filled={!isEmpty}\n data-focus-target={isFocusTarget}\n data-valid={context.intent !== 'error'}\n {...props}\n >\n <span className={isPlaceholder ? 'text-on-surface/dim-3' : ''}>\n {context.type === 'password' && char\n ? '•'\n : char || (!hasFakeCaret && context.placeholder ? context.placeholder : '')}\n </span>\n {hasFakeCaret && (\n <span\n className=\"pointer-events-none absolute inset-0 flex items-center justify-center\"\n aria-hidden=\"true\"\n >\n <span className=\"bg-on-surface animate-standalone-caret-blink h-sz-24 w-sz-2\" />\n </span>\n )}\n </div>\n )\n}\n\nInputOTPSlot.displayName = 'InputOTP.Slot'\n","/* eslint-disable max-lines-per-function */\nimport { useFormFieldControl } from '@spark-ui/components/form-field'\nimport {\n ChangeEventHandler,\n ClipboardEventHandler,\n KeyboardEventHandler,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react'\n\nimport type { InputOTPContextValue } from './InputOTPContext'\n\nconst BACKSPACE_KEY = 'Backspace'\nconst LEFT_ARROW_KEY = 'ArrowLeft'\nconst UP_ARROW_KEY = 'ArrowUp'\nconst RIGHT_ARROW_KEY = 'ArrowRight'\nconst DOWN_ARROW_KEY = 'ArrowDown'\nconst E_KEY = 'e'\n\nexport interface UseInputOTPProps {\n maxLength: number\n type: 'text' | 'number' | 'password' | 'tel'\n value?: string\n defaultValue: string\n onValueChange?: (value: string) => void\n isValid: boolean\n disabledProp: boolean\n readOnlyProp: boolean\n autoFocus: boolean\n forceUppercase: boolean\n filterKeys: string[]\n pattern?: string\n placeholder: string\n nameProp?: string\n}\n\nexport interface UseInputOTPReturn {\n uuid: string\n inputRef: React.RefObject<HTMLInputElement | null>\n containerRef: React.RefObject<HTMLDivElement | null>\n name: string | undefined\n disabled: boolean\n readOnly: boolean\n isInvalid: boolean\n isRequired: boolean\n description: string | undefined\n maxLength: number\n intent: 'neutral' | 'success' | 'alert' | 'error'\n currentValue: string\n activeIndex: number\n slots: {\n char: string\n isActive: boolean\n hasFakeCaret: boolean\n }[]\n contextValue: InputOTPContextValue\n handleChange: ChangeEventHandler<HTMLInputElement>\n handleKeyDown: KeyboardEventHandler<HTMLInputElement>\n handleCopy: ClipboardEventHandler<HTMLInputElement>\n handlePaste: ClipboardEventHandler<HTMLInputElement>\n handleFocus: () => void\n handleBlur: () => void\n handleClick: () => void\n labelId: string | undefined\n}\n\nexport const useInputOTP = ({\n maxLength,\n type,\n value: controlledValue,\n defaultValue,\n onValueChange,\n isValid,\n disabledProp,\n readOnlyProp,\n autoFocus,\n forceUppercase,\n filterKeys,\n pattern,\n placeholder,\n nameProp,\n}: UseInputOTPProps): UseInputOTPReturn => {\n const uuid = useId()\n const inputRef = useRef<HTMLInputElement>(null)\n const containerRef = useRef<HTMLDivElement>(null)\n\n // Get FormField context (optional, falls back gracefully if not present)\n const field = useFormFieldControl()\n\n // Use FormField values if available, otherwise fall back to props\n // Use FormField id when available so label htmlFor works correctly\n const id = field.id ?? uuid\n const name = nameProp ?? field.name\n const disabled = field.disabled ?? disabledProp\n const readOnly = field.readOnly ?? readOnlyProp\n const isInvalid = field.isInvalid ?? !isValid\n const isRequired = field.isRequired ?? false\n const labelId = field.labelId\n const description = field.description\n const fieldState = field.state\n\n // Determine intent based on FormField state or isValid prop\n const getIntent = (): 'neutral' | 'success' | 'alert' | 'error' => {\n // FormField state takes priority\n if (['success', 'alert', 'error'].includes(fieldState ?? '')) {\n return fieldState as 'success' | 'alert' | 'error'\n }\n\n // Fallback to isValid prop for backward compatibility\n if (isInvalid) {\n return 'error'\n }\n\n return 'neutral'\n }\n\n const intent = getIntent()\n\n // Initialize value\n const initialValue = controlledValue !== undefined ? controlledValue : defaultValue\n const processedValue = forceUppercase ? initialValue.toUpperCase() : initialValue\n\n const [internalValue, setInternalValue] = useState<string>(processedValue)\n const [isFocused, setIsFocused] = useState<boolean>(false)\n\n // Use controlled value if provided, otherwise use internal state\n const currentValue = controlledValue !== undefined ? controlledValue : internalValue\n\n // Calculate active index: last empty slot, or last slot if all are filled\n const activeIndex = Math.min(currentValue.length, maxLength - 1)\n\n // Sync cursor position with active index\n useEffect(() => {\n if (inputRef.current) {\n inputRef.current.setSelectionRange(activeIndex, activeIndex)\n }\n }, [activeIndex, currentValue.length, maxLength])\n\n // Create slots array\n const slots = useMemo(\n () =>\n Array.from({ length: maxLength }, (_, i) => ({\n char: currentValue[i] || '',\n isActive: i === activeIndex && isFocused,\n hasFakeCaret: i === activeIndex && !currentValue[i] && !disabled && !readOnly && isFocused,\n })),\n [maxLength, currentValue, activeIndex, isFocused, disabled, readOnly]\n )\n\n // Sync controlled value with input ref\n useEffect(() => {\n if (inputRef.current && controlledValue !== undefined) {\n inputRef.current.value = controlledValue\n }\n }, [controlledValue])\n\n // Focus management\n useEffect(() => {\n if (autoFocus && inputRef.current) {\n inputRef.current.focus()\n }\n }, [autoFocus])\n\n const processInputValue = (inputValue: string): string => {\n let processed = inputValue\n\n if (forceUppercase) {\n processed = processed.toUpperCase()\n }\n\n if (type === 'number') {\n processed = processed.replace(/[^\\d]/g, '')\n }\n\n // Filter characters using pattern if provided\n if (pattern) {\n try {\n // Convert HTML pattern (string) to RegExp\n // HTML patterns validate the entire string, but we need to test each character\n // We create a regex that tests if a single character matches the pattern\n // For example: [0-9]* becomes ^[0-9]$ to test a single digit\n // We wrap the pattern in ^...$ to ensure it matches a single character\n let regexPattern = pattern\n // If pattern doesn't start with ^, wrap it to test single character\n if (!pattern.startsWith('^')) {\n regexPattern = `^${pattern}$`\n }\n const regex = new RegExp(regexPattern)\n processed = processed\n .split('')\n .filter(currChar => {\n // Test if the character matches the pattern\n return regex.test(currChar)\n })\n .join('')\n } catch (error) {\n // If pattern is invalid, ignore it and continue with other filters\n console.error('Invalid pattern provided to InputOTP:', pattern, error)\n }\n }\n\n return processed\n }\n\n const handleChange: ChangeEventHandler<HTMLInputElement> = e => {\n if (disabled || readOnly) return\n\n const inputValue = e.target.value\n const processedValue = processInputValue(inputValue)\n\n // Limit to maxLength\n const newValue = processedValue.slice(0, maxLength)\n\n // Call onValueChange callback first (before updating state)\n if (onValueChange) {\n onValueChange(newValue)\n }\n\n // Update state only in uncontrolled mode\n if (controlledValue === undefined) {\n setInternalValue(newValue)\n }\n\n // Active index is automatically calculated based on value length\n // Sync cursor position\n const newActiveIndex = Math.min(newValue.length, maxLength - 1)\n if (inputRef.current) {\n inputRef.current.setSelectionRange(newActiveIndex, newActiveIndex)\n }\n }\n\n const handleKeyDown: KeyboardEventHandler<HTMLInputElement> = e => {\n if (disabled || readOnly) return\n\n // Allow copy/cut/paste/selectAll shortcuts even when key is in filterKeys\n const isShortcut =\n (e.ctrlKey || e.metaKey) && ['a', 'c', 'v', 'x'].includes(e.key.toLowerCase())\n\n // Filter keys\n if (filterKeys.length > 0 && filterKeys.includes(e.key) && !isShortcut) {\n e.preventDefault()\n\n return\n }\n\n switch (e.key) {\n case BACKSPACE_KEY:\n e.preventDefault()\n const currentLength = currentValue.length\n if (currentLength > 0) {\n const newValue = currentValue.slice(0, currentLength - 1)\n\n // Call onValueChange first\n if (onValueChange) {\n onValueChange(newValue)\n }\n\n // Update state only in uncontrolled mode\n if (controlledValue === undefined) {\n setInternalValue(newValue)\n }\n\n // Active index is automatically calculated based on value length\n // Sync cursor position\n const newActiveIndex = Math.max(0, newValue.length)\n if (inputRef.current) {\n inputRef.current.setSelectionRange(newActiveIndex, newActiveIndex)\n }\n }\n break\n\n case LEFT_ARROW_KEY:\n case RIGHT_ARROW_KEY:\n // Prevent navigation with arrow keys - focus stays on last empty slot\n e.preventDefault()\n break\n\n case UP_ARROW_KEY:\n case DOWN_ARROW_KEY:\n e.preventDefault()\n break\n\n case E_KEY:\n case 'E':\n // Prevent 'e' or 'E' in number inputs\n if (type === 'number') {\n e.preventDefault()\n }\n break\n\n default:\n break\n }\n }\n\n const handleCopy: ClipboardEventHandler<HTMLInputElement> = e => {\n if (disabled) return\n\n e.preventDefault()\n if (currentValue.length > 0) {\n e.clipboardData.setData('text/plain', currentValue)\n }\n }\n\n const handlePaste: ClipboardEventHandler<HTMLInputElement> = e => {\n if (disabled || readOnly) return\n\n e.preventDefault()\n\n const pastedText = e.clipboardData.getData('text')\n\n if (!pastedText) return\n\n const processedText = processInputValue(pastedText)\n const newValue = processedText.slice(0, maxLength)\n\n // Call onValueChange callback first (before updating state)\n if (onValueChange) {\n onValueChange(newValue)\n }\n\n // Update state only in uncontrolled mode\n if (controlledValue === undefined) {\n setInternalValue(newValue)\n }\n\n // Active index is automatically calculated based on value length\n // Move cursor to end\n const newActiveIndex = Math.min(newValue.length, maxLength - 1)\n if (inputRef.current) {\n inputRef.current.setSelectionRange(newActiveIndex, newActiveIndex)\n }\n }\n\n const handleFocus = () => {\n setIsFocused(true)\n if (inputRef.current) {\n // Focus on last empty slot, or last slot if all are filled\n const cursorPosition = Math.min(currentValue.length, maxLength - 1)\n inputRef.current.setSelectionRange(cursorPosition, cursorPosition)\n }\n }\n\n const handleBlur = () => {\n setIsFocused(false)\n }\n\n const handleClick = () => {\n if (inputRef.current) {\n inputRef.current.focus()\n }\n }\n\n const contextValue: InputOTPContextValue = {\n value: currentValue,\n maxLength,\n slots,\n activeIndex,\n intent,\n disabled,\n readOnly,\n placeholder,\n type,\n }\n\n const returnValue: UseInputOTPReturn = {\n uuid: id,\n inputRef,\n containerRef,\n name,\n disabled,\n readOnly,\n isInvalid,\n isRequired,\n description,\n maxLength,\n intent,\n currentValue,\n activeIndex,\n slots,\n contextValue,\n handleChange,\n handleKeyDown,\n handleCopy,\n handlePaste,\n handleFocus,\n handleBlur,\n handleClick,\n labelId,\n }\n\n return returnValue\n}\n","/* eslint-disable max-lines-per-function */\nimport { cx } from 'class-variance-authority'\nimport {\n Children,\n cloneElement,\n ComponentPropsWithoutRef,\n isValidElement,\n ReactElement,\n ReactNode,\n Ref,\n useMemo,\n} from 'react'\n\nimport { InputOTPContext } from './InputOTPContext'\nimport { InputOTPSlot } from './InputOTPSlot'\nimport { useInputOTP } from './useInputOTP'\n\n/**\n * Counts the number of InputOTPSlot components in the children tree\n */\nconst countSlots = (children: ReactNode): number => {\n let count = 0\n\n Children.forEach(children, child => {\n if (isValidElement(child)) {\n const props = child.props as { children?: ReactNode }\n // Check if it's an InputOTPSlot by checking displayName\n if (\n child.type === InputOTPSlot ||\n (child.type as { displayName?: string })?.displayName === 'InputOTP.Slot'\n ) {\n count++\n } else if (props.children) {\n // Recursively count slots in nested children (e.g., inside InputOTPGroup)\n count += countSlots(props.children)\n }\n }\n })\n\n return count\n}\n\n/**\n * Recursively assigns index to InputOTPSlot components\n * Returns a tuple of [processedChildren, nextIndex]\n */\nconst assignSlotIndexes = (children: ReactNode, startIndex: number = 0): [ReactNode, number] => {\n let currentIndex = startIndex\n\n const processed = Children.map(children, child => {\n if (isValidElement(child)) {\n const props = child.props as { index?: number; children?: ReactNode }\n // Check if it's an InputOTPSlot\n if (\n child.type === InputOTPSlot ||\n (child.type as { displayName?: string })?.displayName === 'InputOTP.Slot'\n ) {\n // Only assign index if not already provided\n const slotIndex = typeof props.index === 'number' ? props.index : currentIndex++\n\n return cloneElement(child as ReactElement<{ index?: number }>, {\n ...props,\n index: slotIndex,\n })\n } else if (props.children) {\n // Recursively process nested children\n const [processedChildren, nextIndex] = assignSlotIndexes(props.children, currentIndex)\n currentIndex = nextIndex\n\n return cloneElement(child, {\n ...(child.props as Record<string, unknown>),\n children: processedChildren,\n } as Parameters<typeof cloneElement>[1])\n }\n }\n\n return child\n })\n\n return [processed, currentIndex]\n}\n\nexport interface InputOTPProps extends Omit<\n ComponentPropsWithoutRef<'div'>,\n 'onChange' | 'inputMode'\n> {\n /**\n * Maximum length of the input value.\n * If not provided, will be automatically detected from the number of InputOTP.Slot children.\n */\n maxLength?: number\n /**\n * Type of input\n * @default 'text'\n */\n type?: 'text' | 'number' | 'password' | 'tel'\n /**\n * Current value (controlled mode)\n */\n value?: string\n /**\n * Default value (uncontrolled mode)\n */\n defaultValue?: string\n /**\n * Callback fired when the value changes\n */\n onValueChange?: (value: string) => void\n /**\n * Whether the input is valid\n * @default true\n */\n isValid?: boolean\n /**\n * Whether the input is disabled\n * @default false\n */\n disabled?: boolean\n /**\n * Whether the input is read-only (value visible but not editable)\n * @default false\n */\n readOnly?: boolean\n /**\n * Whether to auto-focus the input\n * @default false\n */\n autoFocus?: boolean\n /**\n * Auto-complete attribute\n * @default 'off'\n */\n autoComplete?: string\n /**\n * Whether to force uppercase\n * @default false\n */\n forceUppercase?: boolean\n /**\n * Array of keys to filter out (using KeyboardEvent.key values)\n * @default ['-', '.']\n */\n filterKeys?: string[]\n /**\n * Pattern attribute for input validation and character filtering.\n * Uses a regular expression to filter allowed characters in real-time.\n * For example: \"[0-9]\" for digits only, \"[a-c]\" for letters a, b, c only.\n */\n pattern?: string\n /**\n * Input mode attribute\n */\n inputMode?: string\n /**\n * Placeholder text\n */\n placeholder?: string\n /**\n * Name attribute for form integration\n */\n name?: string\n /**\n * Children components (InputOTPGroup, InputOTPSlot, InputOTPSeparator)\n */\n children: ReactNode\n /**\n * Ref callback for the container\n */\n ref?: Ref<HTMLDivElement>\n}\n\nexport const InputOTP = ({\n maxLength: maxLengthProp,\n type = 'text',\n value: controlledValue,\n defaultValue = '',\n onValueChange,\n isValid = true,\n disabled: disabledProp = false,\n readOnly: readOnlyProp = false,\n autoFocus = false,\n autoComplete = 'off',\n forceUppercase = false,\n filterKeys = ['-', '.'],\n pattern,\n inputMode,\n placeholder = '-',\n name: nameProp,\n className,\n children,\n ...others\n}: InputOTPProps) => {\n // Auto-detect maxLength from children if not provided\n const maxLength = useMemo(() => {\n if (maxLengthProp !== undefined) {\n return maxLengthProp\n }\n\n const detectedLength = countSlots(children)\n const DEFAULT_MAX_LENGTH = 4\n\n return detectedLength > 0 ? detectedLength : DEFAULT_MAX_LENGTH // fallback to 4 if no slots found\n }, [maxLengthProp, children])\n\n // Assign indexes to slots automatically\n const processedChildren = useMemo(() => {\n const [processed] = assignSlotIndexes(children)\n\n return processed\n }, [children])\n\n // Use the hook for all business logic\n const {\n uuid,\n inputRef,\n containerRef,\n name,\n disabled,\n readOnly,\n isInvalid,\n isRequired,\n description,\n currentValue,\n contextValue,\n handleChange,\n handleKeyDown,\n handleCopy,\n handlePaste,\n handleFocus,\n handleBlur,\n handleClick,\n labelId,\n } = useInputOTP({\n maxLength,\n type,\n value: controlledValue,\n defaultValue,\n onValueChange,\n isValid,\n disabledProp,\n readOnlyProp,\n autoFocus,\n forceUppercase,\n filterKeys,\n pattern,\n placeholder,\n nameProp,\n })\n\n // Extract aria-label from others if provided (for cases without FormField)\n const ariaLabel =\n 'aria-label' in others ? (others['aria-label'] as string | undefined) : undefined\n const { 'aria-label': _, ...restOthers } = others\n\n const getAccessibleNameProps = (): Record<string, string | undefined> => {\n if (labelId) {\n return { 'aria-labelledby': labelId }\n }\n\n if (ariaLabel) {\n return { 'aria-label': ariaLabel }\n }\n\n return {}\n }\n\n const accessibleNameProps = getAccessibleNameProps()\n\n return (\n <InputOTPContext.Provider value={contextValue}>\n <div\n ref={containerRef}\n data-spark-component=\"input-otp\"\n role=\"group\"\n {...accessibleNameProps}\n {...(description ? { 'aria-describedby': description } : {})}\n className={cx(\n 'group gap-md relative inline-flex w-fit items-center default:cursor-text',\n {\n 'cursor-not-allowed': disabled,\n 'cursor-default': readOnly,\n },\n className\n )}\n onClick={handleClick}\n {...restOthers}\n >\n {/* Hidden input for form submission with complete value */}\n {name && (\n <input\n type=\"hidden\"\n name={name}\n value={currentValue}\n required={isRequired}\n aria-required={isRequired}\n aria-invalid={isInvalid}\n {...accessibleNameProps}\n />\n )}\n {/* Actual input that handles all interactions */}\n <input\n ref={inputRef}\n id={uuid}\n type={type === 'password' ? 'password' : 'text'}\n value={currentValue}\n maxLength={maxLength}\n autoFocus={autoFocus}\n autoComplete={autoComplete}\n disabled={disabled}\n readOnly={readOnly}\n pattern={pattern}\n inputMode={inputMode as React.InputHTMLAttributes<HTMLInputElement>['inputMode']}\n {...accessibleNameProps}\n {...(description ? { 'aria-describedby': description } : {})}\n aria-invalid={isInvalid}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n onCopy={handleCopy}\n onPaste={handlePaste}\n onFocus={handleFocus}\n onBlur={handleBlur}\n className=\"bg-success z-raised absolute inset-0 m-0 p-0 opacity-0 read-only:cursor-default disabled:cursor-not-allowed\"\n tabIndex={0}\n />\n {/* Children render slots with auto-assigned indexes */}\n {processedChildren}\n </div>\n </InputOTPContext.Provider>\n )\n}\n\nInputOTP.displayName = 'InputOTP'\n","import { ComponentPropsWithoutRef } from 'react'\n\nexport interface InputOTPGroupProps extends ComponentPropsWithoutRef<'div'> {}\n\nexport const InputOTPGroup = ({ children, className, ...props }: InputOTPGroupProps) => {\n return (\n <div className={`gap-md flex ${className}`} {...props}>\n {children}\n </div>\n )\n}\n\nInputOTPGroup.displayName = 'InputOTP.Group'\n","import { ComponentPropsWithoutRef } from 'react'\n\nexport interface InputOTPSeparatorProps extends ComponentPropsWithoutRef<'div'> {}\n\nexport const InputOTPSeparator = ({ className, ...props }: InputOTPSeparatorProps) => {\n return (\n <div\n className={`text-on-surface/dim-3 flex items-center justify-center ${className || ''}`}\n {...props}\n >\n <div className=\"h-sz-4 w-sz-8 bg-outline rounded-full\" />\n </div>\n )\n}\n\nInputOTPSeparator.displayName = 'InputOTP.Separator'\n","import { InputOTP as Root } from './InputOTP'\nimport { InputOTPGroup } from './InputOTPGroup'\nimport { InputOTPSeparator } from './InputOTPSeparator'\nimport { InputOTPSlot } from './InputOTPSlot'\n\n/**\n * An input component for entering one-time passwords or verification codes with individual character slots.\n */\nexport const InputOTP: typeof Root & {\n Group: typeof InputOTPGroup\n Slot: typeof InputOTPSlot\n Separator: typeof InputOTPSeparator\n} = Object.assign(Root, {\n Group: InputOTPGroup,\n Slot: InputOTPSlot,\n Separator: InputOTPSeparator,\n})\n\nInputOTP.displayName = 'InputOTP'\nInputOTPGroup.displayName = 'InputOTP.Group'\nInputOTPSlot.displayName = 'InputOTP.Slot'\nInputOTPSeparator.displayName = 'InputOTP.Separator'\n\nexport { type InputOTPProps } from './InputOTP'\nexport { type InputOTPGroupProps } from './InputOTPGroup'\nexport { type InputOTPSlotProps } from './InputOTPSlot'\nexport { type InputOTPSeparatorProps } from './InputOTPSeparator'\nexport {\n inputOTPSlotStyles,\n inputOTPStyles,\n type InputOTPSlotStylesProps,\n type InputOTPStylesProps,\n} from './InputOTP.styles'\n"],"mappings":";;;;;AAkBA,IAAa,IAAkB,EAA2C,KAAK,EAElE,UAA2B;CACtC,IAAM,IAAU,EAAW,EAAgB;AAC3C,KAAI,CAAC,EACH,OAAU,MAAM,mDAAmD;AAGrE,QAAO;;ACxB8B,EAAI;CAAC;CAAY;CAAe;CAAgB;CAAS,CAAC;AAEjG,IAAa,IAAqB,EAChC;CAEE;CACA;CACA;CACA;CACA;CACA;CAIA;CACA;CACA;CACA;CACA;CAEA;CACA;CACA;CACA;CAEA;CACA;CACA;CACA;CACD,EACD;CACE,UAAU,EAIR,QAAQ;EACN,SAAS,CAAC,oEAAoE;EAC9E,SAAS,CAAC,gEAAgE;EAC1E,OAAO,CAAC,0DAA0D;EAClE,OAAO,CAAC,0DAA0D;EACnE,EACF;CACD,iBAAiB,EACf,QAAQ,WACT;CACF,CACF,EAKY,IAAiB,GCxCjB,KAAgB,EAAE,OAAO,GAAW,cAAW,GAAG,QAA+B;CAC5F,IAAM,IAAU,GAAoB,EAG9B,IAAQ,KAAa,GACrB,IAAO,EAAQ,MAAM;AAE3B,KAAI,CAAC,EACH,QAAO;CAGT,IAAM,EAAE,SAAM,aAAU,oBAAiB,GACnC,IAAU,CAAC,GACX,IAAgB,KAAW,CAAC,KAAgB,EAAQ,aAEpD,IAAgB,MAAU,EAAQ;AAExC,QACE,kBAAC,OAAD;EACE,WAAW,EAAmB;GAC5B,QAAQ,EAAQ;GAChB;GACD,CAAC;EACF,eAAa;EACb,iBAAe,EAAQ;EACvB,iBAAe,EAAQ;EACvB,eAAa,CAAC;EACd,qBAAmB;EACnB,cAAY,EAAQ,WAAW;EAC/B,GAAI;YAXN,CAaE,kBAAC,QAAD;GAAM,WAAW,IAAgB,0BAA0B;aACxD,EAAQ,SAAS,cAAc,IAC5B,MACA,MAAS,CAAC,KAAgB,EAAQ,cAAc,EAAQ,cAAc;GACrE,CAAA,EACN,KACC,kBAAC,QAAD;GACE,WAAU;GACV,eAAY;aAEZ,kBAAC,QAAD,EAAM,WAAU,+DAAgE,CAAA;GAC3E,CAAA,CAEL;;;AAIV,EAAa,cAAc;;;AC9C3B,IAAM,IAAgB,aAChB,IAAiB,aACjB,IAAe,WACf,IAAkB,cAClB,IAAiB,aACjB,IAAQ,KAiDD,KAAe,EAC1B,cACA,SACA,OAAO,GACP,iBACA,kBACA,YACA,iBACA,iBACA,cACA,mBACA,eACA,YACA,gBACA,kBACyC;CACzC,IAAM,IAAO,GAAO,EACd,IAAW,EAAyB,KAAK,EACzC,IAAe,EAAuB,KAAK,EAG3C,IAAQ,GAAqB,EAI7B,IAAK,EAAM,MAAM,GACjB,IAAO,KAAY,EAAM,MACzB,IAAW,EAAM,YAAY,GAC7B,IAAW,EAAM,YAAY,GAC7B,IAAY,EAAM,aAAa,CAAC,GAChC,IAAa,EAAM,cAAc,IACjC,IAAU,EAAM,SAChB,IAAc,EAAM,aACpB,IAAa,EAAM,OAiBnB,IAZA;EAAC;EAAW;EAAS;EAAQ,CAAC,SAAS,KAAc,GAAG,GACnD,IAIL,IACK,UAGF,WAMH,IAAe,MAAoB,KAAA,IAA8B,IAAlB,GAG/C,CAAC,GAAe,KAAoB,EAFnB,IAAiB,EAAa,aAAa,GAAG,EAEK,EACpE,CAAC,GAAW,KAAgB,EAAkB,GAAM,EAGpD,IAAe,MAAoB,KAAA,IAA8B,IAAlB,GAG/C,IAAc,KAAK,IAAI,EAAa,QAAQ,IAAY,EAAE;AAGhE,SAAgB;AACd,EAAI,EAAS,WACX,EAAS,QAAQ,kBAAkB,GAAa,EAAY;IAE7D;EAAC;EAAa,EAAa;EAAQ;EAAU,CAAC;CAGjD,IAAM,IAAQ,QAEV,MAAM,KAAK,EAAE,QAAQ,GAAW,GAAG,GAAG,OAAO;EAC3C,MAAM,EAAa,MAAM;EACzB,UAAU,MAAM,KAAe;EAC/B,cAAc,MAAM,KAAe,CAAC,EAAa,MAAM,CAAC,KAAY,CAAC,KAAY;EAClF,EAAE,EACL;EAAC;EAAW;EAAc;EAAa;EAAW;EAAU;EAAS,CACtE;AAUD,CAPA,QAAgB;AACd,EAAI,EAAS,WAAW,MAAoB,KAAA,MAC1C,EAAS,QAAQ,QAAQ;IAE1B,CAAC,EAAgB,CAAC,EAGrB,QAAgB;AACd,EAAI,KAAa,EAAS,WACxB,EAAS,QAAQ,OAAO;IAEzB,CAAC,EAAU,CAAC;CAEf,IAAM,KAAqB,MAA+B;EACxD,IAAI,IAAY;AAWhB,MATI,MACF,IAAY,EAAU,aAAa,GAGjC,MAAS,aACX,IAAY,EAAU,QAAQ,UAAU,GAAG,GAIzC,EACF,KAAI;GAMF,IAAI,IAAe;AAEnB,GAAK,EAAQ,WAAW,IAAI,KAC1B,IAAe,IAAI,EAAQ;GAE7B,IAAM,IAAQ,IAAI,OAAO,EAAa;AACtC,OAAY,EACT,MAAM,GAAG,CACT,QAAO,MAEC,EAAM,KAAK,EAAS,CAC3B,CACD,KAAK,GAAG;WACJ,GAAO;AAEd,WAAQ,MAAM,yCAAyC,GAAS,EAAM;;AAI1E,SAAO;;AA8LT,QA1BuC;EACrC,MAAM;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,cA3ByC;GACzC,OAAO;GACP;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACD;EAkBC,eAjLyD,MAAK;AAC9D,OAAI,KAAY,EAAU;GAE1B,IAAM,IAAa,EAAE,OAAO,OAItB,IAHiB,EAAkB,EAAW,CAGpB,MAAM,GAAG,EAAU;AAQnD,GALI,KACF,EAAc,EAAS,EAIrB,MAAoB,KAAA,KACtB,EAAiB,EAAS;GAK5B,IAAM,IAAiB,KAAK,IAAI,EAAS,QAAQ,IAAY,EAAE;AAC/D,GAAI,EAAS,WACX,EAAS,QAAQ,kBAAkB,GAAgB,EAAe;;EA2JpE,gBAvJ4D,MAAK;AACjE,OAAI,KAAY,EAAU;GAG1B,IAAM,KACH,EAAE,WAAW,EAAE,YAAY;IAAC;IAAK;IAAK;IAAK;IAAI,CAAC,SAAS,EAAE,IAAI,aAAa,CAAC;AAGhF,OAAI,EAAW,SAAS,KAAK,EAAW,SAAS,EAAE,IAAI,IAAI,CAAC,GAAY;AACtE,MAAE,gBAAgB;AAElB;;AAGF,WAAQ,EAAE,KAAV;IACE,KAAK;AACH,OAAE,gBAAgB;KAClB,IAAM,IAAgB,EAAa;AACnC,SAAI,IAAgB,GAAG;MACrB,IAAM,IAAW,EAAa,MAAM,GAAG,IAAgB,EAAE;AAQzD,MALI,KACF,EAAc,EAAS,EAIrB,MAAoB,KAAA,KACtB,EAAiB,EAAS;MAK5B,IAAM,IAAiB,KAAK,IAAI,GAAG,EAAS,OAAO;AACnD,MAAI,EAAS,WACX,EAAS,QAAQ,kBAAkB,GAAgB,EAAe;;AAGtE;IAEF,KAAK;IACL,KAAK;AAEH,OAAE,gBAAgB;AAClB;IAEF,KAAK;IACL,KAAK;AACH,OAAE,gBAAgB;AAClB;IAEF,KAAK;IACL,KAAK;AAEH,KAAI,MAAS,YACX,EAAE,gBAAgB;AAEpB;IAEF,QACE;;;EA4FJ,aAxF0D,MAAK;AAC3D,SAEJ,EAAE,gBAAgB,EACd,EAAa,SAAS,KACxB,EAAE,cAAc,QAAQ,cAAc,EAAa;;EAoFrD,cAhF2D,MAAK;AAChE,OAAI,KAAY,EAAU;AAE1B,KAAE,gBAAgB;GAElB,IAAM,IAAa,EAAE,cAAc,QAAQ,OAAO;AAElD,OAAI,CAAC,EAAY;GAGjB,IAAM,IADgB,EAAkB,EAAW,CACpB,MAAM,GAAG,EAAU;AAQlD,GALI,KACF,EAAc,EAAS,EAIrB,MAAoB,KAAA,KACtB,EAAiB,EAAS;GAK5B,IAAM,IAAiB,KAAK,IAAI,EAAS,QAAQ,IAAY,EAAE;AAC/D,GAAI,EAAS,WACX,EAAS,QAAQ,kBAAkB,GAAgB,EAAe;;EAuDpE,mBAnDwB;AAExB,OADA,EAAa,GAAK,EACd,EAAS,SAAS;IAEpB,IAAM,IAAiB,KAAK,IAAI,EAAa,QAAQ,IAAY,EAAE;AACnE,MAAS,QAAQ,kBAAkB,GAAgB,EAAe;;;EA+CpE,kBA3CuB;AACvB,KAAa,GAAM;;EA2CnB,mBAxCwB;AACxB,GAAI,EAAS,WACX,EAAS,QAAQ,OAAO;;EAuC1B;EACD;GCpXG,KAAc,MAAgC;CAClD,IAAI,IAAQ;AAkBZ,QAhBA,EAAS,QAAQ,IAAU,MAAS;AAClC,MAAI,EAAe,EAAM,EAAE;GACzB,IAAM,IAAQ,EAAM;AAEpB,GACE,EAAM,SAAS,KACd,EAAM,MAAmC,gBAAgB,kBAE1D,MACS,EAAM,aAEf,KAAS,EAAW,EAAM,SAAS;;GAGvC,EAEK;GAOH,KAAqB,GAAqB,IAAqB,MAA2B;CAC9F,IAAI,IAAe;AAgCnB,QAAO,CA9BW,EAAS,IAAI,IAAU,MAAS;AAChD,MAAI,EAAe,EAAM,EAAE;GACzB,IAAM,IAAQ,EAAM;AAEpB,OACE,EAAM,SAAS,KACd,EAAM,MAAmC,gBAAgB,iBAC1D;IAEA,IAAM,IAAY,OAAO,EAAM,SAAU,WAAW,EAAM,QAAQ;AAElE,WAAO,EAAa,GAA2C;KAC7D,GAAG;KACH,OAAO;KACR,CAAC;cACO,EAAM,UAAU;IAEzB,IAAM,CAAC,GAAmB,KAAa,EAAkB,EAAM,UAAU,EAAa;AAGtF,WAFA,IAAe,GAER,EAAa,GAAO;KACzB,GAAI,EAAM;KACV,UAAU;KACX,CAAuC;;;AAI5C,SAAO;GACP,EAEiB,EAAa;GA4FrB,KAAY,EACvB,WAAW,GACX,UAAO,QACP,OAAO,GACP,kBAAe,IACf,kBACA,aAAU,IACV,UAAU,IAAe,IACzB,UAAU,IAAe,IACzB,eAAY,IACZ,kBAAe,OACf,oBAAiB,IACjB,gBAAa,CAAC,KAAK,IAAI,EACvB,YACA,cACA,iBAAc,KACd,MAAM,GACN,cACA,aACA,GAAG,QACgB;CAEnB,IAAM,IAAY,QAAc;AAC9B,MAAI,MAAkB,KAAA,EACpB,QAAO;EAGT,IAAM,IAAiB,EAAW,EAAS;AAG3C,SAAO,IAAiB,IAAI,IAFD;IAG1B,CAAC,GAAe,EAAS,CAAC,EAGvB,IAAoB,QAAc;EACtC,IAAM,CAAC,KAAa,EAAkB,EAAS;AAE/C,SAAO;IACN,CAAC,EAAS,CAAC,EAGR,EACJ,SACA,aACA,iBACA,SACA,aACA,aACA,cACA,eACA,gBACA,iBACA,iBACA,iBACA,kBACA,eACA,gBACA,gBACA,eACA,gBACA,eACE,EAAY;EACd;EACA;EACA,OAAO;EACP;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,EAGI,IACJ,gBAAgB,IAAU,EAAO,gBAAuC,KAAA,GACpE,EAAE,cAAc,GAAG,GAAG,MAAe,GAcrC,IAXA,IACK,EAAE,mBAAmB,GAAS,GAGnC,IACK,EAAE,cAAc,GAAW,GAG7B,EAAE;AAKX,QACE,kBAAC,EAAgB,UAAjB;EAA0B,OAAO;YAC/B,kBAAC,OAAD;GACE,KAAK;GACL,wBAAqB;GACrB,MAAK;GACL,GAAI;GACJ,GAAK,IAAc,EAAE,oBAAoB,GAAa,GAAG,EAAE;GAC3D,WAAW,EACT,4EACA;IACE,sBAAsB;IACtB,kBAAkB;IACnB,EACD,EACD;GACD,SAAS;GACT,GAAI;aAfN;IAkBG,KACC,kBAAC,SAAD;KACE,MAAK;KACC;KACN,OAAO;KACP,UAAU;KACV,iBAAe;KACf,gBAAc;KACd,GAAI;KACJ,CAAA;IAGJ,kBAAC,SAAD;KACE,KAAK;KACL,IAAI;KACJ,MAAM,MAAS,aAAa,aAAa;KACzC,OAAO;KACI;KACA;KACG;KACJ;KACA;KACD;KACE;KACX,GAAI;KACJ,GAAK,IAAc,EAAE,oBAAoB,GAAa,GAAG,EAAE;KAC3D,gBAAc;KACd,UAAU;KACV,WAAW;KACX,QAAQ;KACR,SAAS;KACT,SAAS;KACT,QAAQ;KACR,WAAU;KACV,UAAU;KACV,CAAA;IAED;IACG;;EACmB,CAAA;;AAI/B,EAAS,cAAc;;;ACvUvB,IAAa,KAAiB,EAAE,aAAU,cAAW,GAAG,QAEpD,kBAAC,OAAD;CAAK,WAAW,eAAe;CAAa,GAAI;CAC7C;CACG,CAAA;AAIV,EAAc,cAAc;;;ACR5B,IAAa,KAAqB,EAAE,cAAW,GAAG,QAE9C,kBAAC,OAAD;CACE,WAAW,0DAA0D,KAAa;CAClF,GAAI;WAEJ,kBAAC,OAAD,EAAK,WAAU,yCAA0C,CAAA;CACrD,CAAA;AAIV,EAAkB,cAAc;;;ACPhC,IAAa,IAIT,OAAO,OAAO,GAAM;CACtB,OAAO;CACP,MAAM;CACN,WAAW;CACZ,CAAC;AAEF,EAAS,cAAc,YACvB,EAAc,cAAc,kBAC5B,EAAa,cAAc,iBAC3B,EAAkB,cAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/kbd/Kbd.tsx"],"sourcesContent":["import { ComponentPropsWithoutRef, PropsWithChildren, Ref } from 'react'\n\nexport type KbdProps = ComponentPropsWithoutRef<'div'> & {\n ref?: Ref<HTMLElement>\n}\n\nexport const Kbd = ({ className, ref, ...props }: PropsWithChildren<KbdProps>) => {\n return (\n <kbd\n data-spark-component=\"kbd\"\n ref={ref}\n className={[\n 'border-sm border-b-md border-outline bg-neutral-container pe-md ps-md text-caption rounded-sm font-mono leading-4 font-bold whitespace-nowrap',\n className,\n ].join(' ')}\n {...props}\n />\n )\n}\n"],"mappings":"sIAMA,IAAa,GAAO,CAAE,YAAW,MAAK,GAAG,MAErC,EAAA,EAAA,KAAC,MAAD,CACE,uBAAqB,MAChB,MACL,UAAW,CACT,gJACA,EACD,CAAC,KAAK,IAAI,CACX,GAAI,EACJ,CAAA"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/kbd/Kbd.tsx"],"sourcesContent":["import { ComponentPropsWithoutRef, PropsWithChildren, Ref } from 'react'\n\nexport type KbdProps = ComponentPropsWithoutRef<'div'> & {\n ref?: Ref<HTMLElement>\n}\n\n/**\n * A component that displays keyboard keys or shortcuts in a styled format.\n */\nexport const Kbd = ({ className, ref, ...props }: PropsWithChildren<KbdProps>) => {\n return (\n <kbd\n data-spark-component=\"kbd\"\n ref={ref}\n className={[\n 'border-sm border-b-md border-outline bg-neutral-container pe-md ps-md text-caption rounded-sm font-mono leading-4 font-bold whitespace-nowrap',\n className,\n ].join(' ')}\n {...props}\n />\n )\n}\n"],"mappings":"sIASA,IAAa,GAAO,CAAE,YAAW,MAAK,GAAG,MAErC,EAAA,EAAA,KAAC,MAAD,CACE,uBAAqB,MAChB,MACL,UAAW,CACT,gJACA,EACD,CAAC,KAAK,IAAI,CACX,GAAI,EACJ,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/kbd/Kbd.tsx"],"sourcesContent":["import { ComponentPropsWithoutRef, PropsWithChildren, Ref } from 'react'\n\nexport type KbdProps = ComponentPropsWithoutRef<'div'> & {\n ref?: Ref<HTMLElement>\n}\n\nexport const Kbd = ({ className, ref, ...props }: PropsWithChildren<KbdProps>) => {\n return (\n <kbd\n data-spark-component=\"kbd\"\n ref={ref}\n className={[\n 'border-sm border-b-md border-outline bg-neutral-container pe-md ps-md text-caption rounded-sm font-mono leading-4 font-bold whitespace-nowrap',\n className,\n ].join(' ')}\n {...props}\n />\n )\n}\n"],"mappings":";;AAMA,IAAa,KAAO,EAAE,cAAW,QAAK,GAAG,QAErC,kBAAC,OAAD;CACE,wBAAqB;CAChB;CACL,WAAW,CACT,iJACA,EACD,CAAC,KAAK,IAAI;CACX,GAAI;CACJ,CAAA"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/kbd/Kbd.tsx"],"sourcesContent":["import { ComponentPropsWithoutRef, PropsWithChildren, Ref } from 'react'\n\nexport type KbdProps = ComponentPropsWithoutRef<'div'> & {\n ref?: Ref<HTMLElement>\n}\n\n/**\n * A component that displays keyboard keys or shortcuts in a styled format.\n */\nexport const Kbd = ({ className, ref, ...props }: PropsWithChildren<KbdProps>) => {\n return (\n <kbd\n data-spark-component=\"kbd\"\n ref={ref}\n className={[\n 'border-sm border-b-md border-outline bg-neutral-container pe-md ps-md text-caption rounded-sm font-mono leading-4 font-bold whitespace-nowrap',\n className,\n ].join(' ')}\n {...props}\n />\n )\n}\n"],"mappings":";;AASA,IAAa,KAAO,EAAE,cAAW,QAAK,GAAG,QAErC,kBAAC,OAAD;CACE,wBAAqB;CAChB;CACL,WAAW,CACT,iJACA,EACD,CAAC,KAAK,IAAI;CACX,GAAI;CACJ,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"label-BCSEss4U.js","names":[],"sources":["../src/label/Label.tsx","../src/label/LabelRequiredIndicator.tsx","../src/label/index.ts"],"sourcesContent":["import { cx } from 'class-variance-authority'\nimport { Label as RadixLabel } from 'radix-ui'\nimport { Ref } from 'react'\n\nexport type LabelProps = RadixLabel.LabelProps & {\n ref?: Ref<HTMLLabelElement>\n}\n\nexport const Label = ({ className, ref, ...others }: LabelProps) => {\n return (\n <RadixLabel.Label\n ref={ref}\n data-spark-component=\"label\"\n className={cx('text-body-1', className)}\n {...others}\n />\n )\n}\n\nLabel.displayName = 'Label'\n","import { cx } from 'class-variance-authority'\nimport { ComponentPropsWithRef } from 'react'\n\nexport type LabelRequiredIndicatorProps = ComponentPropsWithRef<'span'>\n\nexport const LabelRequiredIndicator = ({\n className,\n children = '*',\n ref,\n ...others\n}: LabelRequiredIndicatorProps) => {\n return (\n <span\n ref={ref}\n data-spark-component=\"label-required-indicator\"\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cx(className, 'text-caption text-on-surface/dim-1')}\n {...others}\n >\n {children}\n </span>\n )\n}\n\nLabelRequiredIndicator.displayName = 'Label.RequiredIndicator'\n","import { Label as Root } from './Label'\nimport { LabelRequiredIndicator } from './LabelRequiredIndicator'\n\nexport const Label: typeof Root & {\n RequiredIndicator: typeof LabelRequiredIndicator\n} = Object.assign(Root, {\n RequiredIndicator: LabelRequiredIndicator,\n})\n\nLabel.displayName = 'Label'\nLabelRequiredIndicator.displayName = 'Label.RequiredIndicator'\n\nexport type { LabelProps } from './Label'\nexport type { LabelRequiredIndicatorProps } from './LabelRequiredIndicator'\n"],"mappings":"8HAQA,IAAa,GAAS,CAAE,YAAW,MAAK,GAAG,MAEvC,EAAA,EAAA,KAAC,EAAA,MAAW,MAAZ,CACO,MACL,uBAAqB,QACrB,WAAA,EAAA,EAAA,IAAc,cAAe,EAAU,CACvC,GAAI,EACJ,CAAA,CAIN,EAAM,YAAc,QCdpB,IAAa,GAA0B,CACrC,YACA,WAAW,IACX,MACA,GAAG,MAGD,EAAA,EAAA,KAAC,OAAD,CACO,MACL,uBAAqB,2BACrB,KAAK,eACL,cAAY,OACZ,WAAA,EAAA,EAAA,IAAc,EAAW,qCAAqC,CAC9D,GAAI,EAEH,WACI,CAAA,CAIX,EAAuB,YAAc,0BCtBrC,IAAa,EAET,OAAO,OAAO,EAAM,CACtB,kBAAmB,EACpB,CAAC,CAEF,EAAM,YAAc,QACpB,EAAuB,YAAc"}
1
+ {"version":3,"file":"label-BCSEss4U.js","names":[],"sources":["../src/label/Label.tsx","../src/label/LabelRequiredIndicator.tsx","../src/label/index.ts"],"sourcesContent":["import { cx } from 'class-variance-authority'\nimport { Label as RadixLabel } from 'radix-ui'\nimport { Ref } from 'react'\n\nexport type LabelProps = RadixLabel.LabelProps & {\n ref?: Ref<HTMLLabelElement>\n}\n\nexport const Label = ({ className, ref, ...others }: LabelProps) => {\n return (\n <RadixLabel.Label\n ref={ref}\n data-spark-component=\"label\"\n className={cx('text-body-1', className)}\n {...others}\n />\n )\n}\n\nLabel.displayName = 'Label'\n","import { cx } from 'class-variance-authority'\nimport { ComponentPropsWithRef } from 'react'\n\nexport type LabelRequiredIndicatorProps = ComponentPropsWithRef<'span'>\n\nexport const LabelRequiredIndicator = ({\n className,\n children = '*',\n ref,\n ...others\n}: LabelRequiredIndicatorProps) => {\n return (\n <span\n ref={ref}\n data-spark-component=\"label-required-indicator\"\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cx(className, 'text-caption text-on-surface/dim-1')}\n {...others}\n >\n {children}\n </span>\n )\n}\n\nLabelRequiredIndicator.displayName = 'Label.RequiredIndicator'\n","import { Label as Root } from './Label'\nimport { LabelRequiredIndicator } from './LabelRequiredIndicator'\n\n/**\n * A text label component that describes a form control and provides accessible name for inputs.\n */\nexport const Label: typeof Root & {\n RequiredIndicator: typeof LabelRequiredIndicator\n} = Object.assign(Root, {\n RequiredIndicator: LabelRequiredIndicator,\n})\n\nLabel.displayName = 'Label'\nLabelRequiredIndicator.displayName = 'Label.RequiredIndicator'\n\nexport type { LabelProps } from './Label'\nexport type { LabelRequiredIndicatorProps } from './LabelRequiredIndicator'\n"],"mappings":"8HAQA,IAAa,GAAS,CAAE,YAAW,MAAK,GAAG,MAEvC,EAAA,EAAA,KAAC,EAAA,MAAW,MAAZ,CACO,MACL,uBAAqB,QACrB,WAAA,EAAA,EAAA,IAAc,cAAe,EAAU,CACvC,GAAI,EACJ,CAAA,CAIN,EAAM,YAAc,QCdpB,IAAa,GAA0B,CACrC,YACA,WAAW,IACX,MACA,GAAG,MAGD,EAAA,EAAA,KAAC,OAAD,CACO,MACL,uBAAqB,2BACrB,KAAK,eACL,cAAY,OACZ,WAAA,EAAA,EAAA,IAAc,EAAW,qCAAqC,CAC9D,GAAI,EAEH,WACI,CAAA,CAIX,EAAuB,YAAc,0BCnBrC,IAAa,EAET,OAAO,OAAO,EAAM,CACtB,kBAAmB,EACpB,CAAC,CAEF,EAAM,YAAc,QACpB,EAAuB,YAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"label-DDBRKLUX.mjs","names":[],"sources":["../src/label/Label.tsx","../src/label/LabelRequiredIndicator.tsx","../src/label/index.ts"],"sourcesContent":["import { cx } from 'class-variance-authority'\nimport { Label as RadixLabel } from 'radix-ui'\nimport { Ref } from 'react'\n\nexport type LabelProps = RadixLabel.LabelProps & {\n ref?: Ref<HTMLLabelElement>\n}\n\nexport const Label = ({ className, ref, ...others }: LabelProps) => {\n return (\n <RadixLabel.Label\n ref={ref}\n data-spark-component=\"label\"\n className={cx('text-body-1', className)}\n {...others}\n />\n )\n}\n\nLabel.displayName = 'Label'\n","import { cx } from 'class-variance-authority'\nimport { ComponentPropsWithRef } from 'react'\n\nexport type LabelRequiredIndicatorProps = ComponentPropsWithRef<'span'>\n\nexport const LabelRequiredIndicator = ({\n className,\n children = '*',\n ref,\n ...others\n}: LabelRequiredIndicatorProps) => {\n return (\n <span\n ref={ref}\n data-spark-component=\"label-required-indicator\"\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cx(className, 'text-caption text-on-surface/dim-1')}\n {...others}\n >\n {children}\n </span>\n )\n}\n\nLabelRequiredIndicator.displayName = 'Label.RequiredIndicator'\n","import { Label as Root } from './Label'\nimport { LabelRequiredIndicator } from './LabelRequiredIndicator'\n\nexport const Label: typeof Root & {\n RequiredIndicator: typeof LabelRequiredIndicator\n} = Object.assign(Root, {\n RequiredIndicator: LabelRequiredIndicator,\n})\n\nLabel.displayName = 'Label'\nLabelRequiredIndicator.displayName = 'Label.RequiredIndicator'\n\nexport type { LabelProps } from './Label'\nexport type { LabelRequiredIndicatorProps } from './LabelRequiredIndicator'\n"],"mappings":";;;;AAQA,IAAa,KAAS,EAAE,cAAW,QAAK,GAAG,QAEvC,kBAAC,EAAW,OAAZ;CACO;CACL,wBAAqB;CACrB,WAAW,EAAG,eAAe,EAAU;CACvC,GAAI;CACJ,CAAA;AAIN,EAAM,cAAc;;;ACdpB,IAAa,KAA0B,EACrC,cACA,cAAW,KACX,QACA,GAAG,QAGD,kBAAC,QAAD;CACO;CACL,wBAAqB;CACrB,MAAK;CACL,eAAY;CACZ,WAAW,EAAG,GAAW,qCAAqC;CAC9D,GAAI;CAEH;CACI,CAAA;AAIX,EAAuB,cAAc;;;ACtBrC,IAAa,IAET,OAAO,OAAO,GAAM,EACtB,mBAAmB,GACpB,CAAC;AAEF,EAAM,cAAc,SACpB,EAAuB,cAAc"}
1
+ {"version":3,"file":"label-DDBRKLUX.mjs","names":[],"sources":["../src/label/Label.tsx","../src/label/LabelRequiredIndicator.tsx","../src/label/index.ts"],"sourcesContent":["import { cx } from 'class-variance-authority'\nimport { Label as RadixLabel } from 'radix-ui'\nimport { Ref } from 'react'\n\nexport type LabelProps = RadixLabel.LabelProps & {\n ref?: Ref<HTMLLabelElement>\n}\n\nexport const Label = ({ className, ref, ...others }: LabelProps) => {\n return (\n <RadixLabel.Label\n ref={ref}\n data-spark-component=\"label\"\n className={cx('text-body-1', className)}\n {...others}\n />\n )\n}\n\nLabel.displayName = 'Label'\n","import { cx } from 'class-variance-authority'\nimport { ComponentPropsWithRef } from 'react'\n\nexport type LabelRequiredIndicatorProps = ComponentPropsWithRef<'span'>\n\nexport const LabelRequiredIndicator = ({\n className,\n children = '*',\n ref,\n ...others\n}: LabelRequiredIndicatorProps) => {\n return (\n <span\n ref={ref}\n data-spark-component=\"label-required-indicator\"\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cx(className, 'text-caption text-on-surface/dim-1')}\n {...others}\n >\n {children}\n </span>\n )\n}\n\nLabelRequiredIndicator.displayName = 'Label.RequiredIndicator'\n","import { Label as Root } from './Label'\nimport { LabelRequiredIndicator } from './LabelRequiredIndicator'\n\n/**\n * A text label component that describes a form control and provides accessible name for inputs.\n */\nexport const Label: typeof Root & {\n RequiredIndicator: typeof LabelRequiredIndicator\n} = Object.assign(Root, {\n RequiredIndicator: LabelRequiredIndicator,\n})\n\nLabel.displayName = 'Label'\nLabelRequiredIndicator.displayName = 'Label.RequiredIndicator'\n\nexport type { LabelProps } from './Label'\nexport type { LabelRequiredIndicatorProps } from './LabelRequiredIndicator'\n"],"mappings":";;;;AAQA,IAAa,KAAS,EAAE,cAAW,QAAK,GAAG,QAEvC,kBAAC,EAAW,OAAZ;CACO;CACL,wBAAqB;CACrB,WAAW,EAAG,eAAe,EAAU;CACvC,GAAI;CACJ,CAAA;AAIN,EAAM,cAAc;;;ACdpB,IAAa,KAA0B,EACrC,cACA,cAAW,KACX,QACA,GAAG,QAGD,kBAAC,QAAD;CACO;CACL,wBAAqB;CACrB,MAAK;CACL,eAAY;CACZ,WAAW,EAAG,GAAW,qCAAqC;CAC9D,GAAI;CAEH;CACI,CAAA;AAIX,EAAuB,cAAc;;;ACnBrC,IAAa,IAET,OAAO,OAAO,GAAM,EACtB,mBAAmB,GACpB,CAAC;AAEF,EAAM,cAAc,SACpB,EAAuB,cAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/link-box/LinkBox.tsx","../../src/link-box/LinkBoxLink.tsx","../../src/link-box/LinkBoxRaised.tsx","../../src/link-box/index.ts"],"sourcesContent":["import { cx } from 'class-variance-authority'\nimport { ComponentPropsWithRef } from 'react'\n\nimport { Slot } from '../slot'\n\nexport interface LinkBoxProps extends ComponentPropsWithRef<'div'> {\n asChild?: boolean\n}\n\nexport const LinkBox = ({ className, asChild, ref, ...props }: LinkBoxProps) => {\n const Component = asChild ? Slot : 'div'\n\n return (\n <Component\n ref={ref}\n data-spark-component=\"link-box\"\n className={cx('default:relative', className)}\n {...props}\n />\n )\n}\n\nLinkBox.displayName = 'LinkBox'\n","import { cx } from 'class-variance-authority'\nimport { ComponentPropsWithRef } from 'react'\n\nimport { Slot } from '../slot'\n\nexport interface LinkBoxLinkProps extends ComponentPropsWithRef<'a'> {\n asChild?: boolean\n}\n\nexport const LinkBoxLink = ({ className, asChild, ref, ...props }: LinkBoxLinkProps) => {\n const Component = asChild ? Slot : 'a'\n\n return (\n <Component\n ref={ref}\n data-spark-component=\"link-box-link\"\n className={cx(\n \"before:z-base static before:absolute before:top-0 before:left-0 before:block before:size-full before:content-['']\",\n className\n )}\n {...props}\n />\n )\n}\n\nLinkBoxLink.displayName = 'LinkBox.Link'\n","import { cx } from 'class-variance-authority'\nimport { ReactNode } from 'react'\n\nimport { Slot } from '../slot'\n\nexport interface LinkBoxRaisedProps {\n className?: string\n children: ReactNode\n}\n\nexport const LinkBoxRaised = ({ className, ...props }: LinkBoxRaisedProps) => {\n return <Slot className={cx('default:z-raised default:relative', className)} {...props} />\n}\n\nLinkBoxRaised.displayName = 'LinkBox.Raised'\n","import { LinkBox as Root } from './LinkBox'\nimport { LinkBoxLink } from './LinkBoxLink'\nimport { LinkBoxRaised } from './LinkBoxRaised'\n\nexport const LinkBox: typeof Root & {\n Link: typeof LinkBoxLink\n Raised: typeof LinkBoxRaised\n} = Object.assign(Root, { Link: LinkBoxLink, Raised: LinkBoxRaised })\n\nLinkBox.displayName = 'LinkBox'\nLinkBox.Link.displayName = 'LinkBox.Link'\nLinkBox.Raised.displayName = 'LinkBox.Raised'\n\nexport { type LinkBoxProps } from './LinkBox'\nexport { type LinkBoxLinkProps } from './LinkBoxLink'\n"],"mappings":"gNASA,IAAa,GAAW,CAAE,YAAW,UAAS,MAAK,GAAG,MAIlD,EAAA,EAAA,KAHgB,EAAU,EAAA,KAAO,MAGjC,CACO,MACL,uBAAqB,WACrB,WAAA,EAAA,EAAA,IAAc,mBAAoB,EAAU,CAC5C,GAAI,EACJ,CAAA,CAIN,EAAQ,YAAc,UCbtB,IAAa,GAAe,CAAE,YAAW,UAAS,MAAK,GAAG,MAItD,EAAA,EAAA,KAHgB,EAAU,EAAA,KAAO,IAGjC,CACO,MACL,uBAAqB,gBACrB,WAAA,EAAA,EAAA,IACE,oHACA,EACD,CACD,GAAI,EACJ,CAAA,CAIN,EAAY,YAAc,eCf1B,IAAa,GAAiB,CAAE,YAAW,GAAG,MACrC,EAAA,EAAA,KAAC,EAAA,KAAD,CAAM,WAAA,EAAA,EAAA,IAAc,oCAAqC,EAAU,CAAE,GAAI,EAAS,CAAA,CAG3F,EAAc,YAAc,iBCV5B,IAAa,EAGT,OAAO,OAAO,EAAM,CAAE,KAAM,EAAa,OAAQ,EAAe,CAAC,CAErE,EAAQ,YAAc,UACtB,EAAQ,KAAK,YAAc,eAC3B,EAAQ,OAAO,YAAc"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/link-box/LinkBox.tsx","../../src/link-box/LinkBoxLink.tsx","../../src/link-box/LinkBoxRaised.tsx","../../src/link-box/index.ts"],"sourcesContent":["import { cx } from 'class-variance-authority'\nimport { ComponentPropsWithRef } from 'react'\n\nimport { Slot } from '../slot'\n\nexport interface LinkBoxProps extends ComponentPropsWithRef<'div'> {\n asChild?: boolean\n}\n\nexport const LinkBox = ({ className, asChild, ref, ...props }: LinkBoxProps) => {\n const Component = asChild ? Slot : 'div'\n\n return (\n <Component\n ref={ref}\n data-spark-component=\"link-box\"\n className={cx('default:relative', className)}\n {...props}\n />\n )\n}\n\nLinkBox.displayName = 'LinkBox'\n","import { cx } from 'class-variance-authority'\nimport { ComponentPropsWithRef } from 'react'\n\nimport { Slot } from '../slot'\n\nexport interface LinkBoxLinkProps extends ComponentPropsWithRef<'a'> {\n asChild?: boolean\n}\n\nexport const LinkBoxLink = ({ className, asChild, ref, ...props }: LinkBoxLinkProps) => {\n const Component = asChild ? Slot : 'a'\n\n return (\n <Component\n ref={ref}\n data-spark-component=\"link-box-link\"\n className={cx(\n \"before:z-base static before:absolute before:top-0 before:left-0 before:block before:size-full before:content-['']\",\n className\n )}\n {...props}\n />\n )\n}\n\nLinkBoxLink.displayName = 'LinkBox.Link'\n","import { cx } from 'class-variance-authority'\nimport { ReactNode } from 'react'\n\nimport { Slot } from '../slot'\n\nexport interface LinkBoxRaisedProps {\n className?: string\n children: ReactNode\n}\n\nexport const LinkBoxRaised = ({ className, ...props }: LinkBoxRaisedProps) => {\n return <Slot className={cx('default:z-raised default:relative', className)} {...props} />\n}\n\nLinkBoxRaised.displayName = 'LinkBox.Raised'\n","import { LinkBox as Root } from './LinkBox'\nimport { LinkBoxLink } from './LinkBoxLink'\nimport { LinkBoxRaised } from './LinkBoxRaised'\n\n/**\n * A container component that makes an entire area clickable while keeping nested links semantically correct.\n */\nexport const LinkBox: typeof Root & {\n Link: typeof LinkBoxLink\n Raised: typeof LinkBoxRaised\n} = Object.assign(Root, { Link: LinkBoxLink, Raised: LinkBoxRaised })\n\nLinkBox.displayName = 'LinkBox'\nLinkBox.Link.displayName = 'LinkBox.Link'\nLinkBox.Raised.displayName = 'LinkBox.Raised'\n\nexport { type LinkBoxProps } from './LinkBox'\nexport { type LinkBoxLinkProps } from './LinkBoxLink'\n"],"mappings":"gNASA,IAAa,GAAW,CAAE,YAAW,UAAS,MAAK,GAAG,MAIlD,EAAA,EAAA,KAHgB,EAAU,EAAA,KAAO,MAGjC,CACO,MACL,uBAAqB,WACrB,WAAA,EAAA,EAAA,IAAc,mBAAoB,EAAU,CAC5C,GAAI,EACJ,CAAA,CAIN,EAAQ,YAAc,UCbtB,IAAa,GAAe,CAAE,YAAW,UAAS,MAAK,GAAG,MAItD,EAAA,EAAA,KAHgB,EAAU,EAAA,KAAO,IAGjC,CACO,MACL,uBAAqB,gBACrB,WAAA,EAAA,EAAA,IACE,oHACA,EACD,CACD,GAAI,EACJ,CAAA,CAIN,EAAY,YAAc,eCf1B,IAAa,GAAiB,CAAE,YAAW,GAAG,MACrC,EAAA,EAAA,KAAC,EAAA,KAAD,CAAM,WAAA,EAAA,EAAA,IAAc,oCAAqC,EAAU,CAAE,GAAI,EAAS,CAAA,CAG3F,EAAc,YAAc,iBCP5B,IAAa,EAGT,OAAO,OAAO,EAAM,CAAE,KAAM,EAAa,OAAQ,EAAe,CAAC,CAErE,EAAQ,YAAc,UACtB,EAAQ,KAAK,YAAc,eAC3B,EAAQ,OAAO,YAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/link-box/LinkBox.tsx","../../src/link-box/LinkBoxLink.tsx","../../src/link-box/LinkBoxRaised.tsx","../../src/link-box/index.ts"],"sourcesContent":["import { cx } from 'class-variance-authority'\nimport { ComponentPropsWithRef } from 'react'\n\nimport { Slot } from '../slot'\n\nexport interface LinkBoxProps extends ComponentPropsWithRef<'div'> {\n asChild?: boolean\n}\n\nexport const LinkBox = ({ className, asChild, ref, ...props }: LinkBoxProps) => {\n const Component = asChild ? Slot : 'div'\n\n return (\n <Component\n ref={ref}\n data-spark-component=\"link-box\"\n className={cx('default:relative', className)}\n {...props}\n />\n )\n}\n\nLinkBox.displayName = 'LinkBox'\n","import { cx } from 'class-variance-authority'\nimport { ComponentPropsWithRef } from 'react'\n\nimport { Slot } from '../slot'\n\nexport interface LinkBoxLinkProps extends ComponentPropsWithRef<'a'> {\n asChild?: boolean\n}\n\nexport const LinkBoxLink = ({ className, asChild, ref, ...props }: LinkBoxLinkProps) => {\n const Component = asChild ? Slot : 'a'\n\n return (\n <Component\n ref={ref}\n data-spark-component=\"link-box-link\"\n className={cx(\n \"before:z-base static before:absolute before:top-0 before:left-0 before:block before:size-full before:content-['']\",\n className\n )}\n {...props}\n />\n )\n}\n\nLinkBoxLink.displayName = 'LinkBox.Link'\n","import { cx } from 'class-variance-authority'\nimport { ReactNode } from 'react'\n\nimport { Slot } from '../slot'\n\nexport interface LinkBoxRaisedProps {\n className?: string\n children: ReactNode\n}\n\nexport const LinkBoxRaised = ({ className, ...props }: LinkBoxRaisedProps) => {\n return <Slot className={cx('default:z-raised default:relative', className)} {...props} />\n}\n\nLinkBoxRaised.displayName = 'LinkBox.Raised'\n","import { LinkBox as Root } from './LinkBox'\nimport { LinkBoxLink } from './LinkBoxLink'\nimport { LinkBoxRaised } from './LinkBoxRaised'\n\nexport const LinkBox: typeof Root & {\n Link: typeof LinkBoxLink\n Raised: typeof LinkBoxRaised\n} = Object.assign(Root, { Link: LinkBoxLink, Raised: LinkBoxRaised })\n\nLinkBox.displayName = 'LinkBox'\nLinkBox.Link.displayName = 'LinkBox.Link'\nLinkBox.Raised.displayName = 'LinkBox.Raised'\n\nexport { type LinkBoxProps } from './LinkBox'\nexport { type LinkBoxLinkProps } from './LinkBoxLink'\n"],"mappings":";;;;AASA,IAAa,KAAW,EAAE,cAAW,YAAS,QAAK,GAAG,QAIlD,kBAHgB,IAAU,IAAO,OAGjC;CACO;CACL,wBAAqB;CACrB,WAAW,EAAG,oBAAoB,EAAU;CAC5C,GAAI;CACJ,CAAA;AAIN,EAAQ,cAAc;;;ACbtB,IAAa,KAAe,EAAE,cAAW,YAAS,QAAK,GAAG,QAItD,kBAHgB,IAAU,IAAO,KAGjC;CACO;CACL,wBAAqB;CACrB,WAAW,EACT,qHACA,EACD;CACD,GAAI;CACJ,CAAA;AAIN,EAAY,cAAc;;;ACf1B,IAAa,KAAiB,EAAE,cAAW,GAAG,QACrC,kBAAC,GAAD;CAAM,WAAW,EAAG,qCAAqC,EAAU;CAAE,GAAI;CAAS,CAAA;AAG3F,EAAc,cAAc;;;ACV5B,IAAa,IAGT,OAAO,OAAO,GAAM;CAAE,MAAM;CAAa,QAAQ;CAAe,CAAC;AAErE,EAAQ,cAAc,WACtB,EAAQ,KAAK,cAAc,gBAC3B,EAAQ,OAAO,cAAc"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/link-box/LinkBox.tsx","../../src/link-box/LinkBoxLink.tsx","../../src/link-box/LinkBoxRaised.tsx","../../src/link-box/index.ts"],"sourcesContent":["import { cx } from 'class-variance-authority'\nimport { ComponentPropsWithRef } from 'react'\n\nimport { Slot } from '../slot'\n\nexport interface LinkBoxProps extends ComponentPropsWithRef<'div'> {\n asChild?: boolean\n}\n\nexport const LinkBox = ({ className, asChild, ref, ...props }: LinkBoxProps) => {\n const Component = asChild ? Slot : 'div'\n\n return (\n <Component\n ref={ref}\n data-spark-component=\"link-box\"\n className={cx('default:relative', className)}\n {...props}\n />\n )\n}\n\nLinkBox.displayName = 'LinkBox'\n","import { cx } from 'class-variance-authority'\nimport { ComponentPropsWithRef } from 'react'\n\nimport { Slot } from '../slot'\n\nexport interface LinkBoxLinkProps extends ComponentPropsWithRef<'a'> {\n asChild?: boolean\n}\n\nexport const LinkBoxLink = ({ className, asChild, ref, ...props }: LinkBoxLinkProps) => {\n const Component = asChild ? Slot : 'a'\n\n return (\n <Component\n ref={ref}\n data-spark-component=\"link-box-link\"\n className={cx(\n \"before:z-base static before:absolute before:top-0 before:left-0 before:block before:size-full before:content-['']\",\n className\n )}\n {...props}\n />\n )\n}\n\nLinkBoxLink.displayName = 'LinkBox.Link'\n","import { cx } from 'class-variance-authority'\nimport { ReactNode } from 'react'\n\nimport { Slot } from '../slot'\n\nexport interface LinkBoxRaisedProps {\n className?: string\n children: ReactNode\n}\n\nexport const LinkBoxRaised = ({ className, ...props }: LinkBoxRaisedProps) => {\n return <Slot className={cx('default:z-raised default:relative', className)} {...props} />\n}\n\nLinkBoxRaised.displayName = 'LinkBox.Raised'\n","import { LinkBox as Root } from './LinkBox'\nimport { LinkBoxLink } from './LinkBoxLink'\nimport { LinkBoxRaised } from './LinkBoxRaised'\n\n/**\n * A container component that makes an entire area clickable while keeping nested links semantically correct.\n */\nexport const LinkBox: typeof Root & {\n Link: typeof LinkBoxLink\n Raised: typeof LinkBoxRaised\n} = Object.assign(Root, { Link: LinkBoxLink, Raised: LinkBoxRaised })\n\nLinkBox.displayName = 'LinkBox'\nLinkBox.Link.displayName = 'LinkBox.Link'\nLinkBox.Raised.displayName = 'LinkBox.Raised'\n\nexport { type LinkBoxProps } from './LinkBox'\nexport { type LinkBoxLinkProps } from './LinkBoxLink'\n"],"mappings":";;;;AASA,IAAa,KAAW,EAAE,cAAW,YAAS,QAAK,GAAG,QAIlD,kBAHgB,IAAU,IAAO,OAGjC;CACO;CACL,wBAAqB;CACrB,WAAW,EAAG,oBAAoB,EAAU;CAC5C,GAAI;CACJ,CAAA;AAIN,EAAQ,cAAc;;;ACbtB,IAAa,KAAe,EAAE,cAAW,YAAS,QAAK,GAAG,QAItD,kBAHgB,IAAU,IAAO,KAGjC;CACO;CACL,wBAAqB;CACrB,WAAW,EACT,qHACA,EACD;CACD,GAAI;CACJ,CAAA;AAIN,EAAY,cAAc;;;ACf1B,IAAa,KAAiB,EAAE,cAAW,GAAG,QACrC,kBAAC,GAAD;CAAM,WAAW,EAAG,qCAAqC,EAAU;CAAE,GAAI;CAAS,CAAA;AAG3F,EAAc,cAAc;;;ACP5B,IAAa,IAGT,OAAO,OAAO,GAAM;CAAE,MAAM;CAAa,QAAQ;CAAe,CAAC;AAErE,EAAQ,cAAc,WACtB,EAAQ,KAAK,cAAc,gBAC3B,EAAQ,OAAO,cAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/meter/MeterContext.tsx","../../src/meter/Meter.tsx","../../src/meter/MeterLabel.tsx","../../src/meter/MeterTrack.styles.ts","../../src/meter/useIntersectionAnimation.ts","../../src/meter/MeterTrack.tsx","../../src/meter/MeterValue.tsx","../../src/meter/index.ts"],"sourcesContent":["import { createContext, useContext } from 'react'\n\nimport { MeterIndicatorStylesProps } from './MeterTrack.styles'\n\nexport interface MeterContextValue {\n value: number\n max: number\n min: number\n intent: MeterIndicatorStylesProps['intent']\n shape: 'square' | 'rounded'\n onLabelId: (id?: string) => void\n}\n\nexport const MeterContext = createContext<MeterContextValue | null>(null)\n\nexport const ID_PREFIX = ':meter'\n\nexport const useMeter = () => {\n const context = useContext(MeterContext)\n\n if (!context) {\n throw new Error('useMeter must be used within a Meter provider')\n }\n\n return context\n}\n","import { Meter as BaseMeter } from '@base-ui/react/meter'\nimport { cx } from 'class-variance-authority'\nimport { ComponentProps, PropsWithChildren, Ref, useMemo, useState } from 'react'\n\nimport { MeterContext } from './MeterContext'\nimport { MeterIndicatorStylesProps } from './MeterTrack.styles'\n\nexport interface MeterProps\n extends\n Omit<ComponentProps<typeof BaseMeter.Root>, 'render'>,\n Pick<MeterIndicatorStylesProps, 'intent'> {\n /**\n * Shape of the meter track and indicator.\n */\n shape?: 'square' | 'rounded'\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n */\n asChild?: boolean\n ref?: Ref<HTMLDivElement>\n}\n\nexport const Meter = ({\n className,\n value,\n max = 100,\n min = 0,\n shape = 'rounded',\n intent = 'support',\n children,\n ref,\n ...others\n}: PropsWithChildren<MeterProps>) => {\n const [labelId, setLabelId] = useState<string>()\n\n const contextValue = useMemo(() => {\n return {\n value: value ?? 0,\n max,\n min,\n intent,\n shape,\n onLabelId: setLabelId,\n }\n }, [max, min, value, intent, shape, setLabelId])\n\n return (\n <MeterContext.Provider value={contextValue}>\n <BaseMeter.Root\n data-spark-component=\"meter\"\n ref={ref}\n className={cx(\n 'gap-y-sm gap-x-md focus-visible:u-outline box-border grid grid-cols-[1fr_auto]',\n className\n )}\n value={value}\n max={max}\n min={min}\n aria-labelledby={labelId}\n {...others}\n >\n {children}\n </BaseMeter.Root>\n </MeterContext.Provider>\n )\n}\n\nMeter.displayName = 'Meter'\n","import { Meter as BaseMeter } from '@base-ui/react/meter'\nimport { useMergeRefs } from '@spark-ui/hooks/use-merge-refs'\nimport { ComponentProps, useCallback, useId } from 'react'\n\nimport { ID_PREFIX, useMeter } from './MeterContext'\n\nexport type MeterLabelProps = Omit<ComponentProps<typeof BaseMeter.Label>, 'render'>\n\nexport const MeterLabel = ({\n id: idProp,\n children,\n ref: forwardedRef,\n ...others\n}: MeterLabelProps) => {\n const internalID = `${ID_PREFIX}-label-${useId()}`\n const id = idProp || internalID\n\n const { onLabelId } = useMeter()\n const rootRef = useCallback(\n (el: HTMLSpanElement) => {\n onLabelId(el ? id : undefined)\n },\n [id, onLabelId]\n )\n const ref = useMergeRefs(forwardedRef, rootRef)\n\n return (\n <BaseMeter.Label\n data-spark-component=\"meter-label\"\n id={id}\n className=\"default:text-body-1 text-on-surface default:font-bold\"\n ref={ref}\n {...others}\n >\n {children}\n </BaseMeter.Label>\n )\n}\n\nMeterLabel.displayName = 'Meter.Label'\n","import { cva, VariantProps } from 'class-variance-authority'\n\nexport const meterTrackStyles = cva([\n 'relative col-span-2',\n 'h-sz-8 w-full',\n 'transform-gpu overflow-hidden',\n 'bg-on-background/dim-4',\n])\n\nexport type MeterTrackStylesProps = VariantProps<typeof meterTrackStyles>\n\nexport const meterIndicatorStyles = cva(\n ['size-full', 'ease-standard transition-[width] duration-700', 'motion-reduce:transition-none'],\n {\n variants: {\n /**\n * Color scheme of the meter component.\n */\n intent: {\n main: ['bg-main'],\n support: ['bg-support'],\n success: ['bg-success'],\n alert: ['bg-alert'],\n danger: ['bg-error'],\n info: ['bg-info'],\n },\n /**\n * Shape of the meter component.\n */\n shape: {\n square: [],\n rounded: ['rounded-sm'],\n },\n },\n }\n)\n\nexport type MeterIndicatorStylesProps = VariantProps<typeof meterIndicatorStyles>\n","import { RefObject, useEffect, useRef } from 'react'\n\nexport interface UseIntersectionAnimationOptions {\n /**\n * The threshold at which the callback should be triggered.\n * A value of 0 means as soon as any part of the element is visible.\n * A value of 1 means the entire element must be visible.\n * @default 0.1\n */\n threshold?: number\n /**\n * The root margin for the Intersection Observer.\n * This can be used to trigger the animation before the element enters the viewport.\n * @default undefined\n */\n rootMargin?: string\n}\n\n/**\n * Hook to trigger an animation callback when an element enters the viewport.\n * The callback is only triggered once, when the element first becomes visible.\n *\n * @param elementRef - Reference to the element to observe\n * @param onIntersect - Callback to execute when the element enters the viewport\n * @param options - Configuration options for the Intersection Observer\n * @returns Whether the animation has been triggered\n */\nexport function useIntersectionAnimation(\n elementRef: RefObject<Element | null>,\n onIntersect: () => void,\n options: UseIntersectionAnimationOptions = {}\n): boolean {\n const { threshold = 0.1, rootMargin } = options\n const hasTriggeredRef = useRef(false)\n const callbackRef = useRef(onIntersect)\n\n // Keep callback ref up to date\n useEffect(() => {\n callbackRef.current = onIntersect\n }, [onIntersect])\n\n useEffect(() => {\n const element = elementRef.current\n if (!element || hasTriggeredRef.current) return\n\n const observer = new IntersectionObserver(\n entries => {\n entries.forEach(entry => {\n if (entry.isIntersecting && !hasTriggeredRef.current) {\n // Use requestAnimationFrame to ensure the callback runs at the right time\n requestAnimationFrame(() => {\n if (!hasTriggeredRef.current) {\n hasTriggeredRef.current = true\n callbackRef.current()\n // Disconnect observer after callback is triggered (only trigger once)\n observer.disconnect()\n }\n })\n }\n })\n },\n {\n threshold,\n rootMargin,\n }\n )\n\n observer.observe(element)\n\n return () => {\n observer.disconnect()\n }\n }, [elementRef, threshold, rootMargin])\n\n return hasTriggeredRef.current\n}\n","import { Meter as BaseMeter } from '@base-ui/react/meter'\nimport { cx } from 'class-variance-authority'\nimport { ComponentProps, useRef, useState } from 'react'\n\nimport { useMeter } from './MeterContext'\nimport { meterIndicatorStyles, meterTrackStyles } from './MeterTrack.styles'\nimport { useIntersectionAnimation } from './useIntersectionAnimation'\n\nexport type MeterTrackProps = Omit<ComponentProps<typeof BaseMeter.Track>, 'render'>\n\nexport const MeterTrack = ({ className, ...others }: MeterTrackProps) => {\n const { value, max, min, intent, shape } = useMeter()\n const percentage = ((value - min) / (max - min)) * 100\n const trackRef = useRef<HTMLDivElement>(null)\n const [hasAnimated, setHasAnimated] = useState(false)\n\n // Trigger animation when component enters viewport\n useIntersectionAnimation(trackRef, () => {\n setHasAnimated(true)\n })\n\n return (\n <BaseMeter.Track\n ref={trackRef}\n data-spark-component=\"meter-track\"\n className={cx(meterTrackStyles(), { 'rounded-sm': shape === 'rounded' }, className)}\n {...others}\n >\n <BaseMeter.Indicator\n data-spark-component=\"meter-indicator\"\n className={meterIndicatorStyles({ intent, shape })}\n style={{\n width: hasAnimated ? `${percentage}%` : '0%',\n }}\n />\n </BaseMeter.Track>\n )\n}\n\nMeterTrack.displayName = 'Meter.Track'\n","import { Meter as BaseMeter } from '@base-ui/react/meter'\nimport { cx } from 'class-variance-authority'\nimport { ComponentProps, ReactNode } from 'react'\n\nexport type MeterValueProps = Omit<\n ComponentProps<typeof BaseMeter.Value>,\n 'render' | 'children'\n> & {\n children?: ((formattedValue: string, value: number) => ReactNode) | null | undefined\n}\n\nexport const MeterValue = ({ className, children, ...others }: MeterValueProps) => {\n return (\n <BaseMeter.Value\n data-spark-component=\"meter-value\"\n className={cx('default:text-body-1 text-on-surface', 'col-start-2 text-right', className)}\n {...others}\n >\n {children}\n </BaseMeter.Value>\n )\n}\n\nMeterValue.displayName = 'Meter.Value'\n","import { Meter as Root } from './Meter'\nimport { MeterLabel } from './MeterLabel'\nimport { MeterTrack } from './MeterTrack'\nimport { MeterValue } from './MeterValue'\n\nexport const Meter: typeof Root & {\n Label: typeof MeterLabel\n Track: typeof MeterTrack\n Value: typeof MeterValue\n} = Object.assign(Root, {\n Label: MeterLabel,\n Track: MeterTrack,\n Value: MeterValue,\n})\n\nMeter.displayName = 'Meter'\nMeterLabel.displayName = 'Meter.Label'\nMeterTrack.displayName = 'Meter.Track'\nMeterValue.displayName = 'Meter.Value'\n\nexport { type MeterProps } from './Meter'\nexport { type MeterLabelProps } from './MeterLabel'\nexport { type MeterTrackProps } from './MeterTrack'\nexport { type MeterValueProps } from './MeterValue'\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/meter/MeterContext.tsx","../../src/meter/Meter.tsx","../../src/meter/MeterLabel.tsx","../../src/meter/MeterTrack.styles.ts","../../src/meter/useIntersectionAnimation.ts","../../src/meter/MeterTrack.tsx","../../src/meter/MeterValue.tsx","../../src/meter/index.ts"],"sourcesContent":["import { createContext, useContext } from 'react'\n\nimport { MeterIndicatorStylesProps } from './MeterTrack.styles'\n\nexport interface MeterContextValue {\n value: number\n max: number\n min: number\n intent: MeterIndicatorStylesProps['intent']\n shape: 'square' | 'rounded'\n onLabelId: (id?: string) => void\n}\n\nexport const MeterContext = createContext<MeterContextValue | null>(null)\n\nexport const ID_PREFIX = ':meter'\n\nexport const useMeter = () => {\n const context = useContext(MeterContext)\n\n if (!context) {\n throw new Error('useMeter must be used within a Meter provider')\n }\n\n return context\n}\n","import { Meter as BaseMeter } from '@base-ui/react/meter'\nimport { cx } from 'class-variance-authority'\nimport { ComponentProps, PropsWithChildren, Ref, useMemo, useState } from 'react'\n\nimport { MeterContext } from './MeterContext'\nimport { MeterIndicatorStylesProps } from './MeterTrack.styles'\n\nexport interface MeterProps\n extends\n Omit<ComponentProps<typeof BaseMeter.Root>, 'render'>,\n Pick<MeterIndicatorStylesProps, 'intent'> {\n /**\n * Shape of the meter track and indicator.\n */\n shape?: 'square' | 'rounded'\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n */\n asChild?: boolean\n ref?: Ref<HTMLDivElement>\n}\n\nexport const Meter = ({\n className,\n value,\n max = 100,\n min = 0,\n shape = 'rounded',\n intent = 'support',\n children,\n ref,\n ...others\n}: PropsWithChildren<MeterProps>) => {\n const [labelId, setLabelId] = useState<string>()\n\n const contextValue = useMemo(() => {\n return {\n value: value ?? 0,\n max,\n min,\n intent,\n shape,\n onLabelId: setLabelId,\n }\n }, [max, min, value, intent, shape, setLabelId])\n\n return (\n <MeterContext.Provider value={contextValue}>\n <BaseMeter.Root\n data-spark-component=\"meter\"\n ref={ref}\n className={cx(\n 'gap-y-sm gap-x-md focus-visible:u-outline box-border grid grid-cols-[1fr_auto]',\n className\n )}\n value={value}\n max={max}\n min={min}\n aria-labelledby={labelId}\n {...others}\n >\n {children}\n </BaseMeter.Root>\n </MeterContext.Provider>\n )\n}\n\nMeter.displayName = 'Meter'\n","import { Meter as BaseMeter } from '@base-ui/react/meter'\nimport { useMergeRefs } from '@spark-ui/hooks/use-merge-refs'\nimport { ComponentProps, useCallback, useId } from 'react'\n\nimport { ID_PREFIX, useMeter } from './MeterContext'\n\nexport type MeterLabelProps = Omit<ComponentProps<typeof BaseMeter.Label>, 'render'>\n\nexport const MeterLabel = ({\n id: idProp,\n children,\n ref: forwardedRef,\n ...others\n}: MeterLabelProps) => {\n const internalID = `${ID_PREFIX}-label-${useId()}`\n const id = idProp || internalID\n\n const { onLabelId } = useMeter()\n const rootRef = useCallback(\n (el: HTMLSpanElement) => {\n onLabelId(el ? id : undefined)\n },\n [id, onLabelId]\n )\n const ref = useMergeRefs(forwardedRef, rootRef)\n\n return (\n <BaseMeter.Label\n data-spark-component=\"meter-label\"\n id={id}\n className=\"default:text-body-1 text-on-surface default:font-bold\"\n ref={ref}\n {...others}\n >\n {children}\n </BaseMeter.Label>\n )\n}\n\nMeterLabel.displayName = 'Meter.Label'\n","import { cva, VariantProps } from 'class-variance-authority'\n\nexport const meterTrackStyles = cva([\n 'relative col-span-2',\n 'h-sz-8 w-full',\n 'transform-gpu overflow-hidden',\n 'bg-on-background/dim-4',\n])\n\nexport type MeterTrackStylesProps = VariantProps<typeof meterTrackStyles>\n\nexport const meterIndicatorStyles = cva(\n ['size-full', 'ease-standard transition-[width] duration-700', 'motion-reduce:transition-none'],\n {\n variants: {\n /**\n * Color scheme of the meter component.\n */\n intent: {\n main: ['bg-main'],\n support: ['bg-support'],\n success: ['bg-success'],\n alert: ['bg-alert'],\n danger: ['bg-error'],\n info: ['bg-info'],\n },\n /**\n * Shape of the meter component.\n */\n shape: {\n square: [],\n rounded: ['rounded-sm'],\n },\n },\n }\n)\n\nexport type MeterIndicatorStylesProps = VariantProps<typeof meterIndicatorStyles>\n","import { RefObject, useEffect, useRef } from 'react'\n\nexport interface UseIntersectionAnimationOptions {\n /**\n * The threshold at which the callback should be triggered.\n * A value of 0 means as soon as any part of the element is visible.\n * A value of 1 means the entire element must be visible.\n * @default 0.1\n */\n threshold?: number\n /**\n * The root margin for the Intersection Observer.\n * This can be used to trigger the animation before the element enters the viewport.\n * @default undefined\n */\n rootMargin?: string\n}\n\n/**\n * Hook to trigger an animation callback when an element enters the viewport.\n * The callback is only triggered once, when the element first becomes visible.\n *\n * @param elementRef - Reference to the element to observe\n * @param onIntersect - Callback to execute when the element enters the viewport\n * @param options - Configuration options for the Intersection Observer\n * @returns Whether the animation has been triggered\n */\nexport function useIntersectionAnimation(\n elementRef: RefObject<Element | null>,\n onIntersect: () => void,\n options: UseIntersectionAnimationOptions = {}\n): boolean {\n const { threshold = 0.1, rootMargin } = options\n const hasTriggeredRef = useRef(false)\n const callbackRef = useRef(onIntersect)\n\n // Keep callback ref up to date\n useEffect(() => {\n callbackRef.current = onIntersect\n }, [onIntersect])\n\n useEffect(() => {\n const element = elementRef.current\n if (!element || hasTriggeredRef.current) return\n\n const observer = new IntersectionObserver(\n entries => {\n entries.forEach(entry => {\n if (entry.isIntersecting && !hasTriggeredRef.current) {\n // Use requestAnimationFrame to ensure the callback runs at the right time\n requestAnimationFrame(() => {\n if (!hasTriggeredRef.current) {\n hasTriggeredRef.current = true\n callbackRef.current()\n // Disconnect observer after callback is triggered (only trigger once)\n observer.disconnect()\n }\n })\n }\n })\n },\n {\n threshold,\n rootMargin,\n }\n )\n\n observer.observe(element)\n\n return () => {\n observer.disconnect()\n }\n }, [elementRef, threshold, rootMargin])\n\n return hasTriggeredRef.current\n}\n","import { Meter as BaseMeter } from '@base-ui/react/meter'\nimport { cx } from 'class-variance-authority'\nimport { ComponentProps, useRef, useState } from 'react'\n\nimport { useMeter } from './MeterContext'\nimport { meterIndicatorStyles, meterTrackStyles } from './MeterTrack.styles'\nimport { useIntersectionAnimation } from './useIntersectionAnimation'\n\nexport type MeterTrackProps = Omit<ComponentProps<typeof BaseMeter.Track>, 'render'>\n\nexport const MeterTrack = ({ className, ...others }: MeterTrackProps) => {\n const { value, max, min, intent, shape } = useMeter()\n const percentage = ((value - min) / (max - min)) * 100\n const trackRef = useRef<HTMLDivElement>(null)\n const [hasAnimated, setHasAnimated] = useState(false)\n\n // Trigger animation when component enters viewport\n useIntersectionAnimation(trackRef, () => {\n setHasAnimated(true)\n })\n\n return (\n <BaseMeter.Track\n ref={trackRef}\n data-spark-component=\"meter-track\"\n className={cx(meterTrackStyles(), { 'rounded-sm': shape === 'rounded' }, className)}\n {...others}\n >\n <BaseMeter.Indicator\n data-spark-component=\"meter-indicator\"\n className={meterIndicatorStyles({ intent, shape })}\n style={{\n width: hasAnimated ? `${percentage}%` : '0%',\n }}\n />\n </BaseMeter.Track>\n )\n}\n\nMeterTrack.displayName = 'Meter.Track'\n","import { Meter as BaseMeter } from '@base-ui/react/meter'\nimport { cx } from 'class-variance-authority'\nimport { ComponentProps, ReactNode } from 'react'\n\nexport type MeterValueProps = Omit<\n ComponentProps<typeof BaseMeter.Value>,\n 'render' | 'children'\n> & {\n children?: ((formattedValue: string, value: number) => ReactNode) | null | undefined\n}\n\nexport const MeterValue = ({ className, children, ...others }: MeterValueProps) => {\n return (\n <BaseMeter.Value\n data-spark-component=\"meter-value\"\n className={cx('default:text-body-1 text-on-surface', 'col-start-2 text-right', className)}\n {...others}\n >\n {children}\n </BaseMeter.Value>\n )\n}\n\nMeterValue.displayName = 'Meter.Value'\n","import { Meter as Root } from './Meter'\nimport { MeterLabel } from './MeterLabel'\nimport { MeterTrack } from './MeterTrack'\nimport { MeterValue } from './MeterValue'\n\n/**\n * A horizontal progress indicator that displays a scalar measurement within a known range.\n */\nexport const Meter: typeof Root & {\n Label: typeof MeterLabel\n Track: typeof MeterTrack\n Value: typeof MeterValue\n} = Object.assign(Root, {\n Label: MeterLabel,\n Track: MeterTrack,\n Value: MeterValue,\n})\n\nMeter.displayName = 'Meter'\nMeterLabel.displayName = 'Meter.Label'\nMeterTrack.displayName = 'Meter.Track'\nMeterValue.displayName = 'Meter.Value'\n\nexport { type MeterProps } from './Meter'\nexport { type MeterLabelProps } from './MeterLabel'\nexport { type MeterTrackProps } from './MeterTrack'\nexport { type MeterValueProps } from './MeterValue'\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/meter/MeterContext.tsx","../../src/meter/Meter.tsx","../../src/meter/MeterLabel.tsx","../../src/meter/MeterTrack.styles.ts","../../src/meter/useIntersectionAnimation.ts","../../src/meter/MeterTrack.tsx","../../src/meter/MeterValue.tsx","../../src/meter/index.ts"],"sourcesContent":["import { createContext, useContext } from 'react'\n\nimport { MeterIndicatorStylesProps } from './MeterTrack.styles'\n\nexport interface MeterContextValue {\n value: number\n max: number\n min: number\n intent: MeterIndicatorStylesProps['intent']\n shape: 'square' | 'rounded'\n onLabelId: (id?: string) => void\n}\n\nexport const MeterContext = createContext<MeterContextValue | null>(null)\n\nexport const ID_PREFIX = ':meter'\n\nexport const useMeter = () => {\n const context = useContext(MeterContext)\n\n if (!context) {\n throw new Error('useMeter must be used within a Meter provider')\n }\n\n return context\n}\n","import { Meter as BaseMeter } from '@base-ui/react/meter'\nimport { cx } from 'class-variance-authority'\nimport { ComponentProps, PropsWithChildren, Ref, useMemo, useState } from 'react'\n\nimport { MeterContext } from './MeterContext'\nimport { MeterIndicatorStylesProps } from './MeterTrack.styles'\n\nexport interface MeterProps\n extends\n Omit<ComponentProps<typeof BaseMeter.Root>, 'render'>,\n Pick<MeterIndicatorStylesProps, 'intent'> {\n /**\n * Shape of the meter track and indicator.\n */\n shape?: 'square' | 'rounded'\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n */\n asChild?: boolean\n ref?: Ref<HTMLDivElement>\n}\n\nexport const Meter = ({\n className,\n value,\n max = 100,\n min = 0,\n shape = 'rounded',\n intent = 'support',\n children,\n ref,\n ...others\n}: PropsWithChildren<MeterProps>) => {\n const [labelId, setLabelId] = useState<string>()\n\n const contextValue = useMemo(() => {\n return {\n value: value ?? 0,\n max,\n min,\n intent,\n shape,\n onLabelId: setLabelId,\n }\n }, [max, min, value, intent, shape, setLabelId])\n\n return (\n <MeterContext.Provider value={contextValue}>\n <BaseMeter.Root\n data-spark-component=\"meter\"\n ref={ref}\n className={cx(\n 'gap-y-sm gap-x-md focus-visible:u-outline box-border grid grid-cols-[1fr_auto]',\n className\n )}\n value={value}\n max={max}\n min={min}\n aria-labelledby={labelId}\n {...others}\n >\n {children}\n </BaseMeter.Root>\n </MeterContext.Provider>\n )\n}\n\nMeter.displayName = 'Meter'\n","import { Meter as BaseMeter } from '@base-ui/react/meter'\nimport { useMergeRefs } from '@spark-ui/hooks/use-merge-refs'\nimport { ComponentProps, useCallback, useId } from 'react'\n\nimport { ID_PREFIX, useMeter } from './MeterContext'\n\nexport type MeterLabelProps = Omit<ComponentProps<typeof BaseMeter.Label>, 'render'>\n\nexport const MeterLabel = ({\n id: idProp,\n children,\n ref: forwardedRef,\n ...others\n}: MeterLabelProps) => {\n const internalID = `${ID_PREFIX}-label-${useId()}`\n const id = idProp || internalID\n\n const { onLabelId } = useMeter()\n const rootRef = useCallback(\n (el: HTMLSpanElement) => {\n onLabelId(el ? id : undefined)\n },\n [id, onLabelId]\n )\n const ref = useMergeRefs(forwardedRef, rootRef)\n\n return (\n <BaseMeter.Label\n data-spark-component=\"meter-label\"\n id={id}\n className=\"default:text-body-1 text-on-surface default:font-bold\"\n ref={ref}\n {...others}\n >\n {children}\n </BaseMeter.Label>\n )\n}\n\nMeterLabel.displayName = 'Meter.Label'\n","import { cva, VariantProps } from 'class-variance-authority'\n\nexport const meterTrackStyles = cva([\n 'relative col-span-2',\n 'h-sz-8 w-full',\n 'transform-gpu overflow-hidden',\n 'bg-on-background/dim-4',\n])\n\nexport type MeterTrackStylesProps = VariantProps<typeof meterTrackStyles>\n\nexport const meterIndicatorStyles = cva(\n ['size-full', 'ease-standard transition-[width] duration-700', 'motion-reduce:transition-none'],\n {\n variants: {\n /**\n * Color scheme of the meter component.\n */\n intent: {\n main: ['bg-main'],\n support: ['bg-support'],\n success: ['bg-success'],\n alert: ['bg-alert'],\n danger: ['bg-error'],\n info: ['bg-info'],\n },\n /**\n * Shape of the meter component.\n */\n shape: {\n square: [],\n rounded: ['rounded-sm'],\n },\n },\n }\n)\n\nexport type MeterIndicatorStylesProps = VariantProps<typeof meterIndicatorStyles>\n","import { RefObject, useEffect, useRef } from 'react'\n\nexport interface UseIntersectionAnimationOptions {\n /**\n * The threshold at which the callback should be triggered.\n * A value of 0 means as soon as any part of the element is visible.\n * A value of 1 means the entire element must be visible.\n * @default 0.1\n */\n threshold?: number\n /**\n * The root margin for the Intersection Observer.\n * This can be used to trigger the animation before the element enters the viewport.\n * @default undefined\n */\n rootMargin?: string\n}\n\n/**\n * Hook to trigger an animation callback when an element enters the viewport.\n * The callback is only triggered once, when the element first becomes visible.\n *\n * @param elementRef - Reference to the element to observe\n * @param onIntersect - Callback to execute when the element enters the viewport\n * @param options - Configuration options for the Intersection Observer\n * @returns Whether the animation has been triggered\n */\nexport function useIntersectionAnimation(\n elementRef: RefObject<Element | null>,\n onIntersect: () => void,\n options: UseIntersectionAnimationOptions = {}\n): boolean {\n const { threshold = 0.1, rootMargin } = options\n const hasTriggeredRef = useRef(false)\n const callbackRef = useRef(onIntersect)\n\n // Keep callback ref up to date\n useEffect(() => {\n callbackRef.current = onIntersect\n }, [onIntersect])\n\n useEffect(() => {\n const element = elementRef.current\n if (!element || hasTriggeredRef.current) return\n\n const observer = new IntersectionObserver(\n entries => {\n entries.forEach(entry => {\n if (entry.isIntersecting && !hasTriggeredRef.current) {\n // Use requestAnimationFrame to ensure the callback runs at the right time\n requestAnimationFrame(() => {\n if (!hasTriggeredRef.current) {\n hasTriggeredRef.current = true\n callbackRef.current()\n // Disconnect observer after callback is triggered (only trigger once)\n observer.disconnect()\n }\n })\n }\n })\n },\n {\n threshold,\n rootMargin,\n }\n )\n\n observer.observe(element)\n\n return () => {\n observer.disconnect()\n }\n }, [elementRef, threshold, rootMargin])\n\n return hasTriggeredRef.current\n}\n","import { Meter as BaseMeter } from '@base-ui/react/meter'\nimport { cx } from 'class-variance-authority'\nimport { ComponentProps, useRef, useState } from 'react'\n\nimport { useMeter } from './MeterContext'\nimport { meterIndicatorStyles, meterTrackStyles } from './MeterTrack.styles'\nimport { useIntersectionAnimation } from './useIntersectionAnimation'\n\nexport type MeterTrackProps = Omit<ComponentProps<typeof BaseMeter.Track>, 'render'>\n\nexport const MeterTrack = ({ className, ...others }: MeterTrackProps) => {\n const { value, max, min, intent, shape } = useMeter()\n const percentage = ((value - min) / (max - min)) * 100\n const trackRef = useRef<HTMLDivElement>(null)\n const [hasAnimated, setHasAnimated] = useState(false)\n\n // Trigger animation when component enters viewport\n useIntersectionAnimation(trackRef, () => {\n setHasAnimated(true)\n })\n\n return (\n <BaseMeter.Track\n ref={trackRef}\n data-spark-component=\"meter-track\"\n className={cx(meterTrackStyles(), { 'rounded-sm': shape === 'rounded' }, className)}\n {...others}\n >\n <BaseMeter.Indicator\n data-spark-component=\"meter-indicator\"\n className={meterIndicatorStyles({ intent, shape })}\n style={{\n width: hasAnimated ? `${percentage}%` : '0%',\n }}\n />\n </BaseMeter.Track>\n )\n}\n\nMeterTrack.displayName = 'Meter.Track'\n","import { Meter as BaseMeter } from '@base-ui/react/meter'\nimport { cx } from 'class-variance-authority'\nimport { ComponentProps, ReactNode } from 'react'\n\nexport type MeterValueProps = Omit<\n ComponentProps<typeof BaseMeter.Value>,\n 'render' | 'children'\n> & {\n children?: ((formattedValue: string, value: number) => ReactNode) | null | undefined\n}\n\nexport const MeterValue = ({ className, children, ...others }: MeterValueProps) => {\n return (\n <BaseMeter.Value\n data-spark-component=\"meter-value\"\n className={cx('default:text-body-1 text-on-surface', 'col-start-2 text-right', className)}\n {...others}\n >\n {children}\n </BaseMeter.Value>\n )\n}\n\nMeterValue.displayName = 'Meter.Value'\n","import { Meter as Root } from './Meter'\nimport { MeterLabel } from './MeterLabel'\nimport { MeterTrack } from './MeterTrack'\nimport { MeterValue } from './MeterValue'\n\nexport const Meter: typeof Root & {\n Label: typeof MeterLabel\n Track: typeof MeterTrack\n Value: typeof MeterValue\n} = Object.assign(Root, {\n Label: MeterLabel,\n Track: MeterTrack,\n Value: MeterValue,\n})\n\nMeter.displayName = 'Meter'\nMeterLabel.displayName = 'Meter.Label'\nMeterTrack.displayName = 'Meter.Track'\nMeterValue.displayName = 'Meter.Value'\n\nexport { type MeterProps } from './Meter'\nexport { type MeterLabelProps } from './MeterLabel'\nexport { type MeterTrackProps } from './MeterTrack'\nexport { type MeterValueProps } from './MeterValue'\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/meter/MeterContext.tsx","../../src/meter/Meter.tsx","../../src/meter/MeterLabel.tsx","../../src/meter/MeterTrack.styles.ts","../../src/meter/useIntersectionAnimation.ts","../../src/meter/MeterTrack.tsx","../../src/meter/MeterValue.tsx","../../src/meter/index.ts"],"sourcesContent":["import { createContext, useContext } from 'react'\n\nimport { MeterIndicatorStylesProps } from './MeterTrack.styles'\n\nexport interface MeterContextValue {\n value: number\n max: number\n min: number\n intent: MeterIndicatorStylesProps['intent']\n shape: 'square' | 'rounded'\n onLabelId: (id?: string) => void\n}\n\nexport const MeterContext = createContext<MeterContextValue | null>(null)\n\nexport const ID_PREFIX = ':meter'\n\nexport const useMeter = () => {\n const context = useContext(MeterContext)\n\n if (!context) {\n throw new Error('useMeter must be used within a Meter provider')\n }\n\n return context\n}\n","import { Meter as BaseMeter } from '@base-ui/react/meter'\nimport { cx } from 'class-variance-authority'\nimport { ComponentProps, PropsWithChildren, Ref, useMemo, useState } from 'react'\n\nimport { MeterContext } from './MeterContext'\nimport { MeterIndicatorStylesProps } from './MeterTrack.styles'\n\nexport interface MeterProps\n extends\n Omit<ComponentProps<typeof BaseMeter.Root>, 'render'>,\n Pick<MeterIndicatorStylesProps, 'intent'> {\n /**\n * Shape of the meter track and indicator.\n */\n shape?: 'square' | 'rounded'\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n */\n asChild?: boolean\n ref?: Ref<HTMLDivElement>\n}\n\nexport const Meter = ({\n className,\n value,\n max = 100,\n min = 0,\n shape = 'rounded',\n intent = 'support',\n children,\n ref,\n ...others\n}: PropsWithChildren<MeterProps>) => {\n const [labelId, setLabelId] = useState<string>()\n\n const contextValue = useMemo(() => {\n return {\n value: value ?? 0,\n max,\n min,\n intent,\n shape,\n onLabelId: setLabelId,\n }\n }, [max, min, value, intent, shape, setLabelId])\n\n return (\n <MeterContext.Provider value={contextValue}>\n <BaseMeter.Root\n data-spark-component=\"meter\"\n ref={ref}\n className={cx(\n 'gap-y-sm gap-x-md focus-visible:u-outline box-border grid grid-cols-[1fr_auto]',\n className\n )}\n value={value}\n max={max}\n min={min}\n aria-labelledby={labelId}\n {...others}\n >\n {children}\n </BaseMeter.Root>\n </MeterContext.Provider>\n )\n}\n\nMeter.displayName = 'Meter'\n","import { Meter as BaseMeter } from '@base-ui/react/meter'\nimport { useMergeRefs } from '@spark-ui/hooks/use-merge-refs'\nimport { ComponentProps, useCallback, useId } from 'react'\n\nimport { ID_PREFIX, useMeter } from './MeterContext'\n\nexport type MeterLabelProps = Omit<ComponentProps<typeof BaseMeter.Label>, 'render'>\n\nexport const MeterLabel = ({\n id: idProp,\n children,\n ref: forwardedRef,\n ...others\n}: MeterLabelProps) => {\n const internalID = `${ID_PREFIX}-label-${useId()}`\n const id = idProp || internalID\n\n const { onLabelId } = useMeter()\n const rootRef = useCallback(\n (el: HTMLSpanElement) => {\n onLabelId(el ? id : undefined)\n },\n [id, onLabelId]\n )\n const ref = useMergeRefs(forwardedRef, rootRef)\n\n return (\n <BaseMeter.Label\n data-spark-component=\"meter-label\"\n id={id}\n className=\"default:text-body-1 text-on-surface default:font-bold\"\n ref={ref}\n {...others}\n >\n {children}\n </BaseMeter.Label>\n )\n}\n\nMeterLabel.displayName = 'Meter.Label'\n","import { cva, VariantProps } from 'class-variance-authority'\n\nexport const meterTrackStyles = cva([\n 'relative col-span-2',\n 'h-sz-8 w-full',\n 'transform-gpu overflow-hidden',\n 'bg-on-background/dim-4',\n])\n\nexport type MeterTrackStylesProps = VariantProps<typeof meterTrackStyles>\n\nexport const meterIndicatorStyles = cva(\n ['size-full', 'ease-standard transition-[width] duration-700', 'motion-reduce:transition-none'],\n {\n variants: {\n /**\n * Color scheme of the meter component.\n */\n intent: {\n main: ['bg-main'],\n support: ['bg-support'],\n success: ['bg-success'],\n alert: ['bg-alert'],\n danger: ['bg-error'],\n info: ['bg-info'],\n },\n /**\n * Shape of the meter component.\n */\n shape: {\n square: [],\n rounded: ['rounded-sm'],\n },\n },\n }\n)\n\nexport type MeterIndicatorStylesProps = VariantProps<typeof meterIndicatorStyles>\n","import { RefObject, useEffect, useRef } from 'react'\n\nexport interface UseIntersectionAnimationOptions {\n /**\n * The threshold at which the callback should be triggered.\n * A value of 0 means as soon as any part of the element is visible.\n * A value of 1 means the entire element must be visible.\n * @default 0.1\n */\n threshold?: number\n /**\n * The root margin for the Intersection Observer.\n * This can be used to trigger the animation before the element enters the viewport.\n * @default undefined\n */\n rootMargin?: string\n}\n\n/**\n * Hook to trigger an animation callback when an element enters the viewport.\n * The callback is only triggered once, when the element first becomes visible.\n *\n * @param elementRef - Reference to the element to observe\n * @param onIntersect - Callback to execute when the element enters the viewport\n * @param options - Configuration options for the Intersection Observer\n * @returns Whether the animation has been triggered\n */\nexport function useIntersectionAnimation(\n elementRef: RefObject<Element | null>,\n onIntersect: () => void,\n options: UseIntersectionAnimationOptions = {}\n): boolean {\n const { threshold = 0.1, rootMargin } = options\n const hasTriggeredRef = useRef(false)\n const callbackRef = useRef(onIntersect)\n\n // Keep callback ref up to date\n useEffect(() => {\n callbackRef.current = onIntersect\n }, [onIntersect])\n\n useEffect(() => {\n const element = elementRef.current\n if (!element || hasTriggeredRef.current) return\n\n const observer = new IntersectionObserver(\n entries => {\n entries.forEach(entry => {\n if (entry.isIntersecting && !hasTriggeredRef.current) {\n // Use requestAnimationFrame to ensure the callback runs at the right time\n requestAnimationFrame(() => {\n if (!hasTriggeredRef.current) {\n hasTriggeredRef.current = true\n callbackRef.current()\n // Disconnect observer after callback is triggered (only trigger once)\n observer.disconnect()\n }\n })\n }\n })\n },\n {\n threshold,\n rootMargin,\n }\n )\n\n observer.observe(element)\n\n return () => {\n observer.disconnect()\n }\n }, [elementRef, threshold, rootMargin])\n\n return hasTriggeredRef.current\n}\n","import { Meter as BaseMeter } from '@base-ui/react/meter'\nimport { cx } from 'class-variance-authority'\nimport { ComponentProps, useRef, useState } from 'react'\n\nimport { useMeter } from './MeterContext'\nimport { meterIndicatorStyles, meterTrackStyles } from './MeterTrack.styles'\nimport { useIntersectionAnimation } from './useIntersectionAnimation'\n\nexport type MeterTrackProps = Omit<ComponentProps<typeof BaseMeter.Track>, 'render'>\n\nexport const MeterTrack = ({ className, ...others }: MeterTrackProps) => {\n const { value, max, min, intent, shape } = useMeter()\n const percentage = ((value - min) / (max - min)) * 100\n const trackRef = useRef<HTMLDivElement>(null)\n const [hasAnimated, setHasAnimated] = useState(false)\n\n // Trigger animation when component enters viewport\n useIntersectionAnimation(trackRef, () => {\n setHasAnimated(true)\n })\n\n return (\n <BaseMeter.Track\n ref={trackRef}\n data-spark-component=\"meter-track\"\n className={cx(meterTrackStyles(), { 'rounded-sm': shape === 'rounded' }, className)}\n {...others}\n >\n <BaseMeter.Indicator\n data-spark-component=\"meter-indicator\"\n className={meterIndicatorStyles({ intent, shape })}\n style={{\n width: hasAnimated ? `${percentage}%` : '0%',\n }}\n />\n </BaseMeter.Track>\n )\n}\n\nMeterTrack.displayName = 'Meter.Track'\n","import { Meter as BaseMeter } from '@base-ui/react/meter'\nimport { cx } from 'class-variance-authority'\nimport { ComponentProps, ReactNode } from 'react'\n\nexport type MeterValueProps = Omit<\n ComponentProps<typeof BaseMeter.Value>,\n 'render' | 'children'\n> & {\n children?: ((formattedValue: string, value: number) => ReactNode) | null | undefined\n}\n\nexport const MeterValue = ({ className, children, ...others }: MeterValueProps) => {\n return (\n <BaseMeter.Value\n data-spark-component=\"meter-value\"\n className={cx('default:text-body-1 text-on-surface', 'col-start-2 text-right', className)}\n {...others}\n >\n {children}\n </BaseMeter.Value>\n )\n}\n\nMeterValue.displayName = 'Meter.Value'\n","import { Meter as Root } from './Meter'\nimport { MeterLabel } from './MeterLabel'\nimport { MeterTrack } from './MeterTrack'\nimport { MeterValue } from './MeterValue'\n\n/**\n * A horizontal progress indicator that displays a scalar measurement within a known range.\n */\nexport const Meter: typeof Root & {\n Label: typeof MeterLabel\n Track: typeof MeterTrack\n Value: typeof MeterValue\n} = Object.assign(Root, {\n Label: MeterLabel,\n Track: MeterTrack,\n Value: MeterValue,\n})\n\nMeter.displayName = 'Meter'\nMeterLabel.displayName = 'Meter.Label'\nMeterTrack.displayName = 'Meter.Track'\nMeterValue.displayName = 'Meter.Value'\n\nexport { type MeterProps } from './Meter'\nexport { type MeterLabelProps } from './MeterLabel'\nexport { type MeterTrackProps } from './MeterTrack'\nexport { type MeterValueProps } from './MeterValue'\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/pagination/utils.ts","../../src/pagination/PaginationContext.tsx","../../src/pagination/Pagination.tsx","../../src/pagination/PaginationEllipsis.tsx","../../src/pagination/PaginationFirstPageTrigger.tsx","../../src/pagination/PaginationItem.tsx","../../src/pagination/PaginationLastPageTrigger.tsx","../../src/pagination/PaginationNextTrigger.tsx","../../src/pagination/PaginationPages.tsx","../../src/pagination/PaginationPrevTrigger.tsx","../../src/pagination/index.ts"],"sourcesContent":["export function sliceArrayWithIndex(arr: any[], index: number, length: number) {\n const relativeElements = (length - 1) / 2\n\n let start = Math.max(0, index - relativeElements)\n let end = Math.min(arr.length, index + relativeElements + 1)\n\n if (end - start < length) {\n start = Math.max(0, Math.min(start, arr.length - length))\n end = Math.min(arr.length, start + length)\n }\n\n return arr.slice(start, end)\n}\n","import * as pagination from '@zag-js/pagination'\nimport { normalizeProps, type PropTypes, useMachine } from '@zag-js/react'\nimport { createContext, type ReactNode, useContext, useId } from 'react'\n\nimport { sliceArrayWithIndex } from './utils'\n\nexport interface PaginationContextState<T extends PropTypes = PropTypes> {\n type: pagination.Props['type']\n pagination: pagination.Api<T> & {\n getFirstPageTriggerProps: () => ReturnType<pagination.Api<T>['getPrevTriggerProps']> & {\n 'data-part': string\n onClick: () => void\n }\n getLastPageTriggerProps: () => ReturnType<pagination.Api<T>['getNextTriggerProps']> & {\n 'data-part': string\n onClick: () => void\n }\n }\n}\n\nconst PaginationContext = createContext<PaginationContextState | null>(null)\n\nexport interface PaginationProviderProps {\n children: ReactNode\n /**\n * Total number of data items available across all pages.\n */\n count: number\n /**\n * Maximum amount of items displayed on a single page.\n */\n pageSize: number\n /**\n * Number of visible pages (or ellipsis) between previous and next page triggers.\n */\n visiblePageItems?: number\n /**\n * The current page (active page)\n */\n page?: pagination.Props['page']\n /**\n * If your pagination contains buttons instead of links, set `type` to `button`, extra attributes will be applied on page items for a11y.\n */\n type?: pagination.Props['type']\n onPageChange?: pagination.Props['onPageChange']\n noEllipsis?: boolean\n}\n\nexport const PaginationProvider = ({\n children,\n count,\n visiblePageItems = 7,\n pageSize,\n page,\n onPageChange,\n noEllipsis,\n type = 'link',\n}: PaginationProviderProps) => {\n /**\n * Here `Infinity` is used because we apply a custom slice ourselves to manage the \"no ellipsis\" version.\n * It means Zag won't filter out any page item, allowing us to apply our own slicing logic.\n */\n const siblingCount = noEllipsis ? Infinity : Math.max(0, Math.floor((visiblePageItems - 5) / 2))\n\n const id = useId()\n\n const service = useMachine(pagination.machine, {\n id,\n count,\n siblingCount,\n pageSize,\n page,\n onPageChange,\n type,\n })\n\n const api = pagination.connect(service, normalizeProps)\n const pages = noEllipsis\n ? sliceArrayWithIndex(api.pages, api.page - 1, visiblePageItems)\n : api.pages\n\n return (\n <PaginationContext.Provider\n value={{\n type,\n pagination: {\n ...api,\n pages,\n // Extending ZagJS anatomy\n getFirstPageTriggerProps: () => {\n return {\n ...api.getPrevTriggerProps(),\n id: `${api.getRootProps().id}:first`,\n 'data-part': 'first-page-trigger',\n onClick: api.goToFirstPage,\n }\n },\n getLastPageTriggerProps: () => {\n return {\n ...api.getNextTriggerProps(),\n id: `${api.getRootProps().id}:last`,\n 'data-part': 'last-page-trigger',\n onClick: api.goToLastPage,\n }\n },\n },\n }}\n >\n {children}\n </PaginationContext.Provider>\n )\n}\n\nexport const usePagination = () => {\n const context = useContext(PaginationContext)\n\n if (!context) {\n throw Error('usePagination must be used within a Pagination provider')\n }\n\n return context\n}\n","import { ReactNode } from 'react'\n\nimport {\n PaginationProvider,\n type PaginationProviderProps,\n usePagination,\n} from './PaginationContext'\n\nexport type PaginationProps = PaginationProviderProps & { className?: string }\n\nexport const Pagination = ({\n children,\n visiblePageItems = 5,\n type = 'link',\n noEllipsis = false,\n className,\n ...rest\n}: PaginationProps) => {\n return (\n <PaginationProvider\n visiblePageItems={visiblePageItems}\n noEllipsis={noEllipsis}\n type={type}\n {...rest}\n >\n <PaginationWrapper className={className}>{children}</PaginationWrapper>\n </PaginationProvider>\n )\n}\n\nconst PaginationWrapper = ({\n children,\n className,\n}: {\n children: ReactNode\n className?: string\n}) => {\n const { pagination } = usePagination()\n\n const props = pagination.getRootProps()\n\n return (\n <nav data-spark-component=\"pagination\" {...props} className={className}>\n <ul className=\"gap-md flex flex-wrap\">{children}</ul>\n </nav>\n )\n}\n\nPagination.displayName = 'Pagination'\n","import { mergeProps } from '@zag-js/react'\nimport { cx } from 'class-variance-authority'\nimport { type ComponentPropsWithRef } from 'react'\n\nimport { usePagination } from './PaginationContext'\n\ninterface EllipsisProps extends ComponentPropsWithRef<'span'> {\n index: number\n}\n\nexport const Ellipsis = ({ children, index, className, ref, ...rest }: EllipsisProps) => {\n const { pagination } = usePagination()\n const apiProps = pagination.getEllipsisProps({ index })\n const localProps = {\n className: cx('flex size-sz-44 items-center justify-center', className),\n ...rest,\n }\n\n const mergedProps = mergeProps(apiProps, localProps)\n\n return (\n <li>\n <span data-spark-component=\"pagination-ellipsis\" ref={ref} {...mergedProps}>\n {children || '\\u2026'}\n </span>\n </li>\n )\n}\n\nEllipsis.displayName = 'Pagination.Ellipsis'\n","import { ArrowDoubleLeft } from '@spark-ui/icons/ArrowDoubleLeft'\nimport { mergeProps } from '@zag-js/react'\nimport { ComponentPropsWithoutRef, Ref } from 'react'\n\nimport { Icon } from '../icon'\nimport { IconButton } from '../icon-button'\nimport { usePagination } from './PaginationContext'\n\ntype AnchorProps = ComponentPropsWithoutRef<'a'> & {\n href: string\n asChild?: never\n}\n\ntype ButtonProps = ComponentPropsWithoutRef<'button'> & {\n /**\n * Change the component to the HTML tag or custom component of the only child.\n * Unavailable for anchor items (with `href` prop) since the component will already be rendered as an anchor element.\n */\n asChild?: boolean\n href?: never\n}\n\nexport type FirstPageTriggerProps = (AnchorProps | ButtonProps) & {\n 'aria-label': string\n ref?: Ref<HTMLButtonElement>\n}\n\nexport const FirstPageTrigger = ({\n children,\n className,\n href,\n ref,\n ...props\n}: FirstPageTriggerProps) => {\n const { pagination, type } = usePagination()\n\n // ZagJS props\n const apiProps = pagination.getFirstPageTriggerProps()\n\n const shouldDisableLink =\n type === 'link' &&\n (apiProps as typeof apiProps & { 'data-disabled'?: string })['data-disabled'] === ''\n\n // Locally managed props\n const localProps = {\n 'data-spark-component': 'pagination-first-page-trigger',\n intent: 'support',\n design: 'contrast',\n ...props,\n className,\n ...(shouldDisableLink && {\n disabled: true,\n role: 'link',\n 'aria-disabled': true,\n }),\n }\n\n // We know 'aria-label' is included in props\n type WithAriaLabel = Omit<typeof apiProps, 'aria-label'> & { 'aria-label': string }\n\n const mergedProps = mergeProps(\n apiProps,\n localProps as unknown as typeof apiProps\n ) as WithAriaLabel\n\n const content = children || (\n <Icon>\n <ArrowDoubleLeft />\n </Icon>\n )\n\n return (\n <li>\n {href ? (\n <IconButton ref={ref} {...mergedProps} asChild>\n <a href={shouldDisableLink ? undefined : href}>{content}</a>\n </IconButton>\n ) : (\n <IconButton ref={ref} {...mergedProps}>\n {content}\n </IconButton>\n )}\n </li>\n )\n}\n\nFirstPageTrigger.displayName = 'Pagination.FirstPageTrigger'\n","import { mergeProps } from '@zag-js/react'\nimport { cx } from 'class-variance-authority'\nimport { ComponentPropsWithoutRef, ReactElement, Ref } from 'react'\n\nimport { Button } from '../button'\nimport { usePagination } from './PaginationContext'\n\ntype AnchorProps = ComponentPropsWithoutRef<'a'> & {\n href: string\n asChild?: never\n}\n\ntype ButtonProps = ComponentPropsWithoutRef<'button'> & {\n /**\n * Change the component to the HTML tag or custom component of the only child.\n * Unavailable for anchor items (with `href` prop) since the component will already be rendered as an anchor element.\n */\n asChild?: boolean\n href?: never\n}\n\nexport type ItemProps = (AnchorProps | ButtonProps) & {\n 'aria-label': string\n value: number\n ref?: Ref<HTMLButtonElement>\n}\n\n/**\n * A numbered page item.\n * Should be used within `Pagination.Pages` to ensure proper functionality and accessibility.\n *\n * Can be rendered as an anchor or a button :\n * - Set a `href` prop to render the item as an anchor element.\n * - When using `href`, the `asChild` prop isn’t available since the component will already be rendered as an anchor element.\n */\nexport function Item({ children, value, className, href, ref, ...props }: ItemProps): ReactElement {\n const { pagination } = usePagination()\n\n // ZagJS props\n const apiProps = pagination.getItemProps({ type: 'page', value })\n\n // Locally managed props\n const localProps = {\n 'data-spark-component': 'pagination-item',\n intent: 'support',\n design: apiProps['aria-current'] === 'page' ? 'filled' : 'contrast',\n className: cx('size-sz-44', className),\n ...props,\n }\n\n const mergedProps = mergeProps(apiProps, localProps)\n\n return (\n <li>\n {href ? (\n <Button ref={ref} {...mergedProps} asChild>\n <a href={href}>{children || value}</a>\n </Button>\n ) : (\n <Button ref={ref} {...mergedProps}>\n {children || value}\n </Button>\n )}\n </li>\n )\n}\n\nItem.displayName = 'Pagination.Item'\n","import { ArrowDoubleRight } from '@spark-ui/icons/ArrowDoubleRight'\nimport { mergeProps } from '@zag-js/react'\nimport { ComponentPropsWithoutRef, Ref } from 'react'\n\nimport { Icon } from '../icon'\nimport { IconButton } from '../icon-button'\nimport { usePagination } from './PaginationContext'\n\ntype AnchorProps = ComponentPropsWithoutRef<'a'> & {\n href: string\n asChild?: never\n}\n\ntype ButtonProps = ComponentPropsWithoutRef<'button'> & {\n /**\n * Change the component to the HTML tag or custom component of the only child.\n * Unavailable for anchor items (with `href` prop) since the component will already be rendered as an anchor element.\n */\n asChild?: boolean\n href?: never\n}\n\nexport type LastPageTriggerProps = (AnchorProps | ButtonProps) & {\n 'aria-label': string\n ref?: Ref<HTMLButtonElement>\n}\n\nexport const LastPageTrigger = ({\n children,\n className,\n href,\n ref,\n ...props\n}: LastPageTriggerProps) => {\n const { pagination, type } = usePagination()\n\n // ZagJS props\n const apiProps = pagination.getLastPageTriggerProps()\n\n const shouldDisableLink =\n type === 'link' &&\n (apiProps as typeof apiProps & { 'data-disabled'?: string })['data-disabled'] === ''\n\n // Locally managed props\n const localProps = {\n 'data-spark-component': 'pagination-last-page-trigger',\n intent: 'support',\n design: 'contrast',\n ...props,\n className,\n ...(shouldDisableLink && {\n disabled: true,\n role: 'link',\n 'aria-disabled': true,\n }),\n }\n\n // We know 'aria-label' is included in props\n type WithAriaLabel = Omit<typeof apiProps, 'aria-label'> & { 'aria-label': string }\n\n const mergedProps = mergeProps(\n apiProps,\n localProps as unknown as typeof apiProps\n ) as WithAriaLabel\n\n const content = children || (\n <Icon>\n <ArrowDoubleRight />\n </Icon>\n )\n\n return (\n <li>\n {href ? (\n <IconButton ref={ref} {...mergedProps} asChild>\n <a href={shouldDisableLink ? undefined : href}>{content}</a>\n </IconButton>\n ) : (\n <IconButton ref={ref} {...mergedProps}>\n {content}\n </IconButton>\n )}\n </li>\n )\n}\n\nLastPageTrigger.displayName = 'Pagination.LastPageTrigger'\n","import { ArrowVerticalRight } from '@spark-ui/icons/ArrowVerticalRight'\nimport { mergeProps } from '@zag-js/react'\nimport { ComponentPropsWithoutRef, Ref } from 'react'\n\nimport { Icon } from '../icon'\nimport { IconButton } from '../icon-button'\nimport { usePagination } from './PaginationContext'\n\ntype AnchorProps = ComponentPropsWithoutRef<'a'> & {\n href: string\n asChild?: never\n}\n\ntype ButtonProps = ComponentPropsWithoutRef<'button'> & {\n /**\n * Change the component to the HTML tag or custom component of the only child.\n * Unavailable for anchor items (with `href` prop) since the component will already be rendered as an anchor element.\n */\n asChild?: boolean\n href?: never\n}\n\nexport type NextTriggerProps = (AnchorProps | ButtonProps) & {\n 'aria-label': string\n ref?: Ref<HTMLButtonElement>\n}\n\nexport const NextTrigger = ({ children, className, href, ref, ...props }: NextTriggerProps) => {\n const { pagination, type } = usePagination()\n\n // ZagJS props\n const apiProps = pagination.getNextTriggerProps()\n\n const shouldDisableLink =\n type === 'link' &&\n (apiProps as typeof apiProps & { 'data-disabled'?: string })['data-disabled'] === ''\n\n // Locally managed props\n const localProps = {\n 'data-spark-component': 'pagination-next-trigger',\n intent: 'support',\n design: 'contrast',\n ...props,\n className,\n ...(shouldDisableLink && {\n disabled: true,\n role: 'link',\n 'aria-disabled': true,\n }),\n }\n\n // We know 'aria-label' is included in props\n type WithAriaLabel = Omit<typeof apiProps, 'aria-label'> & { 'aria-label': string }\n\n const mergedProps = mergeProps(\n apiProps,\n localProps as unknown as typeof apiProps\n ) as WithAriaLabel\n\n const content = children || (\n <Icon>\n <ArrowVerticalRight />\n </Icon>\n )\n\n return (\n <li>\n {href ? (\n <IconButton ref={ref} {...mergedProps} asChild>\n <a href={shouldDisableLink ? undefined : href}>{content}</a>\n </IconButton>\n ) : (\n <IconButton ref={ref} {...mergedProps}>\n {content}\n </IconButton>\n )}\n </li>\n )\n}\n\nNextTrigger.displayName = 'Pagination.NextTrigger'\n","import * as pagination from '@zag-js/pagination'\nimport { ReactNode } from 'react'\n\nimport { usePagination } from './PaginationContext'\n\n// Extract the 'page' type element from the pagination API's 'pages' array.\ntype PageItem = Extract<pagination.Api['pages'][number], { type: 'page' }>\n\n// Define a type that conditionally tweaks the pagination API\n// based on the generic T parameter.\ntype TweakedPaginationApi<T extends 'noEllipsis' | ''> = Omit<pagination.Api, 'pages'> & {\n pages: T extends 'noEllipsis' ? PageItem[] : pagination.Api['pages']\n}\n\ninterface PagesProps<T extends 'noEllipsis' | ''> {\n children: (pagination: TweakedPaginationApi<T>) => ReactNode\n}\n\nexport const Pages = <T extends 'noEllipsis' | '' = ''>({ children }: PagesProps<T>) => {\n const { pagination } = usePagination()\n\n return children(pagination as TweakedPaginationApi<T>)\n}\n\nPages.displayName = 'Pagination.Pages'\n","import { ArrowVerticalLeft } from '@spark-ui/icons/ArrowVerticalLeft'\nimport { mergeProps } from '@zag-js/react'\nimport { ComponentPropsWithoutRef, Ref } from 'react'\n\nimport { Icon } from '../icon'\nimport { IconButton } from '../icon-button'\nimport { usePagination } from './PaginationContext'\n\ntype AnchorProps = ComponentPropsWithoutRef<'a'> & {\n href: string\n asChild?: never\n}\n\ntype ButtonProps = ComponentPropsWithoutRef<'button'> & {\n /**\n * Change the component to the HTML tag or custom component of the only child.\n * Unavailable for anchor items (with `href` prop) since the component will already be rendered as an anchor element.\n */\n asChild?: boolean\n href?: never\n}\n\nexport type PrevTriggerProps = (AnchorProps | ButtonProps) & {\n 'aria-label': string\n ref?: Ref<HTMLButtonElement>\n}\n\nexport const PrevTrigger = ({ children, className, href, ref, ...props }: PrevTriggerProps) => {\n const { pagination, type } = usePagination()\n\n // ZagJS props\n const apiProps = pagination.getPrevTriggerProps()\n\n const shouldDisableLink =\n type === 'link' &&\n (apiProps as typeof apiProps & { 'data-disabled'?: string })['data-disabled'] === ''\n\n // Locally managed props\n const localProps = {\n 'data-spark-component': 'pagination-prev-trigger',\n intent: 'support',\n design: 'contrast',\n ...props,\n className,\n ...(shouldDisableLink && {\n disabled: true,\n role: 'link',\n 'aria-disabled': true,\n }),\n }\n\n // We know 'aria-label' is included in props\n type WithAriaLabel = Omit<typeof apiProps, 'aria-label'> & { 'aria-label': string }\n\n const mergedProps = mergeProps(\n apiProps,\n localProps as unknown as typeof apiProps\n ) as WithAriaLabel\n\n const content = children || (\n <Icon>\n <ArrowVerticalLeft />\n </Icon>\n )\n\n return (\n <li>\n {href ? (\n <IconButton ref={ref} {...mergedProps} asChild>\n <a href={shouldDisableLink ? undefined : href}>{content}</a>\n </IconButton>\n ) : (\n <IconButton ref={ref} {...mergedProps}>\n {content}\n </IconButton>\n )}\n </li>\n )\n}\n\nPrevTrigger.displayName = 'Pagination.PrevTrigger'\n","import type { FC } from 'react'\n\nimport { Pagination as Root, type PaginationProps } from './Pagination'\nimport { Ellipsis } from './PaginationEllipsis'\nimport { FirstPageTrigger } from './PaginationFirstPageTrigger'\nimport { Item } from './PaginationItem'\nimport { LastPageTrigger } from './PaginationLastPageTrigger'\nimport { NextTrigger } from './PaginationNextTrigger'\nimport { Pages } from './PaginationPages'\nimport { PrevTrigger } from './PaginationPrevTrigger'\n\nexport const Pagination: FC<PaginationProps> & {\n PrevTrigger: typeof PrevTrigger\n NextTrigger: typeof NextTrigger\n Pages: typeof Pages\n Item: typeof Item\n Ellipsis: typeof Ellipsis\n FirstPageTrigger: typeof FirstPageTrigger\n LastPageTrigger: typeof LastPageTrigger\n} = Object.assign(Root, {\n PrevTrigger,\n NextTrigger,\n Pages,\n Item,\n Ellipsis,\n FirstPageTrigger,\n LastPageTrigger,\n})\n\nPagination.displayName = 'Pagination'\n\nPrevTrigger.displayName = 'Pagination.PrevTrigger'\nNextTrigger.displayName = 'Pagination.NextTrigger'\nPages.displayName = 'Pagination.Pages'\nItem.displayName = 'Pagination.Item'\nEllipsis.displayName = 'Pagination.Ellipsis'\nFirstPageTrigger.displayName = 'Pagination.FirstPageTrigger'\nLastPageTrigger.displayName = 'Pagination.LastPageTrigger'\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/pagination/utils.ts","../../src/pagination/PaginationContext.tsx","../../src/pagination/Pagination.tsx","../../src/pagination/PaginationEllipsis.tsx","../../src/pagination/PaginationFirstPageTrigger.tsx","../../src/pagination/PaginationItem.tsx","../../src/pagination/PaginationLastPageTrigger.tsx","../../src/pagination/PaginationNextTrigger.tsx","../../src/pagination/PaginationPages.tsx","../../src/pagination/PaginationPrevTrigger.tsx","../../src/pagination/index.ts"],"sourcesContent":["export function sliceArrayWithIndex(arr: any[], index: number, length: number) {\n const relativeElements = (length - 1) / 2\n\n let start = Math.max(0, index - relativeElements)\n let end = Math.min(arr.length, index + relativeElements + 1)\n\n if (end - start < length) {\n start = Math.max(0, Math.min(start, arr.length - length))\n end = Math.min(arr.length, start + length)\n }\n\n return arr.slice(start, end)\n}\n","import * as pagination from '@zag-js/pagination'\nimport { normalizeProps, type PropTypes, useMachine } from '@zag-js/react'\nimport { createContext, type ReactNode, useContext, useId } from 'react'\n\nimport { sliceArrayWithIndex } from './utils'\n\nexport interface PaginationContextState<T extends PropTypes = PropTypes> {\n type: pagination.Props['type']\n pagination: pagination.Api<T> & {\n getFirstPageTriggerProps: () => ReturnType<pagination.Api<T>['getPrevTriggerProps']> & {\n 'data-part': string\n onClick: () => void\n }\n getLastPageTriggerProps: () => ReturnType<pagination.Api<T>['getNextTriggerProps']> & {\n 'data-part': string\n onClick: () => void\n }\n }\n}\n\nconst PaginationContext = createContext<PaginationContextState | null>(null)\n\nexport interface PaginationProviderProps {\n children: ReactNode\n /**\n * Total number of data items available across all pages.\n */\n count: number\n /**\n * Maximum amount of items displayed on a single page.\n */\n pageSize: number\n /**\n * Number of visible pages (or ellipsis) between previous and next page triggers.\n */\n visiblePageItems?: number\n /**\n * The current page (active page)\n */\n page?: pagination.Props['page']\n /**\n * If your pagination contains buttons instead of links, set `type` to `button`, extra attributes will be applied on page items for a11y.\n */\n type?: pagination.Props['type']\n onPageChange?: pagination.Props['onPageChange']\n noEllipsis?: boolean\n}\n\nexport const PaginationProvider = ({\n children,\n count,\n visiblePageItems = 7,\n pageSize,\n page,\n onPageChange,\n noEllipsis,\n type = 'link',\n}: PaginationProviderProps) => {\n /**\n * Here `Infinity` is used because we apply a custom slice ourselves to manage the \"no ellipsis\" version.\n * It means Zag won't filter out any page item, allowing us to apply our own slicing logic.\n */\n const siblingCount = noEllipsis ? Infinity : Math.max(0, Math.floor((visiblePageItems - 5) / 2))\n\n const id = useId()\n\n const service = useMachine(pagination.machine, {\n id,\n count,\n siblingCount,\n pageSize,\n page,\n onPageChange,\n type,\n })\n\n const api = pagination.connect(service, normalizeProps)\n const pages = noEllipsis\n ? sliceArrayWithIndex(api.pages, api.page - 1, visiblePageItems)\n : api.pages\n\n return (\n <PaginationContext.Provider\n value={{\n type,\n pagination: {\n ...api,\n pages,\n // Extending ZagJS anatomy\n getFirstPageTriggerProps: () => {\n return {\n ...api.getPrevTriggerProps(),\n id: `${api.getRootProps().id}:first`,\n 'data-part': 'first-page-trigger',\n onClick: api.goToFirstPage,\n }\n },\n getLastPageTriggerProps: () => {\n return {\n ...api.getNextTriggerProps(),\n id: `${api.getRootProps().id}:last`,\n 'data-part': 'last-page-trigger',\n onClick: api.goToLastPage,\n }\n },\n },\n }}\n >\n {children}\n </PaginationContext.Provider>\n )\n}\n\nexport const usePagination = () => {\n const context = useContext(PaginationContext)\n\n if (!context) {\n throw Error('usePagination must be used within a Pagination provider')\n }\n\n return context\n}\n","import { ReactNode } from 'react'\n\nimport {\n PaginationProvider,\n type PaginationProviderProps,\n usePagination,\n} from './PaginationContext'\n\nexport type PaginationProps = PaginationProviderProps & { className?: string }\n\nexport const Pagination = ({\n children,\n visiblePageItems = 5,\n type = 'link',\n noEllipsis = false,\n className,\n ...rest\n}: PaginationProps) => {\n return (\n <PaginationProvider\n visiblePageItems={visiblePageItems}\n noEllipsis={noEllipsis}\n type={type}\n {...rest}\n >\n <PaginationWrapper className={className}>{children}</PaginationWrapper>\n </PaginationProvider>\n )\n}\n\nconst PaginationWrapper = ({\n children,\n className,\n}: {\n children: ReactNode\n className?: string\n}) => {\n const { pagination } = usePagination()\n\n const props = pagination.getRootProps()\n\n return (\n <nav data-spark-component=\"pagination\" {...props} className={className}>\n <ul className=\"gap-md flex flex-wrap\">{children}</ul>\n </nav>\n )\n}\n\nPagination.displayName = 'Pagination'\n","import { mergeProps } from '@zag-js/react'\nimport { cx } from 'class-variance-authority'\nimport { type ComponentPropsWithRef } from 'react'\n\nimport { usePagination } from './PaginationContext'\n\ninterface EllipsisProps extends ComponentPropsWithRef<'span'> {\n index: number\n}\n\nexport const Ellipsis = ({ children, index, className, ref, ...rest }: EllipsisProps) => {\n const { pagination } = usePagination()\n const apiProps = pagination.getEllipsisProps({ index })\n const localProps = {\n className: cx('flex size-sz-44 items-center justify-center', className),\n ...rest,\n }\n\n const mergedProps = mergeProps(apiProps, localProps)\n\n return (\n <li>\n <span data-spark-component=\"pagination-ellipsis\" ref={ref} {...mergedProps}>\n {children || '\\u2026'}\n </span>\n </li>\n )\n}\n\nEllipsis.displayName = 'Pagination.Ellipsis'\n","import { ArrowDoubleLeft } from '@spark-ui/icons/ArrowDoubleLeft'\nimport { mergeProps } from '@zag-js/react'\nimport { ComponentPropsWithoutRef, Ref } from 'react'\n\nimport { Icon } from '../icon'\nimport { IconButton } from '../icon-button'\nimport { usePagination } from './PaginationContext'\n\ntype AnchorProps = ComponentPropsWithoutRef<'a'> & {\n href: string\n asChild?: never\n}\n\ntype ButtonProps = ComponentPropsWithoutRef<'button'> & {\n /**\n * Change the component to the HTML tag or custom component of the only child.\n * Unavailable for anchor items (with `href` prop) since the component will already be rendered as an anchor element.\n */\n asChild?: boolean\n href?: never\n}\n\nexport type FirstPageTriggerProps = (AnchorProps | ButtonProps) & {\n 'aria-label': string\n ref?: Ref<HTMLButtonElement>\n}\n\nexport const FirstPageTrigger = ({\n children,\n className,\n href,\n ref,\n ...props\n}: FirstPageTriggerProps) => {\n const { pagination, type } = usePagination()\n\n // ZagJS props\n const apiProps = pagination.getFirstPageTriggerProps()\n\n const shouldDisableLink =\n type === 'link' &&\n (apiProps as typeof apiProps & { 'data-disabled'?: string })['data-disabled'] === ''\n\n // Locally managed props\n const localProps = {\n 'data-spark-component': 'pagination-first-page-trigger',\n intent: 'support',\n design: 'contrast',\n ...props,\n className,\n ...(shouldDisableLink && {\n disabled: true,\n role: 'link',\n 'aria-disabled': true,\n }),\n }\n\n // We know 'aria-label' is included in props\n type WithAriaLabel = Omit<typeof apiProps, 'aria-label'> & { 'aria-label': string }\n\n const mergedProps = mergeProps(\n apiProps,\n localProps as unknown as typeof apiProps\n ) as WithAriaLabel\n\n const content = children || (\n <Icon>\n <ArrowDoubleLeft />\n </Icon>\n )\n\n return (\n <li>\n {href ? (\n <IconButton ref={ref} {...mergedProps} asChild>\n <a href={shouldDisableLink ? undefined : href}>{content}</a>\n </IconButton>\n ) : (\n <IconButton ref={ref} {...mergedProps}>\n {content}\n </IconButton>\n )}\n </li>\n )\n}\n\nFirstPageTrigger.displayName = 'Pagination.FirstPageTrigger'\n","import { mergeProps } from '@zag-js/react'\nimport { cx } from 'class-variance-authority'\nimport { ComponentPropsWithoutRef, ReactElement, Ref } from 'react'\n\nimport { Button } from '../button'\nimport { usePagination } from './PaginationContext'\n\ntype AnchorProps = ComponentPropsWithoutRef<'a'> & {\n href: string\n asChild?: never\n}\n\ntype ButtonProps = ComponentPropsWithoutRef<'button'> & {\n /**\n * Change the component to the HTML tag or custom component of the only child.\n * Unavailable for anchor items (with `href` prop) since the component will already be rendered as an anchor element.\n */\n asChild?: boolean\n href?: never\n}\n\nexport type ItemProps = (AnchorProps | ButtonProps) & {\n 'aria-label': string\n value: number\n ref?: Ref<HTMLButtonElement>\n}\n\n/**\n * A numbered page item.\n * Should be used within `Pagination.Pages` to ensure proper functionality and accessibility.\n *\n * Can be rendered as an anchor or a button :\n * - Set a `href` prop to render the item as an anchor element.\n * - When using `href`, the `asChild` prop isn’t available since the component will already be rendered as an anchor element.\n */\nexport function Item({ children, value, className, href, ref, ...props }: ItemProps): ReactElement {\n const { pagination } = usePagination()\n\n // ZagJS props\n const apiProps = pagination.getItemProps({ type: 'page', value })\n\n // Locally managed props\n const localProps = {\n 'data-spark-component': 'pagination-item',\n intent: 'support',\n design: apiProps['aria-current'] === 'page' ? 'filled' : 'contrast',\n className: cx('size-sz-44', className),\n ...props,\n }\n\n const mergedProps = mergeProps(apiProps, localProps)\n\n return (\n <li>\n {href ? (\n <Button ref={ref} {...mergedProps} asChild>\n <a href={href}>{children || value}</a>\n </Button>\n ) : (\n <Button ref={ref} {...mergedProps}>\n {children || value}\n </Button>\n )}\n </li>\n )\n}\n\nItem.displayName = 'Pagination.Item'\n","import { ArrowDoubleRight } from '@spark-ui/icons/ArrowDoubleRight'\nimport { mergeProps } from '@zag-js/react'\nimport { ComponentPropsWithoutRef, Ref } from 'react'\n\nimport { Icon } from '../icon'\nimport { IconButton } from '../icon-button'\nimport { usePagination } from './PaginationContext'\n\ntype AnchorProps = ComponentPropsWithoutRef<'a'> & {\n href: string\n asChild?: never\n}\n\ntype ButtonProps = ComponentPropsWithoutRef<'button'> & {\n /**\n * Change the component to the HTML tag or custom component of the only child.\n * Unavailable for anchor items (with `href` prop) since the component will already be rendered as an anchor element.\n */\n asChild?: boolean\n href?: never\n}\n\nexport type LastPageTriggerProps = (AnchorProps | ButtonProps) & {\n 'aria-label': string\n ref?: Ref<HTMLButtonElement>\n}\n\nexport const LastPageTrigger = ({\n children,\n className,\n href,\n ref,\n ...props\n}: LastPageTriggerProps) => {\n const { pagination, type } = usePagination()\n\n // ZagJS props\n const apiProps = pagination.getLastPageTriggerProps()\n\n const shouldDisableLink =\n type === 'link' &&\n (apiProps as typeof apiProps & { 'data-disabled'?: string })['data-disabled'] === ''\n\n // Locally managed props\n const localProps = {\n 'data-spark-component': 'pagination-last-page-trigger',\n intent: 'support',\n design: 'contrast',\n ...props,\n className,\n ...(shouldDisableLink && {\n disabled: true,\n role: 'link',\n 'aria-disabled': true,\n }),\n }\n\n // We know 'aria-label' is included in props\n type WithAriaLabel = Omit<typeof apiProps, 'aria-label'> & { 'aria-label': string }\n\n const mergedProps = mergeProps(\n apiProps,\n localProps as unknown as typeof apiProps\n ) as WithAriaLabel\n\n const content = children || (\n <Icon>\n <ArrowDoubleRight />\n </Icon>\n )\n\n return (\n <li>\n {href ? (\n <IconButton ref={ref} {...mergedProps} asChild>\n <a href={shouldDisableLink ? undefined : href}>{content}</a>\n </IconButton>\n ) : (\n <IconButton ref={ref} {...mergedProps}>\n {content}\n </IconButton>\n )}\n </li>\n )\n}\n\nLastPageTrigger.displayName = 'Pagination.LastPageTrigger'\n","import { ArrowVerticalRight } from '@spark-ui/icons/ArrowVerticalRight'\nimport { mergeProps } from '@zag-js/react'\nimport { ComponentPropsWithoutRef, Ref } from 'react'\n\nimport { Icon } from '../icon'\nimport { IconButton } from '../icon-button'\nimport { usePagination } from './PaginationContext'\n\ntype AnchorProps = ComponentPropsWithoutRef<'a'> & {\n href: string\n asChild?: never\n}\n\ntype ButtonProps = ComponentPropsWithoutRef<'button'> & {\n /**\n * Change the component to the HTML tag or custom component of the only child.\n * Unavailable for anchor items (with `href` prop) since the component will already be rendered as an anchor element.\n */\n asChild?: boolean\n href?: never\n}\n\nexport type NextTriggerProps = (AnchorProps | ButtonProps) & {\n 'aria-label': string\n ref?: Ref<HTMLButtonElement>\n}\n\nexport const NextTrigger = ({ children, className, href, ref, ...props }: NextTriggerProps) => {\n const { pagination, type } = usePagination()\n\n // ZagJS props\n const apiProps = pagination.getNextTriggerProps()\n\n const shouldDisableLink =\n type === 'link' &&\n (apiProps as typeof apiProps & { 'data-disabled'?: string })['data-disabled'] === ''\n\n // Locally managed props\n const localProps = {\n 'data-spark-component': 'pagination-next-trigger',\n intent: 'support',\n design: 'contrast',\n ...props,\n className,\n ...(shouldDisableLink && {\n disabled: true,\n role: 'link',\n 'aria-disabled': true,\n }),\n }\n\n // We know 'aria-label' is included in props\n type WithAriaLabel = Omit<typeof apiProps, 'aria-label'> & { 'aria-label': string }\n\n const mergedProps = mergeProps(\n apiProps,\n localProps as unknown as typeof apiProps\n ) as WithAriaLabel\n\n const content = children || (\n <Icon>\n <ArrowVerticalRight />\n </Icon>\n )\n\n return (\n <li>\n {href ? (\n <IconButton ref={ref} {...mergedProps} asChild>\n <a href={shouldDisableLink ? undefined : href}>{content}</a>\n </IconButton>\n ) : (\n <IconButton ref={ref} {...mergedProps}>\n {content}\n </IconButton>\n )}\n </li>\n )\n}\n\nNextTrigger.displayName = 'Pagination.NextTrigger'\n","import * as pagination from '@zag-js/pagination'\nimport { ReactNode } from 'react'\n\nimport { usePagination } from './PaginationContext'\n\n// Extract the 'page' type element from the pagination API's 'pages' array.\ntype PageItem = Extract<pagination.Api['pages'][number], { type: 'page' }>\n\n// Define a type that conditionally tweaks the pagination API\n// based on the generic T parameter.\ntype TweakedPaginationApi<T extends 'noEllipsis' | ''> = Omit<pagination.Api, 'pages'> & {\n pages: T extends 'noEllipsis' ? PageItem[] : pagination.Api['pages']\n}\n\ninterface PagesProps<T extends 'noEllipsis' | ''> {\n children: (pagination: TweakedPaginationApi<T>) => ReactNode\n}\n\nexport const Pages = <T extends 'noEllipsis' | '' = ''>({ children }: PagesProps<T>) => {\n const { pagination } = usePagination()\n\n return children(pagination as TweakedPaginationApi<T>)\n}\n\nPages.displayName = 'Pagination.Pages'\n","import { ArrowVerticalLeft } from '@spark-ui/icons/ArrowVerticalLeft'\nimport { mergeProps } from '@zag-js/react'\nimport { ComponentPropsWithoutRef, Ref } from 'react'\n\nimport { Icon } from '../icon'\nimport { IconButton } from '../icon-button'\nimport { usePagination } from './PaginationContext'\n\ntype AnchorProps = ComponentPropsWithoutRef<'a'> & {\n href: string\n asChild?: never\n}\n\ntype ButtonProps = ComponentPropsWithoutRef<'button'> & {\n /**\n * Change the component to the HTML tag or custom component of the only child.\n * Unavailable for anchor items (with `href` prop) since the component will already be rendered as an anchor element.\n */\n asChild?: boolean\n href?: never\n}\n\nexport type PrevTriggerProps = (AnchorProps | ButtonProps) & {\n 'aria-label': string\n ref?: Ref<HTMLButtonElement>\n}\n\nexport const PrevTrigger = ({ children, className, href, ref, ...props }: PrevTriggerProps) => {\n const { pagination, type } = usePagination()\n\n // ZagJS props\n const apiProps = pagination.getPrevTriggerProps()\n\n const shouldDisableLink =\n type === 'link' &&\n (apiProps as typeof apiProps & { 'data-disabled'?: string })['data-disabled'] === ''\n\n // Locally managed props\n const localProps = {\n 'data-spark-component': 'pagination-prev-trigger',\n intent: 'support',\n design: 'contrast',\n ...props,\n className,\n ...(shouldDisableLink && {\n disabled: true,\n role: 'link',\n 'aria-disabled': true,\n }),\n }\n\n // We know 'aria-label' is included in props\n type WithAriaLabel = Omit<typeof apiProps, 'aria-label'> & { 'aria-label': string }\n\n const mergedProps = mergeProps(\n apiProps,\n localProps as unknown as typeof apiProps\n ) as WithAriaLabel\n\n const content = children || (\n <Icon>\n <ArrowVerticalLeft />\n </Icon>\n )\n\n return (\n <li>\n {href ? (\n <IconButton ref={ref} {...mergedProps} asChild>\n <a href={shouldDisableLink ? undefined : href}>{content}</a>\n </IconButton>\n ) : (\n <IconButton ref={ref} {...mergedProps}>\n {content}\n </IconButton>\n )}\n </li>\n )\n}\n\nPrevTrigger.displayName = 'Pagination.PrevTrigger'\n","import type { FC } from 'react'\n\nimport { Pagination as Root, type PaginationProps } from './Pagination'\nimport { Ellipsis } from './PaginationEllipsis'\nimport { FirstPageTrigger } from './PaginationFirstPageTrigger'\nimport { Item } from './PaginationItem'\nimport { LastPageTrigger } from './PaginationLastPageTrigger'\nimport { NextTrigger } from './PaginationNextTrigger'\nimport { Pages } from './PaginationPages'\nimport { PrevTrigger } from './PaginationPrevTrigger'\n\n/**\n * A navigation component that allows users to navigate through multiple pages of content.\n */\nexport const Pagination: FC<PaginationProps> & {\n PrevTrigger: typeof PrevTrigger\n NextTrigger: typeof NextTrigger\n Pages: typeof Pages\n Item: typeof Item\n Ellipsis: typeof Ellipsis\n FirstPageTrigger: typeof FirstPageTrigger\n LastPageTrigger: typeof LastPageTrigger\n} = Object.assign(Root, {\n PrevTrigger,\n NextTrigger,\n Pages,\n Item,\n Ellipsis,\n FirstPageTrigger,\n LastPageTrigger,\n})\n\nPagination.displayName = 'Pagination'\n\nPrevTrigger.displayName = 'Pagination.PrevTrigger'\nNextTrigger.displayName = 'Pagination.NextTrigger'\nPages.displayName = 'Pagination.Pages'\nItem.displayName = 'Pagination.Item'\nEllipsis.displayName = 'Pagination.Ellipsis'\nFirstPageTrigger.displayName = 'Pagination.FirstPageTrigger'\nLastPageTrigger.displayName = 'Pagination.LastPageTrigger'\n"],"mappings":"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"}