@vllnt/ui 0.2.1-canary.f8033e5 → 0.3.0-canary.a42d8f4

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 (198) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +38 -24
  3. package/dist/components/accordion/accordion.js +2 -2
  4. package/dist/components/activity-heatmap/activity-heatmap.js +17 -14
  5. package/dist/components/activity-log/activity-log.js +6 -6
  6. package/dist/components/agent-activity/agent-activity.js +8 -8
  7. package/dist/components/ai-artifact/ai-artifact.js +16 -16
  8. package/dist/components/ai-chat-input/ai-chat-input.js +3 -3
  9. package/dist/components/ai-message-bubble/ai-message-bubble.js +2 -2
  10. package/dist/components/ai-sidebar/ai-sidebar.js +8 -8
  11. package/dist/components/ai-source-citation/ai-source-citation.js +2 -2
  12. package/dist/components/ai-tool-call-display/ai-tool-call-display.js +5 -5
  13. package/dist/components/animated-text/animated-text.js +7 -7
  14. package/dist/components/annotation/annotation.js +1 -1
  15. package/dist/components/auto-reload/auto-reload.js +14 -4
  16. package/dist/components/avatar/avatar.js +1 -1
  17. package/dist/components/avatar-group/avatar-group.js +5 -5
  18. package/dist/components/banner/banner.js +3 -3
  19. package/dist/components/blog-card/blog-card.js +4 -2
  20. package/dist/components/border-beam/border-beam.js +2 -2
  21. package/dist/components/bottom-activity-strip/bottom-activity-strip.js +3 -3
  22. package/dist/components/breadcrumb/breadcrumb.js +33 -26
  23. package/dist/components/button/button.js +1 -1
  24. package/dist/components/calendar/calendar.js +6 -6
  25. package/dist/components/callout/callout.js +1 -1
  26. package/dist/components/candlestick-chart/candlestick-chart.js +6 -5
  27. package/dist/components/canvas-shell/canvas-foundation-demo.js +10 -10
  28. package/dist/components/canvas-shell/canvas-shell.js +2 -2
  29. package/dist/components/carousel/carousel.js +18 -10
  30. package/dist/components/category-filter/category-filter.js +1 -1
  31. package/dist/components/chat-dock-section/chat-dock-section.js +3 -3
  32. package/dist/components/checkbox/checkbox.js +2 -2
  33. package/dist/components/checklist/checklist.js +38 -10
  34. package/dist/components/checklist/index.js +8 -2
  35. package/dist/components/chronological-timeline/chronological-timeline.js +43 -37
  36. package/dist/components/civilization-card/civilization-card.js +1 -1
  37. package/dist/components/code-block/code-block.js +33 -12
  38. package/dist/components/code-playground/code-playground.js +12 -9
  39. package/dist/components/combobox/combobox.js +47 -28
  40. package/dist/components/command/command.js +1 -1
  41. package/dist/components/comment-pin/comment-pin.js +3 -3
  42. package/dist/components/comparison/comparison.js +11 -10
  43. package/dist/components/completion-dialog/completion-dialog.js +20 -12
  44. package/dist/components/connector-edge/connector-edge.js +1 -1
  45. package/dist/components/content-intro/content-intro.js +25 -21
  46. package/dist/components/context-menu/context-menu.js +4 -4
  47. package/dist/components/conversation-thread/conversation-thread.js +9 -9
  48. package/dist/components/cookie-consent/cookie-consent.js +1 -1
  49. package/dist/components/copy-button/copy-button.js +3 -3
  50. package/dist/components/countdown-timer/countdown-timer.js +9 -8
  51. package/dist/components/credit-badge/credit-badge.js +1 -7
  52. package/dist/components/curriculum/curriculum.js +10 -10
  53. package/dist/components/data-list/data-list.js +1 -1
  54. package/dist/components/data-table/data-table.js +6 -5
  55. package/dist/components/date-picker/date-picker.js +2 -7
  56. package/dist/components/dialog/dialog.js +1 -1
  57. package/dist/components/dropdown-menu/dropdown-menu.js +3 -3
  58. package/dist/components/empty-state/empty-state.js +3 -3
  59. package/dist/components/exercise/exercise.js +15 -7
  60. package/dist/components/faq/faq.js +8 -4
  61. package/dist/components/file-upload/file-upload.js +4 -9
  62. package/dist/components/filter-bar/filter-bar.js +9 -8
  63. package/dist/components/flashcard/flashcard.js +2 -2
  64. package/dist/components/floating-action-button/floating-action-button.js +1 -1
  65. package/dist/components/floating-toolbar/floating-toolbar.js +3 -3
  66. package/dist/components/flow-diagram/flow-controls.js +9 -9
  67. package/dist/components/flow-diagram/flow-error-boundary.js +2 -2
  68. package/dist/components/flow-diagram/flow-fullscreen.js +2 -2
  69. package/dist/components/form/form.js +1 -1
  70. package/dist/components/gantt-chart/gantt-chart.js +22 -19
  71. package/dist/components/glass-panel/glass-panel.js +1 -1
  72. package/dist/components/globe-3d/globe-3d.js +16 -4
  73. package/dist/components/handoff-beacon/handoff-beacon.js +1 -1
  74. package/dist/components/historic-timeline/historic-timeline.js +2 -2
  75. package/dist/components/historical-figure-card/historical-figure-card.js +4 -7
  76. package/dist/components/horizontal-scroll-row/horizontal-scroll-row.js +6 -5
  77. package/dist/components/index.js +6 -0
  78. package/dist/components/infinite-plane/infinite-plane.js +2 -2
  79. package/dist/components/inline-input/inline-input.js +1 -1
  80. package/dist/components/input-otp/input-otp.js +1 -1
  81. package/dist/components/interactive-timeline/interactive-timeline.js +12 -9
  82. package/dist/components/jarvis-dock/jarvis-dock.js +4 -4
  83. package/dist/components/kbd/kbd.js +1 -1
  84. package/dist/components/key-concept/key-concept.js +6 -5
  85. package/dist/components/keyboard-shortcuts-help/keyboard-shortcuts-help.js +4 -3
  86. package/dist/components/knowledge-check/knowledge-check.js +5 -5
  87. package/dist/components/lang-provider/lang-provider.js +3 -3
  88. package/dist/components/learning-objectives/learning-objectives.js +14 -13
  89. package/dist/components/live-feed/live-feed.js +17 -15
  90. package/dist/components/map-2d/map-2d.js +3 -3
  91. package/dist/components/map-timeline/map-timeline.js +5 -5
  92. package/dist/components/market-treemap/market-treemap.js +3 -3
  93. package/dist/components/mdx-content/mdx-content.js +21 -10
  94. package/dist/components/menubar/menubar.js +4 -4
  95. package/dist/components/metric-cluster/metric-cluster.js +1 -1
  96. package/dist/components/metric-gauge/metric-gauge.js +2 -2
  97. package/dist/components/model-comparison/model-comparison.js +2 -2
  98. package/dist/components/model-selector/model-selector.js +3 -3
  99. package/dist/components/multi-select/multi-select.js +4 -4
  100. package/dist/components/navbar-saas/navbar-saas.js +9 -8
  101. package/dist/components/navigation-menu/navigation-menu.js +2 -2
  102. package/dist/components/newsletter-signup/newsletter-signup.js +3 -3
  103. package/dist/components/number-input/number-input.js +2 -2
  104. package/dist/components/number-ticker/number-ticker.js +11 -4
  105. package/dist/components/object-card/object-card.js +3 -3
  106. package/dist/components/object-inspector/object-inspector.js +1 -1
  107. package/dist/components/order-book/order-book.js +2 -2
  108. package/dist/components/overview-board/overview-board.js +2 -2
  109. package/dist/components/parallel-timeline/parallel-timeline.js +2 -2
  110. package/dist/components/password-input/password-input.js +1 -1
  111. package/dist/components/plan-badge/plan-badge.js +1 -7
  112. package/dist/components/policy-delivery-panel/policy-delivery-panel.js +2 -2
  113. package/dist/components/presence-stack/presence-stack.js +2 -2
  114. package/dist/components/presence-sync-indicator/presence-sync-indicator.js +1 -1
  115. package/dist/components/pricing-table/pricing-table.js +3 -3
  116. package/dist/components/pro-tip/pro-tip.js +6 -6
  117. package/dist/components/profile-section/profile-section.js +3 -2
  118. package/dist/components/progress-card/progress-card.js +5 -4
  119. package/dist/components/progress-tracker/progress-tracker.js +24 -14
  120. package/dist/components/prompt-templates/prompt-templates.js +4 -4
  121. package/dist/components/quiz/quiz.js +7 -6
  122. package/dist/components/radio-group/radio-group.js +2 -2
  123. package/dist/components/rating/rating.js +3 -3
  124. package/dist/components/relationship-inspector/relationship-inspector.js +2 -2
  125. package/dist/components/resizable/resizable.js +1 -1
  126. package/dist/components/routing-assignment-panel/routing-assignment-panel.js +2 -2
  127. package/dist/components/run-timeline/run-timeline.js +2 -2
  128. package/dist/components/runtime-overview-panel/runtime-overview-panel.js +1 -1
  129. package/dist/components/scope-selector/scope-selector.js +8 -8
  130. package/dist/components/search-bar/search-bar.js +24 -2
  131. package/dist/components/search-dialog/search-dialog.js +484 -51
  132. package/dist/components/select/select.js +5 -5
  133. package/dist/components/selection-halo/selection-halo.js +1 -1
  134. package/dist/components/severity-badge/severity-badge.js +2 -2
  135. package/dist/components/share-dialog/share-dialog.js +2 -2
  136. package/dist/components/share-section/share-section.js +2 -1
  137. package/dist/components/sheet/sheet.js +1 -1
  138. package/dist/components/sidebar/sidebar.js +31 -26
  139. package/dist/components/sidebar-toggle/sidebar-toggle.js +5 -3
  140. package/dist/components/slider/slider.js +1 -1
  141. package/dist/components/slideshow/slideshow.js +15 -13
  142. package/dist/components/social-fab/social-fab.js +12 -11
  143. package/dist/components/sparkline-grid/sparkline-grid.js +1 -1
  144. package/dist/components/spinner/spinner.js +4 -4
  145. package/dist/components/spinner/unicode-spinner.js +4 -2
  146. package/dist/components/stat-card/stat-card.js +5 -5
  147. package/dist/components/state-badge-overlay/state-badge-overlay.js +1 -1
  148. package/dist/components/static-code/index.js +4 -0
  149. package/dist/components/static-code/static-code-copy.js +29 -0
  150. package/dist/components/static-code/static-code.js +41 -0
  151. package/dist/components/status-board/status-board.js +14 -7
  152. package/dist/components/status-indicator/status-indicator.js +3 -3
  153. package/dist/components/step-by-step/step-by-step.js +10 -8
  154. package/dist/components/step-navigation/step-navigation.js +2 -2
  155. package/dist/components/stepper/stepper.js +3 -3
  156. package/dist/components/sticky-metric/sticky-metric.js +1 -1
  157. package/dist/components/subscription-card/subscription-card.js +1 -1
  158. package/dist/components/switch/switch.js +1 -1
  159. package/dist/components/table-of-contents/table-of-contents.js +5 -2
  160. package/dist/components/table-of-contents-panel/table-of-contents-panel.js +8 -6
  161. package/dist/components/tabs/tabs.js +26 -8
  162. package/dist/components/tags-input/tags-input.js +12 -4
  163. package/dist/components/terminal/terminal.js +61 -37
  164. package/dist/components/theme-preset-provider/index.js +4 -0
  165. package/dist/components/theme-preset-provider/theme-preset-provider.js +55 -0
  166. package/dist/components/theme-switcher/index.js +4 -0
  167. package/dist/components/theme-switcher/theme-switcher.js +43 -0
  168. package/dist/components/theme-toggle/theme-toggle.js +2 -2
  169. package/dist/components/thinking-block/thinking-block.js +3 -3
  170. package/dist/components/ticker-tape/ticker-tape.js +4 -4
  171. package/dist/components/timeline/timeline.js +2 -2
  172. package/dist/components/timeline-scrubber/timeline-scrubber.js +2 -2
  173. package/dist/components/tldr-section/tldr-section.js +11 -9
  174. package/dist/components/tour/tour.js +2 -2
  175. package/dist/components/transaction-list/transaction-list.js +30 -9
  176. package/dist/components/tree-view/tree-view.js +2 -2
  177. package/dist/components/tutorial-card/tutorial-card.js +1 -1
  178. package/dist/components/tutorial-complete/tutorial-complete.js +16 -14
  179. package/dist/components/tutorial-filters/tutorial-filters.js +2 -2
  180. package/dist/components/tutorial-intro-content/tutorial-intro-content.js +5 -5
  181. package/dist/components/tutorial-mdx/tutorial-mdx.js +6 -6
  182. package/dist/components/usage-breakdown/usage-breakdown.js +10 -6
  183. package/dist/components/video-embed/video-embed.js +2 -2
  184. package/dist/components/viewport-bookmarks/viewport-bookmarks.js +6 -4
  185. package/dist/components/wallet-card/wallet-card.js +1 -1
  186. package/dist/components/watchlist/watchlist.js +7 -6
  187. package/dist/components/world-breadcrumbs/world-breadcrumbs.js +2 -2
  188. package/dist/components/world-clock-bar/world-clock-bar.js +35 -14
  189. package/dist/components/zoom-hud/zoom-hud.js +1 -1
  190. package/dist/index.d.ts +202 -30
  191. package/dist/index.js +19 -1
  192. package/dist/lib/theme-presets.js +32 -0
  193. package/dist/lib/use-theme-preset.js +94 -0
  194. package/dist/tailwind-preset.js +19 -19
  195. package/package.json +7 -6
  196. package/styles.css +38 -38
  197. package/themes/default.css +39 -39
  198. package/themes/presets.css +547 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,43 @@ All notable changes to `@vllnt/ui` are documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [Unreleased]
