@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.
Files changed (101) hide show
  1. package/README.md +195 -4
  2. package/dist/alert/alert.d.ts +49 -4
  3. package/dist/alert/alert.js +66 -38
  4. package/dist/alert/alert.js.map +1 -1
  5. package/dist/alert/index.d.ts +2 -2
  6. package/dist/alert/index.js +2 -2
  7. package/dist/alert-dialog/alert-dialog.d.ts +17 -4
  8. package/dist/alert-dialog/alert-dialog.js +26 -2
  9. package/dist/alert-dialog/alert-dialog.js.map +1 -1
  10. package/dist/badge/badge.d.ts +1 -1
  11. package/dist/button/button.d.ts +2 -2
  12. package/dist/calendar/calendar.d.ts +1 -1
  13. package/dist/card/card.d.ts +22 -1
  14. package/dist/card/card.js +60 -7
  15. package/dist/card/card.js.map +1 -1
  16. package/dist/carousel/carousel.d.ts +21 -0
  17. package/dist/carousel/carousel.js +34 -8
  18. package/dist/carousel/carousel.js.map +1 -1
  19. package/dist/copy-button/copy-button.d.ts +18 -2
  20. package/dist/copy-button/copy-button.js +29 -8
  21. package/dist/copy-button/copy-button.js.map +1 -1
  22. package/dist/donut-chart/donut-chart.d.ts +22 -0
  23. package/dist/donut-chart/donut-chart.js +35 -18
  24. package/dist/donut-chart/donut-chart.js.map +1 -1
  25. package/dist/donut-chart/index.d.ts +2 -2
  26. package/dist/empty-state/empty-state.d.ts +21 -0
  27. package/dist/empty-state/empty-state.js +16 -4
  28. package/dist/empty-state/empty-state.js.map +1 -1
  29. package/dist/empty-state/index.d.ts +2 -2
  30. package/dist/empty-state/index.js +2 -2
  31. package/dist/filter-bar/filter-bar.d.ts +4 -1
  32. package/dist/filter-bar/filter-bar.js +53 -9
  33. package/dist/filter-bar/filter-bar.js.map +1 -1
  34. package/dist/index.d.ts +10 -10
  35. package/dist/index.js +7 -7
  36. package/dist/input/input.js +4 -4
  37. package/dist/input/input.js.map +1 -1
  38. package/dist/lib/field-shell.js +10 -3
  39. package/dist/lib/field-shell.js.map +1 -1
  40. package/dist/lib/field-surface.js +22 -1
  41. package/dist/lib/field-surface.js.map +1 -1
  42. package/dist/lib/use-copy-feedback.js +17 -3
  43. package/dist/lib/use-copy-feedback.js.map +1 -1
  44. package/dist/line-chart/index.d.ts +2 -2
  45. package/dist/line-chart/line-chart.d.ts +42 -2
  46. package/dist/line-chart/line-chart.js +143 -14
  47. package/dist/line-chart/line-chart.js.map +1 -1
  48. package/dist/money-input/money-input.d.ts +22 -1
  49. package/dist/money-input/money-input.js +13 -7
  50. package/dist/money-input/money-input.js.map +1 -1
  51. package/dist/morph-select/morph-select.d.ts +19 -1
  52. package/dist/morph-select/morph-select.js +21 -2
  53. package/dist/morph-select/morph-select.js.map +1 -1
  54. package/dist/multi-select/index.d.ts +2 -2
  55. package/dist/multi-select/index.js +2 -2
  56. package/dist/multi-select/multi-select.d.ts +43 -2
  57. package/dist/multi-select/multi-select.js +93 -36
  58. package/dist/multi-select/multi-select.js.map +1 -1
  59. package/dist/password-field/password-field.d.ts +16 -0
  60. package/dist/password-field/password-field.js +37 -8
  61. package/dist/password-field/password-field.js.map +1 -1
  62. package/dist/popover/index.d.ts +2 -2
  63. package/dist/popover/index.js +2 -2
  64. package/dist/popover/popover.d.ts +39 -2
  65. package/dist/popover/popover.js +29 -2
  66. package/dist/popover/popover.js.map +1 -1
  67. package/dist/progress/progress.d.ts +16 -2
  68. package/dist/progress/progress.js +15 -8
  69. package/dist/progress/progress.js.map +1 -1
  70. package/dist/radio-group/index.d.ts +2 -2
  71. package/dist/radio-group/index.js +2 -2
  72. package/dist/radio-group/radio-group.d.ts +33 -3
  73. package/dist/radio-group/radio-group.js +109 -9
  74. package/dist/radio-group/radio-group.js.map +1 -1
  75. package/dist/scroll-area/scroll-area.js +4 -3
  76. package/dist/scroll-area/scroll-area.js.map +1 -1
  77. package/dist/search-field/search-field.d.ts +22 -1
  78. package/dist/search-field/search-field.js +22 -7
  79. package/dist/search-field/search-field.js.map +1 -1
  80. package/dist/select/select.d.ts +1 -1
  81. package/dist/select/select.js +8 -6
  82. package/dist/select/select.js.map +1 -1
  83. package/dist/separator/separator.d.ts +21 -9
  84. package/dist/separator/separator.js +33 -11
  85. package/dist/separator/separator.js.map +1 -1
  86. package/dist/stat-card/index.d.ts +2 -2
  87. package/dist/stat-card/index.js +2 -2
  88. package/dist/stat-card/stat-card.d.ts +34 -1
  89. package/dist/stat-card/stat-card.js +51 -21
  90. package/dist/stat-card/stat-card.js.map +1 -1
  91. package/dist/styles.css +1 -1
  92. package/dist/table/table.d.ts +1 -1
  93. package/dist/time-picker/time-picker.d.ts +36 -1
  94. package/dist/time-picker/time-picker.js +33 -5
  95. package/dist/time-picker/time-picker.js.map +1 -1
  96. package/dist/toast/toast.d.ts +2 -2
  97. package/dist/usage-meter/index.d.ts +2 -2
  98. package/dist/usage-meter/usage-meter.d.ts +30 -0
  99. package/dist/usage-meter/usage-meter.js +56 -38
  100. package/dist/usage-meter/usage-meter.js.map +1 -1
  101. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"usage-meter.js","names":[],"sources":["../../src/usage-meter/usage-meter.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n type KeyboardEvent,\n type PointerEvent,\n} from \"react\";\n\nimport { Badge } from \"../badge/badge.js\";\nimport { cn } from \"../lib/cn.js\";\nimport { useCountTo } from \"../lib/count-to.js\";\nimport { mergeRefs } from \"../lib/merge-refs.js\";\nimport { prefersReducedMotion, useIsomorphicLayoutEffect } from \"../lib/motion.js\";\nimport { FILL, live, retarget, SMOOTH, type Live } from \"../lib/spring-tween.js\";\nimport { useSvgId } from \"../lib/svg-id.js\";\nimport { SwapText } from \"../lib/swap-text.js\";\n\n/**\n * UsageMeter: a fixed allowance, such as storage or seats, when people need to\n * see what takes the space and how close they are to the limit.\n *\n * The segments grow into place from the left once the meter is seen, each a\n * beat after the one before. After that every change re-flows them: a segment\n * that grows pushes the ones after it along in the same frame. The bar spans\n * the limit, or everything used once that is more; past the limit the overflow\n * keeps its colours but is struck through with a hatch, and a marker shows\n * where the limit was, so \"over\" never rests on colour alone. The headline and\n * every legend value count to their new number, and the status mark swaps its\n * words and icon while its width follows.\n *\n * Hover previews a category, focus previews it too, and a press pins it until\n * pressed again or Escape. The legend is the keyboard path: arrow keys move\n * between categories. The bar names every amount for assistive technology,\n * and a change of status (almost full, over, back under) is announced.\n *\n * Plain DOM and CSS; one small spring tween writes the segments straight to\n * their elements.\n */\nexport interface UsageMeterSegment {\n /** Stable identity. Keep it the same while the value changes, so the segment re-flows instead of being replaced. */\n id: string;\n label: string;\n value: number;\n}\n\nexport interface UsageMeterProps extends Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> {\n /** What is measured, such as \"Workspace storage\". */\n label: string;\n /** Used amounts in display order. Up to four read clearly. */\n segments: UsageMeterSegment[];\n /** The plan limit, in the same unit as the segments. */\n limit: number;\n /** Unit after each number, such as \"GB\". */\n unit?: string;\n /** Digits after the decimal point. @default 1 */\n decimals?: number;\n /** Name of the unused share. @default \"Free\" */\n freeLabel?: string;\n /** Name of the share past the limit. @default \"Over limit\" */\n overLabel?: string;\n /** Share of the limit at which the meter warns that it is almost full. @default 0.9 */\n warnAt?: number;\n}\n\ntype Status = \"ok\" | \"near\" | \"over\";\n\n/** A segment stops two pixels short of the next, so neighbours read apart without an outline. */\nconst GAP = 2;\n/** Stagger of each segment's first growth. */\nconst STAGGER_MS = 70;\nconst formats = new Map<number, Intl.NumberFormat>();\nfunction numberFormat(decimals: number) {\n let format = formats.get(decimals);\n if (!format) {\n format = new Intl.NumberFormat(\"en-US\", {\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n });\n formats.set(decimals, format);\n }\n return format;\n}\n\n/** A number that counts to each new value on the smooth spring. useCountTo counts whole steps, so decimals are counted in units of the last place. */\nfunction Count({ value, decimals }: { value: number; decimals: number }) {\n const scale = 10 ** decimals;\n const shown = useCountTo(Math.round(value * scale));\n return <>{numberFormat(decimals).format(shown / scale)}</>;\n}\n\nfunction AlertCircleIcon() {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n className=\"size-3.5\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 8v4M12 16h.01\" />\n </svg>\n );\n}\n\nfunction AlertTriangleIcon() {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n className=\"size-3.5\"\n >\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" />\n <path d=\"M12 9v4M12 17h.01\" />\n </svg>\n );\n}\n\nexport const UsageMeter = forwardRef<HTMLDivElement, UsageMeterProps>(function UsageMeter(\n {\n label,\n segments,\n limit,\n unit = \"\",\n decimals = 1,\n freeLabel = \"Free\",\n overLabel = \"Over limit\",\n warnAt = 0.9,\n className,\n ...props\n },\n ref,\n) {\n const root = useRef<HTMLDivElement | null>(null);\n const refs = useMemo(() => mergeRefs(ref, root), [ref]);\n const bar = useRef<HTMLDivElement>(null);\n const track = useRef<HTMLDivElement>(null);\n const marker = useRef<HTMLSpanElement>(null);\n const overflow = useRef<SVGSVGElement>(null);\n const legend = useRef<HTMLDivElement>(null);\n const titleId = useId();\n const hatchId = `hatch${useSvgId()}`;\n\n const round = (value: number) => Math.round(value * 10 ** decimals) / 10 ** decimals;\n const total = round(segments.reduce((sum, segment) => sum + segment.value, 0));\n const free = round(Math.max(0, limit - total));\n const over = round(Math.max(0, total - limit));\n const status: Status = total > limit ? \"over\" : total >= limit * warnAt ? \"near\" : \"ok\";\n const format = (value: number) =>\n `${numberFormat(decimals).format(value)}${unit ? ` ${unit}` : \"\"}`;\n const limitText = format(limit).replace(/\\.0+(?= |$)/, \"\");\n\n // Seen: the segments grow once a good part of the meter is in view.\n const [ready, setReady] = useState(false);\n useEffect(() => {\n const node = root.current;\n if (!node || prefersReducedMotion() || typeof IntersectionObserver === \"undefined\") {\n setReady(true);\n return;\n }\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (!entry?.isIntersecting) return;\n observer.disconnect();\n setReady(true);\n },\n { threshold: 0.4 },\n );\n observer.observe(node);\n return () => observer.disconnect();\n }, []);\n\n // One live value per segment id, kept across renders so a changed value springs from where it is.\n const [amounts] = useState(() => new Map<string, Live>());\n const shownLimit = useRef(live(limit));\n const width = useRef(0);\n\n /** One writer: every segment's place and length, the limit marker and the overflow hatch. */\n const paint = useCallback(() => {\n const frame = track.current;\n if (!frame) return;\n const w = width.current;\n const nodes = frame.querySelectorAll<HTMLElement>(\"[data-segment]\");\n let used = 0;\n for (const node of nodes) used += amounts.get(node.dataset.segment!)?.value ?? 0;\n const limitNow = shownLimit.current.value;\n // The bar spans the limit, or everything used once that is more; both follow their springs, so crossing the limit is continuous.\n const span = Math.max(limitNow, used, 1e-6);\n let start = 0;\n for (const node of nodes) {\n const amount = amounts.get(node.dataset.segment!)?.value ?? 0;\n const x = (start / span) * w;\n const size = (amount / span) * w;\n const rest = w - x - size;\n const scale = w ? Math.max(0, size - Math.min(GAP, size, Math.max(0, rest))) / w : 0;\n node.style.transform = `translateX(${x.toFixed(2)}px) scaleX(${scale.toFixed(4)})`;\n start += amount;\n }\n const limitX = Math.round((limitNow / span) * w);\n if (marker.current) marker.current.style.translate = `${limitX}px 0`;\n if (overflow.current) overflow.current.style.clipPath = `inset(0 0 0 ${limitX + GAP}px)`;\n if (bar.current) {\n if (used > limitNow) bar.current.setAttribute(\"data-over\", \"\");\n else bar.current.removeAttribute(\"data-over\");\n }\n }, [amounts]);\n\n useIsomorphicLayoutEffect(() => {\n const node = track.current;\n if (!node) return;\n const read = () => {\n width.current = 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 // Segments grow into place once seen, left to right; later changes re-flow every segment on one spring each.\n const values = segments.map((segment) => `${segment.id}:${segment.value}`).join(\"|\");\n const revealed = useRef(false);\n const latest = useRef(segments);\n useIsomorphicLayoutEffect(() => {\n latest.current = segments;\n });\n useEffect(() => {\n if (!ready) return;\n const first = !revealed.current;\n revealed.current = true;\n latest.current.forEach((segment, index) => {\n let amount = amounts.get(segment.id);\n if (!amount) {\n amount = live(0);\n amounts.set(segment.id, amount);\n }\n retarget(amount, segment.value, first ? FILL : SMOOTH, paint, first ? index * STAGGER_MS : 0);\n });\n // `values` stands for every segment id and value.\n }, [values, ready, paint, amounts]);\n useEffect(() => {\n retarget(shownLimit.current, limit, SMOOTH, paint);\n }, [limit, paint]);\n useEffect(() => {\n const bound = shownLimit.current;\n return () => {\n for (const amount of amounts.values()) amount.stop();\n bound.stop();\n };\n }, [amounts]);\n\n // Hover previews a category, focus previews it too, and a press pins it until pressed again or Escape.\n const [hovered, setHovered] = useState<string | null>(null);\n const [focused, setFocused] = useState<string | null>(null);\n const [pinned, setPinned] = useState<string | null>(null);\n const [roving, setRoving] = useState(0);\n const items = [\n ...segments.map((segment) => ({ id: segment.id, label: segment.label, value: segment.value })),\n {\n id: \"free\",\n label: status === \"over\" ? overLabel : freeLabel,\n value: status === \"over\" ? over : free,\n },\n ];\n const active = hovered ?? focused ?? pinned;\n const activeItem = items.find((item) => item.id === active) ?? null;\n\n const idAt = (clientX: number) => {\n const rect = track.current?.getBoundingClientRect();\n if (!rect?.width) return null;\n const at = ((clientX - rect.left) / rect.width) * Math.max(limit, total);\n // Past the limit the hatch stands for the overage, so pointing there highlights it rather than the category beneath.\n if (at > limit) return \"free\";\n let end = 0;\n for (const segment of segments) {\n end += segment.value;\n if (at <= end) return segment.id;\n }\n return \"free\";\n };\n const onTrackMove = (event: PointerEvent<HTMLDivElement>) => {\n if (event.pointerType === \"mouse\") setHovered(idAt(event.clientX));\n };\n const onTrackTap = (event: PointerEvent<HTMLDivElement>) => {\n if (event.pointerType === \"mouse\") return;\n const id = idAt(event.clientX);\n setPinned((current) => (current === id ? null : id));\n };\n const onLegendKey = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key === \"Escape\") {\n if (pinned || focused) {\n event.preventDefault();\n setPinned(null);\n setFocused(null);\n }\n return;\n }\n const next = (\n {\n ArrowRight: roving + 1,\n ArrowDown: roving + 1,\n ArrowLeft: roving - 1,\n ArrowUp: roving - 1,\n Home: 0,\n End: items.length - 1,\n } as Record<string, number>\n )[event.key];\n if (next === undefined) return;\n event.preventDefault();\n const index = (next + items.length) % items.length;\n setRoving(index);\n legend.current?.querySelectorAll<HTMLButtonElement>(\"button\")[index]?.focus();\n };\n\n const headline = ready ? (activeItem ? activeItem.value : total) : 0;\n const share = activeItem ? Math.round((activeItem.value / limit) * 100) : 0;\n const caption = !activeItem\n ? `${unit} of ${limitText} used`\n : activeItem.id === \"free\"\n ? `${unit} ${status === \"over\" ? \"over the limit\" : \"free\"}`\n : `${unit} in ${activeItem.label} · ${share}% of plan`;\n const badge =\n status === \"over\"\n ? `${format(over)} over`\n : status === \"near\"\n ? \"Almost full\"\n : `${format(free)} free`;\n const summary = `${label}: ${format(total)} of ${limitText} used. ${segments\n .map((segment) => `${segment.label} ${format(segment.value)}`)\n .join(\", \")}. ${\n status === \"over\"\n ? `Over the limit by ${format(over)}.`\n : `${format(free)} free${status === \"near\" ? \", almost full\" : \"\"}.`\n }`;\n\n // Status changes are announced, and so is a growing overage; routine changes inside a status stay quiet.\n const notice = status === \"over\" ? `over:${over}` : status;\n const [announced, setAnnounced] = useState({ notice, message: \"\" });\n if (announced.notice !== notice) {\n setAnnounced({\n notice,\n message:\n status === \"over\"\n ? `Over the plan limit by ${format(over)}.`\n : status === \"near\"\n ? `Almost full. ${format(free)} free.`\n : `Under the limit. ${format(free)} free.`,\n });\n }\n\n return (\n <div\n ref={refs}\n {...props}\n role=\"group\"\n aria-labelledby={titleId}\n data-slot=\"usage-meter\"\n data-status={status}\n className={cn(\"usage-meter\", className)}\n >\n <div className=\"flex min-h-7 min-w-0 items-center justify-between gap-3\">\n <span id={titleId} className=\"min-w-0 text-base font-medium text-foreground text-balance\">\n {label}\n </span>\n <Badge\n tone={status === \"over\" ? \"danger\" : status === \"near\" ? \"warning\" : \"neutral\"}\n shape=\"pill\"\n size=\"lg\"\n icon={\n status === \"over\" ? (\n <AlertTriangleIcon />\n ) : status === \"near\" ? (\n <AlertCircleIcon />\n ) : undefined\n }\n >\n {badge}\n </Badge>\n </div>\n <p className=\"m-0 flex min-w-0 items-baseline gap-2\">\n <span className=\"sr-only\">\n {format(total)} of {limitText} used\n </span>\n <span\n data-slot=\"usage-meter-amount\"\n aria-hidden=\"true\"\n className=\"flex-none font-display text-h2 font-medium tabular-nums\"\n >\n <Count value={headline} decimals={decimals} />\n </span>\n <span aria-hidden=\"true\" className=\"min-w-0 flex-1 text-sm text-text-secondary\">\n <SwapText swapKey={caption} className=\"block truncate\">\n {caption}\n </SwapText>\n </span>\n </p>\n <div ref={bar} className=\"usage-meter-bar\" data-slot=\"usage-meter-bar\">\n <div\n ref={track}\n role=\"img\"\n aria-label={summary}\n data-active={active ?? undefined}\n onPointerMove={onTrackMove}\n onPointerLeave={() => setHovered(null)}\n onPointerUp={onTrackTap}\n className=\"usage-meter-track\"\n >\n {segments.map((segment, index) => (\n <span\n key={segment.id}\n data-segment={segment.id}\n data-index={index}\n data-highlight={active ? (active === segment.id ? \"on\" : \"off\") : undefined}\n className=\"usage-meter-segment\"\n />\n ))}\n {/* Past the limit the bar is struck through: the overflow keeps its colours, hatched so it reads as over without colour. */}\n <svg\n ref={overflow}\n aria-hidden=\"true\"\n focusable=\"false\"\n data-highlight={active ? (active === \"free\" ? \"on\" : \"off\") : undefined}\n className=\"usage-meter-overflow\"\n >\n <defs>\n <pattern\n id={hatchId}\n width={6}\n height={6}\n patternUnits=\"userSpaceOnUse\"\n patternTransform=\"rotate(45)\"\n >\n <rect width={2.5} height={6} className=\"usage-meter-hatch\" />\n </pattern>\n </defs>\n <rect width=\"100%\" height=\"100%\" className=\"usage-meter-over-tint\" />\n <rect width=\"100%\" height=\"100%\" fill={`url(#${hatchId})`} />\n </svg>\n </div>\n <span ref={marker} aria-hidden=\"true\" className=\"usage-meter-limit\" />\n </div>\n <div\n ref={legend}\n role=\"group\"\n aria-label={`${label} by category`}\n onKeyDown={onLegendKey}\n className=\"usage-meter-legend\"\n >\n {items.map((item, index) => {\n const warning = item.id === \"free\" && status === \"over\";\n return (\n <button\n key={item.id}\n type=\"button\"\n data-slot=\"usage-meter-item\"\n data-highlight={active ? (active === item.id ? \"on\" : \"off\") : undefined}\n aria-pressed={pinned === item.id}\n aria-label={`${item.label}, ${format(item.value)}`}\n tabIndex={index === roving ? 0 : -1}\n onClick={() => {\n setRoving(index);\n setPinned((current) => (current === item.id ? null : item.id));\n }}\n onFocus={(event) => {\n setRoving(index);\n if (event.currentTarget.matches(\":focus-visible\")) setFocused(item.id);\n }}\n onBlur={() => setFocused(null)}\n onPointerEnter={(event) => {\n if (event.pointerType === \"mouse\") setHovered(item.id);\n }}\n onPointerLeave={(event) => {\n if (event.pointerType === \"mouse\") setHovered(null);\n }}\n className=\"usage-meter-item\"\n >\n <span className=\"flex min-w-0 max-w-full items-center gap-2 text-sm text-text-secondary\">\n <span aria-hidden=\"true\" className=\"usage-meter-key\">\n <SwapText\n swapKey={warning ? \"alert\" : \"swatch\"}\n motion=\"glyph\"\n className=\"grid place-items-center\"\n >\n {warning ? (\n <span className=\"text-destructive-strong\">\n <AlertTriangleIcon />\n </span>\n ) : (\n <span\n data-index={item.id === \"free\" ? \"free\" : index}\n className=\"usage-meter-swatch\"\n />\n )}\n </SwapText>\n </span>\n <span className=\"min-w-0 flex-1\">\n <SwapText swapKey={item.label} className=\"block truncate\">\n {item.label}\n </SwapText>\n </span>\n </span>\n <span\n aria-hidden=\"true\"\n className=\"flex items-baseline gap-1 ps-5 text-base font-medium text-foreground tabular-nums\"\n >\n <Count value={item.value} decimals={decimals} />\n {unit ? (\n <span className=\"text-sm font-normal text-text-secondary\">{unit}</span>\n ) : null}\n </span>\n </button>\n );\n })}\n </div>\n <p className=\"sr-only\" aria-live=\"polite\" aria-atomic=\"true\">\n {announced.message}\n </p>\n </div>\n );\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"usage-meter.js","names":[],"sources":["../../src/usage-meter/usage-meter.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n type KeyboardEvent,\n type PointerEvent,\n} from \"react\";\n\nimport { Badge } from \"../badge/badge.js\";\nimport { cn } from \"../lib/cn.js\";\nimport { useCountTo } from \"../lib/count-to.js\";\nimport { mergeRefs } from \"../lib/merge-refs.js\";\nimport { prefersReducedMotion, useIsomorphicLayoutEffect } from \"../lib/motion.js\";\nimport { FILL, live, retarget, SMOOTH, type Live } from \"../lib/spring-tween.js\";\nimport { useSvgId } from \"../lib/svg-id.js\";\nimport { SwapText } from \"../lib/swap-text.js\";\n\n/**\n * UsageMeter: a fixed allowance, such as storage or seats, when people need to\n * see what takes the space and how close they are to the limit.\n *\n * The segments grow into place from the left once the meter is seen, each a\n * beat after the one before. After that every change re-flows them: a segment\n * that grows pushes the ones after it along in the same frame. The bar spans\n * the limit, or everything used once that is more; past the limit the overflow\n * keeps its colours but is struck through with a hatch, and a marker shows\n * where the limit was, so \"over\" never rests on colour alone. The headline and\n * every legend value count to their new number, and the status mark swaps its\n * words and icon while its width follows.\n *\n * Hover previews a category, focus previews it too, and a press pins it until\n * pressed again or Escape. The legend is the keyboard path: arrow keys move\n * between categories. The bar names every amount for assistive technology,\n * and a change of status (almost full, over, back under) is announced.\n *\n * Plain DOM and CSS; one small spring tween writes the segments straight to\n * their elements.\n */\nexport interface UsageMeterSegment {\n /** Stable identity. Keep it the same while the value changes, so the segment re-flows instead of being replaced. */\n id: string;\n label: string;\n value: number;\n}\n\nexport interface UsageMeterProps extends Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> {\n /** What is measured, such as \"Workspace storage\". */\n label: string;\n /** Used amounts in display order. Up to four read clearly. */\n segments: UsageMeterSegment[];\n /** The plan limit, in the same unit as the segments. */\n limit: number;\n /** Unit after each number, such as \"GB\". */\n unit?: string;\n /** Digits after the decimal point. @default 1 */\n decimals?: number;\n /** Name of the unused share. @default \"Free\" */\n freeLabel?: string;\n /** Name of the share past the limit. @default \"Over limit\" */\n overLabel?: string;\n /** Share of the limit at which the meter warns that it is almost full. @default 0.9 */\n warnAt?: number;\n /**\n * The state as the caller (usually the backend) reads it, overriding the one\n * `warnAt` and the limit would give. `ok` and `warn` look as the meter's own\n * under-limit and almost-full states; `full` is the allowance used up\n * (\"Limit reached\"); `exhausted` is nothing left to draw on at all (\"None\n * left\"). Left out, the meter works it out itself.\n *\n * The bar and legend agree with it: under `full` or `exhausted` the free\n * share is shown as none (the bar fills, the free item reads 0), and past\n * the limit `ok` and `warn` give way to the meter's own over state, since\n * the hatch already says over.\n */\n status?: UsageMeterStatus;\n /**\n * The product's words for the status, such as \"Credits paused\". They replace\n * the badge's words (including \"Unlimited\"), the status in the bar's name and\n * the announcement; the tone and icon still follow the status.\n */\n statusLabel?: string;\n /**\n * No limit: the bar shows each category's share of what is used, with no\n * free share, limit marker or overflow, and the badge reads \"Unlimited\"\n * unless `statusLabel` is set. `limit`, `warnAt` and `status` are ignored.\n */\n unlimited?: boolean;\n}\n\n/**\n * A status the caller can impose: under the limit, almost full, allowance used\n * up, and nothing left at all.\n */\nexport type UsageMeterStatus = \"ok\" | \"warn\" | \"full\" | \"exhausted\";\n\ntype Status = \"ok\" | \"near\" | \"over\" | \"full\" | \"exhausted\";\n\n/** The imposed status as `data-status` names it: `warn` is the meter's own `near`. */\nconst IMPOSED: Record<UsageMeterStatus, Status> = {\n ok: \"ok\",\n warn: \"near\",\n full: \"full\",\n exhausted: \"exhausted\",\n};\n\n/** A segment stops two pixels short of the next, so neighbours read apart without an outline. */\nconst GAP = 2;\n/** Stagger of each segment's first growth. */\nconst STAGGER_MS = 70;\nconst formats = new Map<number, Intl.NumberFormat>();\nfunction numberFormat(decimals: number) {\n let format = formats.get(decimals);\n if (!format) {\n format = new Intl.NumberFormat(\"en-US\", {\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n });\n formats.set(decimals, format);\n }\n return format;\n}\n\n/** A number that counts to each new value on the smooth spring. useCountTo counts whole steps, so decimals are counted in units of the last place. */\nfunction Count({ value, decimals }: { value: number; decimals: number }) {\n const scale = 10 ** decimals;\n const shown = useCountTo(Math.round(value * scale));\n return <>{numberFormat(decimals).format(shown / scale)}</>;\n}\n\nfunction AlertCircleIcon() {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n className=\"size-3.5\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 8v4M12 16h.01\" />\n </svg>\n );\n}\n\nfunction AlertTriangleIcon() {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n className=\"size-3.5\"\n >\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" />\n <path d=\"M12 9v4M12 17h.01\" />\n </svg>\n );\n}\n\nexport const UsageMeter = forwardRef<HTMLDivElement, UsageMeterProps>(function UsageMeter(\n {\n label,\n segments,\n limit,\n unit = \"\",\n decimals = 1,\n freeLabel = \"Free\",\n overLabel = \"Over limit\",\n warnAt = 0.9,\n status: imposed,\n statusLabel,\n unlimited = false,\n className,\n ...props\n },\n ref,\n) {\n const root = useRef<HTMLDivElement | null>(null);\n const refs = useMemo(() => mergeRefs(ref, root), [ref]);\n const bar = useRef<HTMLDivElement>(null);\n const track = useRef<HTMLDivElement>(null);\n const marker = useRef<HTMLSpanElement>(null);\n const overflow = useRef<SVGSVGElement>(null);\n const legend = useRef<HTMLDivElement>(null);\n const titleId = useId();\n const hatchId = `hatch${useSvgId()}`;\n\n const round = (value: number) => Math.round(value * 10 ** decimals) / 10 ** decimals;\n const total = round(segments.reduce((sum, segment) => sum + segment.value, 0));\n const over = round(Math.max(0, total - limit));\n // What the numbers say (it decides the free or over share), and what the meter shows (it may be imposed).\n const past = !unlimited && total > limit;\n // Past the limit an imposed calm status would contradict the hatch, so the numbers win.\n const calm = imposed === \"ok\" || imposed === \"warn\";\n const status: Status = unlimited\n ? \"ok\"\n : imposed && !(past && calm)\n ? IMPOSED[imposed]\n : past\n ? \"over\"\n : total >= limit * warnAt\n ? \"near\"\n : \"ok\";\n // An imposed used-up status under the limit: no free share, and the bar spans what is used.\n const capped = !unlimited && !past && (status === \"full\" || status === \"exhausted\");\n const ceiling = capped ? total : limit;\n const free = round(Math.max(0, ceiling - total));\n const danger = status === \"over\" || status === \"full\" || status === \"exhausted\";\n const format = (value: number) =>\n `${numberFormat(decimals).format(value)}${unit ? ` ${unit}` : \"\"}`;\n const limitText = format(limit).replace(/\\.0+(?= |$)/, \"\");\n\n // Seen: the segments grow once a good part of the meter is in view.\n const [ready, setReady] = useState(false);\n useEffect(() => {\n const node = root.current;\n if (!node || prefersReducedMotion() || typeof IntersectionObserver === \"undefined\") {\n setReady(true);\n return;\n }\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (!entry?.isIntersecting) return;\n observer.disconnect();\n setReady(true);\n },\n { threshold: 0.4 },\n );\n observer.observe(node);\n return () => observer.disconnect();\n }, []);\n\n // One live value per segment id, kept across renders so a changed value springs from where it is.\n const [amounts] = useState(() => new Map<string, Live>());\n // Unlimited, the bar spans what is used: the limit springs to nothing and is never \"over\".\n // Used up, the bar spans what is used: the limit springs to the total and nothing is \"over\".\n const shownLimit = useRef(live(unlimited ? 0 : ceiling));\n const width = useRef(0);\n const bounded = useRef(!unlimited && !capped);\n // Before the paint effects below, which read it.\n useIsomorphicLayoutEffect(() => {\n bounded.current = !unlimited && !capped;\n });\n\n /** One writer: every segment's place and length, the limit marker and the overflow hatch. */\n const paint = useCallback(() => {\n const frame = track.current;\n if (!frame) return;\n const w = width.current;\n const nodes = frame.querySelectorAll<HTMLElement>(\"[data-segment]\");\n let used = 0;\n for (const node of nodes) used += amounts.get(node.dataset.segment!)?.value ?? 0;\n const limitNow = shownLimit.current.value;\n // The bar spans the limit, or everything used once that is more; both follow their springs, so crossing the limit is continuous.\n const span = Math.max(limitNow, used, 1e-6);\n let start = 0;\n for (const node of nodes) {\n const amount = amounts.get(node.dataset.segment!)?.value ?? 0;\n const x = (start / span) * w;\n const size = (amount / span) * w;\n const rest = w - x - size;\n const scale = w ? Math.max(0, size - Math.min(GAP, size, Math.max(0, rest))) / w : 0;\n node.style.transform = `translateX(${x.toFixed(2)}px) scaleX(${scale.toFixed(4)})`;\n start += amount;\n }\n const limitX = Math.round((limitNow / span) * w);\n if (marker.current) marker.current.style.translate = `${limitX}px 0`;\n if (overflow.current) overflow.current.style.clipPath = `inset(0 0 0 ${limitX + GAP}px)`;\n if (bar.current) {\n if (bounded.current && used > limitNow) bar.current.setAttribute(\"data-over\", \"\");\n else bar.current.removeAttribute(\"data-over\");\n }\n }, [amounts]);\n\n useIsomorphicLayoutEffect(() => {\n const node = track.current;\n if (!node) return;\n const read = () => {\n width.current = 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 // Segments grow into place once seen, left to right; later changes re-flow every segment on one spring each.\n const values = segments.map((segment) => `${segment.id}:${segment.value}`).join(\"|\");\n const revealed = useRef(false);\n const latest = useRef(segments);\n useIsomorphicLayoutEffect(() => {\n latest.current = segments;\n });\n useEffect(() => {\n if (!ready) return;\n const first = !revealed.current;\n revealed.current = true;\n latest.current.forEach((segment, index) => {\n let amount = amounts.get(segment.id);\n if (!amount) {\n amount = live(0);\n amounts.set(segment.id, amount);\n }\n retarget(amount, segment.value, first ? FILL : SMOOTH, paint, first ? index * STAGGER_MS : 0);\n });\n // `values` stands for every segment id and value.\n }, [values, ready, paint, amounts]);\n useEffect(() => {\n retarget(shownLimit.current, unlimited ? 0 : ceiling, SMOOTH, paint);\n }, [ceiling, unlimited, paint]);\n useEffect(() => {\n const bound = shownLimit.current;\n return () => {\n for (const amount of amounts.values()) amount.stop();\n bound.stop();\n };\n }, [amounts]);\n\n // Hover previews a category, focus previews it too, and a press pins it until pressed again or Escape.\n const [hovered, setHovered] = useState<string | null>(null);\n const [focused, setFocused] = useState<string | null>(null);\n const [pinned, setPinned] = useState<string | null>(null);\n const [roving, setRoving] = useState(0);\n const items = [\n ...segments.map((segment) => ({ id: segment.id, label: segment.label, value: segment.value })),\n // Unlimited has no free share to name.\n ...(unlimited\n ? []\n : [{ id: \"free\", label: past ? overLabel : freeLabel, value: past ? over : free }]),\n ];\n // The list can shrink under the roving item (unlimited drops the free share), so keep it in range.\n const rove = Math.min(roving, Math.max(0, items.length - 1));\n const active = hovered ?? focused ?? pinned;\n const activeItem = items.find((item) => item.id === active) ?? null;\n\n const idAt = (clientX: number) => {\n const rect = track.current?.getBoundingClientRect();\n if (!rect?.width) return null;\n const at =\n ((clientX - rect.left) / rect.width) * (unlimited ? total : Math.max(ceiling, total));\n // Past the limit the hatch stands for the overage, so pointing there highlights it rather than the category beneath.\n if (!unlimited && at > ceiling) return \"free\";\n let end = 0;\n for (const segment of segments) {\n end += segment.value;\n if (at <= end) return segment.id;\n }\n return unlimited ? null : \"free\";\n };\n const onTrackMove = (event: PointerEvent<HTMLDivElement>) => {\n if (event.pointerType === \"mouse\") setHovered(idAt(event.clientX));\n };\n const onTrackTap = (event: PointerEvent<HTMLDivElement>) => {\n if (event.pointerType === \"mouse\") return;\n const id = idAt(event.clientX);\n setPinned((current) => (current === id ? null : id));\n };\n const onLegendKey = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key === \"Escape\") {\n if (pinned || focused) {\n event.preventDefault();\n setPinned(null);\n setFocused(null);\n }\n return;\n }\n const next = (\n {\n ArrowRight: rove + 1,\n ArrowDown: rove + 1,\n ArrowLeft: rove - 1,\n ArrowUp: rove - 1,\n Home: 0,\n End: items.length - 1,\n } as Record<string, number>\n )[event.key];\n if (next === undefined || !items.length) return;\n event.preventDefault();\n const index = (next + items.length) % items.length;\n setRoving(index);\n legend.current?.querySelectorAll<HTMLButtonElement>(\"button\")[index]?.focus();\n };\n\n const headline = ready ? (activeItem ? activeItem.value : total) : 0;\n // Unlimited never shows the share, and a zero limit has none.\n const share =\n activeItem && !unlimited && limit > 0 ? Math.round((activeItem.value / limit) * 100) : 0;\n const caption = !activeItem\n ? unlimited\n ? `${unit} used · no limit`\n : `${unit} of ${limitText} used`\n : activeItem.id === \"free\"\n ? `${unit} ${past ? \"over the limit\" : \"free\"}`\n : unlimited\n ? `${unit} in ${activeItem.label}`\n : `${unit} in ${activeItem.label} · ${share}% of plan`;\n const badge =\n statusLabel ??\n (unlimited\n ? \"Unlimited\"\n : status === \"over\"\n ? `${format(over)} over`\n : status === \"near\"\n ? \"Almost full\"\n : status === \"full\"\n ? \"Limit reached\"\n : status === \"exhausted\"\n ? \"None left\"\n : `${format(free)} free`);\n const breakdown = segments\n .map((segment) => `${segment.label} ${format(segment.value)}`)\n .join(\", \");\n // statusLabel is the status in words wherever the meter states it: badge, bar name and announcement.\n const labelled = statusLabel ? ` ${statusLabel}.` : \"\";\n const summary = unlimited\n ? `${label}: ${format(total)} used, no limit. ${breakdown}.${labelled}`\n : `${label}: ${format(total)} of ${limitText} used. ${breakdown}. ${\n status === \"over\"\n ? `Over the limit by ${format(over)}.`\n : `${format(free)} free${\n statusLabel\n ? \"\"\n : status === \"near\"\n ? \", almost full\"\n : status === \"full\"\n ? \", limit reached\"\n : status === \"exhausted\"\n ? \", none left\"\n : \"\"\n }.`\n }${labelled}`;\n\n // Status changes are announced, and so is a growing overage; routine changes inside a status stay quiet.\n const notice = `${unlimited ? \"unlimited\" : status === \"over\" ? `over:${over}` : status}|${statusLabel ?? \"\"}`;\n const [announced, setAnnounced] = useState({ notice, message: \"\" });\n if (announced.notice !== notice) {\n setAnnounced({\n notice,\n message: unlimited\n ? `No limit.${labelled}`\n : status === \"over\"\n ? `Over the plan limit by ${format(over)}.${labelled}`\n : statusLabel\n ? `${statusLabel}. ${format(free)} free.`\n : status === \"near\"\n ? `Almost full. ${format(free)} free.`\n : status === \"full\"\n ? \"Limit reached.\"\n : status === \"exhausted\"\n ? \"None left.\"\n : `Under the limit. ${format(free)} free.`,\n });\n }\n\n return (\n <div\n ref={refs}\n {...props}\n role=\"group\"\n aria-labelledby={titleId}\n data-slot=\"usage-meter\"\n data-status={status}\n data-unlimited={unlimited || undefined}\n className={cn(\"usage-meter\", className)}\n >\n <div className=\"flex min-h-7 min-w-0 items-center justify-between gap-3\">\n <span id={titleId} className=\"min-w-0 text-base font-medium text-foreground text-balance\">\n {label}\n </span>\n <Badge\n tone={danger ? \"danger\" : status === \"near\" ? \"warning\" : \"neutral\"}\n shape=\"pill\"\n size=\"lg\"\n icon={\n danger ? <AlertTriangleIcon /> : status === \"near\" ? <AlertCircleIcon /> : undefined\n }\n >\n {badge}\n </Badge>\n </div>\n <p className=\"m-0 flex min-w-0 items-baseline gap-2\">\n <span className=\"sr-only\">\n {unlimited ? `${format(total)} used, no limit` : `${format(total)} of ${limitText} used`}\n </span>\n <span\n data-slot=\"usage-meter-amount\"\n aria-hidden=\"true\"\n className=\"flex-none font-display text-h2 font-medium tabular-nums\"\n >\n <Count value={headline} decimals={decimals} />\n </span>\n <span aria-hidden=\"true\" className=\"min-w-0 flex-1 text-sm text-text-secondary\">\n <SwapText swapKey={caption} className=\"block truncate\">\n {caption}\n </SwapText>\n </span>\n </p>\n <div ref={bar} className=\"usage-meter-bar\" data-slot=\"usage-meter-bar\">\n <div\n ref={track}\n role=\"img\"\n aria-label={summary}\n data-active={active ?? undefined}\n onPointerMove={onTrackMove}\n onPointerLeave={() => setHovered(null)}\n onPointerUp={onTrackTap}\n className=\"usage-meter-track\"\n >\n {segments.map((segment, index) => (\n <span\n key={segment.id}\n data-segment={segment.id}\n data-index={index}\n data-highlight={active ? (active === segment.id ? \"on\" : \"off\") : undefined}\n className=\"usage-meter-segment\"\n />\n ))}\n {/* Past the limit the bar is struck through: the overflow keeps its colours, hatched so it reads as over without colour. */}\n {unlimited ? null : (\n <svg\n ref={overflow}\n aria-hidden=\"true\"\n focusable=\"false\"\n data-highlight={active ? (active === \"free\" ? \"on\" : \"off\") : undefined}\n className=\"usage-meter-overflow\"\n >\n <defs>\n <pattern\n id={hatchId}\n width={6}\n height={6}\n patternUnits=\"userSpaceOnUse\"\n patternTransform=\"rotate(45)\"\n >\n <rect width={2.5} height={6} className=\"usage-meter-hatch\" />\n </pattern>\n </defs>\n <rect width=\"100%\" height=\"100%\" className=\"usage-meter-over-tint\" />\n <rect width=\"100%\" height=\"100%\" fill={`url(#${hatchId})`} />\n </svg>\n )}\n </div>\n {unlimited ? null : <span ref={marker} aria-hidden=\"true\" className=\"usage-meter-limit\" />}\n </div>\n <div\n ref={legend}\n role=\"group\"\n aria-label={`${label} by category`}\n onKeyDown={onLegendKey}\n className=\"usage-meter-legend\"\n >\n {items.map((item, index) => {\n const warning = item.id === \"free\" && past;\n return (\n <button\n key={item.id}\n type=\"button\"\n data-slot=\"usage-meter-item\"\n data-highlight={active ? (active === item.id ? \"on\" : \"off\") : undefined}\n aria-pressed={pinned === item.id}\n aria-label={`${item.label}, ${format(item.value)}`}\n tabIndex={index === rove ? 0 : -1}\n onClick={() => {\n setRoving(index);\n setPinned((current) => (current === item.id ? null : item.id));\n }}\n onFocus={(event) => {\n setRoving(index);\n if (event.currentTarget.matches(\":focus-visible\")) setFocused(item.id);\n }}\n onBlur={() => setFocused(null)}\n onPointerEnter={(event) => {\n if (event.pointerType === \"mouse\") setHovered(item.id);\n }}\n onPointerLeave={(event) => {\n if (event.pointerType === \"mouse\") setHovered(null);\n }}\n className=\"usage-meter-item\"\n >\n <span className=\"flex min-w-0 max-w-full items-center gap-2 text-sm text-text-secondary\">\n <span aria-hidden=\"true\" className=\"usage-meter-key\">\n <SwapText\n swapKey={warning ? \"alert\" : \"swatch\"}\n motion=\"glyph\"\n className=\"grid place-items-center\"\n >\n {warning ? (\n <span className=\"text-destructive-strong\">\n <AlertTriangleIcon />\n </span>\n ) : (\n <span\n data-index={item.id === \"free\" ? \"free\" : index}\n className=\"usage-meter-swatch\"\n />\n )}\n </SwapText>\n </span>\n <span className=\"min-w-0 flex-1\">\n <SwapText swapKey={item.label} className=\"block truncate\">\n {item.label}\n </SwapText>\n </span>\n </span>\n <span\n aria-hidden=\"true\"\n className=\"flex items-baseline gap-1 ps-5 text-base font-medium text-foreground tabular-nums\"\n >\n <Count value={item.value} decimals={decimals} />\n {unit ? (\n <span className=\"text-sm font-normal text-text-secondary\">{unit}</span>\n ) : null}\n </span>\n </button>\n );\n })}\n </div>\n <p className=\"sr-only\" aria-live=\"polite\" aria-atomic=\"true\">\n {announced.message}\n </p>\n </div>\n );\n});\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seekalfred/primitives",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Accessible, styled primitives built on React Aria Components.",
@@ -395,7 +395,7 @@
395
395
  "@lexical/rich-text": "0.52.0",
396
396
  "@lexical/selection": "0.52.0",
397
397
  "@lexical/utils": "0.52.0",
398
- "@seekalfred/tokens": "^0.7.1",
398
+ "@seekalfred/tokens": "^0.7.3",
399
399
  "class-variance-authority": "0.7.1",
400
400
  "clsx": "2.1.1",
401
401
  "lexical": "0.52.0",
@@ -404,7 +404,7 @@
404
404
  "devDependencies": {
405
405
  "@arethetypeswrong/cli": "0.18.5",
406
406
  "@internationalized/date": "3.12.4",
407
- "@seekalfred/styles": "^0.7.1",
407
+ "@seekalfred/styles": "^0.7.3",
408
408
  "@seekalfred/tsconfig": "0.0.0",
409
409
  "@size-limit/preset-small-lib": "13.0.3",
410
410
  "@storybook/react-vite": "10.6.0",