@seekalfred/primitives 0.7.1 → 0.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +255 -5
- package/dist/alert/alert.d.ts +49 -4
- package/dist/alert/alert.js +66 -38
- package/dist/alert/alert.js.map +1 -1
- package/dist/alert/index.d.ts +2 -2
- package/dist/alert/index.js +2 -2
- package/dist/alert-dialog/alert-dialog.d.ts +31 -4
- package/dist/alert-dialog/alert-dialog.js +75 -26
- package/dist/alert-dialog/alert-dialog.js.map +1 -1
- package/dist/announcement-bar/announcement-bar.d.ts +15 -4
- package/dist/announcement-bar/announcement-bar.js +31 -6
- package/dist/announcement-bar/announcement-bar.js.map +1 -1
- package/dist/avatar/avatar.d.ts +7 -0
- package/dist/avatar/avatar.js +33 -12
- package/dist/avatar/avatar.js.map +1 -1
- package/dist/badge/badge.d.ts +1 -1
- package/dist/bar-chart/bar-chart-series.d.ts +75 -0
- package/dist/bar-chart/bar-chart-series.js +401 -0
- package/dist/bar-chart/bar-chart-series.js.map +1 -0
- package/dist/bar-chart/bar-chart.d.ts +25 -1
- package/dist/bar-chart/bar-chart.js +26 -1
- package/dist/bar-chart/bar-chart.js.map +1 -1
- package/dist/bar-chart/index.d.ts +2 -1
- package/dist/button/button.d.ts +1 -1
- package/dist/calendar/calendar.d.ts +1 -1
- package/dist/card/card.d.ts +22 -1
- package/dist/card/card.js +60 -7
- package/dist/card/card.js.map +1 -1
- package/dist/carousel/carousel.d.ts +21 -0
- package/dist/carousel/carousel.js +34 -8
- package/dist/carousel/carousel.js.map +1 -1
- package/dist/chip-group/chip-group.d.ts +11 -0
- package/dist/chip-group/chip-group.js +50 -34
- package/dist/chip-group/chip-group.js.map +1 -1
- package/dist/chip-group/index.d.ts +2 -2
- package/dist/copy-button/copy-button.d.ts +37 -5
- package/dist/copy-button/copy-button.js +35 -11
- package/dist/copy-button/copy-button.js.map +1 -1
- package/dist/donut-chart/donut-chart.d.ts +22 -0
- package/dist/donut-chart/donut-chart.js +35 -18
- package/dist/donut-chart/donut-chart.js.map +1 -1
- package/dist/donut-chart/index.d.ts +2 -2
- package/dist/empty-state/empty-state.d.ts +21 -0
- package/dist/empty-state/empty-state.js +16 -4
- package/dist/empty-state/empty-state.js.map +1 -1
- package/dist/empty-state/index.d.ts +2 -2
- package/dist/empty-state/index.js +2 -2
- package/dist/file-drop-zone/file-drop-zone.d.ts +29 -3
- package/dist/file-drop-zone/file-drop-zone.js +26 -8
- package/dist/file-drop-zone/file-drop-zone.js.map +1 -1
- package/dist/filter-bar/filter-bar.d.ts +4 -1
- package/dist/filter-bar/filter-bar.js +53 -9
- package/dist/filter-bar/filter-bar.js.map +1 -1
- package/dist/gauge/gauge.d.ts +18 -1
- package/dist/gauge/gauge.js +35 -21
- package/dist/gauge/gauge.js.map +1 -1
- package/dist/gauge/index.d.ts +2 -2
- package/dist/index.d.ts +15 -14
- package/dist/index.js +9 -9
- package/dist/input/input.d.ts +7 -0
- package/dist/input/input.js +7 -5
- package/dist/input/input.js.map +1 -1
- package/dist/lib/field-shell.js +6 -3
- package/dist/lib/field-shell.js.map +1 -1
- package/dist/lib/field-surface.js +22 -1
- package/dist/lib/field-surface.js.map +1 -1
- package/dist/lib/required-marker.js +20 -0
- package/dist/lib/required-marker.js.map +1 -0
- package/dist/lib/use-copy-feedback.js +17 -3
- package/dist/lib/use-copy-feedback.js.map +1 -1
- package/dist/line-chart/index.d.ts +2 -2
- package/dist/line-chart/line-chart.d.ts +144 -2
- package/dist/line-chart/line-chart.js +314 -46
- package/dist/line-chart/line-chart.js.map +1 -1
- package/dist/money-input/index.d.ts +2 -2
- package/dist/money-input/money-input.d.ts +36 -1
- package/dist/money-input/money-input.js +30 -14
- package/dist/money-input/money-input.js.map +1 -1
- package/dist/morph-select/morph-select.d.ts +26 -1
- package/dist/morph-select/morph-select.js +28 -6
- package/dist/morph-select/morph-select.js.map +1 -1
- package/dist/multi-select/index.d.ts +2 -2
- package/dist/multi-select/index.js +2 -2
- package/dist/multi-select/multi-select.d.ts +74 -2
- package/dist/multi-select/multi-select.js +213 -39
- package/dist/multi-select/multi-select.js.map +1 -1
- package/dist/password-field/password-field.d.ts +16 -0
- package/dist/password-field/password-field.js +37 -8
- package/dist/password-field/password-field.js.map +1 -1
- package/dist/popover/index.d.ts +2 -2
- package/dist/popover/index.js +2 -2
- package/dist/popover/popover.d.ts +39 -2
- package/dist/popover/popover.js +29 -2
- package/dist/popover/popover.js.map +1 -1
- package/dist/progress/index.d.ts +2 -2
- package/dist/progress/index.js +2 -2
- package/dist/progress/progress.d.ts +68 -3
- package/dist/progress/progress.js +156 -39
- package/dist/progress/progress.js.map +1 -1
- package/dist/radio-group/index.d.ts +2 -2
- package/dist/radio-group/index.js +2 -2
- package/dist/radio-group/radio-group.d.ts +33 -3
- package/dist/radio-group/radio-group.js +109 -9
- package/dist/radio-group/radio-group.js.map +1 -1
- package/dist/scroll-area/scroll-area.js +4 -3
- package/dist/scroll-area/scroll-area.js.map +1 -1
- package/dist/scrub-input/scrub-input.d.ts +11 -1
- package/dist/scrub-input/scrub-input.js +22 -10
- package/dist/scrub-input/scrub-input.js.map +1 -1
- package/dist/search-field/search-field.d.ts +22 -1
- package/dist/search-field/search-field.js +22 -7
- package/dist/search-field/search-field.js.map +1 -1
- package/dist/select/select.d.ts +10 -1
- package/dist/select/select.js +11 -8
- package/dist/select/select.js.map +1 -1
- package/dist/separator/separator.d.ts +21 -9
- package/dist/separator/separator.js +33 -11
- package/dist/separator/separator.js.map +1 -1
- package/dist/sparkline/sparkline.d.ts +27 -2
- package/dist/sparkline/sparkline.js +115 -18
- package/dist/sparkline/sparkline.js.map +1 -1
- package/dist/stat-card/index.d.ts +2 -2
- package/dist/stat-card/index.js +2 -2
- package/dist/stat-card/stat-card.d.ts +65 -1
- package/dist/stat-card/stat-card.js +98 -25
- package/dist/stat-card/stat-card.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/table/index.d.ts +2 -2
- package/dist/table/index.js +2 -2
- package/dist/table/table.d.ts +115 -5
- package/dist/table/table.js +374 -94
- package/dist/table/table.js.map +1 -1
- package/dist/text-shimmer/text-shimmer.d.ts +18 -2
- package/dist/text-shimmer/text-shimmer.js +5 -2
- package/dist/text-shimmer/text-shimmer.js.map +1 -1
- package/dist/textarea/textarea.d.ts +7 -0
- package/dist/textarea/textarea.js +3 -1
- package/dist/textarea/textarea.js.map +1 -1
- package/dist/time-picker/time-picker.d.ts +36 -1
- package/dist/time-picker/time-picker.js +33 -5
- package/dist/time-picker/time-picker.js.map +1 -1
- package/dist/toast/toast.d.ts +2 -2
- package/dist/usage-meter/index.d.ts +2 -2
- package/dist/usage-meter/usage-meter.d.ts +30 -0
- package/dist/usage-meter/usage-meter.js +56 -38
- package/dist/usage-meter/usage-meter.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"money-input.js","names":["AriaGroup","AriaInput","AriaSelect","AriaButton","AriaSelectValue","AriaPopover","AriaListBox","Button"],"sources":["../../src/money-input/money-input.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n forwardRef,\n useCallback,\n useId,\n useImperativeHandle,\n useMemo,\n useReducer,\n useRef,\n useState,\n type ClipboardEvent,\n type FocusEvent,\n type KeyboardEvent,\n} from \"react\";\nimport {\n Button as AriaButton,\n Group as AriaGroup,\n Input as AriaInput,\n ListBox as AriaListBox,\n Popover as AriaPopover,\n Select as AriaSelect,\n SelectValue as AriaSelectValue,\n type Key,\n} from \"react-aria-components\";\n\nimport { Button } from \"../button/button.js\";\nimport { cn, cnAll } from \"../lib/cn.js\";\nimport { FieldShell, useFieldWiring } from \"../lib/field-shell.js\";\nimport { RollingNumber } from \"../lib/field-message.js\";\nimport { fieldSurfaceVariants } from \"../lib/field-surface.js\";\nimport { useIsomorphicLayoutEffect, useMorphWidth } from \"../lib/motion.js\";\nimport { SwapText } from \"../lib/swap-text.js\";\nimport { SelectItem, selectPopoverVariants } from \"../select/select.js\";\n\n/** What `onValueChange` hands over beside the minor-unit amount. */\nexport interface MoneyInputDetails {\n currency: string;\n /** The amount in major units, such as 12.5 for $12.50. */\n major: number | null;\n /** The amount as a full currency string, such as \"$12.50\". */\n formatted: string;\n}\n\n/**\n * MoneyInput: a currency amount. The value is in minor units, so $12.50 is 1250\n * and 500 yen is 500. Digits group as they are typed without moving the caret,\n * the cents that are still missing wait as muted ghosts so the amount never\n * changes width when it settles, a long amount scales down to fit instead of\n * scrolling, and the quick-add buttons and the arrow keys roll the digits. A\n * currency menu switches the currency (pass one code to hide it); the symbol\n * swaps in place and the digits are kept. Amounts and the currency come from\n * `Intl.NumberFormat`, so the symbol, its side, the grouping and the number of\n * decimals follow the currency and the locale.\n *\n * `min` is checked when the field loses focus; `max` is enforced as you type: a\n * digit that would pass it is refused and the amount strains toward it. Wording\n * for the range comes from the currency, and `error` replaces it.\n */\nexport interface MoneyInputProps {\n /** What the amount is, and the field's accessible name. */\n label: string;\n /** Render the label for screen readers only. */\n labelHidden?: boolean;\n /** Amount in minor units (cents for USD, yen for JPY). `null` is empty. */\n value?: number | null;\n defaultValue?: number | null;\n onValueChange?: (value: number | null, details: MoneyInputDetails) => void;\n /** ISO 4217 code, such as \"USD\". */\n currency?: string;\n defaultCurrency?: string;\n onCurrencyChange?: (currency: string) => void;\n /** Codes offered by the currency menu. Pass one code to hide the menu. */\n currencies?: string[];\n /** Lowest amount in minor units. Checked when the field loses focus. */\n min?: number;\n /** Highest amount in minor units. Typing past it is refused with a nudge. */\n max?: number;\n /** Quick-add buttons in major units. Pass an empty array to hide them. */\n quickAdd?: number[];\n /** Arrow keys move by this many minor units. Defaults to one major unit; Shift moves ten times as far. */\n step?: number;\n /** Formatting locale. Fixed by default so server and client render the same digits. */\n locale?: string;\n /** Helper text under the field. A string, because the copy is animated word by word. */\n description?: string;\n /** Replaces the built-in range message. */\n error?: string;\n disabled?: boolean;\n /** Adds a hidden input carrying the amount in minor units. */\n name?: string;\n id?: string;\n /** Extra classes for the wrapper. Merged last. */\n className?: string;\n onBlur?: (event: FocusEvent<HTMLInputElement>) => void;\n}\n\ntype Source = \"type\" | \"chip\" | \"key\" | \"external\";\ninterface CurrencyInfo {\n code: string;\n symbol: string;\n position: \"prefix\" | \"suffix\";\n digits: number;\n name: string;\n whole: Intl.NumberFormat;\n full: Intl.NumberFormat;\n}\n\nconst MAX_INTEGER_DIGITS = 12;\n/** How far, in px, the amount is pushed toward a limit it just met. */\nconst STRAIN_PX = 6;\n\nconst infoCache = new Map<string, CurrencyInfo>();\nfunction currencyInfo(code: string, locale: string): CurrencyInfo {\n const cacheKey = `${locale}:${code}`;\n const cached = infoCache.get(cacheKey);\n if (cached) return cached;\n const full = new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency: code,\n currencyDisplay: \"narrowSymbol\",\n numberingSystem: \"latn\",\n });\n const parts = full.formatToParts(1);\n const symbolAt = parts.findIndex((part) => part.type === \"currency\");\n const numberAt = parts.findIndex((part) => part.type === \"integer\");\n const digits = full.resolvedOptions().maximumFractionDigits ?? 2;\n let name = code;\n try {\n name = new Intl.DisplayNames([locale], { type: \"currency\" }).of(code) ?? code;\n } catch {\n // Older engines keep the code.\n }\n const info: CurrencyInfo = {\n code,\n symbol: parts[symbolAt]?.value ?? code,\n position: symbolAt < numberAt ? \"prefix\" : \"suffix\",\n digits,\n name: name.charAt(0).toUpperCase() + name.slice(1),\n full,\n whole: new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency: code,\n currencyDisplay: \"narrowSymbol\",\n maximumFractionDigits: 0,\n numberingSystem: \"latn\",\n }),\n };\n infoCache.set(cacheKey, info);\n return info;\n}\n\nfunction localeSymbols(locale: string) {\n const parts = new Intl.NumberFormat(locale, { numberingSystem: \"latn\" }).formatToParts(12345.6);\n return {\n group: parts.find((part) => part.type === \"group\")?.value ?? \",\",\n decimal: parts.find((part) => part.type === \"decimal\")?.value ?? \".\",\n };\n}\n\n/* A draft is the amount as typed in a canonical form: digits with an optional \".\", such as \"1234.5\". */\nconst pow10 = (digits: number) => 10 ** digits;\nfunction toMinor(draft: string, digits: number): number | null {\n if (!draft) return null;\n const [whole, fraction = \"\"] = draft.split(\".\");\n return (\n Number(whole || \"0\") * pow10(digits) + Number(fraction.padEnd(digits, \"0\").slice(0, digits) || \"0\")\n );\n}\nfunction fromMinor(minor: number | null | undefined, digits: number) {\n if (minor === null || minor === undefined || !Number.isFinite(minor)) return \"\";\n const text = String(Math.round(Math.abs(minor))).padStart(digits + 1, \"0\");\n return digits ? `${text.slice(0, text.length - digits)}.${text.slice(text.length - digits)}` : text;\n}\n/** Settles a draft the way it will be read back: fraction padded to the currency, leading zeros gone. */\nfunction settle(draft: string, digits: number) {\n return draft ? fromMinor(toMinor(draft, digits), digits) : \"\";\n}\n/** Carries an amount across currencies with different minor units, keeping the major amount. */\nfunction convertDraft(draft: string, digits: number) {\n if (!draft) return \"\";\n const [whole = \"\", fraction] = draft.split(\".\");\n if (!digits) return whole || \"0\";\n return fraction === undefined ? whole : `${whole}.${fraction.slice(0, digits)}`;\n}\n\nconst groupInteger = (whole: string, group: string) =>\n whole.replace(/\\B(?=(\\d{3})+(?!\\d))/g, group);\nfunction displayOf(draft: string, symbols: { group: string; decimal: string }) {\n if (!draft) return \"\";\n const [whole = \"\", fraction] = draft.split(\".\");\n return groupInteger(whole, symbols.group) + (fraction !== undefined ? symbols.decimal + fraction : \"\");\n}\n\nconst isSignificant = (char: string, decimal: string) => /\\d/.test(char) || char === decimal;\nfunction positionAfter(text: string, count: number, decimal: string) {\n if (count <= 0) return 0;\n let seen = 0;\n for (let index = 0; index < text.length; index++) {\n if (isSignificant(text[index]!, decimal) && ++seen === count) return index + 1;\n }\n return text.length;\n}\n\n/** The currency symbol swaps with a short rise while its slot springs to the new width. */\nfunction SymbolSlot({ symbol, side }: { symbol: string; side: \"prefix\" | \"suffix\" }) {\n const content = useRef<HTMLSpanElement>(null);\n useMorphWidth(content, symbol);\n return (\n <span\n aria-hidden=\"true\"\n data-slot=\"money-input-symbol\"\n className={cnAll(\"button-slot text-text-secondary\", side === \"prefix\" ? \"me-1\" : \"ms-1.5\")}\n >\n <span ref={content} className=\"inline-flex flex-none items-center whitespace-pre\">\n <SwapText swapKey={symbol} motion=\"rise\" className=\"inline-block\">\n {symbol}\n </SwapText>\n </span>\n </span>\n );\n}\n\n/** The amount the eye sees: whole part, separator and the cents, with the missing ones as muted ghosts. */\nfunction Amount({\n draft,\n digits,\n symbols,\n direction,\n still,\n}: {\n draft: string;\n digits: number;\n symbols: { group: string; decimal: string };\n direction: 1 | -1;\n still: boolean;\n}) {\n const [whole = \"\", fraction] = draft ? draft.split(\".\") : [];\n const typed = fraction ?? \"\";\n const ghostWhole = !whole;\n return (\n <>\n <span data-ghost={ghostWhole || undefined} className=\"inline-flex data-[ghost]:text-muted-foreground\">\n <RollingNumber\n word={groupInteger(whole || \"0\", symbols.group)}\n direction={direction}\n still={still}\n />\n </span>\n {digits > 0 ? (\n <>\n <span\n data-ghost={fraction === undefined || undefined}\n className=\"data-[ghost]:text-muted-foreground\"\n >\n {symbols.decimal}\n </span>\n {typed ? (\n <span className=\"inline-flex\">\n <RollingNumber word={typed} direction={direction} still={still} />\n </span>\n ) : null}\n {typed.length < digits ? (\n <span className=\"text-muted-foreground\">{\"0\".repeat(digits - typed.length)}</span>\n ) : null}\n </>\n ) : null}\n </>\n );\n}\n\nconst triggerClass =\n \"inline-flex h-9 flex-none cursor-pointer items-center gap-1 rounded-pill border-0 bg-transparent ps-3 pe-2 font-sans text-sm font-medium tabular-nums text-foreground outline-none motion-safe:transition-[background-color] motion-safe:duration-(--duration-quick) motion-safe:ease-settle data-[hovered]:bg-muted data-[pressed]:bg-muted data-[disabled]:cursor-not-allowed data-[focus-visible]:outline-solid data-[focus-visible]:outline-(length:--focus-ring-width) data-[focus-visible]:outline-offset-(--focus-ring-offset) data-[focus-visible]:outline-(--color-ring)\";\n\nconst shellClass = cnAll(\n fieldSurfaceVariants(),\n \"flex h-19 items-center gap-2 rounded-panel ps-4.5 pe-2\",\n // Focus turns the box's own border dark whenever the amount holds focus; no separate ring.\n \"has-[input:focus]:not-data-[invalid]:border-foreground\",\n \"forced-colors:has-[input:focus]:outline-solid forced-colors:has-[input:focus]:outline-(length:--focus-ring-width) forced-colors:has-[input:focus]:outline-offset-(--focus-ring-offset)\",\n);\n\nexport const MoneyInput = forwardRef<HTMLInputElement, MoneyInputProps>(function MoneyInput(\n {\n label,\n labelHidden = false,\n value,\n defaultValue = null,\n onValueChange,\n currency: currencyProp,\n defaultCurrency = \"USD\",\n onCurrencyChange,\n currencies = [\"USD\", \"EUR\", \"GBP\", \"JPY\", \"CAD\", \"AUD\", \"CHF\", \"INR\"],\n min,\n max,\n quickAdd = [10, 50, 100],\n step: stepProp,\n locale = \"en-US\",\n description,\n error,\n disabled = false,\n name,\n id,\n className,\n onBlur,\n },\n forwardedRef,\n) {\n const generated = useId();\n const inputId = id ?? `${generated}-amount`;\n const rangeId = `${inputId}-range`;\n\n const [innerCurrency, setInnerCurrency] = useState(defaultCurrency);\n const code = currencyProp ?? innerCurrency;\n const info = useMemo(() => currencyInfo(code, locale), [code, locale]);\n const symbols = useMemo(() => localeSymbols(locale), [locale]);\n const step = stepProp && stepProp > 0 ? stepProp : pow10(info.digits);\n\n const [draft, setDraft] = useState(() => fromMinor(value !== undefined ? value : defaultValue, info.digits));\n const minor = toMinor(draft, info.digits);\n\n const [seenValue, setSeenValue] = useState(value);\n const [source, setSource] = useState<Source>(\"external\");\n const [direction, setDirection] = useState<1 | -1>(1);\n if (value !== seenValue) {\n setSeenValue(value);\n if (value !== undefined && value !== minor) {\n setDraft(fromMinor(value, info.digits));\n setSource(\"external\");\n setDirection((value ?? 0) >= (minor ?? 0) ? 1 : -1);\n }\n }\n\n const [focused, setFocused] = useState(false);\n const [touched, setTouched] = useState(false);\n const [flash, setFlash] = useState(false);\n const [announcement, setAnnouncement] = useState(\"\");\n const [, rerender] = useReducer((count: number) => count + 1, 0);\n\n const inputRef = useRef<HTMLInputElement>(null);\n useImperativeHandle(forwardedRef, () => inputRef.current as HTMLInputElement);\n const pendingCaret = useRef<number | null>(null);\n const latest = useRef({ minor, draft });\n useIsomorphicLayoutEffect(() => {\n latest.current = { minor, draft };\n });\n\n const money = useCallback(\n (amount: number | null) => (amount === null ? \"\" : info.full.format(amount / pow10(info.digits))),\n [info],\n );\n\n /* ---------------------------------------------- Limits and feedback ---------------------------------------------- */\n\n const groupRef = useRef<HTMLDivElement>(null);\n const flashTimer = useRef<number | undefined>(undefined);\n function refuse(toward: 1 | -1, limit: number) {\n const node = groupRef.current;\n if (node) {\n node.style.setProperty(\"--strain-x\", `${toward * STRAIN_PX}px`);\n // Restart the animation: the attribute has to leave and come back across a style recalculation.\n node.removeAttribute(\"data-strain\");\n void node.offsetWidth;\n node.setAttribute(\"data-strain\", \"\");\n }\n setFlash(true);\n window.clearTimeout(flashTimer.current);\n flashTimer.current = window.setTimeout(() => setFlash(false), 1400);\n setAnnouncement(`${toward > 0 ? \"Maximum\" : \"Minimum\"} is ${money(limit)}`);\n }\n\n function emit(nextMinor: number | null, nextInfo = info) {\n onValueChange?.(nextMinor, {\n currency: nextInfo.code,\n major: nextMinor === null ? null : nextMinor / pow10(nextInfo.digits),\n formatted:\n nextMinor === null ? \"\" : nextInfo.full.format(nextMinor / pow10(nextInfo.digits)),\n });\n }\n\n function setAmount(nextDraft: string, nextSource: Source) {\n const nextMinor = toMinor(nextDraft, info.digits);\n setDirection((nextMinor ?? 0) >= (latest.current.minor ?? 0) ? 1 : -1);\n setSource(nextSource);\n setDraft(nextDraft);\n latest.current = { minor: nextMinor, draft: nextDraft };\n if (nextMinor !== minor) emit(nextMinor);\n if (nextSource !== \"type\") setAnnouncement(money(nextMinor));\n }\n\n /* ---------------------------------------------- Typing ---------------------------------------------- */\n\n /** Reads what the input holds into a draft and counts the digits and decimal before the caret, so the caret can return to the same spot. */\n function sanitize(raw: string, caret: number) {\n let out = \"\";\n let before = 0;\n let dot = false;\n for (let index = 0; index < raw.length; index++) {\n const char = raw[index]!;\n let kept = \"\";\n if (/\\d/.test(char)) kept = char;\n else if (\n (char === symbols.decimal || (char === \".\" && symbols.group !== \".\")) &&\n info.digits > 0 &&\n !dot\n ) {\n kept = \".\";\n dot = true;\n }\n if (!kept) continue;\n out += kept;\n if (index < caret) before++;\n }\n const pieces = out.split(\".\");\n let whole = pieces[0]!;\n const fraction = pieces[1];\n const stripped = whole.length - whole.replace(/^0+/, \"\").length;\n whole = whole.replace(/^0+/, \"\");\n let shift = -Math.min(stripped, before);\n if (fraction !== undefined && !whole) {\n whole = \"0\";\n shift += 1;\n }\n if (fraction === undefined && !whole && stripped) {\n whole = \"0\";\n shift += 1;\n }\n if (fraction !== undefined && fraction.length > info.digits) return null;\n if (whole.length > MAX_INTEGER_DIGITS) return null;\n return {\n draft: fraction !== undefined ? `${whole}.${fraction}` : whole,\n before: Math.max(0, before + shift),\n };\n }\n\n function applyRaw(raw: string, caret: number) {\n const result = sanitize(raw, caret);\n // A refused keystroke keeps the caret where it was: one significant character before where the browser left it.\n if (!result) {\n pendingCaret.current = Math.max(\n 0,\n [...raw.slice(0, caret)].filter((char) => isSignificant(char, symbols.decimal) || char === \".\")\n .length - 1,\n );\n rerender();\n return;\n }\n const nextMinor = toMinor(result.draft, info.digits);\n if (max !== undefined && nextMinor !== null && nextMinor > max) {\n pendingCaret.current = Math.max(0, result.before - 1);\n refuse(1, max);\n rerender();\n return;\n }\n pendingCaret.current = result.before;\n setAmount(result.draft, \"type\");\n }\n\n useIsomorphicLayoutEffect(() => {\n const input = inputRef.current;\n const count = pendingCaret.current;\n pendingCaret.current = null;\n if (!input || count === null || document.activeElement !== input) return;\n const position = positionAfter(input.value, count, symbols.decimal);\n input.setSelectionRange(position, position);\n });\n\n function nudge(amount: number, nextSource: Source) {\n const from = latest.current.minor ?? 0;\n const floor = min ?? 0;\n const ceiling = max ?? Number.MAX_SAFE_INTEGER;\n let next = from + amount;\n if (next > ceiling) {\n if (from >= ceiling) {\n refuse(1, ceiling);\n return;\n }\n next = ceiling;\n refuse(1, ceiling);\n }\n if (next < floor) {\n if (from <= floor && latest.current.minor !== null) {\n refuse(-1, floor);\n return;\n }\n next = floor;\n }\n pendingCaret.current = Number.MAX_SAFE_INTEGER;\n setAmount(fromMinor(next, info.digits), nextSource);\n }\n\n function onKeyDown(event: KeyboardEvent<HTMLInputElement>) {\n const input = event.currentTarget;\n const moves: Record<string, number> = { ArrowUp: 1, ArrowDown: -1, PageUp: 10, PageDown: -10 };\n if (event.key in moves) {\n event.preventDefault();\n const unit = moves[event.key]!;\n nudge(unit * step * (event.shiftKey && Math.abs(unit) === 1 ? 10 : 1), \"key\");\n return;\n }\n if (event.key === \"Enter\") {\n setDraft(settle(draft, info.digits));\n pendingCaret.current = Number.MAX_SAFE_INTEGER;\n return;\n }\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n if (start !== end || event.metaKey || event.ctrlKey || event.altKey) return;\n // Deleting a group separator deletes the digit before it instead of doing nothing.\n if (event.key === \"Backspace\" && start > 1 && input.value[start - 1] === symbols.group) {\n event.preventDefault();\n applyRaw(input.value.slice(0, start - 2) + input.value.slice(start - 1), start - 2);\n }\n if (event.key === \"Delete\" && input.value[start] === symbols.group) {\n event.preventDefault();\n applyRaw(input.value.slice(0, start + 1) + input.value.slice(start + 2), start);\n }\n }\n\n function onPaste(event: ClipboardEvent<HTMLInputElement>) {\n const text = event.clipboardData.getData(\"text\").trim();\n if (!text) return;\n event.preventDefault();\n // \"$1,234.56\", \"1.234,56 EUR\", \"1234.5\": a final separator followed by one or two digits is the decimal; the rest are groups.\n const match = /[.,](\\d{1,2})\\s*\\D*$/.exec(text);\n const whole = (match ? text.slice(0, match.index) : text).replace(/\\D/g, \"\");\n const pasted = match && info.digits ? `${whole}.${match[1]}` : whole;\n if (!/\\d/.test(pasted)) return;\n const input = event.currentTarget;\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n const inserted = pasted.replace(\".\", symbols.decimal);\n const replaceAll = (start === 0 && end === input.value.length) || !input.value;\n const raw = replaceAll ? inserted : input.value.slice(0, start) + inserted + input.value.slice(end);\n applyRaw(raw, replaceAll ? raw.length : start + inserted.length);\n }\n\n /* ---------------------------------------------- Fit to width ---------------------------------------------- */\n\n // A long amount scales down to fit its room instead of scrolling, so it is always read whole. The first fit\n // is not animated; later ones follow on the smooth spring (the group's `data-ready` turns the transition on).\n const wrapRef = useRef<HTMLDivElement>(null);\n useIsomorphicLayoutEffect(() => {\n const wrap = wrapRef.current;\n const group = groupRef.current;\n if (!wrap || !group || typeof ResizeObserver === \"undefined\") return;\n const fit = () => {\n const natural = group.offsetWidth;\n const room = wrap.clientWidth;\n group.style.scale = String(natural > 0 && room > 0 ? Math.min(1, room / natural) : 1);\n if (!group.hasAttribute(\"data-ready\")) {\n void group.offsetWidth;\n group.setAttribute(\"data-ready\", \"\");\n }\n };\n fit();\n const observer = new ResizeObserver(fit);\n observer.observe(wrap);\n observer.observe(group);\n return () => observer.disconnect();\n }, []);\n\n /* ---------------------------------------------- Currency ---------------------------------------------- */\n\n const options = useMemo(() => currencies.map((entry) => currencyInfo(entry, locale)), [currencies, locale]);\n\n function chooseCurrency(next: CurrencyInfo) {\n if (next.code === code) return;\n const nextDraft = focused\n ? convertDraft(draft, next.digits)\n : settle(convertDraft(draft, next.digits), next.digits);\n const nextMinor = toMinor(nextDraft, next.digits);\n if (currencyProp === undefined) setInnerCurrency(next.code);\n onCurrencyChange?.(next.code);\n setSource(\"external\");\n setDraft(nextDraft);\n latest.current = { minor: nextMinor, draft: nextDraft };\n emit(nextMinor, next);\n setAnnouncement(\n `${next.name}${nextMinor === null ? \"\" : `, ${next.full.format(nextMinor / pow10(next.digits))}`}`,\n );\n }\n\n /* ---------------------------------------------- Messages ---------------------------------------------- */\n\n const range =\n min !== undefined && max !== undefined\n ? `${money(min)} to ${money(max)}`\n : max !== undefined\n ? `Up to ${money(max)}`\n : min !== undefined\n ? `At least ${money(min)}`\n : \"\";\n const belowMin = minor !== null && min !== undefined && minor < min;\n const aboveMax = minor !== null && max !== undefined && minor > max;\n const builtIn =\n touched && !focused && (belowMin || aboveMax)\n ? belowMin\n ? `The minimum is ${money(min ?? 0)}`\n : `The maximum is ${money(max ?? 0)}`\n : undefined;\n const message = error ?? builtIn;\n const chips = quickAdd.filter((amount) => amount > 0);\n\n const field = useFieldWiring({\n enabled: true,\n id: inputId,\n describedBy: range ? rangeId : undefined,\n invalid: undefined,\n description,\n error: message,\n });\n\n const typing = source === \"type\";\n const display = displayOf(draft, symbols);\n const canSwitch = options.length > 1;\n\n const control = (\n <>\n <AriaGroup\n role=\"presentation\"\n isDisabled={disabled}\n isInvalid={Boolean(message)}\n data-slot=\"money-input-shell\"\n className={shellClass}\n >\n <div\n ref={wrapRef}\n className=\"relative flex h-full min-w-0 flex-1 cursor-text items-center overflow-hidden\"\n onMouseDown={(event) => {\n if (event.target !== inputRef.current) event.preventDefault();\n }}\n onClick={(event) => {\n if (disabled || event.target === inputRef.current) return;\n const input = inputRef.current;\n input?.focus();\n input?.setSelectionRange(input.value.length, input.value.length);\n }}\n >\n <div\n ref={groupRef}\n data-slot=\"money-input-amount\"\n className=\"inline-flex flex-none origin-left items-baseline whitespace-nowrap font-display text-h2 font-medium tabular-nums text-foreground data-[ready]:motion-safe:transition-[scale] data-[ready]:motion-safe:duration-(--duration-smooth) data-[ready]:motion-safe:ease-smooth data-[strain]:motion-safe:animate-field-strain\"\n >\n {info.position === \"prefix\" ? <SymbolSlot symbol={info.symbol} side=\"prefix\" /> : null}\n <span className=\"relative inline-flex\">\n {/* The digits the eye sees. The input over them draws only the caret and the selection. */}\n <span aria-hidden=\"true\" data-slot=\"money-input-display\" className=\"inline-flex\">\n <Amount\n draft={draft}\n digits={info.digits}\n symbols={symbols}\n direction={direction}\n still={typing}\n />\n </span>\n <AriaInput\n ref={inputRef}\n {...field.controlProps}\n data-slot=\"money-input-input\"\n type=\"text\"\n role=\"spinbutton\"\n inputMode={info.digits ? \"decimal\" : \"numeric\"}\n autoComplete=\"off\"\n spellCheck={false}\n value={display}\n disabled={disabled}\n aria-label={labelHidden ? label : undefined}\n aria-valuenow={minor === null ? undefined : minor / pow10(info.digits)}\n aria-valuetext={minor === null ? \"Empty\" : money(minor)}\n aria-valuemin={min === undefined ? undefined : min / pow10(info.digits)}\n aria-valuemax={max === undefined ? undefined : max / pow10(info.digits)}\n onChange={(event) =>\n applyRaw(\n event.currentTarget.value,\n event.currentTarget.selectionStart ?? event.currentTarget.value.length,\n )\n }\n onKeyDown={onKeyDown}\n onPaste={onPaste}\n onFocus={() => setFocused(true)}\n onBlur={(event) => {\n setFocused(false);\n setTouched(true);\n if (draft) setDraft(settle(draft, info.digits));\n onBlur?.(event);\n }}\n className=\"absolute top-0 left-0 z-10 m-0 h-full w-[calc(100%+0.5em)] border-0 bg-transparent p-0 [font:inherit] text-transparent caret-foreground outline-none selection:bg-primary/20 selection:text-transparent data-[disabled]:cursor-not-allowed\"\n />\n </span>\n {info.position === \"suffix\" ? <SymbolSlot symbol={info.symbol} side=\"suffix\" /> : null}\n </div>\n </div>\n\n {canSwitch ? (\n <AriaSelect\n aria-label=\"Currency\"\n selectedKey={code}\n isDisabled={disabled}\n onSelectionChange={(key: Key | null) => {\n const next = options.find((option) => option.code === key);\n if (next) chooseCurrency(next);\n }}\n data-slot=\"money-input-currency\"\n className=\"flex-none\"\n >\n <AriaButton className={cnAll(triggerClass, \"group/trigger\")}>\n <AriaSelectValue>{() => code}</AriaSelectValue>\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"size-4 text-muted-foreground motion-safe:transition-[rotate] motion-safe:duration-(--duration-gentle) motion-safe:ease-gentle group-aria-expanded/trigger:rotate-180\"\n >\n <path d=\"m4 6 4 4 4-4\" />\n </svg>\n </AriaButton>\n <AriaPopover\n placement=\"bottom end\"\n offset={12}\n data-slot=\"money-input-currency-popover\"\n className={cnAll(selectPopoverVariants(), \"w-64\")}\n >\n <AriaListBox aria-label=\"Currency\" className=\"outline-none\">\n {options.map((option) => (\n <SelectItem key={option.code} id={option.code} textValue={option.code}>\n <span aria-hidden=\"true\" className=\"w-6 flex-none text-center text-muted-foreground\">\n {option.symbol}\n </span>\n <span className=\"flex-none font-medium tabular-nums\">{option.code}</span>\n <span className=\"min-w-0 flex-1 truncate text-xs text-muted-foreground\">\n {option.name}\n </span>\n </SelectItem>\n ))}\n </AriaListBox>\n </AriaPopover>\n </AriaSelect>\n ) : (\n <span\n data-slot=\"money-input-currency\"\n className=\"flex-none px-2.5 text-sm font-medium text-text-secondary\"\n >\n {code}\n </span>\n )}\n </AriaGroup>\n\n {chips.length > 0 || range ? (\n <div className=\"flex flex-wrap items-center justify-between gap-x-3 gap-y-2 pt-3\">\n {chips.length > 0 ? (\n <div role=\"group\" aria-label=\"Quick add\" className=\"flex flex-wrap gap-1.5\">\n {chips.map((amount) => (\n <Button\n key={amount}\n variant=\"outlineNeutral\"\n size=\"sm\"\n isDisabled={disabled || (max !== undefined && (minor ?? 0) >= max)}\n aria-controls={inputId}\n aria-label={`Add ${info.whole.format(amount)}`}\n onPress={() => nudge(amount * pow10(info.digits), \"chip\")}\n >\n +{info.whole.format(amount)}\n </Button>\n ))}\n </div>\n ) : null}\n {range ? (\n <span\n id={rangeId}\n data-flash={flash || undefined}\n className=\"text-xs tabular-nums text-muted-foreground motion-safe:transition-colors motion-safe:duration-(--duration-standard) data-[flash]:text-destructive-strong motion-safe:data-[flash]:duration-(--duration-instant)\"\n >\n {range}\n </span>\n ) : null}\n </div>\n ) : null}\n\n {name ? <input type=\"hidden\" name={name} value={minor ?? \"\"} /> : null}\n <span className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n {announcement}\n </span>\n </>\n );\n\n return (\n <div className={cn(\"w-full min-w-0 font-sans\", className)} data-slot=\"money-input\">\n <FieldShell\n label={labelHidden ? null : label}\n controlId={field.controlId}\n description={description}\n hintId={field.hintId}\n error={message}\n errorId={field.errorId}\n >\n {control}\n </FieldShell>\n </div>\n );\n});\n"],"mappings":";;;;;;;;;;;;;AA4GA,MAAM,qBAAqB;;AAE3B,MAAM,YAAY;AAElB,MAAM,4BAAY,IAAI,IAA0B;AAChD,SAAS,aAAa,MAAc,QAA8B;CAChE,MAAM,WAAW,GAAG,OAAO,GAAG;CAC9B,MAAM,SAAS,UAAU,IAAI,QAAQ;CACrC,IAAI,QAAQ,OAAO;CACnB,MAAM,OAAO,IAAI,KAAK,aAAa,QAAQ;EACzC,OAAO;EACP,UAAU;EACV,iBAAiB;EACjB,iBAAiB;CACnB,CAAC;CACD,MAAM,QAAQ,KAAK,cAAc,CAAC;CAClC,MAAM,WAAW,MAAM,WAAW,SAAS,KAAK,SAAS,UAAU;CACnE,MAAM,WAAW,MAAM,WAAW,SAAS,KAAK,SAAS,SAAS;CAClE,MAAM,SAAS,KAAK,gBAAgB,CAAC,CAAC,yBAAyB;CAC/D,IAAI,OAAO;CACX,IAAI;EACF,OAAO,IAAI,KAAK,aAAa,CAAC,MAAM,GAAG,EAAE,MAAM,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK;CAC3E,QAAQ,CAER;CACA,MAAM,OAAqB;EACzB;EACA,QAAQ,MAAM,SAAS,EAAE,SAAS;EAClC,UAAU,WAAW,WAAW,WAAW;EAC3C;EACA,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,KAAK,MAAM,CAAC;EACjD;EACA,OAAO,IAAI,KAAK,aAAa,QAAQ;GACnC,OAAO;GACP,UAAU;GACV,iBAAiB;GACjB,uBAAuB;GACvB,iBAAiB;EACnB,CAAC;CACH;CACA,UAAU,IAAI,UAAU,IAAI;CAC5B,OAAO;AACT;AAEA,SAAS,cAAc,QAAgB;CACrC,MAAM,QAAQ,IAAI,KAAK,aAAa,QAAQ,EAAE,iBAAiB,OAAO,CAAC,CAAC,CAAC,cAAc,OAAO;CAC9F,OAAO;EACL,OAAO,MAAM,MAAM,SAAS,KAAK,SAAS,OAAO,CAAC,EAAE,SAAS;EAC7D,SAAS,MAAM,MAAM,SAAS,KAAK,SAAS,SAAS,CAAC,EAAE,SAAS;CACnE;AACF;AAGA,MAAM,SAAS,WAAmB,MAAM;AACxC,SAAS,QAAQ,OAAe,QAA+B;CAC7D,IAAI,CAAC,OAAO,OAAO;CACnB,MAAM,CAAC,OAAO,WAAW,MAAM,MAAM,MAAM,GAAG;CAC9C,OACE,OAAO,SAAS,GAAG,IAAI,MAAM,MAAM,IAAI,OAAO,SAAS,OAAO,QAAQ,GAAG,CAAC,CAAC,MAAM,GAAG,MAAM,KAAK,GAAG;AAEtG;AACA,SAAS,UAAU,OAAkC,QAAgB;CACnE,IAAI,UAAU,QAAQ,UAAU,KAAA,KAAa,CAAC,OAAO,SAAS,KAAK,GAAG,OAAO;CAC7E,MAAM,OAAO,OAAO,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,SAAS,GAAG,GAAG;CACzE,OAAO,SAAS,GAAG,KAAK,MAAM,GAAG,KAAK,SAAS,MAAM,EAAE,GAAG,KAAK,MAAM,KAAK,SAAS,MAAM,MAAM;AACjG;;AAEA,SAAS,OAAO,OAAe,QAAgB;CAC7C,OAAO,QAAQ,UAAU,QAAQ,OAAO,MAAM,GAAG,MAAM,IAAI;AAC7D;;AAEA,SAAS,aAAa,OAAe,QAAgB;CACnD,IAAI,CAAC,OAAO,OAAO;CACnB,MAAM,CAAC,QAAQ,IAAI,YAAY,MAAM,MAAM,GAAG;CAC9C,IAAI,CAAC,QAAQ,OAAO,SAAS;CAC7B,OAAO,aAAa,KAAA,IAAY,QAAQ,GAAG,MAAM,GAAG,SAAS,MAAM,GAAG,MAAM;AAC9E;AAEA,MAAM,gBAAgB,OAAe,UACnC,MAAM,QAAQ,yBAAyB,KAAK;AAC9C,SAAS,UAAU,OAAe,SAA6C;CAC7E,IAAI,CAAC,OAAO,OAAO;CACnB,MAAM,CAAC,QAAQ,IAAI,YAAY,MAAM,MAAM,GAAG;CAC9C,OAAO,aAAa,OAAO,QAAQ,KAAK,KAAK,aAAa,KAAA,IAAY,QAAQ,UAAU,WAAW;AACrG;AAEA,MAAM,iBAAiB,MAAc,YAAoB,KAAK,KAAK,IAAI,KAAK,SAAS;AACrF,SAAS,cAAc,MAAc,OAAe,SAAiB;CACnE,IAAI,SAAS,GAAG,OAAO;CACvB,IAAI,OAAO;CACX,KAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SACvC,IAAI,cAAc,KAAK,QAAS,OAAO,KAAK,EAAE,SAAS,OAAO,OAAO,QAAQ;CAE/E,OAAO,KAAK;AACd;;AAGA,SAAS,WAAW,EAAE,QAAQ,QAAuD;CACnF,MAAM,UAAU,OAAwB,IAAI;CAC5C,cAAc,SAAS,MAAM;CAC7B,OACE,oBAAC,QAAD;EACE,eAAY;EACZ,aAAU;EACV,WAAW,MAAM,mCAAmC,SAAS,WAAW,SAAS,QAAQ;EAEzF,UAAA,oBAAC,QAAD;GAAM,KAAK;GAAS,WAAU;GAC5B,UAAA,oBAAC,UAAD;IAAU,SAAS;IAAQ,QAAO;IAAO,WAAU;IAChD,UAAA;GACO,CAAA;EACN,CAAA;CACF,CAAA;AAEV;;AAGA,SAAS,OAAO,EACd,OACA,QACA,SACA,WACA,SAOC;CACD,MAAM,CAAC,QAAQ,IAAI,YAAY,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC;CAC3D,MAAM,QAAQ,YAAY;CAE1B,OACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,QAAD;EAAM,cAAY,CAHF,SAGgB,KAAA;EAAW,WAAU;EACnD,UAAA,oBAAC,eAAD;GACE,MAAM,aAAa,SAAS,KAAK,QAAQ,KAAK;GACnC;GACJ;EACR,CAAA;CACG,CAAA,GACL,SAAS,IACR,qBAAA,YAAA,EAAA,UAAA;EACE,oBAAC,QAAD;GACE,cAAY,aAAa,KAAA,KAAa,KAAA;GACtC,WAAU;GAET,UAAA,QAAQ;EACL,CAAA;EACL,QACC,oBAAC,QAAD;GAAM,WAAU;GACd,UAAA,oBAAC,eAAD;IAAe,MAAM;IAAkB;IAAkB;GAAQ,CAAA;EAC7D,CAAA,IACJ;EACH,MAAM,SAAS,SACd,oBAAC,QAAD;GAAM,WAAU;GAAyB,UAAA,IAAI,OAAO,SAAS,MAAM,MAAM;EAAQ,CAAA,IAC/E;CACJ,EAAA,CAAA,IACA,IACJ,EAAA,CAAA;AAEN;AAEA,MAAM,eACJ;AAEF,MAAM,aAAa,MACjB,qBAAqB,GACrB,0DAEA,0DACA,wLACF;AAEA,MAAa,aAAa,WAA8C,SAAS,WAC/E,EACE,OACA,cAAc,OACd,OACA,eAAe,MACf,eACA,UAAU,cACV,kBAAkB,OAClB,kBACA,aAAa;CAAC;CAAO;CAAO;CAAO;CAAO;CAAO;CAAO;CAAO;AAAK,GACpE,KACA,KACA,WAAW;CAAC;CAAI;CAAI;AAAG,GACvB,MAAM,UACN,SAAS,SACT,aACA,OACA,WAAW,OACX,MACA,IACA,WACA,UAEF,cACA;CACA,MAAM,YAAY,MAAM;CACxB,MAAM,UAAU,MAAM,GAAG,UAAU;CACnC,MAAM,UAAU,GAAG,QAAQ;CAE3B,MAAM,CAAC,eAAe,oBAAoB,SAAS,eAAe;CAClE,MAAM,OAAO,gBAAgB;CAC7B,MAAM,OAAO,cAAc,aAAa,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC;CACrE,MAAM,UAAU,cAAc,cAAc,MAAM,GAAG,CAAC,MAAM,CAAC;CAC7D,MAAM,OAAO,YAAY,WAAW,IAAI,WAAW,MAAM,KAAK,MAAM;CAEpE,MAAM,CAAC,OAAO,YAAY,eAAe,UAAU,UAAU,KAAA,IAAY,QAAQ,cAAc,KAAK,MAAM,CAAC;CAC3G,MAAM,QAAQ,QAAQ,OAAO,KAAK,MAAM;CAExC,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAChD,MAAM,CAAC,QAAQ,aAAa,SAAiB,UAAU;CACvD,MAAM,CAAC,WAAW,gBAAgB,SAAiB,CAAC;CACpD,IAAI,UAAU,WAAW;EACvB,aAAa,KAAK;EAClB,IAAI,UAAU,KAAA,KAAa,UAAU,OAAO;GAC1C,SAAS,UAAU,OAAO,KAAK,MAAM,CAAC;GACtC,UAAU,UAAU;GACpB,cAAc,SAAS,OAAO,SAAS,KAAK,IAAI,EAAE;EACpD;CACF;CAEA,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,CAAC,OAAO,YAAY,SAAS,KAAK;CACxC,MAAM,CAAC,cAAc,mBAAmB,SAAS,EAAE;CACnD,MAAM,GAAG,YAAY,YAAY,UAAkB,QAAQ,GAAG,CAAC;CAE/D,MAAM,WAAW,OAAyB,IAAI;CAC9C,oBAAoB,oBAAoB,SAAS,OAA2B;CAC5E,MAAM,eAAe,OAAsB,IAAI;CAC/C,MAAM,SAAS,OAAO;EAAE;EAAO;CAAM,CAAC;CACtC,gCAAgC;EAC9B,OAAO,UAAU;GAAE;GAAO;EAAM;CAClC,CAAC;CAED,MAAM,QAAQ,aACX,WAA2B,WAAW,OAAO,KAAK,KAAK,KAAK,OAAO,SAAS,MAAM,KAAK,MAAM,CAAC,GAC/F,CAAC,IAAI,CACP;CAIA,MAAM,WAAW,OAAuB,IAAI;CAC5C,MAAM,aAAa,OAA2B,KAAA,CAAS;CACvD,SAAS,OAAO,QAAgB,OAAe;EAC7C,MAAM,OAAO,SAAS;EACtB,IAAI,MAAM;GACR,KAAK,MAAM,YAAY,cAAc,GAAG,SAAS,UAAU,GAAG;GAE9D,KAAK,gBAAgB,aAAa;GAClC,KAAU;GACV,KAAK,aAAa,eAAe,EAAE;EACrC;EACA,SAAS,IAAI;EACb,OAAO,aAAa,WAAW,OAAO;EACtC,WAAW,UAAU,OAAO,iBAAiB,SAAS,KAAK,GAAG,IAAI;EAClE,gBAAgB,GAAG,SAAS,IAAI,YAAY,UAAU,MAAM,MAAM,KAAK,GAAG;CAC5E;CAEA,SAAS,KAAK,WAA0B,WAAW,MAAM;EACvD,gBAAgB,WAAW;GACzB,UAAU,SAAS;GACnB,OAAO,cAAc,OAAO,OAAO,YAAY,MAAM,SAAS,MAAM;GACpE,WACE,cAAc,OAAO,KAAK,SAAS,KAAK,OAAO,YAAY,MAAM,SAAS,MAAM,CAAC;EACrF,CAAC;CACH;CAEA,SAAS,UAAU,WAAmB,YAAoB;EACxD,MAAM,YAAY,QAAQ,WAAW,KAAK,MAAM;EAChD,cAAc,aAAa,OAAO,OAAO,QAAQ,SAAS,KAAK,IAAI,EAAE;EACrE,UAAU,UAAU;EACpB,SAAS,SAAS;EAClB,OAAO,UAAU;GAAE,OAAO;GAAW,OAAO;EAAU;EACtD,IAAI,cAAc,OAAO,KAAK,SAAS;EACvC,IAAI,eAAe,QAAQ,gBAAgB,MAAM,SAAS,CAAC;CAC7D;;CAKA,SAAS,SAAS,KAAa,OAAe;EAC5C,IAAI,MAAM;EACV,IAAI,SAAS;EACb,IAAI,MAAM;EACV,KAAK,IAAI,QAAQ,GAAG,QAAQ,IAAI,QAAQ,SAAS;GAC/C,MAAM,OAAO,IAAI;GACjB,IAAI,OAAO;GACX,IAAI,KAAK,KAAK,IAAI,GAAG,OAAO;QACvB,KACF,SAAS,QAAQ,WAAY,SAAS,OAAO,QAAQ,UAAU,QAChE,KAAK,SAAS,KACd,CAAC,KACD;IACA,OAAO;IACP,MAAM;GACR;GACA,IAAI,CAAC,MAAM;GACX,OAAO;GACP,IAAI,QAAQ,OAAO;EACrB;EACA,MAAM,SAAS,IAAI,MAAM,GAAG;EAC5B,IAAI,QAAQ,OAAO;EACnB,MAAM,WAAW,OAAO;EACxB,MAAM,WAAW,MAAM,SAAS,MAAM,QAAQ,OAAO,EAAE,CAAC,CAAC;EACzD,QAAQ,MAAM,QAAQ,OAAO,EAAE;EAC/B,IAAI,QAAQ,CAAC,KAAK,IAAI,UAAU,MAAM;EACtC,IAAI,aAAa,KAAA,KAAa,CAAC,OAAO;GACpC,QAAQ;GACR,SAAS;EACX;EACA,IAAI,aAAa,KAAA,KAAa,CAAC,SAAS,UAAU;GAChD,QAAQ;GACR,SAAS;EACX;EACA,IAAI,aAAa,KAAA,KAAa,SAAS,SAAS,KAAK,QAAQ,OAAO;EACpE,IAAI,MAAM,SAAS,oBAAoB,OAAO;EAC9C,OAAO;GACL,OAAO,aAAa,KAAA,IAAY,GAAG,MAAM,GAAG,aAAa;GACzD,QAAQ,KAAK,IAAI,GAAG,SAAS,KAAK;EACpC;CACF;CAEA,SAAS,SAAS,KAAa,OAAe;EAC5C,MAAM,SAAS,SAAS,KAAK,KAAK;EAElC,IAAI,CAAC,QAAQ;GACX,aAAa,UAAU,KAAK,IAC1B,GACA,CAAC,GAAG,IAAI,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,SAAS,cAAc,MAAM,QAAQ,OAAO,KAAK,SAAS,GAAG,CAAC,CAC5F,SAAS,CACd;GACA,SAAS;GACT;EACF;EACA,MAAM,YAAY,QAAQ,OAAO,OAAO,KAAK,MAAM;EACnD,IAAI,QAAQ,KAAA,KAAa,cAAc,QAAQ,YAAY,KAAK;GAC9D,aAAa,UAAU,KAAK,IAAI,GAAG,OAAO,SAAS,CAAC;GACpD,OAAO,GAAG,GAAG;GACb,SAAS;GACT;EACF;EACA,aAAa,UAAU,OAAO;EAC9B,UAAU,OAAO,OAAO,MAAM;CAChC;CAEA,gCAAgC;EAC9B,MAAM,QAAQ,SAAS;EACvB,MAAM,QAAQ,aAAa;EAC3B,aAAa,UAAU;EACvB,IAAI,CAAC,SAAS,UAAU,QAAQ,SAAS,kBAAkB,OAAO;EAClE,MAAM,WAAW,cAAc,MAAM,OAAO,OAAO,QAAQ,OAAO;EAClE,MAAM,kBAAkB,UAAU,QAAQ;CAC5C,CAAC;CAED,SAAS,MAAM,QAAgB,YAAoB;EACjD,MAAM,OAAO,OAAO,QAAQ,SAAS;EACrC,MAAM,QAAQ,OAAO;EACrB,MAAM,UAAU,OAAO,OAAO;EAC9B,IAAI,OAAO,OAAO;EAClB,IAAI,OAAO,SAAS;GAClB,IAAI,QAAQ,SAAS;IACnB,OAAO,GAAG,OAAO;IACjB;GACF;GACA,OAAO;GACP,OAAO,GAAG,OAAO;EACnB;EACA,IAAI,OAAO,OAAO;GAChB,IAAI,QAAQ,SAAS,OAAO,QAAQ,UAAU,MAAM;IAClD,OAAO,IAAI,KAAK;IAChB;GACF;GACA,OAAO;EACT;EACA,aAAa,UAAU,OAAO;EAC9B,UAAU,UAAU,MAAM,KAAK,MAAM,GAAG,UAAU;CACpD;CAEA,SAAS,UAAU,OAAwC;EACzD,MAAM,QAAQ,MAAM;EACpB,MAAM,QAAgC;GAAE,SAAS;GAAG,WAAW;GAAI,QAAQ;GAAI,UAAU;EAAI;EAC7F,IAAI,MAAM,OAAO,OAAO;GACtB,MAAM,eAAe;GACrB,MAAM,OAAO,MAAM,MAAM;GACzB,MAAM,OAAO,QAAQ,MAAM,YAAY,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK;GAC5E;EACF;EACA,IAAI,MAAM,QAAQ,SAAS;GACzB,SAAS,OAAO,OAAO,KAAK,MAAM,CAAC;GACnC,aAAa,UAAU,OAAO;GAC9B;EACF;EACA,MAAM,QAAQ,MAAM,kBAAkB;EAEtC,IAAI,WADQ,MAAM,gBAAgB,MACb,MAAM,WAAW,MAAM,WAAW,MAAM,QAAQ;EAErE,IAAI,MAAM,QAAQ,eAAe,QAAQ,KAAK,MAAM,MAAM,QAAQ,OAAO,QAAQ,OAAO;GACtF,MAAM,eAAe;GACrB,SAAS,MAAM,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,MAAM,MAAM,MAAM,QAAQ,CAAC,GAAG,QAAQ,CAAC;EACpF;EACA,IAAI,MAAM,QAAQ,YAAY,MAAM,MAAM,WAAW,QAAQ,OAAO;GAClE,MAAM,eAAe;GACrB,SAAS,MAAM,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,MAAM,MAAM,MAAM,QAAQ,CAAC,GAAG,KAAK;EAChF;CACF;CAEA,SAAS,QAAQ,OAAyC;EACxD,MAAM,OAAO,MAAM,cAAc,QAAQ,MAAM,CAAC,CAAC,KAAK;EACtD,IAAI,CAAC,MAAM;EACX,MAAM,eAAe;EAErB,MAAM,QAAQ,uBAAuB,KAAK,IAAI;EAC9C,MAAM,SAAS,QAAQ,KAAK,MAAM,GAAG,MAAM,KAAK,IAAI,KAAA,CAAM,QAAQ,OAAO,EAAE;EAC3E,MAAM,SAAS,SAAS,KAAK,SAAS,GAAG,MAAM,GAAG,MAAM,OAAO;EAC/D,IAAI,CAAC,KAAK,KAAK,MAAM,GAAG;EACxB,MAAM,QAAQ,MAAM;EACpB,MAAM,QAAQ,MAAM,kBAAkB;EACtC,MAAM,MAAM,MAAM,gBAAgB;EAClC,MAAM,WAAW,OAAO,QAAQ,KAAK,QAAQ,OAAO;EACpD,MAAM,aAAc,UAAU,KAAK,QAAQ,MAAM,MAAM,UAAW,CAAC,MAAM;EACzE,MAAM,MAAM,aAAa,WAAW,MAAM,MAAM,MAAM,GAAG,KAAK,IAAI,WAAW,MAAM,MAAM,MAAM,GAAG;EAClG,SAAS,KAAK,aAAa,IAAI,SAAS,QAAQ,SAAS,MAAM;CACjE;CAMA,MAAM,UAAU,OAAuB,IAAI;CAC3C,gCAAgC;EAC9B,MAAM,OAAO,QAAQ;EACrB,MAAM,QAAQ,SAAS;EACvB,IAAI,CAAC,QAAQ,CAAC,SAAS,OAAO,mBAAmB,aAAa;EAC9D,MAAM,YAAY;GAChB,MAAM,UAAU,MAAM;GACtB,MAAM,OAAO,KAAK;GAClB,MAAM,MAAM,QAAQ,OAAO,UAAU,KAAK,OAAO,IAAI,KAAK,IAAI,GAAG,OAAO,OAAO,IAAI,CAAC;GACpF,IAAI,CAAC,MAAM,aAAa,YAAY,GAAG;IACrC,MAAW;IACX,MAAM,aAAa,cAAc,EAAE;GACrC;EACF;EACA,IAAI;EACJ,MAAM,WAAW,IAAI,eAAe,GAAG;EACvC,SAAS,QAAQ,IAAI;EACrB,SAAS,QAAQ,KAAK;EACtB,aAAa,SAAS,WAAW;CACnC,GAAG,CAAC,CAAC;CAIL,MAAM,UAAU,cAAc,WAAW,KAAK,UAAU,aAAa,OAAO,MAAM,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC;CAE1G,SAAS,eAAe,MAAoB;EAC1C,IAAI,KAAK,SAAS,MAAM;EACxB,MAAM,YAAY,UACd,aAAa,OAAO,KAAK,MAAM,IAC/B,OAAO,aAAa,OAAO,KAAK,MAAM,GAAG,KAAK,MAAM;EACxD,MAAM,YAAY,QAAQ,WAAW,KAAK,MAAM;EAChD,IAAI,iBAAiB,KAAA,GAAW,iBAAiB,KAAK,IAAI;EAC1D,mBAAmB,KAAK,IAAI;EAC5B,UAAU,UAAU;EACpB,SAAS,SAAS;EAClB,OAAO,UAAU;GAAE,OAAO;GAAW,OAAO;EAAU;EACtD,KAAK,WAAW,IAAI;EACpB,gBACE,GAAG,KAAK,OAAO,cAAc,OAAO,KAAK,KAAK,KAAK,KAAK,OAAO,YAAY,MAAM,KAAK,MAAM,CAAC,KAC/F;CACF;CAIA,MAAM,QACJ,QAAQ,KAAA,KAAa,QAAQ,KAAA,IACzB,GAAG,MAAM,GAAG,EAAE,MAAM,MAAM,GAAG,MAC7B,QAAQ,KAAA,IACN,SAAS,MAAM,GAAG,MAClB,QAAQ,KAAA,IACN,YAAY,MAAM,GAAG,MACrB;CACV,MAAM,WAAW,UAAU,QAAQ,QAAQ,KAAA,KAAa,QAAQ;CAEhE,MAAM,UACJ,WAAW,CAAC,YAAY,YAFT,UAAU,QAAQ,QAAQ,KAAA,KAAa,QAAQ,OAG1D,WACE,kBAAkB,MAAM,OAAO,CAAC,MAChC,kBAAkB,MAAM,OAAO,CAAC,MAClC,KAAA;CACN,MAAM,UAAU,SAAS;CACzB,MAAM,QAAQ,SAAS,QAAQ,WAAW,SAAS,CAAC;CAEpD,MAAM,QAAQ,eAAe;EAC3B,SAAS;EACT,IAAI;EACJ,aAAa,QAAQ,UAAU,KAAA;EAC/B,SAAS,KAAA;EACT;EACA,OAAO;CACT,CAAC;CAED,MAAM,SAAS,WAAW;CAC1B,MAAM,UAAU,UAAU,OAAO,OAAO;CACxC,MAAM,YAAY,QAAQ,SAAS;CAEnC,MAAM,UACJ,qBAAA,YAAA,EAAA,UAAA;EACE,qBAACA,OAAD;GACE,MAAK;GACL,YAAY;GACZ,WAAW,QAAQ,OAAO;GAC1B,aAAU;GACV,WAAW;GALb,UAAA,CAOE,oBAAC,OAAD;IACE,KAAK;IACL,WAAU;IACV,cAAc,UAAU;KACtB,IAAI,MAAM,WAAW,SAAS,SAAS,MAAM,eAAe;IAC9D;IACA,UAAU,UAAU;KAClB,IAAI,YAAY,MAAM,WAAW,SAAS,SAAS;KACnD,MAAM,QAAQ,SAAS;KACvB,OAAO,MAAM;KACb,OAAO,kBAAkB,MAAM,MAAM,QAAQ,MAAM,MAAM,MAAM;IACjE;IAEA,UAAA,qBAAC,OAAD;KACE,KAAK;KACL,aAAU;KACV,WAAU;KAHZ,UAAA;MAKG,KAAK,aAAa,WAAW,oBAAC,YAAD;OAAY,QAAQ,KAAK;OAAQ,MAAK;MAAU,CAAA,IAAI;MAClF,qBAAC,QAAD;OAAM,WAAU;OAAhB,UAAA,CAEE,oBAAC,QAAD;QAAM,eAAY;QAAO,aAAU;QAAsB,WAAU;QACjE,UAAA,oBAAC,QAAD;SACS;SACP,QAAQ,KAAK;SACJ;SACE;SACX,OAAO;QACR,CAAA;OACG,CAAA,GACN,oBAACC,OAAD;QACE,KAAK;QACL,GAAI,MAAM;QACV,aAAU;QACV,MAAK;QACL,MAAK;QACL,WAAW,KAAK,SAAS,YAAY;QACrC,cAAa;QACb,YAAY;QACZ,OAAO;QACG;QACV,cAAY,cAAc,QAAQ,KAAA;QAClC,iBAAe,UAAU,OAAO,KAAA,IAAY,QAAQ,MAAM,KAAK,MAAM;QACrE,kBAAgB,UAAU,OAAO,UAAU,MAAM,KAAK;QACtD,iBAAe,QAAQ,KAAA,IAAY,KAAA,IAAY,MAAM,MAAM,KAAK,MAAM;QACtE,iBAAe,QAAQ,KAAA,IAAY,KAAA,IAAY,MAAM,MAAM,KAAK,MAAM;QACtE,WAAW,UACT,SACE,MAAM,cAAc,OACpB,MAAM,cAAc,kBAAkB,MAAM,cAAc,MAAM,MAClE;QAES;QACF;QACT,eAAe,WAAW,IAAI;QAC9B,SAAS,UAAU;SACjB,WAAW,KAAK;SAChB,WAAW,IAAI;SACf,IAAI,OAAO,SAAS,OAAO,OAAO,KAAK,MAAM,CAAC;SAC9C,SAAS,KAAK;QAChB;QACA,WAAU;OACX,CAAA,CACG;;MACL,KAAK,aAAa,WAAW,oBAAC,YAAD;OAAY,QAAQ,KAAK;OAAQ,MAAK;MAAU,CAAA,IAAI;KAC/E;;GACF,CAAA,GAEJ,YACC,qBAACC,QAAD;IACE,cAAW;IACX,aAAa;IACb,YAAY;IACZ,oBAAoB,QAAoB;KACtC,MAAM,OAAO,QAAQ,MAAM,WAAW,OAAO,SAAS,GAAG;KACzD,IAAI,MAAM,eAAe,IAAI;IAC/B;IACA,aAAU;IACV,WAAU;IATZ,UAAA,CAWE,qBAACC,QAAD;KAAY,WAAW,MAAM,cAAc,eAAe;KAA1D,UAAA,CACE,oBAACC,aAAD,EAAA,gBAAwB,KAAsB,CAAA,GAC9C,oBAAC,OAAD;MACE,eAAY;MACZ,SAAQ;MACR,MAAK;MACL,QAAO;MACP,aAAY;MACZ,eAAc;MACd,gBAAe;MACf,WAAU;MAEV,UAAA,oBAAC,QAAD,EAAM,GAAE,eAAgB,CAAA;KACrB,CAAA,CACK;IACZ,CAAA,GAAA,oBAACC,SAAD;KACE,WAAU;KACV,QAAQ;KACR,aAAU;KACV,WAAW,MAAM,sBAAsB,GAAG,MAAM;KAEhD,UAAA,oBAACC,SAAD;MAAa,cAAW;MAAW,WAAU;MAC1C,UAAA,QAAQ,KAAK,WACZ,qBAAC,YAAD;OAA8B,IAAI,OAAO;OAAM,WAAW,OAAO;OAAjE,UAAA;QACE,oBAAC,QAAD;SAAM,eAAY;SAAO,WAAU;SAChC,UAAA,OAAO;QACJ,CAAA;QACN,oBAAC,QAAD;SAAM,WAAU;SAAsC,UAAA,OAAO;QAAW,CAAA;QACxE,oBAAC,QAAD;SAAM,WAAU;SACb,UAAA,OAAO;QACJ,CAAA;OACI;MARK,GAAA,OAAO,IAQZ,CACb;KACU,CAAA;IACF,CAAA,CACH;GAEZ,CAAA,IAAA,oBAAC,QAAD;IACE,aAAU;IACV,WAAU;IAET,UAAA;GACG,CAAA,CAEC;;EAEV,MAAM,SAAS,KAAK,QACnB,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACG,MAAM,SAAS,IACd,oBAAC,OAAD;IAAK,MAAK;IAAQ,cAAW;IAAY,WAAU;IAChD,UAAA,MAAM,KAAK,WACV,qBAACC,UAAD;KAEE,SAAQ;KACR,MAAK;KACL,YAAY,YAAa,QAAQ,KAAA,MAAc,SAAS,MAAM;KAC9D,iBAAe;KACf,cAAY,OAAO,KAAK,MAAM,OAAO,MAAM;KAC3C,eAAe,MAAM,SAAS,MAAM,KAAK,MAAM,GAAG,MAAM;KAP1D,UAAA,CAQC,KACG,KAAK,MAAM,OAAO,MAAM,CACpB;IATD,GAAA,MASC,CACT;GACE,CAAA,IACH,MACH,QACC,oBAAC,QAAD;IACE,IAAI;IACJ,cAAY,SAAS,KAAA;IACrB,WAAU;IAET,UAAA;GACG,CAAA,IACJ,IACD;EACH,CAAA,IAAA;EAEH,OAAO,oBAAC,SAAD;GAAO,MAAK;GAAe;GAAM,OAAO,SAAS;EAAK,CAAA,IAAI;EAClE,oBAAC,QAAD;GAAM,WAAU;GAAU,MAAK;GAAS,aAAU;GAC/C,UAAA;EACG,CAAA;CACN,EAAA,CAAA;CAGJ,OACE,oBAAC,OAAD;EAAK,WAAW,GAAG,4BAA4B,SAAS;EAAG,aAAU;EACnE,UAAA,oBAAC,YAAD;GACE,OAAO,cAAc,OAAO;GAC5B,WAAW,MAAM;GACJ;GACb,QAAQ,MAAM;GACd,OAAO;GACP,SAAS,MAAM;GAEd,UAAA;EACS,CAAA;CACT,CAAA;AAET,CAAC"}
|
|
1
|
+
{"version":3,"file":"money-input.js","names":["AriaGroup","AriaInput","AriaSelect","AriaButton","AriaSelectValue","AriaPopover","AriaListBox","Button"],"sources":["../../src/money-input/money-input.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n forwardRef,\n useCallback,\n useId,\n useImperativeHandle,\n useMemo,\n useReducer,\n useRef,\n useState,\n type ClipboardEvent,\n type FocusEvent,\n type KeyboardEvent,\n} from \"react\";\nimport {\n Button as AriaButton,\n Group as AriaGroup,\n Input as AriaInput,\n ListBox as AriaListBox,\n Popover as AriaPopover,\n Select as AriaSelect,\n SelectValue as AriaSelectValue,\n type Key,\n} from \"react-aria-components\";\n\nimport { Button } from \"../button/button.js\";\nimport { cn, cnAll } from \"../lib/cn.js\";\nimport { FieldShell, useFieldWiring } from \"../lib/field-shell.js\";\nimport { FieldMessage, RollingNumber } from \"../lib/field-message.js\";\nimport { fieldBoxSize, fieldSurfaceVariants, fieldTextSize } from \"../lib/field-surface.js\";\nimport { useIsomorphicLayoutEffect, useMorphWidth } from \"../lib/motion.js\";\nimport { SwapText } from \"../lib/swap-text.js\";\nimport { SelectItem, selectPopoverVariants } from \"../select/select.js\";\n\n/** What `onValueChange` hands over beside the minor-unit amount. */\nexport interface MoneyInputDetails {\n currency: string;\n /** The amount in major units, such as 12.5 for $12.50. */\n major: number | null;\n /** The amount as a full currency string, such as \"$12.50\". */\n formatted: string;\n}\n\n/** The field sizes: the large `\"hero\"` amount, or one of Input's `sm`, `md` and `lg` rungs. */\nexport type MoneyInputSize = \"hero\" | \"sm\" | \"md\" | \"lg\";\n\n/**\n * MoneyInput: a currency amount. The value is in minor units, so $12.50 is 1250\n * and 500 yen is 500. Digits group as they are typed without moving the caret,\n * the cents that are still missing wait as muted ghosts so the amount never\n * changes width when it settles, a long amount scales down to fit instead of\n * scrolling, and the quick-add buttons and the arrow keys roll the digits. A\n * currency menu switches the currency (pass one code to hide it); the symbol\n * swaps in place and the digits are kept. Amounts and the currency come from\n * `Intl.NumberFormat`, so the symbol, its side, the grouping and the number of\n * decimals follow the currency and the locale.\n *\n * `min` is checked when the field loses focus; `max` is enforced as you type: a\n * digit that would pass it is refused and the amount strains toward it. Wording\n * for the range comes from the currency, and `error` replaces it.\n *\n * `isInvalid` and `errorMessage` are the pair Select and MultiSelect take: the\n * app's own validation marks the field invalid, and the message shows only while\n * it is (or while the amount is out of range, whose wording it then replaces).\n */\nexport interface MoneyInputProps {\n /**\n * How big the field is. `\"hero\"` is the large amount field: a 76px panel\n * with the amount at the type scale's h2 size. `\"sm\"`, `\"md\"` and `\"lg\"`\n * are Input's own rungs: the same height and inline padding (the\n * `--density-control-*` tokens), the same text size, the same radius and\n * the same border, so the amount sits level with an Input, a Select or a\n * Button of that size in a form row. The currency menu shrinks to fit inside\n * the box; the quick-add row and the messages are unchanged.\n *\n * @default \"hero\"\n */\n size?: MoneyInputSize;\n /** What the amount is, and the field's accessible name. */\n label: string;\n /** Render the label for screen readers only. */\n labelHidden?: boolean;\n /** Amount in minor units (cents for USD, yen for JPY). `null` is empty. */\n value?: number | null;\n defaultValue?: number | null;\n onValueChange?: (value: number | null, details: MoneyInputDetails) => void;\n /** ISO 4217 code, such as \"USD\". */\n currency?: string;\n defaultCurrency?: string;\n onCurrencyChange?: (currency: string) => void;\n /** Codes offered by the currency menu. Pass one code to hide the menu. */\n currencies?: string[];\n /** Lowest amount in minor units. Checked when the field loses focus. */\n min?: number;\n /** Highest amount in minor units. Typing past it is refused with a nudge. */\n max?: number;\n /** Quick-add buttons in major units. Pass an empty array to hide them. */\n quickAdd?: number[];\n /** Arrow keys move by this many minor units. Defaults to one major unit; Shift moves ten times as far. */\n step?: number;\n /** Formatting locale. Fixed by default so server and client render the same digits. */\n locale?: string;\n /** Helper text under the field. A string, because the copy is animated word by word. */\n description?: string;\n /** Replaces the built-in range message. Shown whenever it is set. */\n error?: string;\n /**\n * Marks the amount invalid: the destructive border and `aria-invalid`, with or\n * without a message. An amount outside `min`/`max` also becomes invalid on its\n * own, once the field loses focus. Without `errorMessage` no text is shown, so\n * the app must say what is wrong itself (WCAG 3.3.1).\n *\n * @default false\n */\n isInvalid?: boolean;\n /**\n * Why the amount is wrong, shown under the field while it is invalid\n * (`isInvalid`, or out of range, whose built-in wording it replaces) and tied\n * to the input as its error. A string, because the copy is animated word by\n * word: unlike Select and MultiSelect, whose `errorMessage` is a `ReactNode`.\n * `error`, when set, wins.\n */\n errorMessage?: string;\n disabled?: boolean;\n /** Adds a hidden input carrying the amount in minor units. */\n name?: string;\n id?: string;\n /** Extra classes for the wrapper. Merged last. */\n className?: string;\n onBlur?: (event: FocusEvent<HTMLInputElement>) => void;\n}\n\ntype Source = \"type\" | \"chip\" | \"key\" | \"external\";\ninterface CurrencyInfo {\n code: string;\n symbol: string;\n position: \"prefix\" | \"suffix\";\n digits: number;\n name: string;\n whole: Intl.NumberFormat;\n full: Intl.NumberFormat;\n}\n\nconst MAX_INTEGER_DIGITS = 12;\n/** How far, in px, the amount is pushed toward a limit it just met. */\nconst STRAIN_PX = 6;\n\nconst infoCache = new Map<string, CurrencyInfo>();\nfunction currencyInfo(code: string, locale: string): CurrencyInfo {\n const cacheKey = `${locale}:${code}`;\n const cached = infoCache.get(cacheKey);\n if (cached) return cached;\n const full = new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency: code,\n currencyDisplay: \"narrowSymbol\",\n numberingSystem: \"latn\",\n });\n const parts = full.formatToParts(1);\n const symbolAt = parts.findIndex((part) => part.type === \"currency\");\n const numberAt = parts.findIndex((part) => part.type === \"integer\");\n const digits = full.resolvedOptions().maximumFractionDigits ?? 2;\n let name = code;\n try {\n name = new Intl.DisplayNames([locale], { type: \"currency\" }).of(code) ?? code;\n } catch {\n // Older engines keep the code.\n }\n const info: CurrencyInfo = {\n code,\n symbol: parts[symbolAt]?.value ?? code,\n position: symbolAt < numberAt ? \"prefix\" : \"suffix\",\n digits,\n name: name.charAt(0).toUpperCase() + name.slice(1),\n full,\n whole: new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency: code,\n currencyDisplay: \"narrowSymbol\",\n maximumFractionDigits: 0,\n numberingSystem: \"latn\",\n }),\n };\n infoCache.set(cacheKey, info);\n return info;\n}\n\nfunction localeSymbols(locale: string) {\n const parts = new Intl.NumberFormat(locale, { numberingSystem: \"latn\" }).formatToParts(12345.6);\n return {\n group: parts.find((part) => part.type === \"group\")?.value ?? \",\",\n decimal: parts.find((part) => part.type === \"decimal\")?.value ?? \".\",\n };\n}\n\n/* A draft is the amount as typed in a canonical form: digits with an optional \".\", such as \"1234.5\". */\nconst pow10 = (digits: number) => 10 ** digits;\nfunction toMinor(draft: string, digits: number): number | null {\n if (!draft) return null;\n const [whole, fraction = \"\"] = draft.split(\".\");\n return (\n Number(whole || \"0\") * pow10(digits) + Number(fraction.padEnd(digits, \"0\").slice(0, digits) || \"0\")\n );\n}\nfunction fromMinor(minor: number | null | undefined, digits: number) {\n if (minor === null || minor === undefined || !Number.isFinite(minor)) return \"\";\n const text = String(Math.round(Math.abs(minor))).padStart(digits + 1, \"0\");\n return digits ? `${text.slice(0, text.length - digits)}.${text.slice(text.length - digits)}` : text;\n}\n/** Settles a draft the way it will be read back: fraction padded to the currency, leading zeros gone. */\nfunction settle(draft: string, digits: number) {\n return draft ? fromMinor(toMinor(draft, digits), digits) : \"\";\n}\n/** Carries an amount across currencies with different minor units, keeping the major amount. */\nfunction convertDraft(draft: string, digits: number) {\n if (!draft) return \"\";\n const [whole = \"\", fraction] = draft.split(\".\");\n if (!digits) return whole || \"0\";\n return fraction === undefined ? whole : `${whole}.${fraction.slice(0, digits)}`;\n}\n\nconst groupInteger = (whole: string, group: string) =>\n whole.replace(/\\B(?=(\\d{3})+(?!\\d))/g, group);\nfunction displayOf(draft: string, symbols: { group: string; decimal: string }) {\n if (!draft) return \"\";\n const [whole = \"\", fraction] = draft.split(\".\");\n return groupInteger(whole, symbols.group) + (fraction !== undefined ? symbols.decimal + fraction : \"\");\n}\n\nconst isSignificant = (char: string, decimal: string) => /\\d/.test(char) || char === decimal;\nfunction positionAfter(text: string, count: number, decimal: string) {\n if (count <= 0) return 0;\n let seen = 0;\n for (let index = 0; index < text.length; index++) {\n if (isSignificant(text[index]!, decimal) && ++seen === count) return index + 1;\n }\n return text.length;\n}\n\n/** The currency symbol swaps with a short rise while its slot springs to the new width. */\nfunction SymbolSlot({ symbol, side }: { symbol: string; side: \"prefix\" | \"suffix\" }) {\n const content = useRef<HTMLSpanElement>(null);\n useMorphWidth(content, symbol);\n return (\n <span\n aria-hidden=\"true\"\n data-slot=\"money-input-symbol\"\n className={cnAll(\"button-slot text-text-secondary\", side === \"prefix\" ? \"me-1\" : \"ms-1.5\")}\n >\n <span ref={content} className=\"inline-flex flex-none items-center whitespace-pre\">\n <SwapText swapKey={symbol} motion=\"rise\" className=\"inline-block\">\n {symbol}\n </SwapText>\n </span>\n </span>\n );\n}\n\n/** The amount the eye sees: whole part, separator and the cents, with the missing ones as muted ghosts. */\nfunction Amount({\n draft,\n digits,\n symbols,\n direction,\n still,\n}: {\n draft: string;\n digits: number;\n symbols: { group: string; decimal: string };\n direction: 1 | -1;\n still: boolean;\n}) {\n const [whole = \"\", fraction] = draft ? draft.split(\".\") : [];\n const typed = fraction ?? \"\";\n const ghostWhole = !whole;\n return (\n <>\n <span data-ghost={ghostWhole || undefined} className=\"inline-flex data-[ghost]:text-muted-foreground\">\n <RollingNumber\n word={groupInteger(whole || \"0\", symbols.group)}\n direction={direction}\n still={still}\n />\n </span>\n {digits > 0 ? (\n <>\n <span\n data-ghost={fraction === undefined || undefined}\n className=\"data-[ghost]:text-muted-foreground\"\n >\n {symbols.decimal}\n </span>\n {typed ? (\n <span className=\"inline-flex\">\n <RollingNumber word={typed} direction={direction} still={still} />\n </span>\n ) : null}\n {typed.length < digits ? (\n <span className=\"text-muted-foreground\">{\"0\".repeat(digits - typed.length)}</span>\n ) : null}\n </>\n ) : null}\n </>\n );\n}\n\nconst triggerClass =\n \"inline-flex h-9 flex-none cursor-pointer items-center gap-1 rounded-pill border-0 bg-transparent ps-3 pe-2 font-sans text-sm font-medium tabular-nums text-foreground outline-none motion-safe:transition-[background-color] motion-safe:duration-(--duration-quick) motion-safe:ease-settle data-[hovered]:bg-muted data-[pressed]:bg-muted data-[disabled]:cursor-not-allowed data-[focus-visible]:outline-solid data-[focus-visible]:outline-(length:--focus-ring-width) data-[focus-visible]:outline-offset-(--focus-ring-offset) data-[focus-visible]:outline-(--color-ring)\";\n\n// Focus turns the box's own border dark whenever the amount holds focus; no separate ring.\nconst shellFocus = [\n \"has-[input:focus]:not-data-[invalid]:border-foreground\",\n \"forced-colors:has-[input:focus]:outline-solid forced-colors:has-[input:focus]:outline-(length:--focus-ring-width) forced-colors:has-[input:focus]:outline-offset-(--focus-ring-offset)\",\n];\n\nconst shellClass = cnAll(\n fieldSurfaceVariants(),\n \"flex h-19 items-center gap-2 rounded-panel ps-4.5 pe-2\",\n ...shellFocus,\n);\n\n/*\n * The field sizes take Input's box whole: fieldSurfaceVariants (border, radius\n * `rounded-control`, ground) plus fieldBoxSize (height and inline padding from\n * the `--density-control-*` tokens), so the two cannot drift apart. With a\n * currency menu the end padding drops to a 4px inset and the menu button\n * stretches to the box's inner height less that inset, so it sits centred in\n * the field at every rung and density.\n */\nconst fieldShellClass = (size: Exclude<MoneyInputSize, \"hero\">, hasMenu: boolean) =>\n cnAll(\n fieldSurfaceVariants(),\n \"flex items-center gap-2\",\n fieldBoxSize[size],\n ...shellFocus,\n hasMenu && \"pe-1\",\n );\nconst fieldTriggerClass = cnAll(triggerClass, \"h-auto self-stretch my-1 ps-2.5 pe-1.5\");\n\n/* The amount's type: the h2 display face for the hero, Input's own text rule for a field size. */\nconst amountBase = \"inline-flex flex-none origin-left items-baseline whitespace-nowrap\";\nconst amountRest =\n \"tabular-nums text-foreground data-[ready]:motion-safe:transition-[scale] data-[ready]:motion-safe:duration-(--duration-smooth) data-[ready]:motion-safe:ease-smooth data-[strain]:motion-safe:animate-field-strain\";\n// A field size sets no face or weight of its own, as Input sets none: both inherit the wrapper's.\nconst amountClass = (size: MoneyInputSize) =>\n [\n amountBase,\n size === \"hero\" ? \"font-display text-h2 font-medium\" : fieldTextSize[size],\n amountRest,\n ].join(\" \");\n\nexport const MoneyInput = forwardRef<HTMLInputElement, MoneyInputProps>(function MoneyInput(\n {\n size = \"hero\",\n label,\n labelHidden = false,\n value,\n defaultValue = null,\n onValueChange,\n currency: currencyProp,\n defaultCurrency = \"USD\",\n onCurrencyChange,\n currencies = [\"USD\", \"EUR\", \"GBP\", \"JPY\", \"CAD\", \"AUD\", \"CHF\", \"INR\"],\n min,\n max,\n quickAdd = [10, 50, 100],\n step: stepProp,\n locale = \"en-US\",\n description,\n error,\n isInvalid = false,\n errorMessage,\n disabled = false,\n name,\n id,\n className,\n onBlur,\n },\n forwardedRef,\n) {\n const generated = useId();\n const inputId = id ?? `${generated}-amount`;\n const rangeId = `${inputId}-range`;\n\n const [innerCurrency, setInnerCurrency] = useState(defaultCurrency);\n const code = currencyProp ?? innerCurrency;\n const info = useMemo(() => currencyInfo(code, locale), [code, locale]);\n const symbols = useMemo(() => localeSymbols(locale), [locale]);\n const step = stepProp && stepProp > 0 ? stepProp : pow10(info.digits);\n\n const [draft, setDraft] = useState(() => fromMinor(value !== undefined ? value : defaultValue, info.digits));\n const minor = toMinor(draft, info.digits);\n\n const [seenValue, setSeenValue] = useState(value);\n const [source, setSource] = useState<Source>(\"external\");\n const [direction, setDirection] = useState<1 | -1>(1);\n if (value !== seenValue) {\n setSeenValue(value);\n if (value !== undefined && value !== minor) {\n setDraft(fromMinor(value, info.digits));\n setSource(\"external\");\n setDirection((value ?? 0) >= (minor ?? 0) ? 1 : -1);\n }\n }\n\n const [focused, setFocused] = useState(false);\n const [touched, setTouched] = useState(false);\n const [flash, setFlash] = useState(false);\n const [announcement, setAnnouncement] = useState(\"\");\n const [, rerender] = useReducer((count: number) => count + 1, 0);\n\n const inputRef = useRef<HTMLInputElement>(null);\n useImperativeHandle(forwardedRef, () => inputRef.current as HTMLInputElement);\n const pendingCaret = useRef<number | null>(null);\n const latest = useRef({ minor, draft });\n useIsomorphicLayoutEffect(() => {\n latest.current = { minor, draft };\n });\n\n const money = useCallback(\n (amount: number | null) => (amount === null ? \"\" : info.full.format(amount / pow10(info.digits))),\n [info],\n );\n\n /* ---------------------------------------------- Limits and feedback ---------------------------------------------- */\n\n const groupRef = useRef<HTMLDivElement>(null);\n const flashTimer = useRef<number | undefined>(undefined);\n function refuse(toward: 1 | -1, limit: number) {\n const node = groupRef.current;\n if (node) {\n node.style.setProperty(\"--strain-x\", `${toward * STRAIN_PX}px`);\n // Restart the animation: the attribute has to leave and come back across a style recalculation.\n node.removeAttribute(\"data-strain\");\n void node.offsetWidth;\n node.setAttribute(\"data-strain\", \"\");\n }\n setFlash(true);\n window.clearTimeout(flashTimer.current);\n flashTimer.current = window.setTimeout(() => setFlash(false), 1400);\n setAnnouncement(`${toward > 0 ? \"Maximum\" : \"Minimum\"} is ${money(limit)}`);\n }\n\n function emit(nextMinor: number | null, nextInfo = info) {\n onValueChange?.(nextMinor, {\n currency: nextInfo.code,\n major: nextMinor === null ? null : nextMinor / pow10(nextInfo.digits),\n formatted:\n nextMinor === null ? \"\" : nextInfo.full.format(nextMinor / pow10(nextInfo.digits)),\n });\n }\n\n function setAmount(nextDraft: string, nextSource: Source) {\n const nextMinor = toMinor(nextDraft, info.digits);\n setDirection((nextMinor ?? 0) >= (latest.current.minor ?? 0) ? 1 : -1);\n setSource(nextSource);\n setDraft(nextDraft);\n latest.current = { minor: nextMinor, draft: nextDraft };\n if (nextMinor !== minor) emit(nextMinor);\n if (nextSource !== \"type\") setAnnouncement(money(nextMinor));\n }\n\n /* ---------------------------------------------- Typing ---------------------------------------------- */\n\n /** Reads what the input holds into a draft and counts the digits and decimal before the caret, so the caret can return to the same spot. */\n function sanitize(raw: string, caret: number) {\n let out = \"\";\n let before = 0;\n let dot = false;\n for (let index = 0; index < raw.length; index++) {\n const char = raw[index]!;\n let kept = \"\";\n if (/\\d/.test(char)) kept = char;\n else if (\n (char === symbols.decimal || (char === \".\" && symbols.group !== \".\")) &&\n info.digits > 0 &&\n !dot\n ) {\n kept = \".\";\n dot = true;\n }\n if (!kept) continue;\n out += kept;\n if (index < caret) before++;\n }\n const pieces = out.split(\".\");\n let whole = pieces[0]!;\n const fraction = pieces[1];\n const stripped = whole.length - whole.replace(/^0+/, \"\").length;\n whole = whole.replace(/^0+/, \"\");\n let shift = -Math.min(stripped, before);\n if (fraction !== undefined && !whole) {\n whole = \"0\";\n shift += 1;\n }\n if (fraction === undefined && !whole && stripped) {\n whole = \"0\";\n shift += 1;\n }\n if (fraction !== undefined && fraction.length > info.digits) return null;\n if (whole.length > MAX_INTEGER_DIGITS) return null;\n return {\n draft: fraction !== undefined ? `${whole}.${fraction}` : whole,\n before: Math.max(0, before + shift),\n };\n }\n\n function applyRaw(raw: string, caret: number) {\n const result = sanitize(raw, caret);\n // A refused keystroke keeps the caret where it was: one significant character before where the browser left it.\n if (!result) {\n pendingCaret.current = Math.max(\n 0,\n [...raw.slice(0, caret)].filter((char) => isSignificant(char, symbols.decimal) || char === \".\")\n .length - 1,\n );\n rerender();\n return;\n }\n const nextMinor = toMinor(result.draft, info.digits);\n if (max !== undefined && nextMinor !== null && nextMinor > max) {\n pendingCaret.current = Math.max(0, result.before - 1);\n refuse(1, max);\n rerender();\n return;\n }\n pendingCaret.current = result.before;\n setAmount(result.draft, \"type\");\n }\n\n useIsomorphicLayoutEffect(() => {\n const input = inputRef.current;\n const count = pendingCaret.current;\n pendingCaret.current = null;\n if (!input || count === null || document.activeElement !== input) return;\n const position = positionAfter(input.value, count, symbols.decimal);\n input.setSelectionRange(position, position);\n });\n\n function nudge(amount: number, nextSource: Source) {\n const from = latest.current.minor ?? 0;\n const floor = min ?? 0;\n const ceiling = max ?? Number.MAX_SAFE_INTEGER;\n let next = from + amount;\n if (next > ceiling) {\n if (from >= ceiling) {\n refuse(1, ceiling);\n return;\n }\n next = ceiling;\n refuse(1, ceiling);\n }\n if (next < floor) {\n if (from <= floor && latest.current.minor !== null) {\n refuse(-1, floor);\n return;\n }\n next = floor;\n }\n pendingCaret.current = Number.MAX_SAFE_INTEGER;\n setAmount(fromMinor(next, info.digits), nextSource);\n }\n\n function onKeyDown(event: KeyboardEvent<HTMLInputElement>) {\n const input = event.currentTarget;\n const moves: Record<string, number> = { ArrowUp: 1, ArrowDown: -1, PageUp: 10, PageDown: -10 };\n if (event.key in moves) {\n event.preventDefault();\n const unit = moves[event.key]!;\n nudge(unit * step * (event.shiftKey && Math.abs(unit) === 1 ? 10 : 1), \"key\");\n return;\n }\n if (event.key === \"Enter\") {\n setDraft(settle(draft, info.digits));\n pendingCaret.current = Number.MAX_SAFE_INTEGER;\n return;\n }\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n if (start !== end || event.metaKey || event.ctrlKey || event.altKey) return;\n // Deleting a group separator deletes the digit before it instead of doing nothing.\n if (event.key === \"Backspace\" && start > 1 && input.value[start - 1] === symbols.group) {\n event.preventDefault();\n applyRaw(input.value.slice(0, start - 2) + input.value.slice(start - 1), start - 2);\n }\n if (event.key === \"Delete\" && input.value[start] === symbols.group) {\n event.preventDefault();\n applyRaw(input.value.slice(0, start + 1) + input.value.slice(start + 2), start);\n }\n }\n\n function onPaste(event: ClipboardEvent<HTMLInputElement>) {\n const text = event.clipboardData.getData(\"text\").trim();\n if (!text) return;\n event.preventDefault();\n // \"$1,234.56\", \"1.234,56 EUR\", \"1234.5\": a final separator followed by one or two digits is the decimal; the rest are groups.\n const match = /[.,](\\d{1,2})\\s*\\D*$/.exec(text);\n const whole = (match ? text.slice(0, match.index) : text).replace(/\\D/g, \"\");\n const pasted = match && info.digits ? `${whole}.${match[1]}` : whole;\n if (!/\\d/.test(pasted)) return;\n const input = event.currentTarget;\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n const inserted = pasted.replace(\".\", symbols.decimal);\n const replaceAll = (start === 0 && end === input.value.length) || !input.value;\n const raw = replaceAll ? inserted : input.value.slice(0, start) + inserted + input.value.slice(end);\n applyRaw(raw, replaceAll ? raw.length : start + inserted.length);\n }\n\n /* ---------------------------------------------- Fit to width ---------------------------------------------- */\n\n // A long amount scales down to fit its room instead of scrolling, so it is always read whole. The first fit\n // is not animated; later ones follow on the smooth spring (the group's `data-ready` turns the transition on).\n const wrapRef = useRef<HTMLDivElement>(null);\n useIsomorphicLayoutEffect(() => {\n const wrap = wrapRef.current;\n const group = groupRef.current;\n if (!wrap || !group || typeof ResizeObserver === \"undefined\") return;\n const fit = () => {\n const natural = group.offsetWidth;\n const room = wrap.clientWidth;\n group.style.scale = String(natural > 0 && room > 0 ? Math.min(1, room / natural) : 1);\n if (!group.hasAttribute(\"data-ready\")) {\n void group.offsetWidth;\n group.setAttribute(\"data-ready\", \"\");\n }\n };\n fit();\n const observer = new ResizeObserver(fit);\n observer.observe(wrap);\n observer.observe(group);\n return () => observer.disconnect();\n }, []);\n\n /* ---------------------------------------------- Currency ---------------------------------------------- */\n\n const options = useMemo(() => currencies.map((entry) => currencyInfo(entry, locale)), [currencies, locale]);\n\n function chooseCurrency(next: CurrencyInfo) {\n if (next.code === code) return;\n const nextDraft = focused\n ? convertDraft(draft, next.digits)\n : settle(convertDraft(draft, next.digits), next.digits);\n const nextMinor = toMinor(nextDraft, next.digits);\n if (currencyProp === undefined) setInnerCurrency(next.code);\n onCurrencyChange?.(next.code);\n setSource(\"external\");\n setDraft(nextDraft);\n latest.current = { minor: nextMinor, draft: nextDraft };\n emit(nextMinor, next);\n setAnnouncement(\n `${next.name}${nextMinor === null ? \"\" : `, ${next.full.format(nextMinor / pow10(next.digits))}`}`,\n );\n }\n\n /* ---------------------------------------------- Messages ---------------------------------------------- */\n\n const range =\n min !== undefined && max !== undefined\n ? `${money(min)} to ${money(max)}`\n : max !== undefined\n ? `Up to ${money(max)}`\n : min !== undefined\n ? `At least ${money(min)}`\n : \"\";\n const belowMin = minor !== null && min !== undefined && minor < min;\n const aboveMax = minor !== null && max !== undefined && minor > max;\n const builtIn =\n touched && !focused && (belowMin || aboveMax)\n ? belowMin\n ? `The minimum is ${money(min ?? 0)}`\n : `The maximum is ${money(max ?? 0)}`\n : undefined;\n const invalid = isInvalid || builtIn !== undefined;\n const message = error ?? (invalid ? (errorMessage ?? builtIn) : undefined);\n const chips = quickAdd.filter((amount) => amount > 0);\n\n const field = useFieldWiring({\n enabled: true,\n id: inputId,\n describedBy: range ? rangeId : undefined,\n invalid: invalid || undefined,\n description,\n error: message,\n });\n\n const typing = source === \"type\";\n const display = displayOf(draft, symbols);\n const canSwitch = options.length > 1;\n\n const control = (\n <>\n <AriaGroup\n role=\"presentation\"\n isDisabled={disabled}\n isInvalid={invalid || Boolean(message)}\n data-slot=\"money-input-shell\"\n className={size === \"hero\" ? shellClass : fieldShellClass(size, canSwitch)}\n >\n <div\n ref={wrapRef}\n className=\"relative flex h-full min-w-0 flex-1 cursor-text items-center overflow-hidden\"\n onMouseDown={(event) => {\n if (event.target !== inputRef.current) event.preventDefault();\n }}\n onClick={(event) => {\n if (disabled || event.target === inputRef.current) return;\n const input = inputRef.current;\n input?.focus();\n input?.setSelectionRange(input.value.length, input.value.length);\n }}\n >\n <div ref={groupRef} data-slot=\"money-input-amount\" className={amountClass(size)}>\n {info.position === \"prefix\" ? <SymbolSlot symbol={info.symbol} side=\"prefix\" /> : null}\n <span className=\"relative inline-flex\">\n {/* The digits the eye sees. The input over them draws only the caret and the selection. */}\n <span aria-hidden=\"true\" data-slot=\"money-input-display\" className=\"inline-flex\">\n <Amount\n draft={draft}\n digits={info.digits}\n symbols={symbols}\n direction={direction}\n still={typing}\n />\n </span>\n <AriaInput\n ref={inputRef}\n {...field.controlProps}\n data-slot=\"money-input-input\"\n type=\"text\"\n role=\"spinbutton\"\n inputMode={info.digits ? \"decimal\" : \"numeric\"}\n autoComplete=\"off\"\n spellCheck={false}\n value={display}\n disabled={disabled}\n aria-label={labelHidden ? label : undefined}\n aria-valuenow={minor === null ? undefined : minor / pow10(info.digits)}\n aria-valuetext={minor === null ? \"Empty\" : money(minor)}\n aria-valuemin={min === undefined ? undefined : min / pow10(info.digits)}\n aria-valuemax={max === undefined ? undefined : max / pow10(info.digits)}\n onChange={(event) =>\n applyRaw(\n event.currentTarget.value,\n event.currentTarget.selectionStart ?? event.currentTarget.value.length,\n )\n }\n onKeyDown={onKeyDown}\n onPaste={onPaste}\n onFocus={() => setFocused(true)}\n onBlur={(event) => {\n setFocused(false);\n setTouched(true);\n if (draft) setDraft(settle(draft, info.digits));\n onBlur?.(event);\n }}\n className=\"absolute top-0 left-0 z-10 m-0 h-full w-[calc(100%+0.5em)] border-0 bg-transparent p-0 [font:inherit] text-transparent caret-foreground outline-none selection:bg-primary/20 selection:text-transparent data-[disabled]:cursor-not-allowed\"\n />\n </span>\n {info.position === \"suffix\" ? <SymbolSlot symbol={info.symbol} side=\"suffix\" /> : null}\n </div>\n </div>\n\n {canSwitch ? (\n <AriaSelect\n aria-label=\"Currency\"\n selectedKey={code}\n isDisabled={disabled}\n onSelectionChange={(key: Key | null) => {\n const next = options.find((option) => option.code === key);\n if (next) chooseCurrency(next);\n }}\n data-slot=\"money-input-currency\"\n className=\"flex-none\"\n >\n <AriaButton\n className={cnAll(size === \"hero\" ? triggerClass : fieldTriggerClass, \"group/trigger\")}\n >\n <AriaSelectValue>{() => code}</AriaSelectValue>\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"size-4 text-muted-foreground motion-safe:transition-[rotate] motion-safe:duration-(--duration-gentle) motion-safe:ease-gentle group-aria-expanded/trigger:rotate-180\"\n >\n <path d=\"m4 6 4 4 4-4\" />\n </svg>\n </AriaButton>\n <AriaPopover\n placement=\"bottom end\"\n offset={12}\n data-slot=\"money-input-currency-popover\"\n className={cnAll(selectPopoverVariants(), \"w-64\")}\n >\n <AriaListBox aria-label=\"Currency\" className=\"outline-none\">\n {options.map((option) => (\n <SelectItem key={option.code} id={option.code} textValue={option.code}>\n <span aria-hidden=\"true\" className=\"w-6 flex-none text-center text-muted-foreground\">\n {option.symbol}\n </span>\n <span className=\"flex-none font-medium tabular-nums\">{option.code}</span>\n <span className=\"min-w-0 flex-1 truncate text-xs text-muted-foreground\">\n {option.name}\n </span>\n </SelectItem>\n ))}\n </AriaListBox>\n </AriaPopover>\n </AriaSelect>\n ) : (\n <span\n data-slot=\"money-input-currency\"\n className={cnAll(\n \"flex-none px-2.5 text-sm font-medium text-text-secondary\",\n size !== \"hero\" && \"pe-0\",\n )}\n >\n {code}\n </span>\n )}\n </AriaGroup>\n\n {/* The error sits directly under the amount, above the quick-add row. */}\n <FieldMessage id={field.errorId} text={message} tone=\"error\" />\n\n {chips.length > 0 || range ? (\n <div className=\"flex flex-wrap items-center justify-between gap-x-3 gap-y-2 pt-3\">\n {chips.length > 0 ? (\n <div role=\"group\" aria-label=\"Quick add\" className=\"flex flex-wrap gap-1.5\">\n {chips.map((amount) => (\n <Button\n key={amount}\n variant=\"outlineNeutral\"\n size=\"sm\"\n isDisabled={disabled || (max !== undefined && (minor ?? 0) >= max)}\n aria-controls={inputId}\n aria-label={`Add ${info.whole.format(amount)}`}\n onPress={() => nudge(amount * pow10(info.digits), \"chip\")}\n >\n +{info.whole.format(amount)}\n </Button>\n ))}\n </div>\n ) : null}\n {range ? (\n <span\n id={rangeId}\n data-flash={flash || undefined}\n className=\"text-xs tabular-nums text-muted-foreground motion-safe:transition-colors motion-safe:duration-(--duration-standard) data-[flash]:text-destructive-strong motion-safe:data-[flash]:duration-(--duration-instant)\"\n >\n {range}\n </span>\n ) : null}\n </div>\n ) : null}\n\n {name ? <input type=\"hidden\" name={name} value={minor ?? \"\"} /> : null}\n <span className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n {announcement}\n </span>\n </>\n );\n\n return (\n <div className={cn(\"w-full min-w-0 font-sans\", className)} data-slot=\"money-input\">\n <FieldShell\n label={labelHidden ? null : label}\n controlId={field.controlId}\n description={description}\n hintId={field.hintId}\n error={undefined}\n errorId={undefined}\n >\n {control}\n </FieldShell>\n </div>\n );\n});\n"],"mappings":"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"}
|
|
@@ -63,9 +63,34 @@ export interface MorphSelectProps {
|
|
|
63
63
|
/** Adds a hidden input for native form submission. */
|
|
64
64
|
name?: string;
|
|
65
65
|
disabled?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* The trigger's `id`, so a `<label htmlFor>` outside the select (or a form
|
|
68
|
+
* library that focuses a field by id) reaches the real control. When such a
|
|
69
|
+
* label exists it NAMES the trigger: the trigger then drops its
|
|
70
|
+
* `aria-labelledby` to the inner `label`, which would otherwise outrank the
|
|
71
|
+
* outside label in the accessible-name computation.
|
|
72
|
+
*/
|
|
73
|
+
id?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Marks the choice as wrong: the trigger takes the invalid border and is
|
|
76
|
+
* `aria-invalid`. Pair it with `errorMessage`, or the state is shown visually in colour only.
|
|
77
|
+
*/
|
|
78
|
+
isInvalid?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Why the choice is wrong, under the control. It shows only while `isInvalid`
|
|
81
|
+
* is set, and is named in the trigger's and the search field's `aria-describedby`.
|
|
82
|
+
*/
|
|
83
|
+
errorMessage?: ReactNode;
|
|
84
|
+
/**
|
|
85
|
+
* Stretches the trigger to fill its container, like Input and Select, instead of hugging
|
|
86
|
+
* its content up to 20rem. The open surface is then as wide as the trigger. `panelWidth`
|
|
87
|
+
* does not apply.
|
|
88
|
+
* @default false
|
|
89
|
+
*/
|
|
90
|
+
fullWidth?: boolean;
|
|
66
91
|
/** Extra classes for the wrapper. Merged last. */
|
|
67
92
|
className?: string;
|
|
68
93
|
}
|
|
69
|
-
export declare function MorphSelect({ label, labelHidden, items, value, defaultValue, onValueChange, placeholder, searchable, searchPlaceholder, panelWidth, maxListHeight, align, size, name, disabled, className }: MorphSelectProps): import("react").JSX.Element;
|
|
94
|
+
export declare function MorphSelect({ label, labelHidden, items, value, defaultValue, onValueChange, placeholder, searchable, searchPlaceholder, panelWidth, maxListHeight, align, size, name, disabled, id, isInvalid, errorMessage, fullWidth, className }: MorphSelectProps): import("react").JSX.Element;
|
|
70
95
|
//#endregion
|
|
71
96
|
//# sourceMappingURL=morph-select.d.ts.map
|
|
@@ -72,9 +72,11 @@ function LeavingLayer({ id, rect, dir, fly, onDone, children }) {
|
|
|
72
72
|
children
|
|
73
73
|
});
|
|
74
74
|
}
|
|
75
|
-
function MorphSelect({ label, labelHidden = false, items, value, defaultValue = null, onValueChange, placeholder = "Select", searchable = "auto", searchPlaceholder, panelWidth = 272, maxListHeight = 296, align = "start", size = "md", name, disabled = false, className }) {
|
|
75
|
+
function MorphSelect({ label, labelHidden = false, items, value, defaultValue = null, onValueChange, placeholder = "Select", searchable = "auto", searchPlaceholder, panelWidth = 272, maxListHeight = 296, align = "start", size = "md", name, disabled = false, id, isInvalid = false, errorMessage, fullWidth = false, className }) {
|
|
76
76
|
const uid = useId();
|
|
77
77
|
const labelId = `${uid}-label`;
|
|
78
|
+
const errorId = `${uid}-error`;
|
|
79
|
+
const showError = isInvalid && errorMessage != null;
|
|
78
80
|
const listId = `${uid}-list`;
|
|
79
81
|
const optionId = (index) => `${uid}-option-${index}`;
|
|
80
82
|
const rootRef = useRef(null);
|
|
@@ -84,6 +86,7 @@ function MorphSelect({ label, labelHidden = false, items, value, defaultValue =
|
|
|
84
86
|
const faceRef = useRef(null);
|
|
85
87
|
const scrollRef = useRef(null);
|
|
86
88
|
const triggerRef = useRef(null);
|
|
89
|
+
const [outsideLabel, setOutsideLabel] = useState(false);
|
|
87
90
|
const inputRef = useRef(null);
|
|
88
91
|
const slotRef = useRef(null);
|
|
89
92
|
const layerRef = useRef(null);
|
|
@@ -121,7 +124,8 @@ function MorphSelect({ label, labelHidden = false, items, value, defaultValue =
|
|
|
121
124
|
});
|
|
122
125
|
const live = useRef({
|
|
123
126
|
open: false,
|
|
124
|
-
anchorW: 0
|
|
127
|
+
anchorW: 0,
|
|
128
|
+
full: fullWidth
|
|
125
129
|
});
|
|
126
130
|
const place = useCallback(() => {
|
|
127
131
|
const { trigger, lid, listW, listH } = sizes.current;
|
|
@@ -133,7 +137,7 @@ function MorphSelect({ label, labelHidden = false, items, value, defaultValue =
|
|
|
133
137
|
anchor.toggleAttribute("data-widening", trigger > live.current.anchorW);
|
|
134
138
|
live.current.anchorW = trigger;
|
|
135
139
|
}
|
|
136
|
-
anchor.style.width = `${trigger}px`;
|
|
140
|
+
anchor.style.width = live.current.full ? "" : `${trigger}px`;
|
|
137
141
|
shape.style.width = `${isOpen ? Math.max(trigger, listW) : trigger}px`;
|
|
138
142
|
shape.style.height = `${isOpen ? lid + listH : lid}px`;
|
|
139
143
|
}, []);
|
|
@@ -153,6 +157,7 @@ function MorphSelect({ label, labelHidden = false, items, value, defaultValue =
|
|
|
153
157
|
place();
|
|
154
158
|
}, [place]);
|
|
155
159
|
useIsomorphicLayoutEffect(() => {
|
|
160
|
+
live.current.full = fullWidth;
|
|
156
161
|
const measure = measureRef.current;
|
|
157
162
|
const face = faceRef.current;
|
|
158
163
|
const root = rootRef.current;
|
|
@@ -165,7 +170,7 @@ function MorphSelect({ label, labelHidden = false, items, value, defaultValue =
|
|
|
165
170
|
observer.observe(measure);
|
|
166
171
|
observer.observe(face);
|
|
167
172
|
return () => observer.disconnect();
|
|
168
|
-
}, [read]);
|
|
173
|
+
}, [read, fullWidth]);
|
|
169
174
|
useIsomorphicLayoutEffect(() => {
|
|
170
175
|
if (live.current.open === open) return;
|
|
171
176
|
live.current.open = open;
|
|
@@ -198,6 +203,9 @@ function MorphSelect({ label, labelHidden = false, items, value, defaultValue =
|
|
|
198
203
|
open,
|
|
199
204
|
visibleSections
|
|
200
205
|
]);
|
|
206
|
+
useIsomorphicLayoutEffect(() => {
|
|
207
|
+
setOutsideLabel(id != null && (triggerRef.current?.labels?.length ?? 0) > 0);
|
|
208
|
+
}, [id]);
|
|
201
209
|
const showSearch = open && canSearch;
|
|
202
210
|
useIsomorphicLayoutEffect(() => {
|
|
203
211
|
triggerRef.current?.toggleAttribute("inert", showSearch);
|
|
@@ -411,11 +419,13 @@ function MorphSelect({ label, labelHidden = false, items, value, defaultValue =
|
|
|
411
419
|
"data-slot": "morph-select",
|
|
412
420
|
"data-open": open || void 0,
|
|
413
421
|
"data-align": align,
|
|
422
|
+
"data-full": fullWidth || void 0,
|
|
414
423
|
"data-size": size,
|
|
415
424
|
"data-disabled": disabled || void 0,
|
|
425
|
+
"data-invalid": isInvalid || void 0,
|
|
416
426
|
style: rootStyle,
|
|
417
427
|
onBlur,
|
|
418
|
-
className: cn("morph-select-root group/ms relative inline-grid min-w-0 justify-items-start gap-2 font-sans leading-(--leading-normal) text-foreground data-[align=end]:justify-items-end data-[open]:z-30 data-[size=sm]:text-sm data-[size=md]:text-base data-[size=lg]:text-base", className),
|
|
428
|
+
className: cn("morph-select-root group/ms relative inline-grid data-[full]:grid data-[full]:w-full min-w-0 justify-items-start gap-2 font-sans leading-(--leading-normal) text-foreground data-[align=end]:justify-items-end data-[open]:z-30 data-[size=sm]:text-sm data-[size=md]:text-base data-[size=lg]:text-base", className),
|
|
419
429
|
children: [
|
|
420
430
|
/* @__PURE__ */ jsx("span", {
|
|
421
431
|
id: labelId,
|
|
@@ -439,16 +449,20 @@ function MorphSelect({ label, labelHidden = false, items, value, defaultValue =
|
|
|
439
449
|
"data-slot": "morph-select-shape",
|
|
440
450
|
"data-open": open || void 0,
|
|
441
451
|
"data-disabled": disabled || void 0,
|
|
452
|
+
"data-invalid": isInvalid || void 0,
|
|
442
453
|
className: "morph-select-shape",
|
|
443
454
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
444
455
|
className: "absolute inset-x-0 top-0 z-10 h-(--ms-h)",
|
|
445
456
|
children: [
|
|
446
457
|
/* @__PURE__ */ jsx("button", {
|
|
447
458
|
ref: triggerRef,
|
|
459
|
+
id,
|
|
448
460
|
type: "button",
|
|
449
461
|
role: "combobox",
|
|
450
462
|
"data-slot": "morph-select-trigger",
|
|
451
|
-
"aria-labelledby": labelId,
|
|
463
|
+
"aria-labelledby": outsideLabel ? void 0 : labelId,
|
|
464
|
+
"aria-invalid": isInvalid || void 0,
|
|
465
|
+
"aria-describedby": showError ? errorId : void 0,
|
|
452
466
|
"aria-haspopup": "listbox",
|
|
453
467
|
"aria-expanded": open,
|
|
454
468
|
"aria-controls": listId,
|
|
@@ -517,6 +531,8 @@ function MorphSelect({ label, labelHidden = false, items, value, defaultValue =
|
|
|
517
531
|
role: "combobox",
|
|
518
532
|
"data-slot": "morph-select-search",
|
|
519
533
|
"aria-label": `Search ${label.toLowerCase()}`,
|
|
534
|
+
"aria-invalid": isInvalid || void 0,
|
|
535
|
+
"aria-describedby": showError ? errorId : void 0,
|
|
520
536
|
"aria-expanded": open,
|
|
521
537
|
"aria-controls": listId,
|
|
522
538
|
"aria-autocomplete": "list",
|
|
@@ -673,6 +689,12 @@ function MorphSelect({ label, labelHidden = false, items, value, defaultValue =
|
|
|
673
689
|
})]
|
|
674
690
|
})]
|
|
675
691
|
}),
|
|
692
|
+
showError ? /* @__PURE__ */ jsx("span", {
|
|
693
|
+
id: errorId,
|
|
694
|
+
"data-slot": "morph-select-error",
|
|
695
|
+
className: "text-sm leading-(--leading-normal) text-destructive-strong",
|
|
696
|
+
children: errorMessage
|
|
697
|
+
}) : null,
|
|
676
698
|
name ? /* @__PURE__ */ jsx("input", {
|
|
677
699
|
type: "hidden",
|
|
678
700
|
name,
|