8
+
9
+ > Target version: **`0.3.0`** — shipping as `0.3.0-canary.<sha>` on the npm `canary` tag on every merge to main. The stable `latest` release is gated on the [ROADMAP.md](../../ROADMAP.md) shipping criteria and is not yet published.
10
+
11
+ ### Added
12
+
13
+ - **Release intelligence surface** — `/changelog`, `/releases`, `/rss.xml`, and `/atom.xml` expose one changelog source through HTML, GitHub release cards, and feed readers. `/docs/changelog` redirects to `/changelog`.
14
+ - **Hooks + utility primitives** — `CopyButton` (+ `useCopyToClipboard` hook), `Banner` + `BannerAction`, `Kbd`, `EmptyState`, `DocumentSiblingNav`.
15
+ - **Pricing + identity cards** — `PricingTable` + `PricingPlan`, `HistoricalFigureCard`, `CivilizationCard` (+ `CivilizationComparison`).
16
+ - **Newsletter** — `NewsletterSignup` (state-machine driven submit flow).
17
+ - **AI compound families** — `ModelComparison` (+ `Column`, `Meta`, `Vote`), `PromptTemplates`, `AgentActivity`, `AISidebar`, `AIArtifact`.
18
+ - **Era / financial** — `EraComparison`, `TransactionList`.
19
+ - **Forms** — `Form`, `MultiSelect`, `SegmentedControl`, `TagsInput`, `AutoReload`.
20
+ - **Educational** — `KnowledgeCheck` (inline question runner).
21
+ - **Charts + timelines** — `GanttChart`, `ParallelTimeline`, `Timeline` + `TimelineItem`, `HistoricTimeline`, `InteractiveTimeline`, `ChronologicalTimeline`, `TreeView`.
22
+ - **Document + reading** — `PrimarySourceViewer` compound family.
23
+ - **Maps + geography** — `Map2D`, `ChoroplethMap`, `RouteMap`, `HeatMapOverlay`, `GeographyQuizMap`, `MapTimeline`, `StoryMap`, `Globe3D`.
24
+ - **Canvas foundation** — `CanvasShell`, `CanvasView`, `InfinitePlane`, `ViewportBookmarks`, `WorldBreadcrumbs`, `TopBar`, `LeftRail`, `RightDock`, `ZoomHud`, `MiniMapPanel`, `WorkspaceSwitcher`.
25
+ - **Canvas selection + manipulation** — `SelectionHalo`, `SnapGuides`, `FloatingToolbar`, `MultiSelectLasso`, `FollowMode`, `HandoffBeacon`.
26
+ - **Canvas spatial objects** — `ObjectCard`, `ObjectHandle`, `AnchorPort`, `ConnectorEdge`, `EdgeLabel`, `GroupHull`.
27
+ - **Canvas collaboration primitives** — `LiveCursor`, `CommentPin`, `PresenceSyncIndicator`, `PresenceStack`, `SelectionPresence`, `ThreadBubble`.
28
+ - **Inspector + dock panels** — `PropertySection`, `ObjectInspector`, `RelationshipInspector`, `RuntimeOverviewPanel`, `RoutingAssignmentPanel`, `PolicyDeliveryPanel`.
29
+ - **Runtime overlays** — `AlertPulse`, `ThresholdRing`, `StickyMetric`, `HeatOverlay`, `StateBadgeOverlay`, `MetricCluster`, `JarvisDock`, `ContextLens`.
30
+ - **Time navigation** — `TimelineScrubber`, `PlaybackGhost`, `BottomActivityStrip`, `RunTimeline`.
31
+ - Total component count: **225** (up from 140).
32
+
33
+ - **A11y heading-level override** — every title-bearing component (`ProfileSection`, `FAQ`, `Slideshow`, `WorldClockBar`, `TableOfContentsPanel`, `TableOfContents`, `KeyboardShortcutsHelp`, `Watchlist`, `OrderBook`, `HorizontalScrollRow`, `MarketTreemap`, `ActivityHeatmap`, `Glossary`, `StatusBoard`, `CodePlayground`, `Comparison`, `Quiz`, `Exercise`, `ShareSection`, `CompletionDialog`, `Checklist`, `LearningObjectives`, `CandlestickChart`, `StepByStep`) accepts an `as` prop (`"h1"`–`"h6"`); multi-title components (`ContentIntro`, `TutorialComplete`) expose `titleAs` + `tocLabelAs` / `sectionLabelAs`. Defaults preserve existing heading tags. `HeadingTag` is re-exported from `@vllnt/ui`.
34
+
35
+ ### Changed
36
+
37
+ - Registry installs use a **hybrid CLI strategy** — leaf component source is inlined, sibling registry items resolve via `@vllnt/ui` to keep installs minimal and dedupe shared primitives.
38
+
39
+ ### Notes
40
+
41
+ - `ROADMAP.md` added at repo root tracking 50 open issues across 8 phases gating the `0.3.0` cut.
42
+ - `0.3.0` requires the codebase-health gate (`react-doctor` CI + 0 errors), the agent-first surface (`/llms.txt`, `/mcp`, sitemap, JSON-LD), and the rebuilt landing page before shipping.
43
+
7
44
  ## [0.2.1] - 2026-04-21
