@rinzai/zen 0.14.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. package/CHANGELOG.md +153 -0
  2. package/README.md +16 -1
  3. package/dist/animated-number/index.js +14 -14
  4. package/dist/breadcrumbs/index.js +14 -14
  5. package/dist/calendar/index.js +29 -29
  6. package/dist/calendar-heatmap/index.js +12 -12
  7. package/dist/canvas/index.js +19 -19
  8. package/dist/carousel/index.d.ts.map +1 -1
  9. package/dist/carousel/index.js +29 -29
  10. package/dist/chart/index.js +7 -7
  11. package/dist/code-block/index.js +5 -5
  12. package/dist/collapse/index.js +6 -6
  13. package/dist/color-picker/index.js +10 -10
  14. package/dist/combobox/index.js +61 -61
  15. package/dist/command-palette/index.js +5 -5
  16. package/dist/confirm-dialog/index.js +4 -4
  17. package/dist/date-picker/index.js +15 -15
  18. package/dist/dialog/index.d.ts.map +1 -1
  19. package/dist/dialog/index.js +45 -65
  20. package/dist/docs/README.md +205 -0
  21. package/dist/docs/accordion.md +122 -0
  22. package/dist/docs/alert.md +69 -0
  23. package/dist/docs/animated-number.md +105 -0
  24. package/dist/docs/avatar.md +91 -0
  25. package/dist/docs/backdrop.md +94 -0
  26. package/dist/docs/badge.md +37 -0
  27. package/dist/docs/breadcrumbs.md +44 -0
  28. package/dist/docs/button-group.md +76 -0
  29. package/dist/docs/button.md +131 -0
  30. package/dist/docs/calendar-heatmap.md +73 -0
  31. package/dist/docs/calendar.md +101 -0
  32. package/dist/docs/canvas.md +584 -0
  33. package/dist/docs/card.md +180 -0
  34. package/dist/docs/carousel.md +162 -0
  35. package/dist/docs/chart.md +325 -0
  36. package/dist/docs/checkbox.md +88 -0
  37. package/dist/docs/chip.md +52 -0
  38. package/dist/docs/code-block.md +116 -0
  39. package/dist/docs/code-input.md +52 -0
  40. package/dist/docs/collapse.md +46 -0
  41. package/dist/docs/color-picker.md +145 -0
  42. package/dist/docs/combobox.md +208 -0
  43. package/dist/docs/command-palette.md +65 -0
  44. package/dist/docs/date-picker.md +167 -0
  45. package/dist/docs/dialog.md +271 -0
  46. package/dist/docs/disclosure.md +88 -0
  47. package/dist/docs/editable-cell.md +90 -0
  48. package/dist/docs/empty-state.md +46 -0
  49. package/dist/docs/field.md +82 -0
  50. package/dist/docs/file-drop.md +44 -0
  51. package/dist/docs/filter-bar.md +66 -0
  52. package/dist/docs/header.md +51 -0
  53. package/dist/docs/hover-card.md +110 -0
  54. package/dist/docs/icon-picker.md +65 -0
  55. package/dist/docs/input-group.md +89 -0
  56. package/dist/docs/input.md +33 -0
  57. package/dist/docs/inset.md +57 -0
  58. package/dist/docs/kbd.md +34 -0
  59. package/dist/docs/keypad.md +51 -0
  60. package/dist/docs/load-more.md +66 -0
  61. package/dist/docs/locale-provider.md +99 -0
  62. package/dist/docs/marquee.md +86 -0
  63. package/dist/docs/menu.md +456 -0
  64. package/dist/docs/meter.md +102 -0
  65. package/dist/docs/money-input.md +169 -0
  66. package/dist/docs/month-picker.md +80 -0
  67. package/dist/docs/navigation-menu.md +157 -0
  68. package/dist/docs/number-field.md +129 -0
  69. package/dist/docs/page-header.md +44 -0
  70. package/dist/docs/page-transition.md +93 -0
  71. package/dist/docs/pagination.md +42 -0
  72. package/dist/docs/pills.md +85 -0
  73. package/dist/docs/player-bar.md +158 -0
  74. package/dist/docs/popover.md +200 -0
  75. package/dist/docs/progress-ring.md +70 -0
  76. package/dist/docs/radio-cards.md +82 -0
  77. package/dist/docs/radio-group.md +86 -0
  78. package/dist/docs/range-slider.md +64 -0
  79. package/dist/docs/repeat-picker.md +44 -0
  80. package/dist/docs/resizable.md +107 -0
  81. package/dist/docs/seek-bar.md +97 -0
  82. package/dist/docs/segmented.md +89 -0
  83. package/dist/docs/select.md +148 -0
  84. package/dist/docs/separator.md +76 -0
  85. package/dist/docs/side-nav.md +75 -0
  86. package/dist/docs/skeleton.md +89 -0
  87. package/dist/docs/slider.md +87 -0
  88. package/dist/docs/sortable.md +244 -0
  89. package/dist/docs/sparkline.md +56 -0
  90. package/dist/docs/spinner.md +69 -0
  91. package/dist/docs/status-pill.md +81 -0
  92. package/dist/docs/stepper.md +59 -0
  93. package/dist/docs/tab-bar.md +78 -0
  94. package/dist/docs/table-of-contents.md +43 -0
  95. package/dist/docs/table.md +714 -0
  96. package/dist/docs/tabs.md +140 -0
  97. package/dist/docs/tag-input.md +45 -0
  98. package/dist/docs/textarea.md +25 -0
  99. package/dist/docs/theme-toggle.md +85 -0
  100. package/dist/docs/theming.md +193 -0
  101. package/dist/docs/time-field.md +71 -0
  102. package/dist/docs/timeline.md +50 -0
  103. package/dist/docs/toast.md +53 -0
  104. package/dist/docs/toggle-group.md +83 -0
  105. package/dist/docs/toggle.md +38 -0
  106. package/dist/docs/toolbar.md +97 -0
  107. package/dist/docs/tooltip.md +102 -0
  108. package/dist/docs/tree.md +295 -0
  109. package/dist/docs/trend.md +50 -0
  110. package/dist/filter-bar/index.js +6 -6
  111. package/dist/header/index.js +6 -6
  112. package/dist/icon-picker/index.js +5 -5
  113. package/dist/icons/arrow-path.d.ts +3 -0
  114. package/dist/icons/arrow-path.d.ts.map +1 -0
  115. package/dist/icons/arrows-right-left.d.ts +3 -0
  116. package/dist/icons/arrows-right-left.d.ts.map +1 -0
  117. package/dist/icons/backward.d.ts +3 -0
  118. package/dist/icons/backward.d.ts.map +1 -0
  119. package/dist/icons/forward.d.ts +3 -0
  120. package/dist/icons/forward.d.ts.map +1 -0
  121. package/dist/icons/heart-solid.d.ts +3 -0
  122. package/dist/icons/heart-solid.d.ts.map +1 -0
  123. package/dist/icons/heart.d.ts +3 -0
  124. package/dist/icons/heart.d.ts.map +1 -0
  125. package/dist/icons/musical-note.d.ts +3 -0
  126. package/dist/icons/musical-note.d.ts.map +1 -0
  127. package/dist/icons/pause.d.ts +3 -0
  128. package/dist/icons/pause.d.ts.map +1 -0
  129. package/dist/icons/play.d.ts +3 -0
  130. package/dist/icons/play.d.ts.map +1 -0
  131. package/dist/icons/queue-list.d.ts +3 -0
  132. package/dist/icons/queue-list.d.ts.map +1 -0
  133. package/dist/icons/speaker-wave.d.ts +3 -0
  134. package/dist/icons/speaker-wave.d.ts.map +1 -0
  135. package/dist/icons/speaker-x-mark.d.ts +3 -0
  136. package/dist/icons/speaker-x-mark.d.ts.map +1 -0
  137. package/dist/index.d.ts +7 -1
  138. package/dist/index.d.ts.map +1 -1
  139. package/dist/keypad/index.js +5 -5
  140. package/dist/lib.js +86 -80
  141. package/dist/load-more/index.js +5 -5
  142. package/dist/marquee/index.d.ts +15 -0
  143. package/dist/marquee/index.d.ts.map +1 -0
  144. package/dist/marquee/index.js +90 -0
  145. package/dist/menu/index.d.ts +7 -1
  146. package/dist/menu/index.d.ts.map +1 -1
  147. package/dist/menu/index.js +222 -178
  148. package/dist/money-input/index.js +54 -54
  149. package/dist/month-picker/index.js +11 -11
  150. package/dist/number-field/index.js +5 -5
  151. package/dist/pagination/index.js +12 -12
  152. package/dist/player-bar/index.d.ts +11 -0
  153. package/dist/player-bar/index.d.ts.map +1 -0
  154. package/dist/player-bar/index.js +17 -0
  155. package/dist/radio-cards/index.d.ts +2 -1
  156. package/dist/radio-cards/index.d.ts.map +1 -1
  157. package/dist/radio-cards/index.js +3 -3
  158. package/dist/range-slider/index.js +11 -11
  159. package/dist/repeat-picker/index.js +5 -5
  160. package/dist/resizable/index.js +22 -22
  161. package/dist/seek-bar/index.d.ts +26 -0
  162. package/dist/seek-bar/index.d.ts.map +1 -0
  163. package/dist/seek-bar/index.js +121 -0
  164. package/dist/segmented/index.d.ts +3 -2
  165. package/dist/segmented/index.d.ts.map +1 -1
  166. package/dist/segmented/index.js +19 -18
  167. package/dist/select/index.js +21 -21
  168. package/dist/slider/index.d.ts +2 -1
  169. package/dist/slider/index.d.ts.map +1 -1
  170. package/dist/sortable/index.d.ts +13 -1
  171. package/dist/sortable/index.d.ts.map +1 -1
  172. package/dist/sortable/index.js +74 -55
  173. package/dist/sortable/shared.js +14 -14
  174. package/dist/sortable/tree.js +17 -17
  175. package/dist/sparkline/index.js +4 -4
  176. package/dist/stepper/index.js +13 -13
  177. package/dist/tab-bar/index.d.ts +4 -2
  178. package/dist/tab-bar/index.d.ts.map +1 -1
  179. package/dist/tab-bar/index.js +24 -19
  180. package/dist/table/index.js +26 -26
  181. package/dist/table/selection.js +9 -9
  182. package/dist/table-of-contents/index.js +11 -11
  183. package/dist/tag-input/index.js +5 -5
  184. package/dist/textarea/index.d.ts +6 -2
  185. package/dist/textarea/index.d.ts.map +1 -1
  186. package/dist/textarea/index.js +2 -1
  187. package/dist/theme-toggle/index.js +4 -4
  188. package/dist/theme.css +143 -0
  189. package/dist/time-field/index.js +21 -21
  190. package/dist/toast/index.d.ts.map +1 -1
  191. package/dist/toast/index.js +41 -41
  192. package/dist/tooltip/index.d.ts +9 -3
  193. package/dist/tooltip/index.d.ts.map +1 -1
  194. package/dist/tooltip/index.js +19 -16
  195. package/dist/tree/index.js +34 -34
  196. package/dist/trend/index.js +5 -5
  197. package/dist/utils/duration.d.ts +3 -0
  198. package/dist/utils/duration.d.ts.map +1 -0
  199. package/dist/utils/duration.js +7 -0
  200. package/dist/utils/messages.d.ts +3 -0
  201. package/dist/utils/messages.d.ts.map +1 -1
  202. package/dist/utils/messages.js +4 -1
  203. package/dist/utils/slot.d.ts +5 -2
  204. package/dist/utils/slot.d.ts.map +1 -1
  205. package/dist/utils/slot.js +16 -11
  206. package/dist/utils/swipe.d.ts +7 -0
  207. package/dist/utils/swipe.d.ts.map +1 -1
  208. package/dist/utils/swipe.js +45 -25
  209. package/dist/utils/useAnchoredPopup.d.ts +2 -1
  210. package/dist/utils/useAnchoredPopup.d.ts.map +1 -1
  211. package/dist/utils/useAnchoredPopup.js +10 -5
  212. package/dist/utils/useHeightVar.d.ts +7 -0
  213. package/dist/utils/useHeightVar.d.ts.map +1 -0
  214. package/dist/utils/useHeightVar.js +17 -0
  215. package/dist/utils/useMediaPlayer.d.ts +38 -0
  216. package/dist/utils/useMediaPlayer.d.ts.map +1 -0
  217. package/dist/utils/useMediaPlayer.js +91 -0
  218. package/dist/utils/useMediaSession.d.ts +24 -0
  219. package/dist/utils/useMediaSession.d.ts.map +1 -0
  220. package/dist/utils/useMediaSession.js +76 -0
  221. package/dist/utils/useVirtualList.d.ts +6 -1
  222. package/dist/utils/useVirtualList.d.ts.map +1 -1
  223. package/dist/utils/useVirtualList.js +12 -12
  224. package/dist/zen.css +1 -1
  225. package/package.json +4 -2
