@seekalfred/primitives 0.7.1 → 0.7.3
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 +195 -4
- 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 +17 -4
- package/dist/alert-dialog/alert-dialog.js +26 -2
- package/dist/alert-dialog/alert-dialog.js.map +1 -1
- package/dist/badge/badge.d.ts +1 -1
- package/dist/button/button.d.ts +2 -2
- 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/copy-button/copy-button.d.ts +18 -2
- package/dist/copy-button/copy-button.js +29 -8
- 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/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/index.d.ts +10 -10
- package/dist/index.js +7 -7
- package/dist/input/input.js +4 -4
- package/dist/input/input.js.map +1 -1
- package/dist/lib/field-shell.js +10 -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/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 +42 -2
- package/dist/line-chart/line-chart.js +143 -14
- package/dist/line-chart/line-chart.js.map +1 -1
- package/dist/money-input/money-input.d.ts +22 -1
- package/dist/money-input/money-input.js +13 -7
- package/dist/money-input/money-input.js.map +1 -1
- package/dist/morph-select/morph-select.d.ts +19 -1
- package/dist/morph-select/morph-select.js +21 -2
- 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 +43 -2
- package/dist/multi-select/multi-select.js +93 -36
- 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/progress.d.ts +16 -2
- package/dist/progress/progress.js +15 -8
- 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/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 +1 -1
- package/dist/select/select.js +8 -6
- 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/stat-card/index.d.ts +2 -2
- package/dist/stat-card/index.js +2 -2
- package/dist/stat-card/stat-card.d.ts +34 -1
- package/dist/stat-card/stat-card.js +51 -21
- package/dist/stat-card/stat-card.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/table/table.d.ts +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":"line-chart.js","names":[],"sources":["../../src/line-chart/line-chart.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type PointerEvent,\n} from \"react\";\n\nimport { cn } from \"../lib/cn.js\";\nimport { mergeRefs } from \"../lib/merge-refs.js\";\nimport { prefersReducedMotion, useIsomorphicLayoutEffect } from \"../lib/motion.js\";\nimport { SMOOTH, SNAPPY, tween } from \"../lib/spring-tween.js\";\n\n/**\n * LineChart: one or more measures over time, when the shape of the trend\n * matters more than any single value.\n *\n * The lines draw left to right the first time the chart is seen. New data\n * morphs every line from the shape on screen, and the value axis slides to its\n * new range while gridlines fade in and out. Hiding a series flattens it into\n * the baseline as it fades and the rest rescale. Hover, drag or the arrow keys\n * scrub: a crosshair glides between points with a dot on each line and a\n * tooltip that follows on its own spring and flips before it leaves the plot.\n * `loading` keeps the current lines on screen, dimmed and breathing.\n *\n * Plain SVG and CSS; one small spring tween drives the shapes, the scale and\n * the crosshair. A visually hidden table carries every value for assistive\n * technology, and the plot itself is a slider.\n */\nexport interface LineChartSeries {\n /** Stable identity. A series keeps its line across data changes, so switching ranges morphs it. */\n key: string;\n /** Name in the legend, the tooltip and the data table. */\n label: string;\n /** Any CSS colour. Defaults to chart-1 for the first series, then quieter neutral steps. */\n color?: string;\n /** A dashed stroke, for a previous period or a target. */\n dashed?: boolean;\n /** A faint fill under the line. Defaults to true for the first series. */\n area?: boolean;\n}\n\nexport interface LineChartDatum {\n /** Stable identity, such as an ISO date. */\n key: string;\n /** Full label for the tooltip and screen readers, such as \"Tue, Sep 15\". */\n label: string;\n /** Short label on the x axis. Leave it out to keep the axis quiet at that point. */\n axisLabel?: string;\n /** One value per series key. A missing value counts as zero. */\n values: Record<string, number | undefined>;\n}\n\nexport interface LineChartProps {\n data: LineChartDatum[];\n series: LineChartSeries[];\n /** What is measured, such as \"Signups\". Names the chart for assistive technology. */\n label: string;\n /** Unit after each value in the tooltip, such as \"ms\". */\n unit?: string;\n /** Plot height in pixels. The width follows the container. @default 220 */\n height?: number;\n /** Formats values in the tooltip and data table. */\n formatValue?: (value: number, series: LineChartSeries) => string;\n /** Formats the value axis. Defaults to a compact number, such as 1.2K. */\n formatTick?: (value: number) => string;\n /** Controlled hidden series keys. */\n hiddenSeries?: string[];\n defaultHiddenSeries?: string[];\n onHiddenSeriesChange?: (hidden: string[]) => void;\n /** Called as the crosshair moves, and with null when it leaves. */\n onActiveChange?: (index: number | null, datum: LineChartDatum | null) => void;\n /** Keeps the current lines on screen, dimmed, while the next range loads. */\n loading?: boolean;\n /** Shown when there are no points. @default \"No data for this range\" */\n emptyLabel?: string;\n /** Series toggles above the plot. Shown by default when there is more than one series. */\n legend?: boolean;\n /** Header of the first column in the data table read by screen readers. @default \"Date\" */\n categoryLabel?: string;\n /** Smooth monotone curves that never swing past the data, or straight segments. @default \"smooth\" */\n curve?: \"smooth\" | \"linear\";\n /** Extra classes for the root. Merged last. */\n className?: string;\n}\n\ntype Point = [x: number, value: number];\ntype Track = { shape: Point[]; presence: number; stop: (() => void) | null };\n\n/** Room above the top gridline, and the gap between the crosshair and its tooltip. */\nconst TOP = 12;\nconst GAP = 14;\n/** The first draw: 480ms x 1.75, slow at both ends. */\nexport const LINE_CHART_DRAW_MS = 840;\nconst PALETTE = [\n \"var(--color-chart-1)\",\n \"color-mix(in oklab, var(--color-foreground) 46%, var(--color-surface))\",\n \"color-mix(in oklab, var(--color-foreground) 26%, var(--color-surface))\",\n];\nconst GROUPED = new Intl.NumberFormat(\"en-US\", { maximumFractionDigits: 1 });\nconst COMPACT = new Intl.NumberFormat(\"en-US\", { notation: \"compact\", maximumFractionDigits: 1 });\nconst GRID = Array.from({ length: 241 }, (_, index) => index / 240);\nconst clamp = (value: number, low: number, high: number) => Math.min(high, Math.max(low, value));\nconst colorOf = (line: LineChartSeries, index: number) =>\n line.color ?? PALETTE[Math.min(index, PALETTE.length - 1)]!;\nconst clean = (value: number) => Number(value.toPrecision(12));\n\n/** Clean gridlines: the smallest step of 1, 2, 2.5 or 5 that covers the data in four rows or fewer, from zero unless the data dips below it. */\nfunction niceScale(low: number, high: number) {\n const lo = Math.min(0, low);\n const hi = Math.max(high, lo + 1);\n const magnitude = 10 ** Math.floor(Math.log10((hi - lo) / 4));\n for (const factor of [1, 2, 2.5, 5, 10]) {\n const step = factor * magnitude;\n const bottom = Math.floor(lo / step) * step;\n const top = Math.ceil(hi / step) * step;\n if ((top - bottom) / step <= 4 + 1e-9) {\n const ticks: number[] = [];\n for (let value = bottom; value <= top + step / 2; value += step) ticks.push(clean(value));\n return { min: clean(bottom), max: clean(top), ticks };\n }\n }\n return { min: lo, max: hi, ticks: [lo, hi] };\n}\n\n/** The line through every value, sampled densely on x from 0 to 1 in data units. Monotone tangents keep a smooth curve from swinging past the data. */\nfunction curveFor(values: number[], smooth: boolean): Point[] {\n if (values.length === 0) return [];\n if (values.length === 1) return [[0, values[0]!], [1, values[0]!]];\n const last = values.length - 1;\n const step = 1 / last;\n if (!smooth) return values.map((value, index) => [index * step, value]);\n const slopes = values.slice(1).map((value, index) => (value - values[index]!) / step);\n const tangents = values.map((_, index) =>\n index === 0 || index === last\n ? 0\n : (Math.sign(slopes[index - 1]!) + Math.sign(slopes[index]!)) *\n Math.min(\n Math.abs(slopes[index - 1]!),\n Math.abs(slopes[index]!),\n Math.abs(slopes[index - 1]! + slopes[index]!) / 4,\n ) || 0,\n );\n if (last > 1) {\n tangents[0] = (3 * slopes[0]! - tangents[1]!) / 2;\n tangents[last] = (3 * slopes[last - 1]! - tangents[last - 1]!) / 2;\n } else {\n tangents[0] = slopes[0]!;\n tangents[1] = slopes[0]!;\n }\n const samples = Math.max(1, Math.min(16, Math.round(192 / last)));\n const points: Point[] = [];\n for (let index = 0; index < last; index++) {\n const low = Math.min(values[index]!, values[index + 1]!);\n const high = Math.max(values[index]!, values[index + 1]!);\n for (let sample = 0; sample < samples; sample++) {\n const t = sample / samples;\n const t2 = t * t;\n const t3 = t2 * t;\n const value =\n (2 * t3 - 3 * t2 + 1) * values[index]! +\n (t3 - 2 * t2 + t) * step * tangents[index]! +\n (3 * t2 - 2 * t3) * values[index + 1]! +\n (t3 - t2) * step * tangents[index + 1]!;\n points.push([(index + t) * step, clamp(value, low, high)]);\n }\n }\n points.push([1, values[last]!]);\n return points;\n}\n\n/** Value of a sampled line at x, straight between samples. */\nfunction valueAt(shape: Point[], x: number) {\n if (!shape.length) return 0;\n let low = 0;\n let high = shape.length - 1;\n if (x <= shape[low]![0]) return shape[low]![1];\n if (x >= shape[high]![0]) return shape[high]![1];\n while (high - low > 1) {\n const middle = (low + high) >> 1;\n if (shape[middle]![0] < x) low = middle;\n else high = middle;\n }\n const [x0, y0] = shape[low]!;\n const [x1, y1] = shape[high]!;\n return x1 === x0 ? y1 : y0 + ((y1 - y0) * (x - x0)) / (x1 - x0);\n}\n\n/** Axis labels that fit: at most one per 76 pixels, counted back from the latest so the newest always shows. */\nfunction axisPicks(data: LineChartDatum[], width: number) {\n const labeled = data.flatMap((item, index) => (item.axisLabel ? [index] : []));\n if (!width || !labeled.length) return [];\n const room = Math.max(2, Math.floor(width / 76));\n const stride = Math.ceil(labeled.length / room);\n return labeled\n .reverse()\n .filter((_, rank) => rank % stride === 0)\n .reverse();\n}\n\nexport const LineChart = forwardRef<HTMLElement, LineChartProps>(function LineChart(\n {\n data,\n series,\n label,\n unit = \"\",\n height = 220,\n formatValue,\n formatTick = (value) => COMPACT.format(value),\n hiddenSeries,\n defaultHiddenSeries,\n onHiddenSeriesChange,\n onActiveChange,\n loading = false,\n emptyLabel = \"No data for this range\",\n legend,\n categoryLabel = \"Date\",\n curve = \"smooth\",\n className,\n },\n ref,\n) {\n const figure = useRef<HTMLElement | null>(null);\n const refs = useMemo(() => mergeRefs(ref, figure), [ref]);\n const plot = useRef<HTMLDivElement>(null);\n const svg = useRef<SVGSVGElement>(null);\n const tip = useRef<HTMLDivElement>(null);\n const gutter = useRef<HTMLDivElement>(null);\n const uid = `line${useId().replace(/[^a-zA-Z0-9_-]/g, \"\")}`;\n const last = data.length - 1;\n const empty = data.length === 0;\n\n const [ownHidden, setOwnHidden] = useState<string[]>(defaultHiddenSeries ?? []);\n const hidden = hiddenSeries ?? ownHidden;\n const toggle = (key: string) => {\n const next = hidden.includes(key) ? hidden.filter((item) => item !== key) : [...hidden, key];\n if (hiddenSeries === undefined) setOwnHidden(next);\n onHiddenSeriesChange?.(next);\n };\n const visible = series.filter((line) => !hidden.includes(line.key));\n const showLegend = legend ?? series.length > 1;\n\n // Each series becomes a dense curve in data units; the scale fits only the series on show.\n const signature = `${curve}|${series.map((line) => line.key).join(\",\")}|${data\n .map((item) => `${item.key}:${series.map((line) => item.values[line.key] ?? 0).join(\",\")}`)\n .join(\";\")}`;\n const targets = useMemo(\n () =>\n new Map(\n series.map((line) => [\n line.key,\n curveFor(\n data.map((item) => item.values[line.key] ?? 0),\n curve === \"smooth\",\n ),\n ]),\n ),\n // The signature captures everything the curves read.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [signature],\n );\n let low = Infinity;\n let high = -Infinity;\n for (const line of visible) {\n for (const item of data) {\n const value = item.values[line.key] ?? 0;\n low = Math.min(low, value);\n high = Math.max(high, value);\n }\n }\n const range = Number.isFinite(low) ? niceScale(low, high) : null;\n const [steady, setSteady] = useState(() => range ?? niceScale(0, 100));\n if (range && (range.min !== steady.min || range.max !== steady.max)) setSteady(range);\n\n // Scrubbing: a new range lets go of the crosshair.\n const [active, setActive] = useState<number | null>(null);\n const [seen, setSeen] = useState(signature);\n if (seen !== signature) {\n setSeen(signature);\n setActive(null);\n }\n const index = active === null || empty ? null : Math.min(active, last);\n const scrubbing = index !== null;\n\n const width = useRef(0);\n const [plotWidth, setPlotWidth] = useState(0);\n const [drawn, setDrawn] = useState(false);\n const tracks = useRef(new Map<string, Track>());\n const scale = useRef({ min: steady.min, max: steady.max });\n const cursor = useRef(1);\n const live = useRef({ series, hidden });\n useIsomorphicLayoutEffect(() => {\n live.current = { series, hidden };\n });\n\n /** One writer for every drawn attribute: morphs, toggles, the scale, the crosshair and the size all repaint through here. */\n const paint = useCallback(() => {\n const w = width.current;\n const root = svg.current;\n if (!w || !root) return;\n const lo = scale.current.min;\n const span = scale.current.max - lo || 1;\n const toY = (value: number) => TOP + (1 - (value - lo) / span) * (height - TOP);\n const at = cursor.current;\n const dotYs: number[] = [];\n for (const line of live.current.series) {\n const track = tracks.current.get(line.key);\n if (!track) continue;\n const p = track.presence;\n const y = (value: number) => toY(lo + (value - lo) * p);\n const path = track.shape.length\n ? `M${track.shape.map(([x, value]) => `${(x * w).toFixed(1)},${y(value).toFixed(1)}`).join(\"L\")}`\n : \"\";\n const group = root.querySelector<SVGGElement>(`[data-series=\"${CSS.escape(line.key)}\"]`);\n group?.querySelector(\"[data-part=line]\")?.setAttribute(\"d\", path);\n group?.querySelector(\"[data-part=area]\")?.setAttribute(\"d\", path ? `${path}L${w},${height}L0,${height}Z` : \"\");\n if (group) group.style.opacity = String(p);\n const dot = root.querySelector<SVGCircleElement>(`[data-dot=\"${CSS.escape(line.key)}\"]`);\n if (dot && track.shape.length) {\n const cy = y(valueAt(track.shape, at));\n dot.setAttribute(\"cx\", (at * w).toFixed(1));\n dot.setAttribute(\"cy\", cy.toFixed(1));\n if (p > 0.5) dotYs.push(cy);\n }\n }\n // Gridlines and tick labels ride the scale.\n for (const node of root.querySelectorAll<SVGLineElement>(\"[data-grid]\")) {\n const yy = String(Math.round(toY(Number(node.dataset.grid))) + 0.5);\n node.setAttribute(\"y1\", yy);\n node.setAttribute(\"y2\", yy);\n }\n for (const node of gutter.current?.querySelectorAll<HTMLElement>(\"[data-tick]\") ?? []) {\n node.style.translate = `0 ${Math.round(toY(Number(node.dataset.tick)))}px`;\n }\n const cx = Math.round(at * w) + 0.5;\n const cross = root.querySelector(\"[data-part=crosshair]\");\n cross?.setAttribute(\"x1\", String(cx));\n cross?.setAttribute(\"x2\", String(cx));\n // The tooltip sits beside the crosshair, flips sides before it would leave the plot, and centres on the points it describes.\n const bubble = tip.current;\n if (bubble) {\n const tw = bubble.offsetWidth;\n const th = bubble.offsetHeight;\n let x = cx + GAP;\n if (x + tw > w) x = cx - GAP - tw;\n const middle = dotYs.length ? dotYs.reduce((sum, value) => sum + value, 0) / dotYs.length : height / 2;\n bubble.style.translate = `${clamp(x, 0, Math.max(0, w - tw))}px ${clamp(middle - th / 2, 0, Math.max(0, height - th))}px`;\n }\n }, [height]);\n\n // The plot draws in its own pixels: measure the width and follow resizes.\n useIsomorphicLayoutEffect(() => {\n const node = plot.current;\n if (!node) return;\n const read = () => {\n width.current = node.clientWidth;\n setPlotWidth(node.clientWidth);\n paint();\n };\n read();\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(read);\n observer.observe(node);\n return () => observer.disconnect();\n }, [paint]);\n useIsomorphicLayoutEffect(paint);\n\n // New data morphs every line from the shape on screen, sampled on shared x positions so a range that gains or loses points still flows.\n useEffect(() => {\n const moves: { track: Track; xs: number[]; from: number[]; to: number[]; target: Point[] }[] = [];\n for (const [key, target] of targets) {\n const track = tracks.current.get(key);\n if (!track) {\n tracks.current.set(key, { shape: target, presence: live.current.hidden.includes(key) ? 0 : 1, stop: null });\n continue;\n }\n if (!track.shape.length || !target.length) {\n track.shape = target;\n continue;\n }\n const xs = [...new Set([...GRID, ...target.map(([x]) => x)])].sort((a, b) => a - b);\n moves.push({ track, xs, from: xs.map((x) => valueAt(track.shape, x)), to: xs.map((x) => valueAt(target, x)), target });\n }\n if (!moves.length) {\n paint();\n return;\n }\n return tween(\n SMOOTH,\n (p) => {\n for (const move of moves) {\n move.track.shape = move.xs.map((x, at): Point => [x, move.from[at]! + (move.to[at]! - move.from[at]!) * p]);\n }\n paint();\n },\n () => {\n for (const move of moves) move.track.shape = move.target;\n paint();\n },\n );\n }, [paint, targets]);\n\n // A hidden series flattens into the baseline as it fades; the ones that stay rescale around it.\n const hiddenKey = hidden.join(\"|\");\n useEffect(() => {\n for (const [key, track] of tracks.current) {\n const to = hidden.includes(key) ? 0 : 1;\n if (track.presence === to) continue;\n track.stop?.();\n const from = track.presence;\n track.stop = tween(SMOOTH, (p) => {\n track.presence = from + (to - from) * p;\n paint();\n });\n }\n paint();\n // hiddenKey stands for `hidden`.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [hiddenKey, paint]);\n\n // The value axis slides to its new range on the smooth spring.\n useEffect(() => {\n const from = { ...scale.current };\n if (from.min === steady.min && from.max === steady.max) return;\n return tween(SMOOTH, (p) => {\n scale.current = { min: from.min + (steady.min - from.min) * p, max: from.max + (steady.max - from.max) * p };\n paint();\n });\n }, [paint, steady]);\n\n // The lines draw left to right the first time the chart is seen with data.\n useEffect(() => {\n if (empty || drawn) return;\n const node = figure.current;\n if (!node || prefersReducedMotion() || typeof IntersectionObserver === \"undefined\") {\n setDrawn(true);\n return;\n }\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (!entry?.isIntersecting) return;\n observer.disconnect();\n setDrawn(true);\n },\n { threshold: 0.3 },\n );\n observer.observe(node);\n return () => observer.disconnect();\n }, [drawn, empty]);\n\n // The crosshair appears on the first scrubbed point and glides between the ones after it.\n const wasScrubbing = useRef(false);\n useEffect(() => {\n if (index === null) {\n wasScrubbing.current = false;\n return;\n }\n const to = last > 0 ? index / last : 0.5;\n const from = cursor.current;\n if (!wasScrubbing.current) {\n wasScrubbing.current = true;\n cursor.current = to;\n paint();\n return;\n }\n return tween(SNAPPY, (p) => {\n cursor.current = from + (to - from) * p;\n paint();\n });\n }, [index, last, paint]);\n\n const onActive = useRef(onActiveChange);\n useIsomorphicLayoutEffect(() => {\n onActive.current = onActiveChange;\n });\n useEffect(() => {\n onActive.current?.(index, index === null ? null : (data[index] ?? null));\n // Report only when the scrubbed point changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [index]);\n\n const pointAt = (clientX: number) => {\n const rect = plot.current?.getBoundingClientRect();\n if (!rect?.width || last < 1) return Math.max(0, last);\n return clamp(Math.round(((clientX - rect.left) / rect.width) * last), 0, last);\n };\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key === \"Escape\" && scrubbing) {\n event.preventDefault();\n setActive(null);\n return;\n }\n const from = index ?? last + 1;\n const page = Math.max(1, Math.round(data.length / 6));\n const next = (\n {\n ArrowLeft: from - 1,\n ArrowDown: from - 1,\n ArrowRight: index === null ? last : from + 1,\n ArrowUp: index === null ? last : from + 1,\n PageDown: from - page,\n PageUp: from + page,\n Home: 0,\n End: last,\n } as Record<string, number>\n )[event.key];\n if (next === undefined || empty) return;\n event.preventDefault();\n setActive(clamp(next, 0, last));\n };\n const onPointerDown = (event: PointerEvent<HTMLDivElement>) => {\n if (empty) return;\n if (event.pointerType !== \"mouse\") event.currentTarget.setPointerCapture?.(event.pointerId);\n setActive(pointAt(event.clientX));\n };\n const onPointerMove = (event: PointerEvent<HTMLDivElement>) => {\n if (!empty && (event.pointerType === \"mouse\" || event.buttons)) setActive(pointAt(event.clientX));\n };\n\n const format = (value: number, line: LineChartSeries) =>\n `${formatValue ? formatValue(value, line) : GROUPED.format(value)}${unit ? ` ${unit}` : \"\"}`;\n const reading = index === null ? null : data[index];\n const shown = reading ?? data[last];\n const valueText = reading\n ? `${reading.label}: ${visible.map((line) => `${line.label} ${format(reading.values[line.key] ?? 0, line)}`).join(\", \")}`\n : empty\n ? emptyLabel\n : `${visible.length} of ${series.length} series shown`;\n const summary = empty\n ? `${label}. ${emptyLabel}.`\n : `${label}, ${data[0]!.label} to ${data[last]!.label}. ${visible\n .map((line) => `${line.label}, latest ${format(data[last]!.values[line.key] ?? 0, line)}`)\n .join(\". \")}.`;\n const picks = axisPicks(data, plotWidth);\n const allHidden = !empty && visible.length === 0;\n\n return (\n <figure\n ref={refs}\n data-slot=\"line-chart\"\n aria-label={label}\n aria-busy={loading || undefined}\n className={cn(\"m-0 grid min-w-0 gap-4 box-border font-sans text-foreground\", className)}\n >\n {showLegend ? (\n <div role=\"group\" aria-label={`${label} series`} className=\"-mx-2 flex min-w-0 flex-wrap gap-x-1 gap-y-0.5\">\n {series.map((line, at) => (\n <button\n key={line.key}\n type=\"button\"\n data-slot=\"line-chart-toggle\"\n aria-pressed={!hidden.includes(line.key)}\n onClick={() => toggle(line.key)}\n style={{ \"--series\": colorOf(line, at) } as CSSProperties}\n className=\"chart-legend-toggle\"\n >\n <span aria-hidden=\"true\" data-dashed={line.dashed || undefined} className=\"chart-swatch\" />\n <span className=\"chart-toggle-label\">{line.label}</span>\n </button>\n ))}\n </div>\n ) : null}\n <div\n data-slot=\"line-chart-chart\"\n data-scrubbing={scrubbing || undefined}\n data-loading={loading || undefined}\n data-drawn={drawn || undefined}\n className=\"line-chart-frame\"\n >\n <div\n ref={plot}\n data-slot=\"line-chart-plot\"\n role=\"slider\"\n tabIndex={empty ? -1 : 0}\n aria-label={`${label}, explore by ${categoryLabel.toLowerCase()}`}\n aria-orientation=\"horizontal\"\n aria-valuemin={1}\n aria-valuemax={Math.max(1, data.length)}\n aria-valuenow={(index ?? last) + 1}\n aria-valuetext={valueText}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={(event) => {\n if (event.pointerType !== \"mouse\") setActive(null);\n }}\n onPointerCancel={() => setActive(null)}\n onPointerLeave={(event) => {\n if (event.pointerType === \"mouse\") setActive(null);\n }}\n onKeyDown={onKeyDown}\n onBlur={() => setActive(null)}\n onFocus={(event) => {\n if (event.currentTarget.matches(\":focus-visible\") && !empty) setActive((current) => current ?? last);\n }}\n className=\"line-chart-plot\"\n style={{ height }}\n >\n <svg ref={svg} width=\"100%\" height={height} aria-hidden=\"true\" focusable=\"false\" className=\"block overflow-visible\">\n <defs>\n <clipPath id={`${uid}-draw`} clipPathUnits=\"userSpaceOnUse\">\n <rect className=\"line-chart-reveal\" x={-8} y={-16} height={height + 32} style={{ width: drawn ? plotWidth + 16 : 0 }} />\n </clipPath>\n </defs>\n {steady.ticks.slice(1).map((value) => (\n <line key={value} data-grid={value} className=\"line-chart-grid\" x1={0} x2=\"100%\" />\n ))}\n <line className=\"line-chart-baseline\" x1={0} x2=\"100%\" y1={height - 0.5} y2={height - 0.5} />\n <line data-part=\"crosshair\" className=\"line-chart-crosshair\" y1={TOP - 4} y2={height} />\n <g className=\"line-chart-series\" clipPath={`url(#${uid}-draw)`}>\n {series.map((line, at) => (\n <g key={line.key} data-series={line.key} style={{ \"--series\": colorOf(line, at) } as CSSProperties}>\n {(line.area ?? at === 0) ? <path data-part=\"area\" className=\"line-chart-area\" /> : null}\n <path data-part=\"line\" data-dashed={line.dashed || undefined} className=\"line-chart-line\" />\n </g>\n ))}\n </g>\n {series.map((line, at) => (\n <circle\n key={line.key}\n data-dot={line.key}\n data-hidden={hidden.includes(line.key) || undefined}\n r={4}\n className=\"line-chart-dot\"\n style={{ \"--series\": colorOf(line, at) } as CSSProperties}\n />\n ))}\n </svg>\n <div ref={tip} aria-hidden=\"true\" data-slot=\"line-chart-tooltip\" className=\"line-chart-tooltip\">\n <p className=\"m-0 mb-0.5 whitespace-nowrap text-xs tabular-nums text-text-secondary\">{shown?.label ?? \"\"}</p>\n {visible.map((line) => (\n <p\n key={line.key}\n className=\"m-0 flex min-w-0 items-center gap-2 text-sm\"\n style={{ \"--series\": colorOf(line, series.indexOf(line)) } as CSSProperties}\n >\n <span data-dashed={line.dashed || undefined} className=\"chart-tip-swatch\" />\n <span className=\"min-w-0 flex-1 truncate text-text-secondary\">{line.label}</span>\n <span className=\"ms-2 flex-none whitespace-nowrap font-medium tabular-nums text-foreground\">\n {format(shown?.values[line.key] ?? 0, line)}\n </span>\n </p>\n ))}\n </div>\n {(empty || allHidden) && !loading ? (\n <p className=\"absolute inset-0 m-0 grid place-items-center text-sm text-muted-foreground pointer-events-none motion-safe:animate-fade-in\">\n {empty ? emptyLabel : \"Choose a series to show\"}\n </p>\n ) : null}\n {loading && empty ? <span aria-hidden=\"true\" className=\"chart-skeleton\" /> : null}\n </div>\n <div ref={gutter} aria-hidden=\"true\" className=\"relative min-w-0 [grid-area:1/2]\">\n {steady.ticks.map((value) => (\n <span key={value} data-tick={value} className=\"line-chart-tick motion-safe:animate-fade-in\">\n <span className=\"block -translate-y-1/2 text-xs leading-none tabular-nums text-muted-foreground\">\n {formatTick(value)}\n </span>\n </span>\n ))}\n </div>\n <div aria-hidden=\"true\" className=\"relative min-w-0 [grid-area:2/1]\">\n {picks.map((at) => {\n const share = last > 0 ? at / last : 0.5;\n return (\n <span\n key={`${data[at]!.key}:${data[at]!.axisLabel}`}\n className=\"absolute top-2 whitespace-nowrap text-xs leading-none tabular-nums text-muted-foreground motion-safe:animate-fade-in\"\n style={{ left: `${share * 100}%`, translate: `${-share * 100}% 0` }}\n >\n {data[at]!.axisLabel}\n </span>\n );\n })}\n </div>\n </div>\n <p className=\"sr-only\">{summary}</p>\n {empty ? null : (\n <div className=\"sr-only\">\n <table>\n <caption>{label}</caption>\n <thead>\n <tr>\n <th scope=\"col\">{categoryLabel}</th>\n {series.map((line) => (\n <th key={line.key} scope=\"col\">\n {line.label}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.map((item) => (\n <tr key={item.key}>\n <th scope=\"row\">{item.label}</th>\n {series.map((line) => (\n <td key={line.key}>{format(item.values[line.key] ?? 0, line)}</td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n <p className=\"sr-only\" aria-live=\"polite\" aria-atomic=\"true\">\n {loading ? \"Loading\" : \"\"}\n </p>\n </figure>\n );\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"line-chart.js","names":[],"sources":["../../src/line-chart/line-chart.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type PointerEvent,\n} from \"react\";\n\nimport { cn } from \"../lib/cn.js\";\nimport { mergeRefs } from \"../lib/merge-refs.js\";\nimport { prefersReducedMotion, useIsomorphicLayoutEffect } from \"../lib/motion.js\";\nimport { SMOOTH, SNAPPY, tween } from \"../lib/spring-tween.js\";\n\n/**\n * LineChart: one or more measures over time, when the shape of the trend\n * matters more than any single value.\n *\n * The lines draw left to right the first time the chart is seen. New data\n * morphs every line from the shape on screen, and the value axis slides to its\n * new range while gridlines fade in and out. Hiding a series flattens it into\n * the baseline as it fades and the rest rescale. Hover, drag or the arrow keys\n * scrub: a crosshair glides between points with a dot on each line and a\n * tooltip that follows on its own spring and flips before it leaves the plot.\n * `loading` keeps the current lines on screen, dimmed and breathing.\n *\n * Plain SVG and CSS; one small spring tween drives the shapes, the scale and\n * the crosshair. A visually hidden table carries every value for assistive\n * technology, and the plot itself is a slider.\n */\nexport interface LineChartSeries {\n /** Stable identity. A series keeps its line across data changes, so switching ranges morphs it. */\n key: string;\n /** Name in the legend, the tooltip and the data table. */\n label: string;\n /** Any CSS colour. Defaults to chart-1 for the first series, then quieter neutral steps. */\n color?: string;\n /** A dashed stroke, for a previous period or a target. */\n dashed?: boolean;\n /** A faint fill under the line. Defaults to true for the first series. */\n area?: boolean;\n}\n\nexport interface LineChartDatum {\n /** Stable identity, such as an ISO date. */\n key: string;\n /** Full label for the tooltip and screen readers, such as \"Tue, Sep 15\". */\n label: string;\n /** Short label on the x axis. Leave it out to keep the axis quiet at that point. */\n axisLabel?: string;\n /**\n * One value per series key. A missing value (`undefined` or `null`) counts as\n * zero, unless the chart's `missing` is `\"gap\"`.\n */\n values: Record<string, number | null | undefined>;\n}\n\n/**\n * A reference line: a horizontal line at a value (a target, a threshold), or a\n * vertical line at one datum (today, a launch). Drawn dashed and quiet, behind\n * the series, with its label at the line's end.\n */\nexport type LineChartReference = {\n /** Stable identity. */\n key: string;\n /** Short text beside the line, such as \"Target\" or \"Today\". Also read to screen readers. */\n label: string;\n} & (\n | {\n /**\n * A value on the value axis: a horizontal line. The scale grows to keep it\n * in view, even when every value is missing. A value that is not finite\n * draws nothing. Read with `formatValue` (given the chart's first series)\n * and `unit`, like the series.\n */\n value: number;\n at?: never;\n }\n | {\n /** The `key` of a datum: a vertical line at that point. A key not in `data` draws nothing. */\n at: string;\n value?: never;\n }\n);\n\nexport interface LineChartProps {\n data: LineChartDatum[];\n series: LineChartSeries[];\n /** What is measured, such as \"Signups\". Names the chart for assistive technology. */\n label: string;\n /** Unit after each value in the tooltip, such as \"ms\". */\n unit?: string;\n /** Plot height in pixels. The width follows the container. @default 220 */\n height?: number;\n /** Formats values in the tooltip and data table. */\n formatValue?: (value: number, series: LineChartSeries) => string;\n /** Formats the value axis. Defaults to a compact number, such as 1.2K. */\n formatTick?: (value: number) => string;\n /** Controlled hidden series keys. */\n hiddenSeries?: string[];\n defaultHiddenSeries?: string[];\n onHiddenSeriesChange?: (hidden: string[]) => void;\n /** Called as the crosshair moves, and with null when it leaves. */\n onActiveChange?: (index: number | null, datum: LineChartDatum | null) => void;\n /** Keeps the current lines on screen, dimmed, while the next range loads. */\n loading?: boolean;\n /** Shown when there are no points. @default \"No data for this range\" */\n emptyLabel?: string;\n /** Series toggles above the plot. Shown by default when there is more than one series. */\n legend?: boolean;\n /** Header of the first column in the data table read by screen readers. @default \"Date\" */\n categoryLabel?: string;\n /** Smooth monotone curves that never swing past the data, or straight segments. @default \"smooth\" */\n curve?: \"smooth\" | \"linear\";\n /**\n * How a missing value (`undefined`, `null` or not a finite number) is drawn.\n * `\"zero\"` counts it as zero, as before. `\"gap\"` breaks the line (and its\n * area) there, leaves it out of the scale, hides the crosshair dot on it and\n * reads it as `missingLabel` in the tooltip and the data table. A point with\n * missing neighbours on both sides is drawn as a dot.\n * @default \"zero\"\n */\n missing?: \"zero\" | \"gap\";\n /** Read in place of a missing value when `missing` is `\"gap\"`. @default \"No data\" */\n missingLabel?: string;\n /** Reference lines: targets at a value, or markers such as \"today\" at a datum. */\n references?: LineChartReference[];\n /** Extra classes for the root. Merged last. */\n className?: string;\n}\n\ntype Point = [x: number, value: number];\n/** Open intervals of x (0 to 1) where a line is not drawn: the gaps around missing values. */\ntype Breaks = [from: number, to: number][];\ntype Track = { shape: Point[]; breaks: Breaks; presence: number; stop: (() => void) | null };\n\n/** Room above the top gridline, and the gap between the crosshair and its tooltip. */\nconst TOP = 12;\nconst GAP = 14;\n/** The first draw: 480ms x 1.75, slow at both ends. */\nexport const LINE_CHART_DRAW_MS = 840;\nconst PALETTE = [\n \"var(--color-chart-1)\",\n \"color-mix(in oklab, var(--color-foreground) 46%, var(--color-surface))\",\n \"color-mix(in oklab, var(--color-foreground) 26%, var(--color-surface))\",\n];\nconst GROUPED = new Intl.NumberFormat(\"en-US\", { maximumFractionDigits: 1 });\nconst COMPACT = new Intl.NumberFormat(\"en-US\", { notation: \"compact\", maximumFractionDigits: 1 });\nconst GRID = Array.from({ length: 241 }, (_, index) => index / 240);\nconst clamp = (value: number, low: number, high: number) => Math.min(high, Math.max(low, value));\nconst colorOf = (line: LineChartSeries, index: number) =>\n line.color ?? PALETTE[Math.min(index, PALETTE.length - 1)]!;\nconst clean = (value: number) => Number(value.toPrecision(12));\n\n/** Clean gridlines: the smallest step of 1, 2, 2.5 or 5 that covers the data in four rows or fewer, from zero unless the data dips below it. */\nfunction niceScale(low: number, high: number) {\n const lo = Math.min(0, low);\n const hi = Math.max(high, lo + 1);\n const magnitude = 10 ** Math.floor(Math.log10((hi - lo) / 4));\n for (const factor of [1, 2, 2.5, 5, 10]) {\n const step = factor * magnitude;\n const bottom = Math.floor(lo / step) * step;\n const top = Math.ceil(hi / step) * step;\n if ((top - bottom) / step <= 4 + 1e-9) {\n const ticks: number[] = [];\n for (let value = bottom; value <= top + step / 2; value += step) ticks.push(clean(value));\n return { min: clean(bottom), max: clean(top), ticks };\n }\n }\n return { min: lo, max: hi, ticks: [lo, hi] };\n}\n\n/** The line through every value, sampled densely on x from 0 to 1 in data units. Monotone tangents keep a smooth curve from swinging past the data. */\nfunction curveFor(values: number[], smooth: boolean): Point[] {\n if (values.length === 0) return [];\n if (values.length === 1) return [[0, values[0]!], [1, values[0]!]];\n const last = values.length - 1;\n const step = 1 / last;\n if (!smooth) return values.map((value, index) => [index * step, value]);\n const slopes = values.slice(1).map((value, index) => (value - values[index]!) / step);\n const tangents = values.map((_, index) =>\n index === 0 || index === last\n ? 0\n : (Math.sign(slopes[index - 1]!) + Math.sign(slopes[index]!)) *\n Math.min(\n Math.abs(slopes[index - 1]!),\n Math.abs(slopes[index]!),\n Math.abs(slopes[index - 1]! + slopes[index]!) / 4,\n ) || 0,\n );\n if (last > 1) {\n tangents[0] = (3 * slopes[0]! - tangents[1]!) / 2;\n tangents[last] = (3 * slopes[last - 1]! - tangents[last - 1]!) / 2;\n } else {\n tangents[0] = slopes[0]!;\n tangents[1] = slopes[0]!;\n }\n const samples = Math.max(1, Math.min(16, Math.round(192 / last)));\n const points: Point[] = [];\n for (let index = 0; index < last; index++) {\n const low = Math.min(values[index]!, values[index + 1]!);\n const high = Math.max(values[index]!, values[index + 1]!);\n for (let sample = 0; sample < samples; sample++) {\n const t = sample / samples;\n const t2 = t * t;\n const t3 = t2 * t;\n const value =\n (2 * t3 - 3 * t2 + 1) * values[index]! +\n (t3 - 2 * t2 + t) * step * tangents[index]! +\n (3 * t2 - 2 * t3) * values[index + 1]! +\n (t3 - t2) * step * tangents[index + 1]!;\n points.push([(index + t) * step, clamp(value, low, high)]);\n }\n }\n points.push([1, values[last]!]);\n return points;\n}\n\n/** Fills each missing value straight between its present neighbours (or with the nearest one at the ends), so a gapped line still has a shape to morph. */\nfunction fillGaps(values: (number | null)[]): number[] {\n const present = values.flatMap((value, index) => (value === null ? [] : [index]));\n if (!present.length) return values.map(() => 0);\n return values.map((value, index) => {\n if (value !== null) return value;\n const after = present.find((at) => at > index);\n const before = [...present].reverse().find((at) => at < index);\n if (before === undefined) return values[after!]!;\n if (after === undefined) return values[before]!;\n return values[before]! + ((values[after]! - values[before]!) * (index - before)) / (after - before);\n });\n}\n\n/** Where a line with missing values is not drawn: before its first value, after its last, and between two values with missing ones between them. */\nfunction breaksFor(values: (number | null)[]): Breaks {\n const present = values.flatMap((value, index) => (value === null ? [] : [index]));\n if (!present.length) return values.length ? [[-Infinity, Infinity]] : [];\n const last = values.length - 1;\n if (last === 0) return [];\n const breaks: Breaks = [];\n if (present[0]! > 0) breaks.push([-Infinity, present[0]! / last]);\n for (let at = 1; at < present.length; at++) {\n if (present[at]! - present[at - 1]! > 1) breaks.push([present[at - 1]! / last, present[at]! / last]);\n }\n if (present[present.length - 1]! < last) breaks.push([present[present.length - 1]! / last, Infinity]);\n return breaks;\n}\n\nconst EDGE = 1e-9;\n/** Radius of a lone point's dot, inside its 2px stroke. */\nconst DOT = 1.5;\nconst inBreak = (breaks: Breaks, x: number) => breaks.some(([from, to]) => x > from + EDGE && x < to - EDGE);\n\n/** The drawn runs of a line, split at its gaps. A run of one point is a dot: a small closed circle the stroke fills out to about 5px. */\nfunction pathsFor(shape: Point[], breaks: Breaks, toX: (x: number) => number, toY: (value: number) => number, bottom: number) {\n const runs: string[][] = [];\n let run: string[] | null = null;\n for (const [x, value] of shape) {\n if (breaks.length && inBreak(breaks, x)) {\n run = null;\n continue;\n }\n if (!run) runs.push((run = []));\n run.push(`${toX(x).toFixed(1)},${toY(value).toFixed(1)}`);\n }\n const line = runs\n .map((points) => {\n if (points.length > 1) return `M${points.join(\"L\")}`;\n const [x, y] = points[0]!.split(\",\").map(Number);\n return `M${(x! - DOT).toFixed(1)},${y!.toFixed(1)}a${DOT},${DOT} 0 1,0 ${DOT * 2},0a${DOT},${DOT} 0 1,0 ${-DOT * 2},0`;\n })\n .join(\"\");\n const area = runs\n .map((points) => {\n const first = points[0]!.split(\",\")[0];\n const lastX = points[points.length - 1]!.split(\",\")[0];\n return `M${points.join(\"L\")}L${lastX},${bottom}L${first},${bottom}Z`;\n })\n .join(\"\");\n return { line, area };\n}\n\nconst isFiniteValue = (reference: LineChartReference): reference is LineChartReference & { value: number } =>\n typeof reference.value === \"number\" && Number.isFinite(reference.value);\n\n/** Value of a sampled line at x, straight between samples. */\nfunction valueAt(shape: Point[], x: number) {\n if (!shape.length) return 0;\n let low = 0;\n let high = shape.length - 1;\n if (x <= shape[low]![0]) return shape[low]![1];\n if (x >= shape[high]![0]) return shape[high]![1];\n while (high - low > 1) {\n const middle = (low + high) >> 1;\n if (shape[middle]![0] < x) low = middle;\n else high = middle;\n }\n const [x0, y0] = shape[low]!;\n const [x1, y1] = shape[high]!;\n return x1 === x0 ? y1 : y0 + ((y1 - y0) * (x - x0)) / (x1 - x0);\n}\n\n/** Axis labels that fit: at most one per 76 pixels, counted back from the latest so the newest always shows. */\nfunction axisPicks(data: LineChartDatum[], width: number) {\n const labeled = data.flatMap((item, index) => (item.axisLabel ? [index] : []));\n if (!width || !labeled.length) return [];\n const room = Math.max(2, Math.floor(width / 76));\n const stride = Math.ceil(labeled.length / room);\n return labeled\n .reverse()\n .filter((_, rank) => rank % stride === 0)\n .reverse();\n}\n\nexport const LineChart = forwardRef<HTMLElement, LineChartProps>(function LineChart(\n {\n data,\n series,\n label,\n unit = \"\",\n height = 220,\n formatValue,\n formatTick = (value) => COMPACT.format(value),\n hiddenSeries,\n defaultHiddenSeries,\n onHiddenSeriesChange,\n onActiveChange,\n loading = false,\n emptyLabel = \"No data for this range\",\n legend,\n categoryLabel = \"Date\",\n curve = \"smooth\",\n missing = \"zero\",\n missingLabel = \"No data\",\n references,\n className,\n },\n ref,\n) {\n const figure = useRef<HTMLElement | null>(null);\n const refs = useMemo(() => mergeRefs(ref, figure), [ref]);\n const plot = useRef<HTMLDivElement>(null);\n const svg = useRef<SVGSVGElement>(null);\n const tip = useRef<HTMLDivElement>(null);\n const gutter = useRef<HTMLDivElement>(null);\n const uid = `line${useId().replace(/[^a-zA-Z0-9_-]/g, \"\")}`;\n const last = data.length - 1;\n const empty = data.length === 0;\n\n const [ownHidden, setOwnHidden] = useState<string[]>(defaultHiddenSeries ?? []);\n const hidden = hiddenSeries ?? ownHidden;\n const toggle = (key: string) => {\n const next = hidden.includes(key) ? hidden.filter((item) => item !== key) : [...hidden, key];\n if (hiddenSeries === undefined) setOwnHidden(next);\n onHiddenSeriesChange?.(next);\n };\n const visible = series.filter((line) => !hidden.includes(line.key));\n const showLegend = legend ?? series.length > 1;\n\n // A missing value is zero, as it always was, unless gaps are asked for.\n const gaps = missing === \"gap\";\n const read = (item: LineChartDatum, key: string): number | null => {\n const value = item.values[key];\n if (!gaps) return value ?? 0;\n return typeof value === \"number\" && Number.isFinite(value) ? value : null;\n };\n\n // Each series becomes a dense curve in data units; the scale fits only the series on show.\n const signature = `${curve}|${missing}|${series.map((line) => line.key).join(\",\")}|${data\n .map((item) => `${item.key}:${series.map((line) => read(item, line.key)).join(\",\")}`)\n .join(\";\")}`;\n const targets = useMemo(\n () =>\n new Map(\n series.map((line) => {\n const values = data.map((item) => read(item, line.key));\n return [\n line.key,\n { shape: curveFor(fillGaps(values), curve === \"smooth\"), breaks: breaksFor(values) },\n ];\n }),\n ),\n // The signature captures everything the curves read.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [signature],\n );\n let low = Infinity;\n let high = -Infinity;\n for (const line of visible) {\n for (const item of data) {\n const value = read(item, line.key);\n if (value === null) continue;\n low = Math.min(low, value);\n high = Math.max(high, value);\n }\n }\n // A target keeps itself in view, even with every value missing, so it never sits on the fallback scale.\n for (const reference of references ?? []) {\n if (!isFiniteValue(reference)) continue;\n low = Math.min(low, reference.value);\n high = Math.max(high, reference.value);\n }\n const range = Number.isFinite(low) ? niceScale(low, high) : null;\n const [steady, setSteady] = useState(() => range ?? niceScale(0, 100));\n if (range && (range.min !== steady.min || range.max !== steady.max)) setSteady(range);\n\n // Scrubbing: a new range lets go of the crosshair.\n const [active, setActive] = useState<number | null>(null);\n const [seen, setSeen] = useState(signature);\n if (seen !== signature) {\n setSeen(signature);\n setActive(null);\n }\n const index = active === null || empty ? null : Math.min(active, last);\n const scrubbing = index !== null;\n\n const width = useRef(0);\n const [plotWidth, setPlotWidth] = useState(0);\n const [drawn, setDrawn] = useState(false);\n const tracks = useRef(new Map<string, Track>());\n const scale = useRef({ min: steady.min, max: steady.max });\n const cursor = useRef(1);\n // `undefined`: nothing to draw (an unknown datum, or a value that is not finite).\n const referenceAt = (reference: LineChartReference) => {\n if (typeof reference.value === \"number\") return isFiniteValue(reference) ? null : undefined;\n const at = data.findIndex((item) => item.key === reference.at);\n return at < 0 ? undefined : last > 0 ? at / last : 0.5;\n };\n const drawnReferences = (references ?? []).filter((reference) => referenceAt(reference) !== undefined);\n const live = useRef({ series, hidden });\n useIsomorphicLayoutEffect(() => {\n live.current = { series, hidden };\n });\n\n /** One writer for every drawn attribute: morphs, toggles, the scale, the crosshair and the size all repaint through here. */\n const paint = useCallback(() => {\n const w = width.current;\n const root = svg.current;\n if (!w || !root) return;\n const lo = scale.current.min;\n const span = scale.current.max - lo || 1;\n const toY = (value: number) => TOP + (1 - (value - lo) / span) * (height - TOP);\n const at = cursor.current;\n const dotYs: number[] = [];\n for (const line of live.current.series) {\n const track = tracks.current.get(line.key);\n if (!track) continue;\n const p = track.presence;\n const y = (value: number) => toY(lo + (value - lo) * p);\n const group = root.querySelector<SVGGElement>(`[data-series=\"${CSS.escape(line.key)}\"]`);\n if (track.breaks.length) {\n const paths = pathsFor(track.shape, track.breaks, (x) => x * w, y, height);\n group?.querySelector(\"[data-part=line]\")?.setAttribute(\"d\", paths.line);\n group?.querySelector(\"[data-part=area]\")?.setAttribute(\"d\", paths.area);\n } else {\n const path = track.shape.length\n ? `M${track.shape.map(([x, value]) => `${(x * w).toFixed(1)},${y(value).toFixed(1)}`).join(\"L\")}`\n : \"\";\n group?.querySelector(\"[data-part=line]\")?.setAttribute(\"d\", path);\n group?.querySelector(\"[data-part=area]\")?.setAttribute(\"d\", path ? `${path}L${w},${height}L0,${height}Z` : \"\");\n }\n if (group) group.style.opacity = String(p);\n const dot = root.querySelector<SVGCircleElement>(`[data-dot=\"${CSS.escape(line.key)}\"]`);\n if (dot && track.shape.length) {\n const gap = inBreak(track.breaks, at);\n const cy = y(valueAt(track.shape, at));\n dot.setAttribute(\"cx\", (at * w).toFixed(1));\n dot.setAttribute(\"cy\", cy.toFixed(1));\n // No value here: no dot, and the tooltip does not centre on one.\n if (gap) dot.setAttribute(\"data-gap\", \"\");\n else dot.removeAttribute(\"data-gap\");\n if (p > 0.5 && !gap) dotYs.push(cy);\n }\n }\n // Gridlines and tick labels ride the scale.\n for (const node of root.querySelectorAll<SVGLineElement>(\"[data-grid]\")) {\n const yy = String(Math.round(toY(Number(node.dataset.grid))) + 0.5);\n node.setAttribute(\"y1\", yy);\n node.setAttribute(\"y2\", yy);\n }\n for (const node of gutter.current?.querySelectorAll<HTMLElement>(\"[data-tick]\") ?? []) {\n node.style.translate = `0 ${Math.round(toY(Number(node.dataset.tick)))}px`;\n }\n // Reference lines: a value rides the scale like a gridline; a datum sits at its x.\n for (const node of root.querySelectorAll<SVGLineElement>(\"[data-reference-value]\")) {\n const yy = String(Math.round(toY(Number(node.dataset.referenceValue))) + 0.5);\n node.setAttribute(\"y1\", yy);\n node.setAttribute(\"y2\", yy);\n }\n for (const node of root.querySelectorAll<SVGLineElement>(\"[data-reference-at]\")) {\n const xx = String(Math.round(Number(node.dataset.referenceAt) * w) + 0.5);\n node.setAttribute(\"x1\", xx);\n node.setAttribute(\"x2\", xx);\n }\n for (const node of plot.current?.querySelectorAll<HTMLElement>(\"[data-reference-label]\") ?? []) {\n const { referenceValue, referenceAt } = node.dataset;\n node.style.translate =\n referenceValue !== undefined\n ? `0 ${Math.round(toY(Number(referenceValue)))}px`\n : `${Math.round(Number(referenceAt) * w)}px 0`;\n }\n const cx = Math.round(at * w) + 0.5;\n const cross = root.querySelector(\"[data-part=crosshair]\");\n cross?.setAttribute(\"x1\", String(cx));\n cross?.setAttribute(\"x2\", String(cx));\n // The tooltip sits beside the crosshair, flips sides before it would leave the plot, and centres on the points it describes.\n const bubble = tip.current;\n if (bubble) {\n const tw = bubble.offsetWidth;\n const th = bubble.offsetHeight;\n let x = cx + GAP;\n if (x + tw > w) x = cx - GAP - tw;\n const middle = dotYs.length ? dotYs.reduce((sum, value) => sum + value, 0) / dotYs.length : height / 2;\n bubble.style.translate = `${clamp(x, 0, Math.max(0, w - tw))}px ${clamp(middle - th / 2, 0, Math.max(0, height - th))}px`;\n }\n }, [height]);\n\n // The plot draws in its own pixels: measure the width and follow resizes.\n useIsomorphicLayoutEffect(() => {\n const node = plot.current;\n if (!node) return;\n const read = () => {\n width.current = node.clientWidth;\n setPlotWidth(node.clientWidth);\n paint();\n };\n read();\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(read);\n observer.observe(node);\n return () => observer.disconnect();\n }, [paint]);\n useIsomorphicLayoutEffect(paint);\n\n // New data morphs every line from the shape on screen, sampled on shared x positions so a range that gains or loses points still flows.\n useEffect(() => {\n const moves: { track: Track; xs: number[]; from: number[]; to: number[]; target: Point[] }[] = [];\n for (const [key, { shape: target, breaks }] of targets) {\n const track = tracks.current.get(key);\n if (!track) {\n tracks.current.set(key, {\n shape: target,\n breaks,\n presence: live.current.hidden.includes(key) ? 0 : 1,\n stop: null,\n });\n continue;\n }\n // The gaps move to the new data at once; the line morphs between them.\n track.breaks = breaks;\n if (!track.shape.length || !target.length) {\n track.shape = target;\n continue;\n }\n const xs = [...new Set([...GRID, ...target.map(([x]) => x)])].sort((a, b) => a - b);\n moves.push({ track, xs, from: xs.map((x) => valueAt(track.shape, x)), to: xs.map((x) => valueAt(target, x)), target });\n }\n if (!moves.length) {\n paint();\n return;\n }\n return tween(\n SMOOTH,\n (p) => {\n for (const move of moves) {\n move.track.shape = move.xs.map((x, at): Point => [x, move.from[at]! + (move.to[at]! - move.from[at]!) * p]);\n }\n paint();\n },\n () => {\n for (const move of moves) move.track.shape = move.target;\n paint();\n },\n );\n }, [paint, targets]);\n\n // A hidden series flattens into the baseline as it fades; the ones that stay rescale around it.\n const hiddenKey = hidden.join(\"|\");\n useEffect(() => {\n for (const [key, track] of tracks.current) {\n const to = hidden.includes(key) ? 0 : 1;\n if (track.presence === to) continue;\n track.stop?.();\n const from = track.presence;\n track.stop = tween(SMOOTH, (p) => {\n track.presence = from + (to - from) * p;\n paint();\n });\n }\n paint();\n // hiddenKey stands for `hidden`.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [hiddenKey, paint]);\n\n // The value axis slides to its new range on the smooth spring.\n useEffect(() => {\n const from = { ...scale.current };\n if (from.min === steady.min && from.max === steady.max) return;\n return tween(SMOOTH, (p) => {\n scale.current = { min: from.min + (steady.min - from.min) * p, max: from.max + (steady.max - from.max) * p };\n paint();\n });\n }, [paint, steady]);\n\n // The lines draw left to right the first time the chart is seen with data.\n useEffect(() => {\n if (empty || drawn) return;\n const node = figure.current;\n if (!node || prefersReducedMotion() || typeof IntersectionObserver === \"undefined\") {\n setDrawn(true);\n return;\n }\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (!entry?.isIntersecting) return;\n observer.disconnect();\n setDrawn(true);\n },\n { threshold: 0.3 },\n );\n observer.observe(node);\n return () => observer.disconnect();\n }, [drawn, empty]);\n\n // The crosshair appears on the first scrubbed point and glides between the ones after it.\n const wasScrubbing = useRef(false);\n useEffect(() => {\n if (index === null) {\n wasScrubbing.current = false;\n return;\n }\n const to = last > 0 ? index / last : 0.5;\n const from = cursor.current;\n if (!wasScrubbing.current) {\n wasScrubbing.current = true;\n cursor.current = to;\n paint();\n return;\n }\n return tween(SNAPPY, (p) => {\n cursor.current = from + (to - from) * p;\n paint();\n });\n }, [index, last, paint]);\n\n const onActive = useRef(onActiveChange);\n useIsomorphicLayoutEffect(() => {\n onActive.current = onActiveChange;\n });\n useEffect(() => {\n onActive.current?.(index, index === null ? null : (data[index] ?? null));\n // Report only when the scrubbed point changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [index]);\n\n const pointAt = (clientX: number) => {\n const rect = plot.current?.getBoundingClientRect();\n if (!rect?.width || last < 1) return Math.max(0, last);\n return clamp(Math.round(((clientX - rect.left) / rect.width) * last), 0, last);\n };\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key === \"Escape\" && scrubbing) {\n event.preventDefault();\n setActive(null);\n return;\n }\n const from = index ?? last + 1;\n const page = Math.max(1, Math.round(data.length / 6));\n const next = (\n {\n ArrowLeft: from - 1,\n ArrowDown: from - 1,\n ArrowRight: index === null ? last : from + 1,\n ArrowUp: index === null ? last : from + 1,\n PageDown: from - page,\n PageUp: from + page,\n Home: 0,\n End: last,\n } as Record<string, number>\n )[event.key];\n if (next === undefined || empty) return;\n event.preventDefault();\n setActive(clamp(next, 0, last));\n };\n const onPointerDown = (event: PointerEvent<HTMLDivElement>) => {\n if (empty) return;\n if (event.pointerType !== \"mouse\") event.currentTarget.setPointerCapture?.(event.pointerId);\n setActive(pointAt(event.clientX));\n };\n const onPointerMove = (event: PointerEvent<HTMLDivElement>) => {\n if (!empty && (event.pointerType === \"mouse\" || event.buttons)) setActive(pointAt(event.clientX));\n };\n\n const formatNumber = (value: number, line: LineChartSeries) =>\n `${formatValue ? formatValue(value, line) : GROUPED.format(value)}${unit ? ` ${unit}` : \"\"}`;\n const format = (value: number | null, line: LineChartSeries) =>\n value === null ? missingLabel : formatNumber(value, line);\n // A reference belongs to no series; `formatValue` gets the first one, so a chart of one unit reads the same.\n const formatReference = (value: number) =>\n series[0] ? formatNumber(value, series[0]) : `${GROUPED.format(value)}${unit ? ` ${unit}` : \"\"}`;\n const reading = index === null ? null : data[index];\n const shown = reading ?? data[last];\n const valueText = reading\n ? `${reading.label}: ${visible.map((line) => `${line.label} ${format(read(reading, line.key), line)}`).join(\", \")}`\n : empty\n ? emptyLabel\n : `${visible.length} of ${series.length} series shown`;\n const summary = empty\n ? `${label}. ${emptyLabel}.`\n : `${label}, ${data[0]!.label} to ${data[last]!.label}. ${visible\n .map((line) => `${line.label}, latest ${format(read(data[last]!, line.key), line)}`)\n .join(\". \")}.${drawnReferences\n .map((reference) =>\n typeof reference.value === \"number\"\n ? ` ${reference.label}: ${formatReference(reference.value)}.`\n : ` ${reference.label}: ${data.find((item) => item.key === reference.at)!.label}.`,\n )\n .join(\"\")}`;\n const picks = axisPicks(data, plotWidth);\n const allHidden = !empty && visible.length === 0;\n\n return (\n <figure\n ref={refs}\n data-slot=\"line-chart\"\n aria-label={label}\n aria-busy={loading || undefined}\n className={cn(\"m-0 grid min-w-0 gap-4 box-border font-sans text-foreground\", className)}\n >\n {showLegend ? (\n <div role=\"group\" aria-label={`${label} series`} className=\"-mx-2 flex min-w-0 flex-wrap gap-x-1 gap-y-0.5\">\n {series.map((line, at) => (\n <button\n key={line.key}\n type=\"button\"\n data-slot=\"line-chart-toggle\"\n aria-pressed={!hidden.includes(line.key)}\n onClick={() => toggle(line.key)}\n style={{ \"--series\": colorOf(line, at) } as CSSProperties}\n className=\"chart-legend-toggle\"\n >\n <span aria-hidden=\"true\" data-dashed={line.dashed || undefined} className=\"chart-swatch\" />\n <span className=\"chart-toggle-label\">{line.label}</span>\n </button>\n ))}\n </div>\n ) : null}\n <div\n data-slot=\"line-chart-chart\"\n data-scrubbing={scrubbing || undefined}\n data-loading={loading || undefined}\n data-drawn={drawn || undefined}\n className=\"line-chart-frame\"\n >\n <div\n ref={plot}\n data-slot=\"line-chart-plot\"\n role=\"slider\"\n tabIndex={empty ? -1 : 0}\n aria-label={`${label}, explore by ${categoryLabel.toLowerCase()}`}\n aria-orientation=\"horizontal\"\n aria-valuemin={1}\n aria-valuemax={Math.max(1, data.length)}\n aria-valuenow={(index ?? last) + 1}\n aria-valuetext={valueText}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={(event) => {\n if (event.pointerType !== \"mouse\") setActive(null);\n }}\n onPointerCancel={() => setActive(null)}\n onPointerLeave={(event) => {\n if (event.pointerType === \"mouse\") setActive(null);\n }}\n onKeyDown={onKeyDown}\n onBlur={() => setActive(null)}\n onFocus={(event) => {\n if (event.currentTarget.matches(\":focus-visible\") && !empty) setActive((current) => current ?? last);\n }}\n className=\"line-chart-plot\"\n style={{ height }}\n >\n <svg ref={svg} width=\"100%\" height={height} aria-hidden=\"true\" focusable=\"false\" className=\"block overflow-visible\">\n <defs>\n <clipPath id={`${uid}-draw`} clipPathUnits=\"userSpaceOnUse\">\n <rect className=\"line-chart-reveal\" x={-8} y={-16} height={height + 32} style={{ width: drawn ? plotWidth + 16 : 0 }} />\n </clipPath>\n </defs>\n {steady.ticks.slice(1).map((value) => (\n <line key={value} data-grid={value} className=\"line-chart-grid\" x1={0} x2=\"100%\" />\n ))}\n <line className=\"line-chart-baseline\" x1={0} x2=\"100%\" y1={height - 0.5} y2={height - 0.5} />\n {drawnReferences.map((reference) =>\n typeof reference.value === \"number\" ? (\n <line\n key={reference.key}\n data-reference={reference.key}\n data-reference-value={reference.value}\n className=\"line-chart-reference\"\n x1={0}\n x2=\"100%\"\n />\n ) : (\n <line\n key={reference.key}\n data-reference={reference.key}\n data-reference-at={referenceAt(reference)!}\n className=\"line-chart-reference\"\n y1={TOP - 4}\n y2={height}\n />\n ),\n )}\n <line data-part=\"crosshair\" className=\"line-chart-crosshair\" y1={TOP - 4} y2={height} />\n <g className=\"line-chart-series\" clipPath={`url(#${uid}-draw)`}>\n {series.map((line, at) => (\n <g key={line.key} data-series={line.key} style={{ \"--series\": colorOf(line, at) } as CSSProperties}>\n {(line.area ?? at === 0) ? <path data-part=\"area\" className=\"line-chart-area\" /> : null}\n <path data-part=\"line\" data-dashed={line.dashed || undefined} className=\"line-chart-line\" />\n </g>\n ))}\n </g>\n {series.map((line, at) => (\n <circle\n key={line.key}\n data-dot={line.key}\n data-hidden={hidden.includes(line.key) || undefined}\n r={4}\n className=\"line-chart-dot\"\n style={{ \"--series\": colorOf(line, at) } as CSSProperties}\n />\n ))}\n </svg>\n {drawnReferences.map((reference) => (\n <span\n key={reference.key}\n aria-hidden=\"true\"\n data-slot=\"line-chart-reference-label\"\n data-reference-label={reference.key}\n data-reference-value={typeof reference.value === \"number\" ? reference.value : undefined}\n data-reference-at={typeof reference.value === \"number\" ? undefined : referenceAt(reference)!}\n data-axis={typeof reference.value === \"number\" ? \"value\" : \"category\"}\n className=\"line-chart-reference-label\"\n >\n {reference.label}\n </span>\n ))}\n <div ref={tip} aria-hidden=\"true\" data-slot=\"line-chart-tooltip\" className=\"line-chart-tooltip\">\n <p className=\"m-0 mb-0.5 whitespace-nowrap text-xs tabular-nums text-text-secondary\">{shown?.label ?? \"\"}</p>\n {visible.map((line) => (\n <p\n key={line.key}\n className=\"m-0 flex min-w-0 items-center gap-2 text-sm\"\n style={{ \"--series\": colorOf(line, series.indexOf(line)) } as CSSProperties}\n >\n <span data-dashed={line.dashed || undefined} className=\"chart-tip-swatch\" />\n <span className=\"min-w-0 flex-1 truncate text-text-secondary\">{line.label}</span>\n <span className=\"ms-2 flex-none whitespace-nowrap font-medium tabular-nums text-foreground\">\n {shown ? format(read(shown, line.key), line) : format(0, line)}\n </span>\n </p>\n ))}\n </div>\n {(empty || allHidden) && !loading ? (\n <p className=\"absolute inset-0 m-0 grid place-items-center text-sm text-muted-foreground pointer-events-none motion-safe:animate-fade-in\">\n {empty ? emptyLabel : \"Choose a series to show\"}\n </p>\n ) : null}\n {loading && empty ? <span aria-hidden=\"true\" className=\"chart-skeleton\" /> : null}\n </div>\n <div ref={gutter} aria-hidden=\"true\" className=\"relative min-w-0 [grid-area:1/2]\">\n {steady.ticks.map((value) => (\n <span key={value} data-tick={value} className=\"line-chart-tick motion-safe:animate-fade-in\">\n <span className=\"block -translate-y-1/2 text-xs leading-none tabular-nums text-muted-foreground\">\n {formatTick(value)}\n </span>\n </span>\n ))}\n </div>\n <div aria-hidden=\"true\" className=\"relative min-w-0 [grid-area:2/1]\">\n {picks.map((at) => {\n const share = last > 0 ? at / last : 0.5;\n return (\n <span\n key={`${data[at]!.key}:${data[at]!.axisLabel}`}\n className=\"absolute top-2 whitespace-nowrap text-xs leading-none tabular-nums text-muted-foreground motion-safe:animate-fade-in\"\n style={{ left: `${share * 100}%`, translate: `${-share * 100}% 0` }}\n >\n {data[at]!.axisLabel}\n </span>\n );\n })}\n </div>\n </div>\n <p className=\"sr-only\">{summary}</p>\n {empty ? null : (\n <div className=\"sr-only\">\n <table>\n <caption>{label}</caption>\n <thead>\n <tr>\n <th scope=\"col\">{categoryLabel}</th>\n {series.map((line) => (\n <th key={line.key} scope=\"col\">\n {line.label}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.map((item) => (\n <tr key={item.key}>\n <th scope=\"row\">{item.label}</th>\n {series.map((line) => (\n <td key={line.key}>{format(read(item, line.key), line)}</td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n <p className=\"sr-only\" aria-live=\"polite\" aria-atomic=\"true\">\n {loading ? \"Loading\" : \"\"}\n </p>\n </figure>\n );\n});\n"],"mappings":";;;;;;;;;AA+IA,MAAM,MAAM;AACZ,MAAM,MAAM;;AAEZ,MAAa,qBAAqB;AAClC,MAAM,UAAU;CACd;CACA;CACA;AACF;AACA,MAAM,UAAU,IAAI,KAAK,aAAa,SAAS,EAAE,uBAAuB,EAAE,CAAC;AAC3E,MAAM,UAAU,IAAI,KAAK,aAAa,SAAS;CAAE,UAAU;CAAW,uBAAuB;AAAE,CAAC;AAChG,MAAM,OAAO,MAAM,KAAK,EAAE,QAAQ,IAAI,IAAI,GAAG,UAAU,QAAQ,GAAG;AAClE,MAAM,SAAS,OAAe,KAAa,SAAiB,KAAK,IAAI,MAAM,KAAK,IAAI,KAAK,KAAK,CAAC;AAC/F,MAAM,WAAW,MAAuB,UACtC,KAAK,SAAS,QAAQ,KAAK,IAAI,OAAO,QAAQ,SAAS,CAAC;AAC1D,MAAM,SAAS,UAAkB,OAAO,MAAM,YAAY,EAAE,CAAC;;AAG7D,SAAS,UAAU,KAAa,MAAc;CAC5C,MAAM,KAAK,KAAK,IAAI,GAAG,GAAG;CAC1B,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,CAAC;CAChC,MAAM,YAAY,MAAM,KAAK,MAAM,KAAK,OAAO,KAAK,MAAM,CAAC,CAAC;CAC5D,KAAK,MAAM,UAAU;EAAC;EAAG;EAAG;EAAK;EAAG;CAAE,GAAG;EACvC,MAAM,OAAO,SAAS;EACtB,MAAM,SAAS,KAAK,MAAM,KAAK,IAAI,IAAI;EACvC,MAAM,MAAM,KAAK,KAAK,KAAK,IAAI,IAAI;EACnC,KAAK,MAAM,UAAU,QAAQ,IAAI,MAAM;GACrC,MAAM,QAAkB,CAAC;GACzB,KAAK,IAAI,QAAQ,QAAQ,SAAS,MAAM,OAAO,GAAG,SAAS,MAAM,MAAM,KAAK,MAAM,KAAK,CAAC;GACxF,OAAO;IAAE,KAAK,MAAM,MAAM;IAAG,KAAK,MAAM,GAAG;IAAG;GAAM;EACtD;CACF;CACA,OAAO;EAAE,KAAK;EAAI,KAAK;EAAI,OAAO,CAAC,IAAI,EAAE;CAAE;AAC7C;;AAGA,SAAS,SAAS,QAAkB,QAA0B;CAC5D,IAAI,OAAO,WAAW,GAAG,OAAO,CAAC;CACjC,IAAI,OAAO,WAAW,GAAG,OAAO,CAAC,CAAC,GAAG,OAAO,EAAG,GAAG,CAAC,GAAG,OAAO,EAAG,CAAC;CACjE,MAAM,OAAO,OAAO,SAAS;CAC7B,MAAM,OAAO,IAAI;CACjB,IAAI,CAAC,QAAQ,OAAO,OAAO,KAAK,OAAO,UAAU,CAAC,QAAQ,MAAM,KAAK,CAAC;CACtE,MAAM,SAAS,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,OAAO,WAAW,QAAQ,OAAO,UAAW,IAAI;CACpF,MAAM,WAAW,OAAO,KAAK,GAAG,UAC9B,UAAU,KAAK,UAAU,OACrB,KACC,KAAK,KAAK,OAAO,QAAQ,EAAG,IAAI,KAAK,KAAK,OAAO,MAAO,KACvD,KAAK,IACH,KAAK,IAAI,OAAO,QAAQ,EAAG,GAC3B,KAAK,IAAI,OAAO,MAAO,GACvB,KAAK,IAAI,OAAO,QAAQ,KAAM,OAAO,MAAO,IAAI,CAClD,KAAK,CACb;CACA,IAAI,OAAO,GAAG;EACZ,SAAS,MAAM,IAAI,OAAO,KAAM,SAAS,MAAO;EAChD,SAAS,SAAS,IAAI,OAAO,OAAO,KAAM,SAAS,OAAO,MAAO;CACnE,OAAO;EACL,SAAS,KAAK,OAAO;EACrB,SAAS,KAAK,OAAO;CACvB;CACA,MAAM,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,MAAM,MAAM,IAAI,CAAC,CAAC;CAChE,MAAM,SAAkB,CAAC;CACzB,KAAK,IAAI,QAAQ,GAAG,QAAQ,MAAM,SAAS;EACzC,MAAM,MAAM,KAAK,IAAI,OAAO,QAAS,OAAO,QAAQ,EAAG;EACvD,MAAM,OAAO,KAAK,IAAI,OAAO,QAAS,OAAO,QAAQ,EAAG;EACxD,KAAK,IAAI,SAAS,GAAG,SAAS,SAAS,UAAU;GAC/C,MAAM,IAAI,SAAS;GACnB,MAAM,KAAK,IAAI;GACf,MAAM,KAAK,KAAK;GAChB,MAAM,SACH,IAAI,KAAK,IAAI,KAAK,KAAK,OAAO,UAC9B,KAAK,IAAI,KAAK,KAAK,OAAO,SAAS,UACnC,IAAI,KAAK,IAAI,MAAM,OAAO,QAAQ,MAClC,KAAK,MAAM,OAAO,SAAS,QAAQ;GACtC,OAAO,KAAK,EAAE,QAAQ,KAAK,MAAM,MAAM,OAAO,KAAK,IAAI,CAAC,CAAC;EAC3D;CACF;CACA,OAAO,KAAK,CAAC,GAAG,OAAO,KAAM,CAAC;CAC9B,OAAO;AACT;;AAGA,SAAS,SAAS,QAAqC;CACrD,MAAM,UAAU,OAAO,SAAS,OAAO,UAAW,UAAU,OAAO,CAAC,IAAI,CAAC,KAAK,CAAE;CAChF,IAAI,CAAC,QAAQ,QAAQ,OAAO,OAAO,UAAU,CAAC;CAC9C,OAAO,OAAO,KAAK,OAAO,UAAU;EAClC,IAAI,UAAU,MAAM,OAAO;EAC3B,MAAM,QAAQ,QAAQ,MAAM,OAAO,KAAK,KAAK;EAC7C,MAAM,SAAS,CAAC,GAAG,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,OAAO,KAAK,KAAK;EAC7D,IAAI,WAAW,KAAA,GAAW,OAAO,OAAO;EACxC,IAAI,UAAU,KAAA,GAAW,OAAO,OAAO;EACvC,OAAO,OAAO,WAAa,OAAO,SAAU,OAAO,YAAa,QAAQ,WAAY,QAAQ;CAC9F,CAAC;AACH;;AAGA,SAAS,UAAU,QAAmC;CACpD,MAAM,UAAU,OAAO,SAAS,OAAO,UAAW,UAAU,OAAO,CAAC,IAAI,CAAC,KAAK,CAAE;CAChF,IAAI,CAAC,QAAQ,QAAQ,OAAO,OAAO,SAAS,CAAC,CAAC,WAAW,QAAQ,CAAC,IAAI,CAAC;CACvE,MAAM,OAAO,OAAO,SAAS;CAC7B,IAAI,SAAS,GAAG,OAAO,CAAC;CACxB,MAAM,SAAiB,CAAC;CACxB,IAAI,QAAQ,KAAM,GAAG,OAAO,KAAK,CAAC,WAAW,QAAQ,KAAM,IAAI,CAAC;CAChE,KAAK,IAAI,KAAK,GAAG,KAAK,QAAQ,QAAQ,MACpC,IAAI,QAAQ,MAAO,QAAQ,KAAK,KAAM,GAAG,OAAO,KAAK,CAAC,QAAQ,KAAK,KAAM,MAAM,QAAQ,MAAO,IAAI,CAAC;CAErG,IAAI,QAAQ,QAAQ,SAAS,KAAM,MAAM,OAAO,KAAK,CAAC,QAAQ,QAAQ,SAAS,KAAM,MAAM,QAAQ,CAAC;CACpG,OAAO;AACT;AAEA,MAAM,OAAO;;AAEb,MAAM,MAAM;AACZ,MAAM,WAAW,QAAgB,MAAc,OAAO,MAAM,CAAC,MAAM,QAAQ,IAAI,OAAO,QAAQ,IAAI,KAAK,IAAI;;AAG3G,SAAS,SAAS,OAAgB,QAAgB,KAA4B,KAAgC,QAAgB;CAC5H,MAAM,OAAmB,CAAC;CAC1B,IAAI,MAAuB;CAC3B,KAAK,MAAM,CAAC,GAAG,UAAU,OAAO;EAC9B,IAAI,OAAO,UAAU,QAAQ,QAAQ,CAAC,GAAG;GACvC,MAAM;GACN;EACF;EACA,IAAI,CAAC,KAAK,KAAK,KAAM,MAAM,CAAC,CAAE;EAC9B,IAAI,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG;CAC1D;CAeA,OAAO;EAAE,MAdI,KACV,KAAK,WAAW;GACf,IAAI,OAAO,SAAS,GAAG,OAAO,IAAI,OAAO,KAAK,GAAG;GACjD,MAAM,CAAC,GAAG,KAAK,OAAO,EAAE,CAAE,MAAM,GAAG,CAAC,CAAC,IAAI,MAAM;GAC/C,OAAO,KAAK,IAAK,IAAA,CAAK,QAAQ,CAAC,EAAE,GAAG,EAAG,QAAQ,CAAC,EAAE,GAAG,IAAI,GAAG,IAAI,SAAS,MAAM,EAAE,KAAK,IAAI,GAAG,IAAI;EACnG,CAAC,CAAC,CACD,KAAK,EAQI;EAAG,MAPF,KACV,KAAK,WAAW;GACf,MAAM,QAAQ,OAAO,EAAE,CAAE,MAAM,GAAG,CAAC,CAAC;GACpC,MAAM,QAAQ,OAAO,OAAO,SAAS,EAAE,CAAE,MAAM,GAAG,CAAC,CAAC;GACpD,OAAO,IAAI,OAAO,KAAK,GAAG,EAAE,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO;EACpE,CAAC,CAAC,CACD,KAAK,EACU;CAAE;AACtB;AAEA,MAAM,iBAAiB,cACrB,OAAO,UAAU,UAAU,YAAY,OAAO,SAAS,UAAU,KAAK;;AAGxE,SAAS,QAAQ,OAAgB,GAAW;CAC1C,IAAI,CAAC,MAAM,QAAQ,OAAO;CAC1B,IAAI,MAAM;CACV,IAAI,OAAO,MAAM,SAAS;CAC1B,IAAI,KAAK,MAAM,IAAI,CAAE,IAAI,OAAO,MAAM,IAAI,CAAE;CAC5C,IAAI,KAAK,MAAM,KAAK,CAAE,IAAI,OAAO,MAAM,KAAK,CAAE;CAC9C,OAAO,OAAO,MAAM,GAAG;EACrB,MAAM,SAAU,MAAM,QAAS;EAC/B,IAAI,MAAM,OAAO,CAAE,KAAK,GAAG,MAAM;OAC5B,OAAO;CACd;CACA,MAAM,CAAC,IAAI,MAAM,MAAM;CACvB,MAAM,CAAC,IAAI,MAAM,MAAM;CACvB,OAAO,OAAO,KAAK,KAAK,MAAO,KAAK,OAAO,IAAI,OAAQ,KAAK;AAC9D;;AAGA,SAAS,UAAU,MAAwB,OAAe;CACxD,MAAM,UAAU,KAAK,SAAS,MAAM,UAAW,KAAK,YAAY,CAAC,KAAK,IAAI,CAAC,CAAE;CAC7E,IAAI,CAAC,SAAS,CAAC,QAAQ,QAAQ,OAAO,CAAC;CACvC,MAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,EAAE,CAAC;CAC/C,MAAM,SAAS,KAAK,KAAK,QAAQ,SAAS,IAAI;CAC9C,OAAO,QACJ,QAAQ,CAAC,CACT,QAAQ,GAAG,SAAS,OAAO,WAAW,CAAC,CAAC,CACxC,QAAQ;AACb;AAEA,MAAa,YAAY,WAAwC,SAAS,UACxE,EACE,MACA,QACA,OACA,OAAO,IACP,SAAS,KACT,aACA,cAAc,UAAU,QAAQ,OAAO,KAAK,GAC5C,cACA,qBACA,sBACA,gBACA,UAAU,OACV,aAAa,0BACb,QACA,gBAAgB,QAChB,QAAQ,UACR,UAAU,QACV,eAAe,WACf,YACA,aAEF,KACA;CACA,MAAM,SAAS,OAA2B,IAAI;CAC9C,MAAM,OAAO,cAAc,UAAU,KAAK,MAAM,GAAG,CAAC,GAAG,CAAC;CACxD,MAAM,OAAO,OAAuB,IAAI;CACxC,MAAM,MAAM,OAAsB,IAAI;CACtC,MAAM,MAAM,OAAuB,IAAI;CACvC,MAAM,SAAS,OAAuB,IAAI;CAC1C,MAAM,MAAM,OAAO,MAAM,CAAC,CAAC,QAAQ,mBAAmB,EAAE;CACxD,MAAM,OAAO,KAAK,SAAS;CAC3B,MAAM,QAAQ,KAAK,WAAW;CAE9B,MAAM,CAAC,WAAW,gBAAgB,SAAmB,uBAAuB,CAAC,CAAC;CAC9E,MAAM,SAAS,gBAAgB;CAC/B,MAAM,UAAU,QAAgB;EAC9B,MAAM,OAAO,OAAO,SAAS,GAAG,IAAI,OAAO,QAAQ,SAAS,SAAS,GAAG,IAAI,CAAC,GAAG,QAAQ,GAAG;EAC3F,IAAI,iBAAiB,KAAA,GAAW,aAAa,IAAI;EACjD,uBAAuB,IAAI;CAC7B;CACA,MAAM,UAAU,OAAO,QAAQ,SAAS,CAAC,OAAO,SAAS,KAAK,GAAG,CAAC;CAClE,MAAM,aAAa,UAAU,OAAO,SAAS;CAG7C,MAAM,OAAO,YAAY;CACzB,MAAM,QAAQ,MAAsB,QAA+B;EACjE,MAAM,QAAQ,KAAK,OAAO;EAC1B,IAAI,CAAC,MAAM,OAAO,SAAS;EAC3B,OAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,IAAI,QAAQ;CACvE;CAGA,MAAM,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,KAAK,SAAS,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,GAAG,KAClF,KAAK,SAAS,GAAG,KAAK,IAAI,GAAG,OAAO,KAAK,SAAS,KAAK,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,CACpF,KAAK,GAAG;CACX,MAAM,UAAU,cAEZ,IAAI,IACF,OAAO,KAAK,SAAS;EACnB,MAAM,SAAS,KAAK,KAAK,SAAS,KAAK,MAAM,KAAK,GAAG,CAAC;EACtD,OAAO,CACL,KAAK,KACL;GAAE,OAAO,SAAS,SAAS,MAAM,GAAG,UAAU,QAAQ;GAAG,QAAQ,UAAU,MAAM;EAAE,CACrF;CACF,CAAC,CACH,GAGF,CAAC,SAAS,CACZ;CACA,IAAI,MAAM;CACV,IAAI,OAAO;CACX,KAAK,MAAM,QAAQ,SACjB,KAAK,MAAM,QAAQ,MAAM;EACvB,MAAM,QAAQ,KAAK,MAAM,KAAK,GAAG;EACjC,IAAI,UAAU,MAAM;EACpB,MAAM,KAAK,IAAI,KAAK,KAAK;EACzB,OAAO,KAAK,IAAI,MAAM,KAAK;CAC7B;CAGF,KAAK,MAAM,aAAa,cAAc,CAAC,GAAG;EACxC,IAAI,CAAC,cAAc,SAAS,GAAG;EAC/B,MAAM,KAAK,IAAI,KAAK,UAAU,KAAK;EACnC,OAAO,KAAK,IAAI,MAAM,UAAU,KAAK;CACvC;CACA,MAAM,QAAQ,OAAO,SAAS,GAAG,IAAI,UAAU,KAAK,IAAI,IAAI;CAC5D,MAAM,CAAC,QAAQ,aAAa,eAAe,SAAS,UAAU,GAAG,GAAG,CAAC;CACrE,IAAI,UAAU,MAAM,QAAQ,OAAO,OAAO,MAAM,QAAQ,OAAO,MAAM,UAAU,KAAK;CAGpF,MAAM,CAAC,QAAQ,aAAa,SAAwB,IAAI;CACxD,MAAM,CAAC,MAAM,WAAW,SAAS,SAAS;CAC1C,IAAI,SAAS,WAAW;EACtB,QAAQ,SAAS;EACjB,UAAU,IAAI;CAChB;CACA,MAAM,QAAQ,WAAW,QAAQ,QAAQ,OAAO,KAAK,IAAI,QAAQ,IAAI;CACrE,MAAM,YAAY,UAAU;CAE5B,MAAM,QAAQ,OAAO,CAAC;CACtB,MAAM,CAAC,WAAW,gBAAgB,SAAS,CAAC;CAC5C,MAAM,CAAC,OAAO,YAAY,SAAS,KAAK;CACxC,MAAM,SAAS,uBAAO,IAAI,IAAmB,CAAC;CAC9C,MAAM,QAAQ,OAAO;EAAE,KAAK,OAAO;EAAK,KAAK,OAAO;CAAI,CAAC;CACzD,MAAM,SAAS,OAAO,CAAC;CAEvB,MAAM,eAAe,cAAkC;EACrD,IAAI,OAAO,UAAU,UAAU,UAAU,OAAO,cAAc,SAAS,IAAI,OAAO,KAAA;EAClF,MAAM,KAAK,KAAK,WAAW,SAAS,KAAK,QAAQ,UAAU,EAAE;EAC7D,OAAO,KAAK,IAAI,KAAA,IAAY,OAAO,IAAI,KAAK,OAAO;CACrD;CACA,MAAM,mBAAmB,cAAc,CAAC,EAAA,CAAG,QAAQ,cAAc,YAAY,SAAS,MAAM,KAAA,CAAS;CACrG,MAAM,OAAO,OAAO;EAAE;EAAQ;CAAO,CAAC;CACtC,gCAAgC;EAC9B,KAAK,UAAU;GAAE;GAAQ;EAAO;CAClC,CAAC;;CAGD,MAAM,QAAQ,kBAAkB;EAC9B,MAAM,IAAI,MAAM;EAChB,MAAM,OAAO,IAAI;EACjB,IAAI,CAAC,KAAK,CAAC,MAAM;EACjB,MAAM,KAAK,MAAM,QAAQ;EACzB,MAAM,OAAO,MAAM,QAAQ,MAAM,MAAM;EACvC,MAAM,OAAO,UAAkB,OAAO,KAAK,QAAQ,MAAM,SAAS,SAAS;EAC3E,MAAM,KAAK,OAAO;EAClB,MAAM,QAAkB,CAAC;EACzB,KAAK,MAAM,QAAQ,KAAK,QAAQ,QAAQ;GACtC,MAAM,QAAQ,OAAO,QAAQ,IAAI,KAAK,GAAG;GACzC,IAAI,CAAC,OAAO;GACZ,MAAM,IAAI,MAAM;GAChB,MAAM,KAAK,UAAkB,IAAI,MAAM,QAAQ,MAAM,CAAC;GACtD,MAAM,QAAQ,KAAK,cAA2B,iBAAiB,IAAI,OAAO,KAAK,GAAG,EAAE,GAAG;GACvF,IAAI,MAAM,OAAO,QAAQ;IACvB,MAAM,QAAQ,SAAS,MAAM,OAAO,MAAM,SAAS,MAAM,IAAI,GAAG,GAAG,MAAM;IACzE,OAAO,cAAc,kBAAkB,CAAC,EAAE,aAAa,KAAK,MAAM,IAAI;IACtE,OAAO,cAAc,kBAAkB,CAAC,EAAE,aAAa,KAAK,MAAM,IAAI;GACxE,OAAO;IACL,MAAM,OAAO,MAAM,MAAM,SACrB,IAAI,MAAM,MAAM,KAAK,CAAC,GAAG,WAAW,IAAI,IAAI,EAAA,CAAG,QAAQ,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,MAC5F;IACJ,OAAO,cAAc,kBAAkB,CAAC,EAAE,aAAa,KAAK,IAAI;IAChE,OAAO,cAAc,kBAAkB,CAAC,EAAE,aAAa,KAAK,OAAO,GAAG,KAAK,GAAG,EAAE,GAAG,OAAO,KAAK,OAAO,KAAK,EAAE;GAC/G;GACA,IAAI,OAAO,MAAM,MAAM,UAAU,OAAO,CAAC;GACzC,MAAM,MAAM,KAAK,cAAgC,cAAc,IAAI,OAAO,KAAK,GAAG,EAAE,GAAG;GACvF,IAAI,OAAO,MAAM,MAAM,QAAQ;IAC7B,MAAM,MAAM,QAAQ,MAAM,QAAQ,EAAE;IACpC,MAAM,KAAK,EAAE,QAAQ,MAAM,OAAO,EAAE,CAAC;IACrC,IAAI,aAAa,OAAO,KAAK,EAAA,CAAG,QAAQ,CAAC,CAAC;IAC1C,IAAI,aAAa,MAAM,GAAG,QAAQ,CAAC,CAAC;IAEpC,IAAI,KAAK,IAAI,aAAa,YAAY,EAAE;SACnC,IAAI,gBAAgB,UAAU;IACnC,IAAI,IAAI,MAAO,CAAC,KAAK,MAAM,KAAK,EAAE;GACpC;EACF;EAEA,KAAK,MAAM,QAAQ,KAAK,iBAAiC,aAAa,GAAG;GACvE,MAAM,KAAK,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAG;GAClE,KAAK,aAAa,MAAM,EAAE;GAC1B,KAAK,aAAa,MAAM,EAAE;EAC5B;EACA,KAAK,MAAM,QAAQ,OAAO,SAAS,iBAA8B,aAAa,KAAK,CAAC,GAClF,KAAK,MAAM,YAAY,KAAK,KAAK,MAAM,IAAI,OAAO,KAAK,QAAQ,IAAI,CAAC,CAAC,EAAE;EAGzE,KAAK,MAAM,QAAQ,KAAK,iBAAiC,wBAAwB,GAAG;GAClF,MAAM,KAAK,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,QAAQ,cAAc,CAAC,CAAC,IAAI,EAAG;GAC5E,KAAK,aAAa,MAAM,EAAE;GAC1B,KAAK,aAAa,MAAM,EAAE;EAC5B;EACA,KAAK,MAAM,QAAQ,KAAK,iBAAiC,qBAAqB,GAAG;GAC/E,MAAM,KAAK,OAAO,KAAK,MAAM,OAAO,KAAK,QAAQ,WAAW,IAAI,CAAC,IAAI,EAAG;GACxE,KAAK,aAAa,MAAM,EAAE;GAC1B,KAAK,aAAa,MAAM,EAAE;EAC5B;EACA,KAAK,MAAM,QAAQ,KAAK,SAAS,iBAA8B,wBAAwB,KAAK,CAAC,GAAG;GAC9F,MAAM,EAAE,gBAAgB,gBAAgB,KAAK;GAC7C,KAAK,MAAM,YACT,mBAAmB,KAAA,IACf,KAAK,KAAK,MAAM,IAAI,OAAO,cAAc,CAAC,CAAC,EAAE,MAC7C,GAAG,KAAK,MAAM,OAAO,WAAW,IAAI,CAAC,EAAE;EAC/C;EACA,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC,IAAI;EAChC,MAAM,QAAQ,KAAK,cAAc,uBAAuB;EACxD,OAAO,aAAa,MAAM,OAAO,EAAE,CAAC;EACpC,OAAO,aAAa,MAAM,OAAO,EAAE,CAAC;EAEpC,MAAM,SAAS,IAAI;EACnB,IAAI,QAAQ;GACV,MAAM,KAAK,OAAO;GAClB,MAAM,KAAK,OAAO;GAClB,IAAI,IAAI,KAAK;GACb,IAAI,IAAI,KAAK,GAAG,IAAI,KAAK,MAAM;GAC/B,MAAM,SAAS,MAAM,SAAS,MAAM,QAAQ,KAAK,UAAU,MAAM,OAAO,CAAC,IAAI,MAAM,SAAS,SAAS;GACrG,OAAO,MAAM,YAAY,GAAG,MAAM,GAAG,GAAG,KAAK,IAAI,GAAG,IAAI,EAAE,CAAC,EAAE,KAAK,MAAM,SAAS,KAAK,GAAG,GAAG,KAAK,IAAI,GAAG,SAAS,EAAE,CAAC,EAAE;EACxH;CACF,GAAG,CAAC,MAAM,CAAC;CAGX,gCAAgC;EAC9B,MAAM,OAAO,KAAK;EAClB,IAAI,CAAC,MAAM;EACX,MAAM,aAAa;GACjB,MAAM,UAAU,KAAK;GACrB,aAAa,KAAK,WAAW;GAC7B,MAAM;EACR;EACA,KAAK;EACL,IAAI,OAAO,mBAAmB,aAAa;EAC3C,MAAM,WAAW,IAAI,eAAe,IAAI;EACxC,SAAS,QAAQ,IAAI;EACrB,aAAa,SAAS,WAAW;CACnC,GAAG,CAAC,KAAK,CAAC;CACV,0BAA0B,KAAK;CAG/B,gBAAgB;EACd,MAAM,QAAyF,CAAC;EAChG,KAAK,MAAM,CAAC,KAAK,EAAE,OAAO,QAAQ,aAAa,SAAS;GACtD,MAAM,QAAQ,OAAO,QAAQ,IAAI,GAAG;GACpC,IAAI,CAAC,OAAO;IACV,OAAO,QAAQ,IAAI,KAAK;KACtB,OAAO;KACP;KACA,UAAU,KAAK,QAAQ,OAAO,SAAS,GAAG,IAAI,IAAI;KAClD,MAAM;IACR,CAAC;IACD;GACF;GAEA,MAAM,SAAS;GACf,IAAI,CAAC,MAAM,MAAM,UAAU,CAAC,OAAO,QAAQ;IACzC,MAAM,QAAQ;IACd;GACF;GACA,MAAM,KAAK,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,MAAM,GAAG,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;GAClF,MAAM,KAAK;IAAE;IAAO;IAAI,MAAM,GAAG,KAAK,MAAM,QAAQ,MAAM,OAAO,CAAC,CAAC;IAAG,IAAI,GAAG,KAAK,MAAM,QAAQ,QAAQ,CAAC,CAAC;IAAG;GAAO,CAAC;EACvH;EACA,IAAI,CAAC,MAAM,QAAQ;GACjB,MAAM;GACN;EACF;EACA,OAAO,MACL,SACC,MAAM;GACL,KAAK,MAAM,QAAQ,OACjB,KAAK,MAAM,QAAQ,KAAK,GAAG,KAAK,GAAG,OAAc,CAAC,GAAG,KAAK,KAAK,OAAQ,KAAK,GAAG,MAAO,KAAK,KAAK,OAAQ,CAAC,CAAC;GAE5G,MAAM;EACR,SACM;GACJ,KAAK,MAAM,QAAQ,OAAO,KAAK,MAAM,QAAQ,KAAK;GAClD,MAAM;EACR,CACF;CACF,GAAG,CAAC,OAAO,OAAO,CAAC;CAGnB,MAAM,YAAY,OAAO,KAAK,GAAG;CACjC,gBAAgB;EACd,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,SAAS;GACzC,MAAM,KAAK,OAAO,SAAS,GAAG,IAAI,IAAI;GACtC,IAAI,MAAM,aAAa,IAAI;GAC3B,MAAM,OAAO;GACb,MAAM,OAAO,MAAM;GACnB,MAAM,OAAO,MAAM,SAAS,MAAM;IAChC,MAAM,WAAW,QAAQ,KAAK,QAAQ;IACtC,MAAM;GACR,CAAC;EACH;EACA,MAAM;CAGR,GAAG,CAAC,WAAW,KAAK,CAAC;CAGrB,gBAAgB;EACd,MAAM,OAAO,EAAE,GAAG,MAAM,QAAQ;EAChC,IAAI,KAAK,QAAQ,OAAO,OAAO,KAAK,QAAQ,OAAO,KAAK;EACxD,OAAO,MAAM,SAAS,MAAM;GAC1B,MAAM,UAAU;IAAE,KAAK,KAAK,OAAO,OAAO,MAAM,KAAK,OAAO;IAAG,KAAK,KAAK,OAAO,OAAO,MAAM,KAAK,OAAO;GAAE;GAC3G,MAAM;EACR,CAAC;CACH,GAAG,CAAC,OAAO,MAAM,CAAC;CAGlB,gBAAgB;EACd,IAAI,SAAS,OAAO;EACpB,MAAM,OAAO,OAAO;EACpB,IAAI,CAAC,QAAQ,qBAAqB,KAAK,OAAO,yBAAyB,aAAa;GAClF,SAAS,IAAI;GACb;EACF;EACA,MAAM,WAAW,IAAI,sBAClB,CAAC,WAAW;GACX,IAAI,CAAC,OAAO,gBAAgB;GAC5B,SAAS,WAAW;GACpB,SAAS,IAAI;EACf,GACA,EAAE,WAAW,GAAI,CACnB;EACA,SAAS,QAAQ,IAAI;EACrB,aAAa,SAAS,WAAW;CACnC,GAAG,CAAC,OAAO,KAAK,CAAC;CAGjB,MAAM,eAAe,OAAO,KAAK;CACjC,gBAAgB;EACd,IAAI,UAAU,MAAM;GAClB,aAAa,UAAU;GACvB;EACF;EACA,MAAM,KAAK,OAAO,IAAI,QAAQ,OAAO;EACrC,MAAM,OAAO,OAAO;EACpB,IAAI,CAAC,aAAa,SAAS;GACzB,aAAa,UAAU;GACvB,OAAO,UAAU;GACjB,MAAM;GACN;EACF;EACA,OAAO,MAAM,SAAS,MAAM;GAC1B,OAAO,UAAU,QAAQ,KAAK,QAAQ;GACtC,MAAM;EACR,CAAC;CACH,GAAG;EAAC;EAAO;EAAM;CAAK,CAAC;CAEvB,MAAM,WAAW,OAAO,cAAc;CACtC,gCAAgC;EAC9B,SAAS,UAAU;CACrB,CAAC;CACD,gBAAgB;EACd,SAAS,UAAU,OAAO,UAAU,OAAO,OAAQ,KAAK,UAAU,IAAK;CAGzE,GAAG,CAAC,KAAK,CAAC;CAEV,MAAM,WAAW,YAAoB;EACnC,MAAM,OAAO,KAAK,SAAS,sBAAsB;EACjD,IAAI,CAAC,MAAM,SAAS,OAAO,GAAG,OAAO,KAAK,IAAI,GAAG,IAAI;EACrD,OAAO,MAAM,KAAK,OAAQ,UAAU,KAAK,QAAQ,KAAK,QAAS,IAAI,GAAG,GAAG,IAAI;CAC/E;CACA,MAAM,aAAa,UAAyC;EAC1D,IAAI,MAAM,QAAQ,YAAY,WAAW;GACvC,MAAM,eAAe;GACrB,UAAU,IAAI;GACd;EACF;EACA,MAAM,OAAO,SAAS,OAAO;EAC7B,MAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,SAAS,CAAC,CAAC;EACpD,MAAM,OACJ;GACE,WAAW,OAAO;GAClB,WAAW,OAAO;GAClB,YAAY,UAAU,OAAO,OAAO,OAAO;GAC3C,SAAS,UAAU,OAAO,OAAO,OAAO;GACxC,UAAU,OAAO;GACjB,QAAQ,OAAO;GACf,MAAM;GACN,KAAK;EACP,EACA,MAAM;EACR,IAAI,SAAS,KAAA,KAAa,OAAO;EACjC,MAAM,eAAe;EACrB,UAAU,MAAM,MAAM,GAAG,IAAI,CAAC;CAChC;CACA,MAAM,iBAAiB,UAAwC;EAC7D,IAAI,OAAO;EACX,IAAI,MAAM,gBAAgB,SAAS,MAAM,cAAc,oBAAoB,MAAM,SAAS;EAC1F,UAAU,QAAQ,MAAM,OAAO,CAAC;CAClC;CACA,MAAM,iBAAiB,UAAwC;EAC7D,IAAI,CAAC,UAAU,MAAM,gBAAgB,WAAW,MAAM,UAAU,UAAU,QAAQ,MAAM,OAAO,CAAC;CAClG;CAEA,MAAM,gBAAgB,OAAe,SACnC,GAAG,cAAc,YAAY,OAAO,IAAI,IAAI,QAAQ,OAAO,KAAK,IAAI,OAAO,IAAI,SAAS;CAC1F,MAAM,UAAU,OAAsB,SACpC,UAAU,OAAO,eAAe,aAAa,OAAO,IAAI;CAE1D,MAAM,mBAAmB,UACvB,OAAO,KAAK,aAAa,OAAO,OAAO,EAAE,IAAI,GAAG,QAAQ,OAAO,KAAK,IAAI,OAAO,IAAI,SAAS;CAC9F,MAAM,UAAU,UAAU,OAAO,OAAO,KAAK;CAC7C,MAAM,QAAQ,WAAW,KAAK;CAC9B,MAAM,YAAY,UACd,GAAG,QAAQ,MAAM,IAAI,QAAQ,KAAK,SAAS,GAAG,KAAK,MAAM,GAAG,OAAO,KAAK,SAAS,KAAK,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,IAAI,MAC9G,QACE,aACA,GAAG,QAAQ,OAAO,MAAM,OAAO,OAAO;CAC5C,MAAM,UAAU,QACZ,GAAG,MAAM,IAAI,WAAW,KACxB,GAAG,MAAM,IAAI,KAAK,EAAE,CAAE,MAAM,MAAM,KAAK,KAAK,CAAE,MAAM,IAAI,QACrD,KAAK,SAAS,GAAG,KAAK,MAAM,WAAW,OAAO,KAAK,KAAK,OAAQ,KAAK,GAAG,GAAG,IAAI,GAAG,CAAC,CACnF,KAAK,IAAI,EAAE,GAAG,gBACd,KAAK,cACJ,OAAO,UAAU,UAAU,WACvB,IAAI,UAAU,MAAM,IAAI,gBAAgB,UAAU,KAAK,EAAE,KACzD,IAAI,UAAU,MAAM,IAAI,KAAK,MAAM,SAAS,KAAK,QAAQ,UAAU,EAAE,CAAC,CAAE,MAAM,EACpF,CAAC,CACA,KAAK,EAAE;CACd,MAAM,QAAQ,UAAU,MAAM,SAAS;CACvC,MAAM,YAAY,CAAC,SAAS,QAAQ,WAAW;CAE/C,OACE,qBAAC,UAAD;EACE,KAAK;EACL,aAAU;EACV,cAAY;EACZ,aAAW,WAAW,KAAA;EACtB,WAAW,GAAG,+DAA+D,SAAS;EALxF,UAAA;GAOG,aACC,oBAAC,OAAD;IAAK,MAAK;IAAQ,cAAY,GAAG,MAAM;IAAU,WAAU;IACxD,UAAA,OAAO,KAAK,MAAM,OACjB,qBAAC,UAAD;KAEE,MAAK;KACL,aAAU;KACV,gBAAc,CAAC,OAAO,SAAS,KAAK,GAAG;KACvC,eAAe,OAAO,KAAK,GAAG;KAC9B,OAAO,EAAE,YAAY,QAAQ,MAAM,EAAE,EAAE;KACvC,WAAU;KAPZ,UAAA,CASE,oBAAC,QAAD;MAAM,eAAY;MAAO,eAAa,KAAK,UAAU,KAAA;MAAW,WAAU;KAAgB,CAAA,GAC1F,oBAAC,QAAD;MAAM,WAAU;MAAsB,UAAA,KAAK;KAAY,CAAA,CACjD;IAVD,GAAA,KAAK,GAUJ,CACT;GACE,CAAA,IACH;GACJ,qBAAC,OAAD;IACE,aAAU;IACV,kBAAgB,aAAa,KAAA;IAC7B,gBAAc,WAAW,KAAA;IACzB,cAAY,SAAS,KAAA;IACrB,WAAU;IALZ,UAAA;KAOE,qBAAC,OAAD;MACE,KAAK;MACL,aAAU;MACV,MAAK;MACL,UAAU,QAAQ,KAAK;MACvB,cAAY,GAAG,MAAM,eAAe,cAAc,YAAY;MAC9D,oBAAiB;MACjB,iBAAe;MACf,iBAAe,KAAK,IAAI,GAAG,KAAK,MAAM;MACtC,kBAAgB,SAAS,QAAQ;MACjC,kBAAgB;MACD;MACA;MACf,cAAc,UAAU;OACtB,IAAI,MAAM,gBAAgB,SAAS,UAAU,IAAI;MACnD;MACA,uBAAuB,UAAU,IAAI;MACrC,iBAAiB,UAAU;OACzB,IAAI,MAAM,gBAAgB,SAAS,UAAU,IAAI;MACnD;MACW;MACX,cAAc,UAAU,IAAI;MAC5B,UAAU,UAAU;OAClB,IAAI,MAAM,cAAc,QAAQ,gBAAgB,KAAK,CAAC,OAAO,WAAW,YAAY,WAAW,IAAI;MACrG;MACA,WAAU;MACV,OAAO,EAAE,OAAO;MA1BlB,UAAA;OA4BE,qBAAC,OAAD;QAAK,KAAK;QAAK,OAAM;QAAe;QAAQ,eAAY;QAAO,WAAU;QAAQ,WAAU;QAA3F,UAAA;SACE,oBAAC,QAAD,EAAA,UACE,oBAAC,YAAD;UAAU,IAAI,GAAG,IAAI;UAAQ,eAAc;UACzC,UAAA,oBAAC,QAAD;WAAM,WAAU;WAAoB,GAAG;WAAI,GAAG;WAAK,QAAQ,SAAS;WAAI,OAAO,EAAE,OAAO,QAAQ,YAAY,KAAK,EAAE;UAAI,CAAA;SAC/G,CAAA,EACN,CAAA;SACL,OAAO,MAAM,MAAM,CAAC,CAAC,CAAC,KAAK,UAC1B,oBAAC,QAAD;UAAkB,aAAW;UAAO,WAAU;UAAkB,IAAI;UAAG,IAAG;SAAQ,GAAvE,KAAuE,CACnF;SACD,oBAAC,QAAD;UAAM,WAAU;UAAsB,IAAI;UAAG,IAAG;UAAO,IAAI,SAAS;UAAK,IAAI,SAAS;SAAM,CAAA;SAC3F,gBAAgB,KAAK,cACpB,OAAO,UAAU,UAAU,WACzB,oBAAC,QAAD;UAEE,kBAAgB,UAAU;UAC1B,wBAAsB,UAAU;UAChC,WAAU;UACV,IAAI;UACJ,IAAG;SACJ,GANM,UAAU,GAMhB,IAED,oBAAC,QAAD;UAEE,kBAAgB,UAAU;UAC1B,qBAAmB,YAAY,SAAS;UACxC,WAAU;UACV,IAAI;UACJ,IAAI;SACL,GANM,UAAU,GAMhB,CAEL;SACA,oBAAC,QAAD;UAAM,aAAU;UAAY,WAAU;UAAuB,IAAI;UAAS,IAAI;SAAS,CAAA;SACvF,oBAAC,KAAD;UAAG,WAAU;UAAoB,UAAU,QAAQ,IAAI;UACpD,UAAA,OAAO,KAAK,MAAM,OACjB,qBAAC,KAAD;WAAkB,eAAa,KAAK;WAAK,OAAO,EAAE,YAAY,QAAQ,MAAM,EAAE,EAAE;WAAhF,UAAA,CACI,KAAK,QAAQ,OAAO,IAAK,oBAAC,QAAD;YAAM,aAAU;YAAO,WAAU;WAAmB,CAAA,IAAI,MACnF,oBAAC,QAAD;YAAM,aAAU;YAAO,eAAa,KAAK,UAAU,KAAA;YAAW,WAAU;WAAmB,CAAA,CAC1F;UAHK,GAAA,KAAK,GAGV,CACJ;SACA,CAAA;SACF,OAAO,KAAK,MAAM,OACjB,oBAAC,UAAD;UAEE,YAAU,KAAK;UACf,eAAa,OAAO,SAAS,KAAK,GAAG,KAAK,KAAA;UAC1C,GAAG;UACH,WAAU;UACV,OAAO,EAAE,YAAY,QAAQ,MAAM,EAAE,EAAE;SACxC,GANM,KAAK,GAMX,CACF;QACE;;OACJ,gBAAgB,KAAK,cACpB,oBAAC,QAAD;QAEE,eAAY;QACZ,aAAU;QACV,wBAAsB,UAAU;QAChC,wBAAsB,OAAO,UAAU,UAAU,WAAW,UAAU,QAAQ,KAAA;QAC9E,qBAAmB,OAAO,UAAU,UAAU,WAAW,KAAA,IAAY,YAAY,SAAS;QAC1F,aAAW,OAAO,UAAU,UAAU,WAAW,UAAU;QAC3D,WAAU;QAET,UAAA,UAAU;OACP,GAVC,UAAU,GAUX,CACP;OACD,qBAAC,OAAD;QAAK,KAAK;QAAK,eAAY;QAAO,aAAU;QAAqB,WAAU;QAA3E,UAAA,CACE,oBAAC,KAAD;SAAG,WAAU;SAAyE,UAAA,OAAO,SAAS;QAAM,CAAA,GAC3G,QAAQ,KAAK,SACZ,qBAAC,KAAD;SAEE,WAAU;SACV,OAAO,EAAE,YAAY,QAAQ,MAAM,OAAO,QAAQ,IAAI,CAAC,EAAE;SAH3D,UAAA;UAKE,oBAAC,QAAD;WAAM,eAAa,KAAK,UAAU,KAAA;WAAW,WAAU;UAAoB,CAAA;UAC3E,oBAAC,QAAD;WAAM,WAAU;WAA+C,UAAA,KAAK;UAAY,CAAA;UAChF,oBAAC,QAAD;WAAM,WAAU;WACb,UAAA,QAAQ,OAAO,KAAK,OAAO,KAAK,GAAG,GAAG,IAAI,IAAI,OAAO,GAAG,IAAI;UACzD,CAAA;SACL;QATI,GAAA,KAAK,GAST,CACJ,CACE;;QACH,SAAS,cAAc,CAAC,UACxB,oBAAC,KAAD;QAAG,WAAU;QACV,UAAA,QAAQ,aAAa;OACrB,CAAA,IACD;OACH,WAAW,QAAQ,oBAAC,QAAD;QAAM,eAAY;QAAO,WAAU;OAAkB,CAAA,IAAI;MAC1E;;KACL,oBAAC,OAAD;MAAK,KAAK;MAAQ,eAAY;MAAO,WAAU;MAC5C,UAAA,OAAO,MAAM,KAAK,UACjB,oBAAC,QAAD;OAAkB,aAAW;OAAO,WAAU;OAC5C,UAAA,oBAAC,QAAD;QAAM,WAAU;QACb,UAAA,WAAW,KAAK;OACb,CAAA;MACF,GAJK,KAIL,CACP;KACE,CAAA;KACL,oBAAC,OAAD;MAAK,eAAY;MAAO,WAAU;MAC/B,UAAA,MAAM,KAAK,OAAO;OACjB,MAAM,QAAQ,OAAO,IAAI,KAAK,OAAO;OACrC,OACE,oBAAC,QAAD;QAEE,WAAU;QACV,OAAO;SAAE,MAAM,GAAG,QAAQ,IAAI;SAAI,WAAW,GAAG,CAAC,QAAQ,IAAI;QAAK;QAEjE,UAAA,KAAK,GAAG,CAAE;OACP,GALC,GAAG,KAAK,GAAG,CAAE,IAAI,GAAG,KAAK,GAAG,CAAE,WAK/B;MAEV,CAAC;KACE,CAAA;IACF;;GACL,oBAAC,KAAD;IAAG,WAAU;IAAW,UAAA;GAAW,CAAA;GAClC,QAAQ,OACP,oBAAC,OAAD;IAAK,WAAU;IACb,UAAA,qBAAC,SAAD,EAAA,UAAA;KACE,oBAAC,WAAD,EAAA,UAAU,MAAe,CAAA;KACzB,oBAAC,SAAD,EAAA,UACE,qBAAC,MAAD,EAAA,UAAA,CACE,oBAAC,MAAD;MAAI,OAAM;MAAO,UAAA;KAAkB,CAAA,GAClC,OAAO,KAAK,SACX,oBAAC,MAAD;MAAmB,OAAM;MACtB,UAAA,KAAK;KACJ,GAFK,KAAK,GAEV,CACL,CACC,EAAA,CAAA,EACC,CAAA;KACP,oBAAC,SAAD,EAAA,UACG,KAAK,KAAK,SACT,qBAAC,MAAD,EAAA,UAAA,CACE,oBAAC,MAAD;MAAI,OAAM;MAAO,UAAA,KAAK;KAAU,CAAA,GAC/B,OAAO,KAAK,SACX,oBAAC,MAAD,EAAA,UAAoB,OAAO,KAAK,MAAM,KAAK,GAAG,GAAG,IAAI,EAAM,GAAlD,KAAK,GAA6C,CAC5D,CACC,EAAA,GALK,KAAK,GAKV,CACL,EACI,CAAA;IACF,EAAA,CAAA;GACJ,CAAA;GAEP,oBAAC,KAAD;IAAG,WAAU;IAAU,aAAU;IAAS,eAAY;IACnD,UAAA,UAAU,YAAY;GACtB,CAAA;EACG;;AAEZ,CAAC"}
|
|
@@ -22,6 +22,10 @@ export interface MoneyInputDetails {
|
|
|
22
22
|
* `min` is checked when the field loses focus; `max` is enforced as you type: a
|
|
23
23
|
* digit that would pass it is refused and the amount strains toward it. Wording
|
|
24
24
|
* for the range comes from the currency, and `error` replaces it.
|
|
25
|
+
*
|
|
26
|
+
* `isInvalid` and `errorMessage` are the pair Select and MultiSelect take: the
|
|
27
|
+
* app's own validation marks the field invalid, and the message shows only while
|
|
28
|
+
* it is (or while the amount is out of range, whose wording it then replaces).
|
|
25
29
|
*/
|
|
26
30
|
export interface MoneyInputProps {
|
|
27
31
|
/** What the amount is, and the field's accessible name. */
|
|
@@ -50,8 +54,25 @@ export interface MoneyInputProps {
|
|
|
50
54
|
locale?: string;
|
|
51
55
|
/** Helper text under the field. A string, because the copy is animated word by word. */
|
|
52
56
|
description?: string;
|
|
53
|
-
/** Replaces the built-in range message. */
|
|
57
|
+
/** Replaces the built-in range message. Shown whenever it is set. */
|
|
54
58
|
error?: string;
|
|
59
|
+
/**
|
|
60
|
+
* Marks the amount invalid: the destructive border and `aria-invalid`, with or
|
|
61
|
+
* without a message. An amount outside `min`/`max` also becomes invalid on its
|
|
62
|
+
* own, once the field loses focus. Without `errorMessage` no text is shown, so
|
|
63
|
+
* the app must say what is wrong itself (WCAG 3.3.1).
|
|
64
|
+
*
|
|
65
|
+
* @default false
|
|
66
|
+
*/
|
|
67
|
+
isInvalid?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Why the amount is wrong, shown under the field while it is invalid
|
|
70
|
+
* (`isInvalid`, or out of range, whose built-in wording it replaces) and tied
|
|
71
|
+
* to the input as its error. A string, because the copy is animated word by
|
|
72
|
+
* word: unlike Select and MultiSelect, whose `errorMessage` is a `ReactNode`.
|
|
73
|
+
* `error`, when set, wins.
|
|
74
|
+
*/
|
|
75
|
+
errorMessage?: string;
|
|
55
76
|
disabled?: boolean;
|
|
56
77
|
/** Adds a hidden input carrying the amount in minor units. */
|
|
57
78
|
name?: string;
|
|
@@ -4,7 +4,7 @@ import { useIsomorphicLayoutEffect, useMorphWidth } from "../lib/motion.js";
|
|
|
4
4
|
import { Button as Button$1 } from "../button/button.js";
|
|
5
5
|
import { SwapText } from "../lib/swap-text.js";
|
|
6
6
|
import { fieldSurfaceVariants } from "../lib/field-surface.js";
|
|
7
|
-
import { RollingNumber } from "../lib/field-message.js";
|
|
7
|
+
import { FieldMessage, RollingNumber } from "../lib/field-message.js";
|
|
8
8
|
import { FieldShell, useFieldWiring } from "../lib/field-shell.js";
|
|
9
9
|
import { SelectItem, selectPopoverVariants } from "../select/select.js";
|
|
10
10
|
import { forwardRef, useCallback, useId, useImperativeHandle, useMemo, useReducer, useRef, useState } from "react";
|
|
@@ -160,7 +160,7 @@ const MoneyInput = forwardRef(function MoneyInput({ label, labelHidden = false,
|
|
|
160
160
|
10,
|
|
161
161
|
50,
|
|
162
162
|
100
|
|
163
|
-
], step: stepProp, locale = "en-US", description, error, disabled = false, name, id, className, onBlur }, forwardedRef) {
|
|
163
|
+
], step: stepProp, locale = "en-US", description, error, isInvalid = false, errorMessage, disabled = false, name, id, className, onBlur }, forwardedRef) {
|
|
164
164
|
const generated = useId();
|
|
165
165
|
const inputId = id ?? `${generated}-amount`;
|
|
166
166
|
const rangeId = `${inputId}-range`;
|
|
@@ -406,13 +406,14 @@ const MoneyInput = forwardRef(function MoneyInput({ label, labelHidden = false,
|
|
|
406
406
|
const range = min !== void 0 && max !== void 0 ? `${money(min)} to ${money(max)}` : max !== void 0 ? `Up to ${money(max)}` : min !== void 0 ? `At least ${money(min)}` : "";
|
|
407
407
|
const belowMin = minor !== null && min !== void 0 && minor < min;
|
|
408
408
|
const builtIn = touched && !focused && (belowMin || minor !== null && max !== void 0 && minor > max) ? belowMin ? `The minimum is ${money(min ?? 0)}` : `The maximum is ${money(max ?? 0)}` : void 0;
|
|
409
|
-
const
|
|
409
|
+
const invalid = isInvalid || builtIn !== void 0;
|
|
410
|
+
const message = error ?? (invalid ? errorMessage ?? builtIn : void 0);
|
|
410
411
|
const chips = quickAdd.filter((amount) => amount > 0);
|
|
411
412
|
const field = useFieldWiring({
|
|
412
413
|
enabled: true,
|
|
413
414
|
id: inputId,
|
|
414
415
|
describedBy: range ? rangeId : void 0,
|
|
415
|
-
invalid: void 0,
|
|
416
|
+
invalid: invalid || void 0,
|
|
416
417
|
description,
|
|
417
418
|
error: message
|
|
418
419
|
});
|
|
@@ -423,7 +424,7 @@ const MoneyInput = forwardRef(function MoneyInput({ label, labelHidden = false,
|
|
|
423
424
|
/* @__PURE__ */ jsxs(Group, {
|
|
424
425
|
role: "presentation",
|
|
425
426
|
isDisabled: disabled,
|
|
426
|
-
isInvalid: Boolean(message),
|
|
427
|
+
isInvalid: invalid || Boolean(message),
|
|
427
428
|
"data-slot": "money-input-shell",
|
|
428
429
|
className: shellClass,
|
|
429
430
|
children: [/* @__PURE__ */ jsx("div", {
|
|
@@ -553,6 +554,11 @@ const MoneyInput = forwardRef(function MoneyInput({ label, labelHidden = false,
|
|
|
553
554
|
children: code
|
|
554
555
|
})]
|
|
555
556
|
}),
|
|
557
|
+
/* @__PURE__ */ jsx(FieldMessage, {
|
|
558
|
+
id: field.errorId,
|
|
559
|
+
text: message,
|
|
560
|
+
tone: "error"
|
|
561
|
+
}),
|
|
556
562
|
chips.length > 0 || range ? /* @__PURE__ */ jsxs("div", {
|
|
557
563
|
className: "flex flex-wrap items-center justify-between gap-x-3 gap-y-2 pt-3",
|
|
558
564
|
children: [chips.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
@@ -595,8 +601,8 @@ const MoneyInput = forwardRef(function MoneyInput({ label, labelHidden = false,
|
|
|
595
601
|
controlId: field.controlId,
|
|
596
602
|
description,
|
|
597
603
|
hintId: field.hintId,
|
|
598
|
-
error:
|
|
599
|
-
errorId:
|
|
604
|
+
error: void 0,
|
|
605
|
+
errorId: void 0,
|
|
600
606
|
children: control
|
|
601
607
|
})
|
|
602
608
|
});
|
|
@@ -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":"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"}
|
|
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 { 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 *\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 /** 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\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 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={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 {/* 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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"}
|