8
45
 
9
46
  ### Fixed
package/README.md CHANGED
@@ -44,7 +44,7 @@ export default {
44
44
  ```
45
45
 
46
46
  The preset configures:
47
- - **Colors**: `primary`, `secondary`, `muted`, `accent`, `destructive`, `background`, `foreground`, `card`, `popover`, `border`, `input`, `ring` — all as `hsl(var(--name))` for theming
47
+ - **Colors**: `primary`, `secondary`, `muted`, `accent`, `destructive`, `background`, `foreground`, `card`, `popover`, `border`, `input`, `ring` — all as `oklch(var(--name) / <alpha-value>)` for theming
48
48
  - **Border radius**: `lg`, `md`, `sm` via `--radius` CSS variable
49
49
  - **Animations**: `accordion-down`, `accordion-up`, `shimmer`
50
50
  - **Font**: `mono` family via `--font-mono` variable
@@ -83,45 +83,59 @@ export function Example() {
83
83
  | `@vllnt/ui/tailwind-preset` | Tailwind CSS preset config |
84
84
  | `@vllnt/ui/styles.css` | Full styles (Tailwind base + theme variables + utilities) |
85
85
  | `@vllnt/ui/themes/default.css` | Theme CSS variables only (no Tailwind base) |
86
+ | `@vllnt/ui/themes/presets.css` | Built-in color presets (applied via `data-theme`) |
86
87
 
87
88
  ## Theming
88
89
 
89
- All colors use HSL CSS variables. Override them after importing styles:
90
+ All colors are **OKLCH channel** CSS variables (`L C H`), consumed as
91
+ `oklch(var(--name) / <alpha-value>)`. Override them after importing styles:
90
92
 
91
93
  ```css
92
94
  /* Light theme */
93
95
  :root {
94
- --background: 0 0% 100%;
95
- --foreground: 0 0% 3.9%;
96
- --primary: 222.2 47.4% 11.2%;
97
- --primary-foreground: 210 40% 98%;
98
- --secondary: 210 40% 96.1%;
99
- --secondary-foreground: 222.2 47.4% 11.2%;
100
- --muted: 210 40% 96.1%;
101
- --muted-foreground: 215.4 16.3% 46.9%;
102
- --accent: 210 40% 96.1%;
103
- --accent-foreground: 222.2 47.4% 11.2%;
104
- --destructive: 0 84.2% 60.2%;
105
- --destructive-foreground: 0 0% 98%;
106
- --border: 214.3 31.8% 91.4%;
107
- --input: 214.3 31.8% 91.4%;
108
- --ring: 222.2 84% 4.9%;
96
+ --background: 1 0 0;
97
+ --foreground: 0.1445 0 0;
98
+ --primary: 0.2044 0 0;
99
+ --primary-foreground: 0.9848 0 0;
100
+ --secondary: 0.9703 0 0;
101
+ --secondary-foreground: 0.2044 0 0;
102
+ --muted: 0.9703 0 0;
103
+ --muted-foreground: 0.5555 0 0;
104
+ --accent: 0.9703 0 0;
105
+ --accent-foreground: 0.2044 0 0;
106
+ --destructive: 0.6368 0.2078 25.326;
107
+ --destructive-foreground: 0.9848 0 0;
108
+ --border: 0.9219 0 0;
109
+ --input: 0.9219 0 0;
110
+ --ring: 0.1445 0 0;
109
111
  --radius: 0.5rem;
110
- --card: 0 0% 100%;
111
- --card-foreground: 0 0% 3.9%;
112
- --popover: 0 0% 100%;
113
- --popover-foreground: 0 0% 3.9%;
112
+ --card: 1 0 0;
113
+ --card-foreground: 0.1445 0 0;
114
+ --popover: 1 0 0;
115
+ --popover-foreground: 0.1445 0 0;
114
116
  }
115
117
 
116
118
  /* Dark theme (applied via class="dark" on html/body) */
117
119
  .dark {
118
- --background: 0 0% 3.9%;
119
- --foreground: 0 0% 98%;
120
+ --background: 0 0 0;
121
+ --foreground: 0.9848 0 0;
120
122
  /* ... override other variables */
121
123
  }
122
124
  ```
123
125
 
124
- Use `@vllnt/ui/themes/default.css` instead of `@vllnt/ui/styles.css` if you only want the variables without Tailwind base layer styles.
126
+ Use `@vllnt/ui/themes/default.css` instead of `@vllnt/ui/styles.css` if you only
127
+ want the variables without the Tailwind base layer.
128
+
129
+ ### Runtime presets & the theme editor
130
+
131
+ Import `@vllnt/ui/themes/presets.css` and switch between built-in color presets
132
+ at runtime with `<ThemeSwitcher />` (or `setThemePreset` / `useThemePreset`),
133
+ which set `data-theme` on the document root. Render `<ThemePresetProvider />`
134
+ once near the root to restore the saved preset before paint.
135
+
136
+ To design and export your own theme, use the visual editor at
137
+ [`/themes`](https://ui.vllnt.ai/themes) — it exports a CSS block, a
138
+ `npx shadcn add` command, or design tokens.
125
139
 
126
140
  ## Component Patterns
127
141
 
@@ -104,7 +104,7 @@ function AccordionTrigger({
104
104
  "span",
105
105
  {
106
106
  className: cn(
107
- "h-4 w-4 flex-shrink-0 transition-transform duration-200",
107
+ "size-4 flex-shrink-0 transition-transform duration-200",
108
108
  isOpen && "rotate-180"
109
109
  ),
110
110
  children: icon
@@ -113,7 +113,7 @@ function AccordionTrigger({
113
113
  "svg",
114
114
  {
115
115
  className: cn(
116
- "h-4 w-4 flex-shrink-0 transition-transform duration-200",
116
+ "size-4 flex-shrink-0 transition-transform duration-200",
117
117
  isOpen && "rotate-180"
118
118
  ),
119
119
  fill: "none",
@@ -72,19 +72,21 @@ function getGridData(data, endDate, weeks) {
72
72
  });
73
73
  });
74
74
  }
75
+ const MONTH_LABEL_FORMATTER = new Intl.DateTimeFormat("en-US", {
76
+ month: "short",
77
+ timeZone: "UTC"
78
+ });
79
+ const TOOLTIP_DATE_FORMATTER = new Intl.DateTimeFormat("en-US", {
80
+ day: "numeric",
81
+ month: "short",
82
+ timeZone: "UTC",
83
+ year: "numeric"
84
+ });
75
85
  function formatMonthLabel(date) {
76
- return new Intl.DateTimeFormat("en-US", {
77
- month: "short",
78
- timeZone: "UTC"
79
- }).format(date);
86
+ return MONTH_LABEL_FORMATTER.format(date);
80
87
  }
81
88
  function formatTooltip(date, count) {
82
- const formattedDate = new Intl.DateTimeFormat("en-US", {
83
- day: "numeric",
84
- month: "short",
85
- timeZone: "UTC",
86
- year: "numeric"
87
- }).format(date);
89
+ const formattedDate = TOOLTIP_DATE_FORMATTER.format(date);
88
90
  return `${count} activity ${count === 1 ? "event" : "events"} on ${formattedDate}`;
89
91
  }
90
92
  function HeatmapGrid({
@@ -127,15 +129,15 @@ function HeatmapGrid({
127
129
  ),
128
130
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2 text-xs text-muted-foreground", children: [
129
131
  /* @__PURE__ */ jsx("span", { children: "Less" }),
130
- LEVEL_CLASS_NAMES.map((className, index) => /* @__PURE__ */ jsx(
132
+ LEVEL_CLASS_NAMES.map((className) => /* @__PURE__ */ jsx(
131
133
  "span",
132
134
  {
133
135
  className: cn(
134
- "h-3 w-3 rounded-[3px] border border-border/40",
136
+ "size-3 rounded-[3px] border border-border/40",
135
137
  className
136
138
  )
137
139
  },
138
- `legend-${index}`
140
+ `legend-${className}`
139
141
  )),
140
142
  /* @__PURE__ */ jsx("span", { children: "More" })
141
143
  ] })
@@ -143,6 +145,7 @@ function HeatmapGrid({
143
145
  }
144
146
  const ActivityHeatmap = React.forwardRef(
145
147
  ({
148
+ as: Heading = "h2",
146
149
  className,
147
150
  data,
148
151
  description,
@@ -155,7 +158,7 @@ const ActivityHeatmap = React.forwardRef(
155
158
  const gridData = getGridData(data, normalizedEndDate, weeks);
156
159
  return /* @__PURE__ */ jsxs("div", { className: cn("space-y-4", className), ref, ...props, children: [
157
160
  /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
158
- /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold tracking-tight", children: title }),
161
+ /* @__PURE__ */ jsx(Heading, { className: "text-lg font-semibold tracking-tight", children: title }),
159
162
  description ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: description }) : null
160
163
  ] }),
161
164
  /* @__PURE__ */ jsx("div", { className: "overflow-x-auto rounded-lg border bg-card p-4 shadow-sm", children: /* @__PURE__ */ jsx(HeatmapGrid, { gridData, weeks }) })
@@ -3,7 +3,7 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { forwardRef, useMemo, useState } from "react";
4
4
  import { ArrowRight, ChevronLeft, ChevronRight } from "lucide-react";
5
5
  import { cn } from "../../lib/utils";
6
- import { Avatar, AvatarFallback } from "../avatar";
6
+ import { Avatar, AvatarFallback } from "../avatar/avatar";
7
7
  import { Badge } from "../badge";
8
8
  import { Button } from "../button";
9
9
  import {
@@ -82,7 +82,7 @@ function PaginationControls({
82
82
  size: "sm",
83
83
  variant: "outline",
84
84
  children: [
85
- /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" }),
85
+ /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4" }),
86
86
  "Previous"
87
87
  ]
88
88
  }
@@ -111,7 +111,7 @@ function PaginationControls({
111
111
  variant: "outline",
112
112
  children: [
113
113
  "Next",
114
- /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
114
+ /* @__PURE__ */ jsx(ChevronRight, { className: "size-4" })
115
115
  ]
116
116
  }
117
117
  )
@@ -132,18 +132,18 @@ function ActivityRow({ item }) {
132
132
  {
133
133
  "aria-hidden": "true",
134
134
  className: cn(
135
- "absolute left-4 top-3 h-3 w-3 rounded-full ring-4 ring-background",
135
+ "absolute left-4 top-3 size-3 rounded-full ring-4 ring-background",
136
136
  palette.markerClassName
137
137
  )
138
138
  }
139
139
  ),
140
140
  /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-background/70 p-4", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between", children: [
141
141
  /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-start gap-3", children: [
142
- /* @__PURE__ */ jsx(Avatar, { className: "h-9 w-9 border bg-muted", children: /* @__PURE__ */ jsx(AvatarFallback, { children: getInitials(item.actor) }) }),
142
+ /* @__PURE__ */ jsx(Avatar, { className: "size-9 border bg-muted", children: /* @__PURE__ */ jsx(AvatarFallback, { children: getInitials(item.actor) }) }),
143
143
  /* @__PURE__ */ jsxs("div", { className: "min-w-0 space-y-1", children: [
144
144
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
145
145
  /* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: item.actor }),
146
- /* @__PURE__ */ jsx(ArrowRight, { className: "h-3.5 w-3.5 text-muted-foreground" }),
146
+ /* @__PURE__ */ jsx(ArrowRight, { className: "size-3.5 text-muted-foreground" }),
147
147
  /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: item.action }),
148
148
  item.target ? /* @__PURE__ */ jsx("span", { className: "truncate text-sm font-medium text-foreground", children: item.target }) : null
149
149
  ] }),
@@ -46,11 +46,11 @@ const STATUS_CLASSES = {
46
46
  }
47
47
  };
48
48
  const DEFAULT_STATUS_ICON = {
49
- completed: /* @__PURE__ */ jsx(CheckCircle2, { "aria-hidden": "true", className: "h-4 w-4" }),
50
- error: /* @__PURE__ */ jsx(AlertTriangle, { "aria-hidden": "true", className: "h-4 w-4" }),
51
- pending: /* @__PURE__ */ jsx(Circle, { "aria-hidden": "true", className: "h-4 w-4" }),
52
- running: /* @__PURE__ */ jsx(Loader2, { "aria-hidden": "true", className: "h-4 w-4 animate-spin" }),
53
- skipped: /* @__PURE__ */ jsx(MinusCircle, { "aria-hidden": "true", className: "h-4 w-4" })
49
+ completed: /* @__PURE__ */ jsx(CheckCircle2, { "aria-hidden": "true", className: "size-4" }),
50
+ error: /* @__PURE__ */ jsx(AlertTriangle, { "aria-hidden": "true", className: "size-4" }),
51
+ pending: /* @__PURE__ */ jsx(Circle, { "aria-hidden": "true", className: "size-4" }),
52
+ running: /* @__PURE__ */ jsx(Loader2, { "aria-hidden": "true", className: "size-4 animate-spin" }),
53
+ skipped: /* @__PURE__ */ jsx(MinusCircle, { "aria-hidden": "true", className: "size-4" })
54
54
  };
55
55
  const StepContext = createContext({ status: "pending" });
56
56
  const DEFAULT_LABELS = {
@@ -148,7 +148,7 @@ function StepRow({
148
148
  {
149
149
  "aria-hidden": "true",
150
150
  className: cn(
151
- "mt-0.5 inline-flex h-5 w-5 shrink-0 items-center justify-center",
151
+ "mt-0.5 inline-flex size-5 shrink-0 items-center justify-center",
152
152
  iconClass
153
153
  ),
154
154
  children: icon
@@ -161,7 +161,7 @@ function StepRow({
161
161
  "aria-controls": detailsId,
162
162
  "aria-expanded": open,
163
163
  "aria-label": open ? labels.collapse : labels.expand,
164
- className: "ml-auto inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-foreground/10 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
164
+ className: "ml-auto inline-flex size-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-foreground/10 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
165
165
  onClick: onToggle,
166
166
  type: "button",
167
167
  children: /* @__PURE__ */ jsx(
@@ -169,7 +169,7 @@ function StepRow({
169
169
  {
170
170
  "aria-hidden": "true",
171
171
  className: cn(
172
- "h-4 w-4 transition-transform",
172
+ "size-4 transition-transform",
173
173
  open ? "rotate-180" : "rotate-0"
174
174
  )
175
175
  }
@@ -259,7 +259,7 @@ const AIArtifactToolbar = forwardRef(({ className, ...rest }, ref) => /* @__PURE
259
259
  AIArtifactToolbar.displayName = "AIArtifactToolbar";
260
260
  const AIArtifactCopyButton = forwardRef(({ className, onClick, ...rest }, ref) => {
261
261
  const { copied, copy, labels } = useAIArtifact();
262
- const handleClick = useCallback(
262
+ const handleCopyArtifact = useCallback(
263
263
  (event) => {
264
264
  onClick?.(event);
265
265
  if (event.defaultPrevented) return;
@@ -271,21 +271,21 @@ const AIArtifactCopyButton = forwardRef(({ className, onClick, ...rest }, ref) =
271
271
  Button,
272
272
  {
273
273
  "aria-label": copied ? labels.copied : labels.copy,
274
- className: cn("h-8 w-8", className),
275
- onClick: handleClick,
274
+ className: cn("size-8", className),
275
+ onClick: handleCopyArtifact,
276
276
  ref,
277
277
  size: "icon",
278
278
  type: "button",
279
279
  variant: "ghost",
280
280
  ...rest,
281
- children: copied ? /* @__PURE__ */ jsx(Check, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ jsx(Copy, { "aria-hidden": "true", className: "h-4 w-4" })
281
+ children: copied ? /* @__PURE__ */ jsx(Check, { "aria-hidden": "true", className: "size-4" }) : /* @__PURE__ */ jsx(Copy, { "aria-hidden": "true", className: "size-4" })
282
282
  }
283
283
  );
284
284
  });
285
285
  AIArtifactCopyButton.displayName = "AIArtifactCopyButton";
286
286
  const AIArtifactEditButton = forwardRef(({ className, onClick, ...rest }, ref) => {
287
287
  const { hasOnEdit, labels, onEdit } = useAIArtifact();
288
- const handleClick = useCallback(
288
+ const handleEditArtifact = useCallback(
289
289
  (event) => {
290
290
  onClick?.(event);
291
291
  if (event.defaultPrevented) return;
@@ -298,21 +298,21 @@ const AIArtifactEditButton = forwardRef(({ className, onClick, ...rest }, ref) =
298
298
  Button,
299
299
  {
300
300
  "aria-label": labels.edit,
301
- className: cn("h-8 w-8", className),
302
- onClick: handleClick,
301
+ className: cn("size-8", className),
302
+ onClick: handleEditArtifact,
303
303
  ref,
304
304
  size: "icon",
305
305
  type: "button",
306
306
  variant: "ghost",
307
307
  ...rest,
308
- children: /* @__PURE__ */ jsx(Pencil, { "aria-hidden": "true", className: "h-4 w-4" })
308
+ children: /* @__PURE__ */ jsx(Pencil, { "aria-hidden": "true", className: "size-4" })
309
309
  }
310
310
  );
311
311
  });
312
312
  AIArtifactEditButton.displayName = "AIArtifactEditButton";
313
313
  const AIArtifactDownloadButton = forwardRef(({ className, onClick, ...rest }, ref) => {
314
314
  const { download, labels } = useAIArtifact();
315
- const handleClick = useCallback(
315
+ const handleDownloadArtifact = useCallback(
316
316
  (event) => {
317
317
  onClick?.(event);
318
318
  if (event.defaultPrevented) return;
@@ -324,21 +324,21 @@ const AIArtifactDownloadButton = forwardRef(({ className, onClick, ...rest }, re
324
324
  Button,
325
325
  {
326
326
  "aria-label": labels.download,
327
- className: cn("h-8 w-8", className),
328
- onClick: handleClick,
327
+ className: cn("size-8", className),
328
+ onClick: handleDownloadArtifact,
329
329
  ref,
330
330
  size: "icon",
331
331
  type: "button",
332
332
  variant: "ghost",
333
333
  ...rest,
334
- children: /* @__PURE__ */ jsx(Download, { "aria-hidden": "true", className: "h-4 w-4" })
334
+ children: /* @__PURE__ */ jsx(Download, { "aria-hidden": "true", className: "size-4" })
335
335
  }
336
336
  );
337
337
  });
338
338
  AIArtifactDownloadButton.displayName = "AIArtifactDownloadButton";
339
339
  const AIArtifactFullscreenButton = forwardRef(({ className, onClick, ...rest }, ref) => {
340
340
  const { fullscreen, labels, toggleFullscreen } = useAIArtifact();
341
- const handleClick = useCallback(
341
+ const handleToggleArtifactFullscreen = useCallback(
342
342
  (event) => {
343
343
  onClick?.(event);
344
344
  if (event.defaultPrevented) return;
@@ -351,14 +351,14 @@ const AIArtifactFullscreenButton = forwardRef(({ className, onClick, ...rest },
351
351
  {
352
352
  "aria-label": fullscreen ? labels.exitFullscreen : labels.enterFullscreen,
353
353
  "aria-pressed": fullscreen,
354
- className: cn("h-8 w-8", className),
355
- onClick: handleClick,
354
+ className: cn("size-8", className),
355
+ onClick: handleToggleArtifactFullscreen,
356
356
  ref,
357
357
  size: "icon",
358
358
  type: "button",
359
359
  variant: "ghost",
360
360
  ...rest,
361
- children: fullscreen ? /* @__PURE__ */ jsx(Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ jsx(Maximize2, { "aria-hidden": "true", className: "h-4 w-4" })
361
+ children: fullscreen ? /* @__PURE__ */ jsx(Minimize2, { "aria-hidden": "true", className: "size-4" }) : /* @__PURE__ */ jsx(Maximize2, { "aria-hidden": "true", className: "size-4" })
362
362
  }
363
363
  );
364
364
  });
@@ -3,7 +3,7 @@ import { forwardRef } from "react";
3
3
  import { cva } from "class-variance-authority";
4
4
  import { LoaderCircle, SendHorizontal } from "lucide-react";
5
5
  import { cn } from "../../lib/utils";
6
- import { Button } from "../button";
6
+ import { Button } from "../button/button";
7
7
  import { Textarea } from "../textarea";
8
8
  const formShellVariants = cva(
9
9
  "rounded-2xl border border-border/70 bg-background shadow-sm"
@@ -36,7 +36,7 @@ function AIChatInputFooter({
36
36
  disabled: isSubmitDisabled,
37
37
  type: "submit",
38
38
  children: [
39
- isSubmitting ? /* @__PURE__ */ jsx(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(SendHorizontal, { className: "mr-2 h-4 w-4" }),
39
+ isSubmitting ? /* @__PURE__ */ jsx(LoaderCircle, { className: "mr-2 size-4 animate-spin" }) : /* @__PURE__ */ jsx(SendHorizontal, { className: "mr-2 size-4" }),
40
40
  submitLabel
41
41
  ]
42
42
  }
@@ -72,7 +72,7 @@ const AIChatInput = forwardRef(
72
72
  /* @__PURE__ */ jsx(
73
73
  Textarea,
74
74
  {
75
- className: "min-h-[120px] resize-none rounded-xl border-0 bg-transparent px-1 py-1 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0",
75
+ className: "min-h-[120px] resize-none rounded-xl border-0 bg-transparent p-1 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0",
76
76
  disabled,
77
77
  onChange: (event) => {
78
78
  textareaProps?.onChange?.(event);
@@ -2,7 +2,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { forwardRef } from "react";
3
3
  import { cva } from "class-variance-authority";
4
4
  import { cn } from "../../lib/utils";
5
- import { Avatar, AvatarFallback } from "../avatar";
5
+ import { Avatar, AvatarFallback } from "../avatar/avatar";
6
6
  import { Badge } from "../badge";
7
7
  const bubbleVariants = cva(
8
8
  "rounded-2xl border px-4 py-3 shadow-sm transition-colors",
@@ -73,7 +73,7 @@ const AIMessageBubble = forwardRef(
73
73
  isUser ? "flex-row-reverse text-right" : "flex-row"
74
74
  ),
75
75
  children: [
76
- /* @__PURE__ */ jsx(Avatar, { className: "mt-0.5 h-8 w-8 border border-border/70", children: /* @__PURE__ */ jsx(AvatarFallback, { className: "bg-muted text-[11px] font-medium uppercase text-muted-foreground", children: fallbackLabel }) }),
76
+ /* @__PURE__ */ jsx(Avatar, { className: "mt-0.5 size-8 border border-border/70", children: /* @__PURE__ */ jsx(AvatarFallback, { className: "bg-muted text-[11px] font-medium uppercase text-muted-foreground", children: fallbackLabel }) }),
77
77
  /* @__PURE__ */ jsxs(
78
78
  "div",
79
79
  {
@@ -160,7 +160,7 @@ const AISidebarTitle = forwardRef(({ children, className, ...rest }, ref) => {
160
160
  ref,
161
161
  ...rest,
162
162
  children: [
163
- /* @__PURE__ */ jsx(Bot, { "aria-hidden": "true", className: "h-4 w-4 text-muted-foreground" }),
163
+ /* @__PURE__ */ jsx(Bot, { "aria-hidden": "true", className: "size-4 text-muted-foreground" }),
164
164
  children ?? labels.defaultTitle
165
165
  ]
166
166
  }
@@ -169,7 +169,7 @@ const AISidebarTitle = forwardRef(({ children, className, ...rest }, ref) => {
169
169
  AISidebarTitle.displayName = "AISidebarTitle";
170
170
  const AISidebarClose = forwardRef(({ className, onClick, ...rest }, ref) => {
171
171
  const { close, labels } = useAISidebar();
172
- const handleClick = useCallback(
172
+ const handleCloseSidebar = useCallback(
173
173
  (event) => {
174
174
  onClick?.(event);
175
175
  if (event.defaultPrevented) return;
@@ -181,14 +181,14 @@ const AISidebarClose = forwardRef(({ className, onClick, ...rest }, ref) => {
181
181
  Button,
182
182
  {
183
183
  "aria-label": labels.close,
184
- className: cn("h-8 w-8", className),
185
- onClick: handleClick,
184
+ className: cn("size-8", className),
185
+ onClick: handleCloseSidebar,
186
186
  ref,
187
187
  size: "icon",
188
188
  type: "button",
189
189
  variant: "ghost",
190
190
  ...rest,
191
- children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true", className: "h-4 w-4" })
191
+ children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true", className: "size-4" })
192
192
  }
193
193
  );
194
194
  });
@@ -215,7 +215,7 @@ const AISidebarFooter = forwardRef(({ children, className, ...rest }, ref) => /*
215
215
  AISidebarFooter.displayName = "AISidebarFooter";
216
216
  const AISidebarTrigger = forwardRef(({ children, className, onClick, ...rest }, ref) => {
217
217
  const { labels, openState, toggle } = useAISidebar();
218
- const handleClick = useCallback(
218
+ const handleToggleSidebar = useCallback(
219
219
  (event) => {
220
220
  onClick?.(event);
221
221
  if (event.defaultPrevented) return;
@@ -230,13 +230,13 @@ const AISidebarTrigger = forwardRef(({ children, className, onClick, ...rest },
230
230
  "aria-label": children ? void 0 : labels.open,
231
231
  className: cn(className),
232
232
  "data-state": openState ? "open" : "closed",
233
- onClick: handleClick,
233
+ onClick: handleToggleSidebar,
234
234
  ref,
235
235
  size: children ? "sm" : "icon",
236
236
  type: "button",
237
237
  variant: "outline",
238
238
  ...rest,
239
- children: children ?? /* @__PURE__ */ jsx(MessageSquarePlus, { "aria-hidden": "true", className: "h-4 w-4" })
239
+ children: children ?? /* @__PURE__ */ jsx(MessageSquarePlus, { "aria-hidden": "true", className: "size-4" })
240
240
  }
241
241
  );
242
242
  });
@@ -18,13 +18,13 @@ const AISourceCitation = forwardRef(
18
18
  ...props,
19
19
  children: [
20
20
  /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
21
- /* @__PURE__ */ jsx(Quote, { className: "mt-0.5 h-4 w-4 shrink-0 text-muted-foreground" }),
21
+ /* @__PURE__ */ jsx(Quote, { className: "mt-0.5 size-4 shrink-0 text-muted-foreground" }),
22
22
  /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
23
23
  /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
24
24
  /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium text-foreground", children: title }),
25
25
  /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: source })
26
26
  ] }),
27
- /* @__PURE__ */ jsx(ExternalLink, { className: "h-4 w-4 shrink-0 text-muted-foreground transition-transform group-hover:-translate-y-0.5 group-hover:translate-x-0.5" })
27
+ /* @__PURE__ */ jsx(ExternalLink, { className: "size-4 shrink-0 text-muted-foreground transition-transform group-hover:-translate-y-0.5 group-hover:translate-x-0.5" })
28
28
  ] }) })
29
29
  ] }),
30
30
  snippet ? /* @__PURE__ */ jsx("p", { className: "line-clamp-3 text-sm leading-6 text-muted-foreground", children: snippet }) : null
@@ -3,7 +3,7 @@ import { forwardRef } from "react";
3
3
  import { cva } from "class-variance-authority";
4
4
  import { AlertCircle, CheckCircle2, Clock3, Wrench } from "lucide-react";
5
5
  import { cn } from "../../lib/utils";
6
- import { Badge } from "../badge";
6
+ import { Badge } from "../badge/badge";
7
7
  const statusVariants = cva(
8
8
  "rounded-full px-2 py-0 text-[10px] uppercase tracking-wide",
9
9
  {
@@ -21,10 +21,10 @@ const statusVariants = cva(
21
21
  }
22
22
  );
23
23
  const statusIconMap = {
24
- complete: /* @__PURE__ */ jsx(CheckCircle2, { className: "h-4 w-4" }),
25
- error: /* @__PURE__ */ jsx(AlertCircle, { className: "h-4 w-4" }),
26
- queued: /* @__PURE__ */ jsx(Clock3, { className: "h-4 w-4" }),
27
- running: /* @__PURE__ */ jsx(Wrench, { className: "h-4 w-4 animate-pulse" })
24
+ complete: /* @__PURE__ */ jsx(CheckCircle2, { className: "size-4" }),
25
+ error: /* @__PURE__ */ jsx(AlertCircle, { className: "size-4" }),
26
+ queued: /* @__PURE__ */ jsx(Clock3, { className: "size-4" }),
27
+ running: /* @__PURE__ */ jsx(Wrench, { className: "size-4 animate-pulse" })
28
28
  };
29
29
  const AIToolCallDisplay = forwardRef(
30
30
  ({
@@ -24,10 +24,7 @@ const ANIMATED_TEXT_RANDOM_CHARACTER_PRESETS = {
24
24
  const DEFAULT_RANDOM_CHARACTERS = ANIMATED_TEXT_RANDOM_CHARACTER_PRESETS.matrix;
25
25
  function getSegments(text, splitBy) {
26
26
  if (splitBy === "character") {
27
- const segmenter = new Intl.Segmenter(void 0, {
28
- granularity: "grapheme"
29
- });
30
- return Array.from(segmenter.segment(text), ({ segment }) => segment);
27
+ return Array.from(GLYPH_SEGMENTER.segment(text), ({ segment }) => segment);
31
28
  }
32
29
  return text.match(/\S+\s*/g) ?? [];
33
30
  }
@@ -90,13 +87,16 @@ function buildRevealPlan(direction, length, randomness) {
90
87
  return revealPlan;
91
88
  }
92
89
  function useRevealProgress(active, length, stagger) {
93
- const [progress, setProgress] = React.useState(0);
90
+ const [progress, setProgress] = React.useState(() => active ? 0 : length);
91
+ const [revealKey, setRevealKey] = React.useState({ active, length, stagger });
92
+ if (revealKey.active !== active || revealKey.length !== length || revealKey.stagger !== stagger) {
93
+ setRevealKey({ active, length, stagger });
94
+ setProgress(active ? 0 : length);
95
+ }
94
96
  React.useEffect(() => {
95
97
  if (!active) {
96
- setProgress(length);
97
98
  return;
98
99
  }
99
- setProgress(0);
100
100
  const revealInterval = window.setInterval(
101
101
  () => {
102
102
  setProgress((current) => {
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { cn } from "../../lib/utils";
4
- import { Popover, PopoverContent, PopoverTrigger } from "../popover";
4
+ import { Popover, PopoverContent, PopoverTrigger } from "../popover/popover";
5
5
  const toneClasses = {
6
6
  amber: "bg-amber-500/20 text-amber-950 dark:text-amber-100",
7
7
  emerald: "bg-emerald-500/20 text-emerald-950 dark:text-emerald-100",
@@ -34,11 +34,21 @@ function valueToCents(value) {
34
34
  if (Number.isNaN(parsed)) return 0;
35
35
  return Math.round(parsed * CENTS_PER_UNIT);
36
36
  }
37
+ const CURRENCY_FORMATTER_CACHE = /* @__PURE__ */ new Map();
38
+ function getCurrencyFormatter(locale, currency) {
39
+ const key = `${locale}|${currency}`;
40
+ let formatter = CURRENCY_FORMATTER_CACHE.get(key);
41
+ if (!formatter) {
42
+ formatter = Intl.NumberFormat(locale, {
43
+ currency,
44
+ style: "currency"
45
+ });
46
+ CURRENCY_FORMATTER_CACHE.set(key, formatter);
47
+ }
48
+ return formatter;
49
+ }
37
50
  function getCurrencySymbol(locale, currency) {
38
- const formatted = new Intl.NumberFormat(locale, {
39
- currency,
40
- style: "currency"
41
- }).format(0);
51
+ const formatted = getCurrencyFormatter(locale, currency).format(0);
42
52
  const symbol = formatted.replaceAll(/[\d\s,.]/g, "");
43
53
  return symbol.length > 0 ? symbol : currency;
44
54
  }