package/CHANGELOG.md ADDED
@@ -0,0 +1,153 @@
1
+ # Changelog
2
+
3
+ ## 0.16.0
4
+
5
+ ### Added to existing components
6
+
7
+ - **MenuContent**: `sheet` makes the menu a bottom sheet on phones (below `md`), as music apps show a song's menu: across the bottom of the screen over a scrim, with a grip, swiped down or tapped outside to close. Its submenus slide in over it, with a row at the top that goes back (the arrow back and Escape still do), and open only when chosen, not on hover. Wider screens keep the popover.
8
+ - **SortableList**: works with a virtualized list. Give it `itemHeight` and render only the rows in view (from `useVirtualList`), each at its place in `value`; a drag works from `value`, not the rows on screen, and rows that come into view as it scrolls the list take their places. `onLiftedChange` says which item is picked up (by its handle or from the keyboard), to keep its row rendered. An item moved with the keyboard is scrolled into view.
9
+ - **useVirtualList**: `keep` renders a row even when it's out of view, such as the one being dragged, with the rows between.
10
+ - **SeekBar**: `times="below"` puts the time played and the length under the ends of the bar, as on a phone's Now Playing screen.
11
+ - **TooltipContent**: `side="beside"` puts the tooltip after its trigger (before it if there's no room) instead of below, centred on it, as for the icons of a collapsed sidebar, where a tooltip below would cover the next icon. `align` lines up its top or bottom with the trigger's instead.
12
+ - **Anchored popups** (`anchoredStyle`): beside the trigger, `align` now chooses top (start, as before), middle (center) or bottom (end).
13
+
14
+ ### Fixes
15
+
16
+ - **ToastProvider**: once its toasts were gone, the empty toast area kept its last height (the height it was given went negative, which browsers ignore) and caught clicks meant for what was under it, such as a player bar's controls. It now shrinks to nothing.
17
+
18
+ ## 0.15.0
19
+
20
+ ### New components
21
+
22
+ - **PlayerBar**: what's playing, in a glass bar along the bottom of the screen, laid out as you like. On phones it sits on the TabBar beside it.
23
+ - **SeekBar**: where playback is, filled to the time played and shaded on to what's loaded, between the time played and the length. Pass `playing` and it glides between the player's time updates, moved by the browser's compositor rather than per-frame renders. Dragging doesn't interrupt playback; letting go seeks; the arrow keys seek 5 seconds.
24
+ - **Marquee**: one line of text cut off with an ellipsis that scrolls to show the rest: on hover or keyboard focus of itself or of its `data-zen-marquee-host` (a row, a tile), or always (`trigger="always"`, for what's playing). Only text that doesn't fit moves, at the same speed whatever its length, with fades at the edges. Stays an ellipsis for reduced motion; the accessible name is the text.
25
+ - **useMediaPlayer**: drives your own `<audio>` or `<video>` (`const [ref, player] = useMediaPlayer()`, then `<audio ref={ref} />`) and keeps its state: playing, waiting, time, duration, buffered, volume. With `play`, `pause`, `toggle`, `seek`, `setVolume` and `setMuted`.
26
+ - **useMediaSession**: puts what's playing on the lock screen and the OS media controls (title, artist, cover, position), and lets play, pause, seek, previous, next and the media keys control your player.
27
+ - **formatDuration**: seconds as a clock reads them (3:07, 1:02:07).
28
+
29
+ ### Renamed
30
+
31
+ - **TextArea** is now **Textarea** (and `TextAreaProps` is `TextareaProps`), like the element. The old names still work, marked deprecated, until the next breaking release.
32
+
33
+ ### Added to existing components
34
+
35
+ - **TabBar**: its height is kept in `--zen-tab-bar-height` on its parent (0px while hidden), for a PlayerBar to sit on and the page to pad its end by. PlayerBar keeps `--zen-player-bar-height` the same way.
36
+ - **Segmented**, **RadioCards**: `label` is optional. Without it, name the group with `aria-label` or `aria-labelledby`, as on RadioGroup.
37
+ - **Slider**: `step="any"` for no snapping.
38
+
39
+ ### Fixes
40
+
41
+ - **SegmentedItem**: an icon and its text sit side by side; they stacked.
42
+ - **Popover, Menu, Select and every anchored popup**: with no room below the trigger, a centred popup wider than its trigger stayed below it, off screen (Chrome) or over the trigger (Firefox), instead of flipping above. It flips now, and a popup lined up with an edge also switches edges when there's no room beside it.
43
+ - **Carousel**: where the slides don't fill the view evenly, Next stopped short of the end, the last slide cut off. The end is now the last stop, with its own dot.
44
+ - **TabBarItem**, **MenuItem**: with `asChild`, `icon` was dropped; it now goes ahead of your link's content, also when that content is a render function (a NavLink's).
45
+
46
+ ### Docs
47
+
48
+ - The docs ship in the package as markdown, for AI agents: `node_modules/@rinzai/zen/dist/docs` has a page per component with every example's source, and the CHANGELOG is included. The site serves the same pages at `/docs/<component>.md`, with `/llms.txt` and `/llms-full.txt`.
49
+ - Props tables cover parts kept outside a package's `index.tsx`, such as SortableTree, SortableItem, DonutChart and the table's selection and swipe parts.
50
+ - The package's markdown pages have the props tables too, the same as the site's. Their README and `llms.txt` carry the README's guide: setup, the props every component takes, values and forms, languages, theming, overlays and browser support. The README now says Zen exports no icons.
51
+
52
+ ## 0.14.0
53
+
54
+ ### Added to existing components
55
+
56
+ - **NumberField**: `onValueChange` gets a second argument saying how the number changed: `{ reason: 'step', delta }` for − +, ↑↓ and Page Up/Down, `'input'` for typing, `'limit'` for Home and End. `onValueCommit` fires once per finished change: each step, and what's typed on Enter or on leaving the field. So a step can be sent on as a step to whatever keeps the number (see Number Field → Steps).
57
+
58
+ ## 0.13.0
59
+
60
+ Since 0.12.0. This release renames things. Every breaking change is listed first, with what to change.
61
+
62
+ ### Breaking changes
63
+
64
+ #### Callbacks are named for what they change
65
+
66
+ | Before | After |
67
+ | -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
68
+ | `onChange` | `onValueChange` on Select, Segmented, RadioGroup, RadioCards, Calendar, DatePicker, DateRangePicker, MonthPicker, MoneyInput, ColorPicker, ColorPanel, IconPicker, RepeatPicker and SortableList (Combobox, Keypad, Slider, RangeSlider, TagInput and Tabs already used it) |
69
+ | `onChange(checked)` on Checkbox, Toggle | `onCheckedChange(checked)`; `onChange` is the native event again |
70
+ | Canvas `onChange` / `onChangeEnd` / `onSelect` | `onItemsChange` / `onItemsChangeEnd` / `onSelectedChange` |
71
+ | CalendarHeatmap `onSelect` | `onSelectedChange` |
72
+ | DatePicker, DateRangePicker, MonthPicker `onClear` | `clearable`; clearing calls `onValueChange(null)` |
73
+
74
+ `value` is optional wherever it was required. Leave it out and pass `defaultValue` to let the control keep its own.
75
+
76
+ #### One tone scale: `default`, `positive`, `negative`
77
+
78
+ | Before | After |
79
+ | --------------------------------------------------------------- | ------------------------------------------ |
80
+ | `destructive` (Button, Badge, ChartReference, TableSwipeAction) | `tone="negative"` |
81
+ | `danger` (Meter), `error` (Toast, FormMessage) | `negative` |
82
+ | `success` | `positive` |
83
+ | `info` (Toast, FormMessage), `primary` (Sparkline) | `default` |
84
+ | MenuItem, ConfirmDialog `destructive` | `tone="negative"` |
85
+ | Button `variant="destructive"` | `tone="negative"` (on the default variant) |
86
+ | Button `variant="icon"` | `variant="ghost"` with an icon size |
87
+
88
+ #### Sizes
89
+
90
+ - Icon buttons line up with fields and buttons of the same size: `icon-sm` is 32px, `icon` is 40px (was 36), `icon-lg` is 44px. The old 24px `icon-sm` is now `icon-xs`.
91
+ - ThemeToggle is 40px.
92
+ - Input's `size` is `"sm" | "lg"` (Button's heights). It no longer passes through the native `size` attribute.
93
+
94
+ #### Right to left
95
+
96
+ - Table: `sticky="left"` is `sticky="start"`.
97
+ - TableContainer's `data-under-left` attribute is `data-under-start`.
98
+ - The `.zen__sticky-left` class is `.zen__sticky-start`.
99
+ - Spacing, corners and positions use logical sides, so a class you override may now be `ps-*`/`pe-*`/`start-*`/`end-*`/`text-start` rather than `pl-*`/`left-*`/`text-left`.
100
+
101
+ #### Forms
102
+
103
+ - MoneyInput with `name` submits the amount in minor units, from a hidden input (e.g. `123450` for $1,234.50). It used to submit the visible text.
104
+
105
+ #### Words
106
+
107
+ - `ICON_COLORS` entries no longer have English labels: `IconColor.label` is optional, and the names come from the messages.
108
+ - `ImageCropError` takes a `reason` code first, `new ImageCropError(reason, message)`, so you can show the error in your own words.
109
+ - `describeRepeat` takes the words as an optional last argument.
110
+
111
+ ### New components
112
+
113
+ - **Accordion**: disclosures where one or several (`multiple`) open at a time, with ↑↓, Home and End between headings.
114
+ - **Separator**: across or upright, and `decorative` when it's only visual.
115
+ - **ToggleGroup**: buttons that stay pressed, one or several (`multiple`).
116
+ - **Toolbar**: one Tab stop, with arrow keys through its controls, a ToggleGroup's items included. Runs across or upright.
117
+ - **ButtonGroup**: buttons joined into one control, a split button's menu included.
118
+ - **HoverCard**: a glass preview of what a link points to, on hover or keyboard focus.
119
+ - **NumberField**: a number with − and + buttons and arrow keys (PageUp/PageDown for larger steps). Typed and shown in the locale's format, including percent.
120
+ - **TimeField**: hours, minutes and AM/PM as segments, in the locale's order and clock.
121
+ - **Carousel**: native scroll snapping, with glass previous/next buttons and dots in CarouselControls, and the arrow keys.
122
+ - **Resizable** (ResizablePanelGroup, ResizablePanel, ResizableHandle): drag a handle or use the arrow keys, within each panel's limits. Groups nest, and `onLayout` reports the sizes.
123
+ - **Menubar**: a row of menus with one Tab stop. ←→ move between them; with one open, ←→ open the next and hover switches.
124
+ - **NavigationMenu**: site navigation with panels of links that open on hover or click.
125
+ - **SortableTree**: drag-and-drop for groups and nested items. Drop into another group, into an open sub-item, or under another item; `accepts` says what goes where. Keyboard: ↑↓ through every allowed place, ←→ a level out or in, each step announced. Works on table rows (see Table → Reorder).
126
+ - **LocaleProvider**: the locale and every word Zen shows or announces. Pass a partial `messages` to translate or reword any of them (`ENGLISH` lists them all).
127
+
128
+ ### Added to existing components
129
+
130
+ - **Menu**:
131
+ - Submenus (MenuSub, MenuSubTrigger, MenuSubContent).
132
+ - MenuCheckboxItem, and MenuRadioGroup with MenuRadioItem.
133
+ - ↓ or ↑ on a MenuTrigger opens the menu at its first or last item.
134
+ - **SortableList**: `asChild` on the list and its items, to sort your own elements, such as a TableBody's rows.
135
+ - **Fields** (Input, InputGroup, MoneyInput, Select, Combobox, DatePicker, DateRangePicker, MonthPicker, ColorPicker): `size="sm" | "lg"`, at Button's heights.
136
+ - **Form submission and reset**: custom controls with a `name` are submitted with their form and reset with it. These are Combobox, the date and month pickers, MoneyInput, ColorPicker, TagInput, RepeatPicker, RangeSlider and IconPicker.
137
+ - **Props and refs**: `id`, `data-*`, `aria-*`, `style`, handlers and `ref` reach every component's element. Where a component keeps its own ref, yours is merged with it.
138
+ - **Exported props types**: every component's props type is exported (`ButtonProps`, `TabsProps`…).
139
+ - **Server components**: `'use client'` marks only modules that use React. Money, dates, `cx`, colours and the package entry can be called from server components.
140
+ - **Right to left**: layout, arrow keys, chevrons and slider fills follow `dir`. Calendar, CalendarHeatmap and Pagination use the locale's digits.
141
+ - **Focus**: every control uses the same keyboard focus ring (the `focus-ring` utility).
142
+
143
+ ### Fixes
144
+
145
+ - Calendar marks today only once hydrated, so server and client render the same.
146
+ - Combobox's list is named after its field.
147
+ - Tabs without panels no longer point `aria-controls` at nothing.
148
+ - Closed popovers and dialogs stay hidden whatever `className` lays them out with.
149
+ - HoverCard and Tooltip are placed against their trigger in browsers without CSS anchor positioning.
150
+
151
+ ### Tests
152
+
153
+ - Behaviour tests now run in Chromium, Firefox and WebKit, with new keyboard tests and accessibility checks of open popups in both themes. CI runs them.
package/README.md CHANGED
@@ -57,18 +57,33 @@ export default function App() {
57
57
  }
58
58
  ```
59
59
 
60
+ ## For AI agents
61
+
62
+ Every docs page ships with the package as markdown, matching the installed version: `node_modules/@rinzai/zen/dist/docs` (README.md lists them), with the CHANGELOG at the package root. Point your agent there from your `AGENTS.md` or `CLAUDE.md`:
63
+
64
+ ```md
65
+ UI components come from @rinzai/zen. Its docs, with every example's source, are in node_modules/@rinzai/zen/dist/docs; start at README.md there.
66
+ ```
67
+
68
+ The site has them too: [llms.txt](https://zen.rinzai.dev/llms.txt), [llms-full.txt](https://zen.rinzai.dev/llms-full.txt) (everything in one file) and `/docs/<component>.md`.
69
+
60
70
  ## What's inside
61
71
 
62
72
  - **Surfaces:** Card, Inset, Alert, Stat, Dialog (and sheets from an edge), ConfirmDialog, Popover, Tooltip, HoverCard, Toast (a stacked deck), Disclosure, Accordion, Separator, Resizable panels, Carousel, Backdrop (aurora, contours or dots, and a pointer light)
63
- - **Inputs:** Button, ButtonGroup, Toggle, ToggleGroup, Toolbar, Input, TextArea, InputGroup, NumberField, TimeField, MoneyInput (with currency conversion), Select, Combobox, Calendar, DatePicker, DateRangePicker, MonthPicker, ColorPicker, Checkbox, RadioGroup, RadioCards, Segmented, Slider, Chip, Field
73
+ - **Inputs:** Button, ButtonGroup, Toggle, ToggleGroup, Toolbar, Input, Textarea, InputGroup, NumberField, TimeField, MoneyInput (with currency conversion), Select, Combobox, Calendar, DatePicker, DateRangePicker, MonthPicker, ColorPicker, Checkbox, RadioGroup, RadioCards, Segmented, Slider, Chip, Field
64
74
  - **Data:** Chart (areas, lines, bars) and DonutChart in plain SVG, composable Table with sticky edges, sorting and rows reordered by drag and drop, tree rows, editable cells, virtual rows, SortableList and SortableTree, Meter, ProgressRing, AnimatedNumber, Badge, StatusPill (a live save status), Skeleton, Spinner, Canvas (items placed freely, with snapping)
65
75
  - **Navigation:** Header, NavigationMenu, Pills, Tabs, TabBar, SideNav, TableOfContents, Menu (with submenus, checkbox and radio items, and context menus), Menubar
76
+ - **Media:** PlayerBar (sits on a TabBar), SeekBar, Marquee (cut-off titles that scroll to show the rest), `useMediaPlayer` for your own `<audio>` or `<video>`, `useMediaSession` for the lock screen and media keys, `formatDuration`
66
77
  - **Theming:** dark and light, OKLCH tokens, and a theme generator (presets or any hue) that keeps contrast readable
67
78
  - **Languages:** LocaleProvider for the locale and every word, and right-to-left layout
68
79
  - **Hooks and utilities:** `themeWave` (the theme spreads from the switch like a drop falling into water: ripples, glints and a rainbow edge, drawn on the GPU; `prepareThemeWave` readies it when the pointer reaches your own switch), `useAnchoredPopup`, `useVirtualList`, `useTree`, `useSort`, `useCopyToClipboard`, money, currency, month and date helpers, `hexToOklch` and `oklchToHex`, `cx` (Tailwind-aware class merging), `cva`
69
80
 
81
+ ## Props
82
+
70
83
  Every component takes `className`, and a class you pass always overrides the component's default. Other props (`id`, `aria-*`, `data-*`, handlers) and `ref` reach its element, and parts that render a link or button take `asChild` to use your own (a router's Link, say).
71
84
 
85
+ Zen exports no icons. Use any icon set (the examples use [Heroicons](https://heroicons.com)) and pass icons in as elements, such as `icon={<HomeIcon />}`.
86
+
72
87
  ## Values and forms
73
88
 
74
89
  Controls report changes with `onValueChange` (`onCheckedChange` for Checkbox and Toggle). Pass `value` to control one, or `defaultValue` to let it keep its own. Give a control a `name` and it's submitted with its form, the custom ones (Combobox, the date pickers, MoneyInput, ColorPicker, TagInput…) included, and goes back to its first value when the form is reset.
@@ -1,14 +1,14 @@
1
1
  "use client";
2
- import { cx as e } from "../utils/cx.js";
3
- import { useLocale as t } from "../locale-provider/index.js";
2
+ import { useLocale as e } from "../locale-provider/index.js";
3
+ import { cx as t } from "../utils/cx.js";
4
4
  import { formatMoney as n } from "../utils/money.js";
5
5
  import { reducedMotion as r } from "../utils/motion.js";
6
6
  import { useEffect as i, useLayoutEffect as a, useRef as o, useState as s } from "react";
7
7
  import { jsx as c, jsxs as l } from "react/jsx-runtime";
8
8
  //#region packages/animated-number/index.tsx
9
9
  var u = typeof window > "u" ? i : a, d = (e) => 1 - (1 - e) ** 3;
10
- function f({ value: t, format: n = String, duration: a = 650, fromZero: f = !0, roll: p = !1, className: h }) {
11
- let [g, _] = s(f ? 0 : t), v = o(f ? 0 : t), [y, b] = s(!f);
10
+ function f({ value: e, format: n = String, duration: a = 650, fromZero: f = !0, roll: p = !1, className: h }) {
11
+ let [g, _] = s(f ? 0 : e), v = o(f ? 0 : e), [y, b] = s(!f);
12
12
  if (i(() => {
13
13
  if (!p || y) return;
14
14
  let e = requestAnimationFrame(() => b(!0));
@@ -16,22 +16,22 @@ function f({ value: t, format: n = String, duration: a = 650, fromZero: f = !0,
16
16
  }, [p, y]), u(() => {
17
17
  if (p) return;
18
18
  if (r() || a <= 0) {
19
- v.current = t, _(t);
19
+ v.current = e, _(e);
20
20
  return;
21
21
  }
22
- let e = v.current, n = performance.now(), i = requestAnimationFrame(function r(o) {
23
- let s = Math.min(1, (o - n) / a), c = Math.round(e + (t - e) * d(s));
22
+ let t = v.current, n = performance.now(), i = requestAnimationFrame(function r(o) {
23
+ let s = Math.min(1, (o - n) / a), c = Math.round(t + (e - t) * d(s));
24
24
  v.current = c, _(c), s < 1 && (i = requestAnimationFrame(r));
25
25
  });
26
26
  return () => cancelAnimationFrame(i);
27
27
  }, [
28
- t,
28
+ e,
29
29
  a,
30
30
  p
31
31
  ]), p) {
32
- let r = n(t);
32
+ let r = n(e);
33
33
  return /* @__PURE__ */ l("span", {
34
- className: e("zen__animated-number inline-flex items-start tabular-nums", h),
34
+ className: t("zen__animated-number inline-flex items-start tabular-nums", h),
35
35
  children: [/* @__PURE__ */ c("span", {
36
36
  className: "sr-only",
37
37
  children: r
@@ -46,7 +46,7 @@ function f({ value: t, format: n = String, duration: a = 650, fromZero: f = !0,
46
46
  });
47
47
  }
48
48
  return /* @__PURE__ */ c("span", {
49
- className: e("zen__animated-number tabular-nums", h),
49
+ className: t("zen__animated-number tabular-nums", h),
50
50
  children: n(g)
51
51
  });
52
52
  }
@@ -75,10 +75,10 @@ function m({ digit: e, duration: t }) {
75
75
  })
76
76
  });
77
77
  }
78
- function h({ value: e, currency: r, locale: i, showDecimals: a = !1, ...o }) {
79
- let s = t(i);
78
+ function h({ value: t, currency: r, locale: i, showDecimals: a = !1, ...o }) {
79
+ let s = e(i);
80
80
  return /* @__PURE__ */ c(f, {
81
- value: e,
81
+ value: t,
82
82
  format: (e) => n(e, r, s, { showDecimals: a }),
83
83
  ...o
84
84
  });
@@ -1,37 +1,37 @@
1
1
  "use client";
2
- import e from "../icons/micro/chevron-right.js";
3
- import { cx as t } from "../utils/cx.js";
4
- import { Slot as n } from "../utils/slot.js";
5
- import { useMessages as r } from "../locale-provider/index.js";
2
+ import { useMessages as e } from "../locale-provider/index.js";
3
+ import t from "../icons/micro/chevron-right.js";
4
+ import { cx as n } from "../utils/cx.js";
5
+ import { Slot as r } from "../utils/slot.js";
6
6
  import { Children as i, Fragment as a, isValidElement as o } from "react";
7
7
  import { jsx as s, jsxs as c } from "react/jsx-runtime";
8
8
  //#region packages/breadcrumbs/index.tsx
9
- function l({ className: n, children: l, "aria-label": u, ...d }) {
10
- let f = r(), p = u ?? f.breadcrumb, m = i.toArray(l).filter(o);
9
+ function l({ className: r, children: l, "aria-label": u, ...d }) {
10
+ let f = e(), p = u ?? f.breadcrumb, m = i.toArray(l).filter(o);
11
11
  return /* @__PURE__ */ s("nav", {
12
12
  "aria-label": p,
13
- className: t("zen__breadcrumbs", n),
13
+ className: n("zen__breadcrumbs", r),
14
14
  ...d,
15
15
  children: /* @__PURE__ */ s("ol", {
16
16
  className: "text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm",
17
- children: m.map((t, n) => /* @__PURE__ */ c(a, { children: [n > 0 && /* @__PURE__ */ s("li", {
17
+ children: m.map((e, n) => /* @__PURE__ */ c(a, { children: [n > 0 && /* @__PURE__ */ s("li", {
18
18
  "aria-hidden": !0,
19
19
  className: "text-muted-foreground/60 flex",
20
- children: /* @__PURE__ */ s(e, { className: "size-3.5 rtl:-scale-x-100" })
20
+ children: /* @__PURE__ */ s(t, { className: "size-3.5 rtl:-scale-x-100" })
21
21
  }), /* @__PURE__ */ s("li", {
22
22
  className: "flex min-w-0",
23
- children: t
24
- })] }, t.key ?? n))
23
+ children: e
24
+ })] }, e.key ?? n))
25
25
  })
26
26
  });
27
27
  }
28
- function u({ current: e, asChild: r, className: i, ...a }) {
29
- let o = t("truncate rounded-sm outline-hidden transition-colors focus-ring", e ? "text-foreground font-medium" : "hover:text-foreground touch-target", i);
28
+ function u({ current: e, asChild: t, className: i, ...a }) {
29
+ let o = n("truncate rounded-sm outline-hidden transition-colors focus-ring", e ? "text-foreground font-medium" : "hover:text-foreground touch-target", i);
30
30
  return e ? /* @__PURE__ */ s("span", {
31
31
  "aria-current": "page",
32
32
  className: o,
33
33
  ...a
34
- }) : s(r ? n : "a", {
34
+ }) : s(t ? r : "a", {
35
35
  className: o,
36
36
  ...a
37
37
  });
@@ -1,8 +1,8 @@
1
1
  "use client";
2
- import { cx as e } from "../utils/cx.js";
3
- import { readingKey as t } from "../utils/direction.js";
4
- import { useControllable as n } from "../utils/useControllable.js";
5
- import { useLocale as r, useMessages as i } from "../locale-provider/index.js";
2
+ import { useLocale as e, useMessages as t } from "../locale-provider/index.js";
3
+ import { cx as n } from "../utils/cx.js";
4
+ import { readingKey as r } from "../utils/direction.js";
5
+ import { useControllable as i } from "../utils/useControllable.js";
6
6
  import { PICKER_MONTH as a, PICKER_NAV as o } from "../utils/styles.js";
7
7
  import s from "../icons/chevron-left.js";
8
8
  import c from "../icons/chevron-right.js";
@@ -13,7 +13,7 @@ import { useEffect as ae, useId as oe, useRef as _, useState as v } from "react"
13
13
  import { jsx as y, jsxs as b } from "react/jsx-runtime";
14
14
  //#region packages/calendar/index.tsx
15
15
  function se(se) {
16
- let { locale: le, min: x, max: S, isDisabled: ue, weekStartsOn: de, months: C = 1, defaultMonth: fe, className: w, autoFocus: pe, mode: T, value: me, defaultValue: he = null, onValueChange: ge, ...E } = se, D = r(le), _e = new Intl.NumberFormat(D), O = i(), k = de ?? re(D), [A, j] = n(me, he, ge), M = T === "range" ? A : null, N = T === "range" ? null : A, P = N ?? M?.start ?? null, F = ne(), I = ie() ? F : null, [L, R] = v(() => fe ?? (P ?? F).slice(0, 7)), [z, B] = v(() => P ?? F), [V, H] = v(null), [U, W] = v("days"), [G, K] = v(() => Number(L.slice(0, 4))), q = _(null), J = _(pe ?? !1), ve = oe(), ye = l(L, C - 1), be = (e) => e.slice(0, 7) >= L && e.slice(0, 7) <= ye, xe = (e) => !!x && e < x || !!S && e > S || !!ue?.(e), Y = be(z) ? z : m(z, f(z.slice(0, 7), L));
16
+ let { locale: le, min: x, max: S, isDisabled: ue, weekStartsOn: de, months: C = 1, defaultMonth: fe, className: w, autoFocus: pe, mode: T, value: me, defaultValue: he = null, onValueChange: ge, ...E } = se, D = e(le), _e = new Intl.NumberFormat(D), O = t(), k = de ?? re(D), [A, j] = i(me, he, ge), M = T === "range" ? A : null, N = T === "range" ? null : A, P = N ?? M?.start ?? null, F = ne(), I = ie() ? F : null, [L, R] = v(() => fe ?? (P ?? F).slice(0, 7)), [z, B] = v(() => P ?? F), [V, H] = v(null), [U, W] = v("days"), [G, K] = v(() => Number(L.slice(0, 4))), q = _(null), J = _(pe ?? !1), ve = oe(), ye = l(L, C - 1), be = (e) => e.slice(0, 7) >= L && e.slice(0, 7) <= ye, xe = (e) => !!x && e < x || !!S && e > S || !!ue?.(e), Y = be(z) ? z : m(z, f(z.slice(0, 7), L));
17
17
  ae(() => {
18
18
  J.current && (J.current = !1, q.current?.querySelector(`[data-date="${Y}"]`)?.focus());
19
19
  }, [Y, U]);
@@ -36,16 +36,16 @@ function se(se) {
36
36
  } else j(e);
37
37
  }
38
38
  }, we = (e) => {
39
- let n = Y, r = (h(n) - k + 7) % 7, i = {
40
- ArrowLeft: p(n, -1),
41
- ArrowRight: p(n, 1),
42
- ArrowUp: p(n, -7),
43
- ArrowDown: p(n, 7),
44
- Home: p(n, -r),
45
- End: p(n, 6 - r),
46
- PageUp: m(n, e.shiftKey ? -12 : -1),
47
- PageDown: m(n, e.shiftKey ? 12 : 1)
48
- }[t(e.key, e.currentTarget)];
39
+ let t = Y, n = (h(t) - k + 7) % 7, i = {
40
+ ArrowLeft: p(t, -1),
41
+ ArrowRight: p(t, 1),
42
+ ArrowUp: p(t, -7),
43
+ ArrowDown: p(t, 7),
44
+ Home: p(t, -n),
45
+ End: p(t, 6 - n),
46
+ PageUp: m(t, e.shiftKey ? -12 : -1),
47
+ PageDown: m(t, e.shiftKey ? 12 : 1)
48
+ }[r(e.key, e.currentTarget)];
49
49
  i && (e.preventDefault(), Se(i));
50
50
  }, X = M && M.end === null ? M.start : null, Te = X && V ? V < X ? [V, X] : [X, V] : null, [Z, Q] = M?.end ? [M.start, M.end] : Te ?? [null, null], Ee = (e) => {
51
51
  R((t) => l(t, e));
@@ -80,16 +80,16 @@ function se(se) {
80
80
  ]
81
81
  });
82
82
  if (U === "months") {
83
- let t = d(D);
83
+ let e = d(D);
84
84
  return /* @__PURE__ */ b("div", {
85
- className: e("zen__calendar w-fit", w),
85
+ className: n("zen__calendar w-fit", w),
86
86
  ...E,
87
87
  children: [$, /* @__PURE__ */ y("div", {
88
88
  className: "grid w-64 grid-cols-3 gap-1",
89
89
  role: "group",
90
90
  "aria-labelledby": ve,
91
- children: t.map((t, n) => {
92
- let r = `${G}-${String(n + 1).padStart(2, "0")}`, i = !!x && r < x.slice(0, 7) || !!S && r > S.slice(0, 7);
91
+ children: e.map((e, t) => {
92
+ let r = `${G}-${String(t + 1).padStart(2, "0")}`, i = !!x && r < x.slice(0, 7) || !!S && r > S.slice(0, 7);
93
93
  return /* @__PURE__ */ y("button", {
94
94
  type: "button",
95
95
  disabled: i,
@@ -98,8 +98,8 @@ function se(se) {
98
98
  onClick: () => {
99
99
  R(r), J.current = !0, B(m(z, f(z.slice(0, 7), r))), W("days");
100
100
  },
101
- className: e(a, r === L && "bg-primary text-primary-foreground hover:bg-primary"),
102
- children: t
101
+ className: n(a, r === L && "bg-primary text-primary-foreground hover:bg-primary"),
102
+ children: e
103
103
  }, r);
104
104
  })
105
105
  })]
@@ -107,15 +107,15 @@ function se(se) {
107
107
  }
108
108
  let De = g(D, "narrow"), Oe = g(D, "long"), ke = Array.from({ length: 7 }, (e, t) => (k + t) % 7);
109
109
  return /* @__PURE__ */ b("div", {
110
- className: e("zen__calendar w-fit", w),
110
+ className: n("zen__calendar w-fit", w),
111
111
  ...E,
112
112
  children: [$, /* @__PURE__ */ y("div", {
113
113
  ref: q,
114
114
  className: "flex gap-4",
115
115
  onKeyDown: we,
116
116
  onMouseLeave: () => H(null),
117
- children: Array.from({ length: C }, (t, n) => {
118
- let r = l(L, n), i = `${r}-01`, a = `${r}-${ee(r)}`, o = p(i, -((h(i) - k + 7) % 7));
117
+ children: Array.from({ length: C }, (e, t) => {
118
+ let r = l(L, t), i = `${r}-01`, a = `${r}-${ee(r)}`, o = p(i, -((h(i) - k + 7) % 7));
119
119
  return /* @__PURE__ */ b("table", {
120
120
  role: "grid",
121
121
  "aria-label": u(r, D, "long"),
@@ -131,14 +131,14 @@ function se(se) {
131
131
  className: "text-muted-foreground size-9 text-xs font-medium",
132
132
  children: De[e]
133
133
  }, e)) }) }),
134
- /* @__PURE__ */ y("tbody", { children: Array.from({ length: 6 }, (t, n) => /* @__PURE__ */ y("tr", { children: Array.from({ length: 7 }, (t, s) => {
135
- let c = p(o, n * 7 + s), l = c.slice(0, 7) === r;
134
+ /* @__PURE__ */ y("tbody", { children: Array.from({ length: 6 }, (e, t) => /* @__PURE__ */ y("tr", { children: Array.from({ length: 7 }, (e, s) => {
135
+ let c = p(o, t * 7 + s), l = c.slice(0, 7) === r;
136
136
  if (!l && C > 1) return /* @__PURE__ */ y("td", { role: "gridcell" }, c);
137
137
  let u = c === Z, d = c === Q, f = !!Z && !!Q && c > Z && c < Q, m = c === N || c === M?.start || c === M?.end, h = xe(c);
138
138
  return /* @__PURE__ */ y("td", {
139
139
  role: "gridcell",
140
140
  "aria-selected": m || f || void 0,
141
- className: e("p-0", (f || (u || d) && Z !== Q) && "bg-primary/15", u && "rounded-s-lg", d && "rounded-e-lg", f && (s === 0 || C > 1 && c === i) && "rounded-s-lg", f && (s === 6 || C > 1 && c === a) && "rounded-e-lg"),
141
+ className: n("p-0", (f || (u || d) && Z !== Q) && "bg-primary/15", u && "rounded-s-lg", d && "rounded-e-lg", f && (s === 0 || C > 1 && c === i) && "rounded-s-lg", f && (s === 6 || C > 1 && c === a) && "rounded-e-lg"),
142
142
  children: /* @__PURE__ */ y("button", {
143
143
  type: "button",
144
144
  "data-date": c,
@@ -152,11 +152,11 @@ function se(se) {
152
152
  B(c), X && H(c);
153
153
  },
154
154
  onMouseEnter: () => X && H(c),
155
- className: e(ce, !l && "text-muted-foreground", h && "cursor-not-allowed opacity-35", m ? "bg-primary text-primary-foreground shadow-[0_0_20px_-4px_oklch(var(--glow)/calc(0.8*var(--glow-k)))]" : !h && "hover:bg-tint/[0.08]", c === I && "after:bg-primary after:absolute after:bottom-1 after:left-1/2 after:size-1 after:-translate-x-1/2 after:rounded-full", c === I && m && "after:bg-primary-foreground"),
155
+ className: n(ce, !l && "text-muted-foreground", h && "cursor-not-allowed opacity-35", m ? "bg-primary text-primary-foreground shadow-[0_0_20px_-4px_oklch(var(--glow)/calc(0.8*var(--glow-k)))]" : !h && "hover:bg-tint/[0.08]", c === I && "after:bg-primary after:absolute after:bottom-1 after:left-1/2 after:size-1 after:-translate-x-1/2 after:rounded-full", c === I && m && "after:bg-primary-foreground"),
156
156
  children: _e.format(Number(c.slice(8)))
157
157
  })
158
158
  }, c);
159
- }) }, n)) })
159
+ }) }, t)) })
160
160
  ]
161
161
  }, r);
162
162
  })
@@ -1,28 +1,28 @@
1
1
  "use client";
2
- import { cx as e } from "../utils/cx.js";
3
- import { useLocale as t } from "../locale-provider/index.js";
2
+ import { useLocale as e } from "../locale-provider/index.js";
3
+ import { cx as t } from "../utils/cx.js";
4
4
  import { formatMonth as n } from "../utils/month.js";
5
5
  import { dayOfWeek as r, daysInMonth as i, formatDate as a, weekStart as o, weekdayNames as s } from "../utils/date.js";
6
6
  import { Fragment as c, jsx as l, jsxs as u } from "react/jsx-runtime";
7
7
  //#region packages/calendar-heatmap/index.tsx
8
8
  function d({ month: d, values: f, locale: p, format: m = String, weekStartsOn: h, onSelectedChange: g, selected: _, label: v, className: y, ...b }) {
9
- let x = t(p), S = new Intl.NumberFormat(x), C = h ?? o(x), w = i(d), T = Array.from({ length: w }, (e, t) => `${d}-${String(t + 1).padStart(2, "0")}`), E = (r(T[0]) - C + 7) % 7, D = [...Array(E).fill(null), ...T];
9
+ let x = e(p), S = new Intl.NumberFormat(x), C = h ?? o(x), w = i(d), T = Array.from({ length: w }, (e, t) => `${d}-${String(t + 1).padStart(2, "0")}`), E = (r(T[0]) - C + 7) % 7, D = [...Array(E).fill(null), ...T];
10
10
  for (; D.length % 7;) D.push(null);
11
11
  let O = Array.from({ length: D.length / 7 }, (e, t) => D.slice(t * 7, t * 7 + 7)), k = s(x, "narrow"), A = s(x, "long"), j = Array.from({ length: 7 }, (e, t) => (C + t) % 7), M = Math.max(0, ...T.map((e) => f[e] ?? 0));
12
12
  return /* @__PURE__ */ u("table", {
13
13
  "aria-label": v ?? n(d, x, "long"),
14
14
  ...b,
15
- className: e("zen__calendar-heatmap w-full table-fixed border-separate border-spacing-1", y),
15
+ className: t("zen__calendar-heatmap w-full table-fixed border-separate border-spacing-1", y),
16
16
  children: [/* @__PURE__ */ l("thead", { children: /* @__PURE__ */ l("tr", { children: j.map((e) => /* @__PURE__ */ l("th", {
17
17
  scope: "col",
18
18
  abbr: A[e],
19
19
  className: "text-muted-foreground pb-1 text-xs font-normal",
20
20
  children: k[e]
21
- }, e)) }) }), /* @__PURE__ */ l("tbody", { children: O.map((t, n) => /* @__PURE__ */ l("tr", { children: t.map((t, n) => {
22
- if (!t) return /* @__PURE__ */ l("td", {}, n);
23
- let r = f[t], i = M > 0 && r ? Math.sqrt(r / M) : 0, o = `${a(t, x, "day")}: ${m(r || 0)}`, s = e("relative grid aspect-square w-full place-items-center rounded-md text-[0.65rem] tabular-nums transition-[box-shadow]", i ? i > .6 ? "text-primary-foreground" : "text-foreground/80" : "bg-tint/[0.04] text-muted-foreground", t === _ && "ring-ring ring-2"), d = i ? { background: `oklch(var(--primary) / ${+(.14 + .81 * i).toFixed(2)})` } : void 0, p = /* @__PURE__ */ u(c, { children: [/* @__PURE__ */ l("span", {
21
+ }, e)) }) }), /* @__PURE__ */ l("tbody", { children: O.map((e, n) => /* @__PURE__ */ l("tr", { children: e.map((e, n) => {
22
+ if (!e) return /* @__PURE__ */ l("td", {}, n);
23
+ let r = f[e], i = M > 0 && r ? Math.sqrt(r / M) : 0, o = `${a(e, x, "day")}: ${m(r || 0)}`, s = t("relative grid aspect-square w-full place-items-center rounded-md text-[0.65rem] tabular-nums transition-[box-shadow]", i ? i > .6 ? "text-primary-foreground" : "text-foreground/80" : "bg-tint/[0.04] text-muted-foreground", e === _ && "ring-ring ring-2"), d = i ? { background: `oklch(var(--primary) / ${+(.14 + .81 * i).toFixed(2)})` } : void 0, p = /* @__PURE__ */ u(c, { children: [/* @__PURE__ */ l("span", {
24
24
  "aria-hidden": !0,
25
- children: S.format(Number(t.slice(8)))
25
+ children: S.format(Number(e.slice(8)))
26
26
  }), /* @__PURE__ */ l("span", {
27
27
  className: "sr-only",
28
28
  children: o
@@ -32,9 +32,9 @@ function d({ month: d, values: f, locale: p, format: m = String, weekStartsOn: h
32
32
  className: "p-0",
33
33
  children: g ? /* @__PURE__ */ l("button", {
34
34
  type: "button",
35
- "aria-pressed": t === _,
36
- onClick: () => g(t),
37
- className: e(s, " cursor-pointer outline-hidden hover:shadow-[0_0_0_1px_oklch(var(--tint)/0.3)] focus-ring"),
35
+ "aria-pressed": e === _,
36
+ onClick: () => g(e),
37
+ className: t(s, " cursor-pointer outline-hidden hover:shadow-[0_0_0_1px_oklch(var(--tint)/0.3)] focus-ring"),
38
38
  style: d,
39
39
  children: p
40
40
  }) : /* @__PURE__ */ l("span", {
@@ -42,7 +42,7 @@ function d({ month: d, values: f, locale: p, format: m = String, weekStartsOn: h
42
42
  style: d,
43
43
  children: p
44
44
  })
45
- }, t);
45
+ }, e);
46
46
  }) }, n)) })]
47
47
  });
48
48
  }
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- import { cx as e } from "../utils/cx.js";
3
- import { useMergedRefs as t } from "../utils/refs.js";
4
- import { useMessages as n } from "../locale-provider/index.js";
2
+ import { useMessages as e } from "../locale-provider/index.js";
3
+ import { cx as t } from "../utils/cx.js";
4
+ import { useMergedRefs as n } from "../utils/refs.js";
5
5
  import { boundsOf as r, intersects as i, moveRect as a, resizeRect as o } from "./geometry.js";
6
6
  import { createContext as s, useContext as c, useEffect as l, useId as u, useLayoutEffect as d, useRef as f, useState as p } from "react";
7
7
  import { jsx as m, jsxs as h } from "react/jsx-runtime";
@@ -31,7 +31,7 @@ var g = typeof window > "u" ? l : d, _ = 3, ee = "input, textarea, select, butto
31
31
  ArrowDown: [0, 1]
32
32
  }, x = (e, t) => e.x === t.x && e.y === t.y && e.w === t.w && e.h === t.h, S = (e, t) => e.length === t.length && e.every((e, n) => e === t[n]), C = s(null);
33
33
  function w({ width: s, height: c, scale: l = 1, items: d, onItemsChange: v, onItemsChangeEnd: y, selected: w = [], onSelectedChange: T, minSize: E = 8, snap: D = !1, grid: O, className: te, style: ne, children: re, onPointerDown: ie, ref: ae, ...k }) {
34
- let A = n(), j = f(null), oe = t(j, ae), M = f(!1), [N, se] = p(null), [ce, P] = p([]), [F, I] = p(null), [L, R] = p(null), [le, z] = p(!1), [B, V] = p(""), H = u();
34
+ let A = e(), j = f(null), oe = n(j, ae), M = f(!1), [N, se] = p(null), [ce, P] = p([]), [F, I] = p(null), [L, R] = p(null), [le, z] = p(!1), [B, V] = p(""), H = u();
35
35
  g(() => {
36
36
  let e = j.current;
37
37
  if (l !== "fit" || !e) return;
@@ -190,7 +190,7 @@ function w({ width: s, height: c, scale: l = 1, items: d, onItemsChange: v, onIt
190
190
  height: c * U
191
191
  }
192
192
  },
193
- className: e("zen__canvas bg-tint/[0.03] relative shrink-0 overflow-hidden rounded-lg shadow-[inset_0_0_0_1px_oklch(var(--tint)/0.08)] select-none", te),
193
+ className: t("zen__canvas bg-tint/[0.03] relative shrink-0 overflow-hidden rounded-lg shadow-[inset_0_0_0_1px_oklch(var(--tint)/0.08)] select-none", te),
194
194
  children: [/* @__PURE__ */ m("div", {
195
195
  style: {
196
196
  width: s,
@@ -198,7 +198,7 @@ function w({ width: s, height: c, scale: l = 1, items: d, onItemsChange: v, onIt
198
198
  scale: String(U),
199
199
  "--canvas-scale": U
200
200
  },
201
- className: e("absolute top-0 left-0 origin-top-left", l === "fit" && N === null && "invisible"),
201
+ className: t("absolute top-0 left-0 origin-top-left", l === "fit" && N === null && "invisible"),
202
202
  children: re
203
203
  }), /* @__PURE__ */ h("div", {
204
204
  "aria-hidden": !0,
@@ -260,30 +260,30 @@ function w({ width: s, height: c, scale: l = 1, items: d, onItemsChange: v, onIt
260
260
  ]
261
261
  });
262
262
  }
263
- function T({ id: t, label: n, className: r, style: i, children: a, ...o }) {
263
+ function T({ id: e, label: n, className: r, style: i, children: a, ...o }) {
264
264
  let s = c(C);
265
265
  if (!s) throw Error("<CanvasItem> must be inside <Canvas>");
266
- let l = s.item(t);
266
+ let l = s.item(e);
267
267
  if (!l) return null;
268
- let u = s.selected.includes(t), d = u && s.selected.length === 1;
268
+ let u = s.selected.includes(e), d = u && s.selected.length === 1;
269
269
  return /* @__PURE__ */ h("div", {
270
270
  role: "group",
271
271
  "aria-roledescription": l.locked ? "locked item" : "movable item",
272
272
  "aria-label": n,
273
273
  "aria-describedby": l.locked ? void 0 : s.hintId,
274
274
  tabIndex: 0,
275
- "data-canvas-id": t,
275
+ "data-canvas-id": e,
276
276
  "data-selected": u || void 0,
277
277
  "data-locked": l.locked || void 0,
278
278
  ...o,
279
- onFocus: (e) => {
280
- o.onFocus?.(e), e.target === e.currentTarget && s.focus(t);
279
+ onFocus: (t) => {
280
+ o.onFocus?.(t), t.target === t.currentTarget && s.focus(e);
281
281
  },
282
- onPointerDown: (e) => {
283
- o.onPointerDown?.(e), s.grab(e, t, n);
282
+ onPointerDown: (t) => {
283
+ o.onPointerDown?.(t), s.grab(t, e, n);
284
284
  },
285
- onKeyDown: (e) => {
286
- o.onKeyDown?.(e), s.key(e, t, n);
285
+ onKeyDown: (t) => {
286
+ o.onKeyDown?.(t), s.key(t, e, n);
287
287
  },
288
288
  style: {
289
289
  ...i,
@@ -292,12 +292,12 @@ function T({ id: t, label: n, className: r, style: i, children: a, ...o }) {
292
292
  width: l.w,
293
293
  height: l.h
294
294
  },
295
- className: e("zen__canvas-item absolute cursor-move touch-none outline-hidden data-locked:cursor-default data-locked:touch-auto", "[outline-offset:calc(1px/var(--canvas-scale))]", "not-data-selected:hover:outline-solid not-data-selected:hover:outline-[length:calc(1px/var(--canvas-scale))] not-data-selected:hover:outline-[color:oklch(var(--tint)/0.35)]", "data-selected:outline-solid data-selected:outline-[length:calc(2px/var(--canvas-scale))] data-selected:outline-[color:oklch(var(--primary)/0.8)]", "focus-visible:outline-solid focus-visible:outline-[length:calc(2px/var(--canvas-scale))] focus-visible:outline-[color:oklch(var(--ring)/0.7)]", r),
295
+ className: t("zen__canvas-item absolute cursor-move touch-none outline-hidden data-locked:cursor-default data-locked:touch-auto", "[outline-offset:calc(1px/var(--canvas-scale))]", "not-data-selected:hover:outline-solid not-data-selected:hover:outline-[length:calc(1px/var(--canvas-scale))] not-data-selected:hover:outline-[color:oklch(var(--tint)/0.35)]", "data-selected:outline-solid data-selected:outline-[length:calc(2px/var(--canvas-scale))] data-selected:outline-[color:oklch(var(--primary)/0.8)]", "focus-visible:outline-solid focus-visible:outline-[length:calc(2px/var(--canvas-scale))] focus-visible:outline-[color:oklch(var(--ring)/0.7)]", r),
296
296
  children: [a, d && !l.locked && v.map((r) => /* @__PURE__ */ m("span", {
297
297
  "aria-hidden": !0,
298
298
  "data-handle": r,
299
- onPointerDown: (e) => s.grab(e, t, n, r),
300
- className: e("bg-foreground absolute z-10 size-[calc(10px/var(--canvas-scale))] -translate-1/2 rounded-full border-[length:calc(2px/var(--canvas-scale))] border-[color:oklch(var(--primary))] shadow-[0_0_8px_oklch(var(--glow)/0.6)]", "after:absolute after:-inset-[calc(6px/var(--canvas-scale))] pointer-coarse:after:-inset-[calc(14px/var(--canvas-scale))]", y[r])
299
+ onPointerDown: (t) => s.grab(t, e, n, r),
300
+ className: t("bg-foreground absolute z-10 size-[calc(10px/var(--canvas-scale))] -translate-1/2 rounded-full border-[length:calc(2px/var(--canvas-scale))] border-[color:oklch(var(--primary))] shadow-[0_0_8px_oklch(var(--glow)/0.6)]", "after:absolute after:-inset-[calc(6px/var(--canvas-scale))] pointer-coarse:after:-inset-[calc(14px/var(--canvas-scale))]", y[r])
301
301
  }, r))]
302
302
  });
303
303
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../packages/carousel/index.tsx"],"names":[],"mappings":"AAMA,OAAO,EACH,cAAc,EASjB,MAAM,OAAO,CAAC;AA8Bf;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,EAAE,aAAa,+BAoE/E;AAED,mCAAmC;AACnC,wBAAgB,eAAe,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,cAAc,CAAC,KAAK,CAAC,+BAiBjF;AAED,sDAAsD;AACtD,wBAAgB,YAAY,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,cAAc,CAAC,KAAK,CAAC,+BAoB9E;AAKD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,cAAc,CAAC,QAAQ,CAAC,+BAoBzF;AAED,mEAAmE;AACnE,wBAAgB,YAAY,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,cAAc,CAAC,QAAQ,CAAC,+BAmBrF;AAED,sGAAsG;AACtG,wBAAgB,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,cAAc,CAAC,KAAK,CAAC,sCA6BzE;AAED,8GAA8G;AAC9G,wBAAgB,gBAAgB,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,cAAc,CAAC,KAAK,CAAC,+BAE7E;AAED,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../packages/carousel/index.tsx"],"names":[],"mappings":"AAMA,OAAO,EACH,cAAc,EASjB,MAAM,OAAO,CAAC;AA8Bf;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,EAAE,aAAa,+BA0E/E;AAED,mCAAmC;AACnC,wBAAgB,eAAe,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,cAAc,CAAC,KAAK,CAAC,+BAiBjF;AAED,sDAAsD;AACtD,wBAAgB,YAAY,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,cAAc,CAAC,KAAK,CAAC,+BAoB9E;AAKD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,cAAc,CAAC,QAAQ,CAAC,+BAoBzF;AAED,mEAAmE;AACnE,wBAAgB,YAAY,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,cAAc,CAAC,QAAQ,CAAC,+BAmBrF;AAED,sGAAsG;AACtG,wBAAgB,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,cAAc,CAAC,KAAK,CAAC,sCA6BzE;AAED,8GAA8G;AAC9G,wBAAgB,gBAAgB,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,cAAc,CAAC,KAAK,CAAC,+BAE7E;AAED,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC"}