@muten/shadcn 0.0.5 → 0.1.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 (213) hide show
  1. package/AGENTS.md +61 -6
  2. package/README.md +57 -4
  3. package/globals.css +30 -2
  4. package/kit.css +2763 -0
  5. package/motion.css +79 -0
  6. package/nova.css +1387 -0
  7. package/package.json +10 -2
  8. package/registry/accordion.muten +11 -10
  9. package/registry/agenda.js +35 -0
  10. package/registry/agenda.muten +10 -0
  11. package/registry/alert-dialog.muten +9 -12
  12. package/registry/alert.muten +8 -8
  13. package/registry/app-shell.js +9 -0
  14. package/registry/app-shell.muten +12 -0
  15. package/registry/attachment.muten +13 -9
  16. package/registry/avatar.muten +24 -5
  17. package/registry/badge.muten +23 -8
  18. package/registry/band.muten +16 -0
  19. package/registry/bar-chart.muten +7 -0
  20. package/registry/bell.muten +3 -0
  21. package/registry/bento.muten +6 -9
  22. package/registry/booking.js +21 -0
  23. package/registry/booking.muten +13 -0
  24. package/registry/breadcrumb.muten +9 -7
  25. package/registry/button-group.muten +13 -4
  26. package/registry/button.muten +21 -8
  27. package/registry/calendar.js +28 -93
  28. package/registry/calendar.muten +9 -8
  29. package/registry/canvas-viewport.js +12 -5
  30. package/registry/canvas-viewport.muten +9 -9
  31. package/registry/card-field.muten +4 -0
  32. package/registry/card.muten +12 -8
  33. package/registry/carousel.js +5 -36
  34. package/registry/carousel.muten +12 -5
  35. package/registry/chatbot.muten +9 -0
  36. package/registry/checklist.muten +6 -0
  37. package/registry/choice-list.muten +16 -0
  38. package/registry/code.js +14 -12
  39. package/registry/code.muten +6 -7
  40. package/registry/collapsible.muten +14 -10
  41. package/registry/color-picker.js +460 -41
  42. package/registry/color-picker.muten +7 -6
  43. package/registry/combobox.js +5 -0
  44. package/registry/combobox.muten +6 -23
  45. package/registry/command-palette.muten +8 -12
  46. package/registry/command.js +32 -0
  47. package/registry/command.muten +32 -11
  48. package/registry/context-menu.muten +9 -8
  49. package/registry/count-up.muten +5 -10
  50. package/registry/date-field.js +5 -0
  51. package/registry/date-field.muten +7 -0
  52. package/registry/device-frame.muten +8 -0
  53. package/registry/dialog.muten +6 -12
  54. package/registry/dirty-bar.js +19 -0
  55. package/registry/dirty-bar.muten +13 -0
  56. package/registry/drawer.muten +6 -11
  57. package/registry/dropdown-menu.muten +37 -13
  58. package/registry/empty.muten +11 -7
  59. package/registry/feature-grid.muten +10 -12
  60. package/registry/feature-rows.muten +12 -8
  61. package/registry/field-behavior.js +33 -0
  62. package/registry/field-behavior.muten +9 -0
  63. package/registry/field.muten +26 -7
  64. package/registry/file-input.js +36 -21
  65. package/registry/file-input.muten +8 -7
  66. package/registry/fixed-card.muten +25 -0
  67. package/registry/folder-picker.js +13 -15
  68. package/registry/folder-picker.muten +5 -8
  69. package/registry/gradient-blinds.muten +6 -13
  70. package/registry/hover-card.muten +7 -9
  71. package/registry/image-upload.js +5 -0
  72. package/registry/image-upload.muten +8 -0
  73. package/registry/indicator.muten +5 -0
  74. package/registry/input-group.muten +27 -4
  75. package/registry/input-otp.js +8 -35
  76. package/registry/input-otp.muten +6 -6
  77. package/registry/input.muten +8 -7
  78. package/registry/inspector.muten +13 -15
  79. package/registry/island.js +7 -0
  80. package/registry/island.muten +5 -0
  81. package/registry/item.muten +20 -7
  82. package/registry/kbd.muten +3 -3
  83. package/registry/kit/board.js +300 -0
  84. package/registry/kit/collections.js +148 -0
  85. package/registry/kit/core.js +989 -0
  86. package/registry/kit/dates.js +106 -0
  87. package/registry/kit/menus.js +90 -0
  88. package/registry/kit/overlays.js +114 -0
  89. package/registry/kit/paint.js +211 -0
  90. package/registry/kit/qrcode.js +2291 -0
  91. package/registry/kit/structure.js +393 -0
  92. package/registry/kit/table.js +198 -0
  93. package/registry/kit/values.js +179 -0
  94. package/registry/kit-layer.js +2 -0
  95. package/registry/kit-layer.muten +5 -0
  96. package/registry/kit-skeleton.js +24 -0
  97. package/registry/kit-skeleton.muten +16 -0
  98. package/registry/kit-widget.js +79 -0
  99. package/registry/kit-widget.muten +4 -0
  100. package/registry/link-btn.muten +9 -7
  101. package/registry/live-stack.js +29 -0
  102. package/registry/live-stack.muten +7 -0
  103. package/registry/logo-cloud.muten +6 -11
  104. package/registry/member-list.muten +6 -0
  105. package/registry/menubar.muten +10 -14
  106. package/registry/message-scroller.js +12 -0
  107. package/registry/message-scroller.muten +8 -4
  108. package/registry/message.muten +27 -10
  109. package/registry/messaging.muten +11 -0
  110. package/registry/modal-behavior.js +56 -0
  111. package/registry/modal-behavior.muten +4 -0
  112. package/registry/modal.muten +29 -0
  113. package/registry/money-field.js +5 -0
  114. package/registry/money-field.muten +7 -0
  115. package/registry/nav-button.muten +14 -0
  116. package/registry/navigation-menu.muten +16 -14
  117. package/registry/navpill.muten +15 -9
  118. package/registry/new-appointment.js +8 -0
  119. package/registry/new-appointment.muten +10 -0
  120. package/registry/number-field.js +34 -24
  121. package/registry/number-field.muten +8 -6
  122. package/registry/order-board.js +6 -0
  123. package/registry/order-board.muten +21 -0
  124. package/registry/overlay-behavior.js +13 -0
  125. package/registry/overlay-behavior.muten +4 -0
  126. package/registry/pagination-nav.js +6 -0
  127. package/registry/pagination-nav.muten +8 -0
  128. package/registry/pagination.muten +12 -9
  129. package/registry/password-field.muten +3 -0
  130. package/registry/permission-matrix.muten +6 -0
  131. package/registry/phone-field.js +5 -0
  132. package/registry/phone-field.muten +7 -0
  133. package/registry/phone-shell.js +7 -0
  134. package/registry/phone-shell.muten +9 -0
  135. package/registry/pill.muten +6 -5
  136. package/registry/plans.muten +4 -0
  137. package/registry/popover.muten +16 -9
  138. package/registry/pricing.muten +21 -21
  139. package/registry/progress.muten +5 -5
  140. package/registry/queue.muten +3 -0
  141. package/registry/radio-group.muten +16 -8
  142. package/registry/range-slider.js +9 -24
  143. package/registry/range-slider.muten +4 -5
  144. package/registry/resizable.js +34 -27
  145. package/registry/resizable.muten +16 -5
  146. package/registry/roving-behavior.js +16 -0
  147. package/registry/roving-behavior.muten +3 -0
  148. package/registry/row-menu.js +5 -0
  149. package/registry/row-menu.muten +5 -0
  150. package/registry/save-button.muten +11 -0
  151. package/registry/scale-slider.js +7 -0
  152. package/registry/scale-slider.muten +9 -0
  153. package/registry/scroll-area.muten +8 -4
  154. package/registry/segmented-control.muten +8 -8
  155. package/registry/separator.muten +3 -3
  156. package/registry/share-button.js +7 -0
  157. package/registry/share-button.muten +10 -0
  158. package/registry/sheet.muten +6 -10
  159. package/registry/sidebar.muten +23 -15
  160. package/registry/skeleton.muten +6 -4
  161. package/registry/slider.js +73 -27
  162. package/registry/slider.muten +6 -6
  163. package/registry/sortable-behavior.js +43 -0
  164. package/registry/sortable-behavior.muten +2 -0
  165. package/registry/sortable-list.js +10 -26
  166. package/registry/sortable-list.muten +6 -7
  167. package/registry/sortable.muten +15 -0
  168. package/registry/spark.js +14 -0
  169. package/registry/spark.muten +3 -0
  170. package/registry/spinner.muten +4 -3
  171. package/registry/split-button.muten +12 -10
  172. package/registry/stamp-card.muten +7 -0
  173. package/registry/stat-band.muten +6 -9
  174. package/registry/stat.muten +23 -0
  175. package/registry/status-bar.muten +7 -6
  176. package/registry/stepper.muten +17 -14
  177. package/registry/store-qr.js +5 -0
  178. package/registry/store-qr.muten +5 -0
  179. package/registry/swatch.muten +8 -8
  180. package/registry/switch.muten +14 -6
  181. package/registry/table-view.muten +10 -0
  182. package/registry/tabs-behavior.js +27 -0
  183. package/registry/tabs-behavior.muten +3 -0
  184. package/registry/tabs.muten +19 -10
  185. package/registry/tag-input.js +4 -27
  186. package/registry/tag-input.muten +6 -6
  187. package/registry/text.muten +7 -0
  188. package/registry/time-field.js +5 -0
  189. package/registry/time-field.muten +6 -0
  190. package/registry/timeline.muten +14 -14
  191. package/registry/toaster.js +34 -22
  192. package/registry/toaster.muten +10 -8
  193. package/registry/toggle-group.muten +11 -6
  194. package/registry/toggle.muten +8 -5
  195. package/registry/toolbar.muten +11 -6
  196. package/registry/tooltip.muten +6 -9
  197. package/registry/tree-view.js +27 -7
  198. package/registry/tree-view.muten +8 -13
  199. package/registry/vector-field.muten +9 -8
  200. package/registry/virtual-list.js +5 -0
  201. package/registry/virtual-list.muten +6 -0
  202. package/registry/weekly-hours.muten +4 -0
  203. package/registry/wordline.muten +6 -0
  204. package/registry/zoom-control.muten +9 -9
  205. package/registry.json +868 -424
  206. package/themes/bloom.css +53 -0
  207. package/themes/editorial.css +65 -0
  208. package/themes/noir.css +54 -0
  209. package/registry/chart.js +0 -34
  210. package/registry/chart.muten +0 -7
  211. package/registry/checkbox.muten +0 -8
  212. package/registry/context-menu.js +0 -34
  213. package/registry/select.muten +0 -21
package/AGENTS.md CHANGED
@@ -2,12 +2,68 @@
2
2
 
3
3
  ## Setup (once): `plugins { shadcn {} }` in muten.config + `@import "@muten/shadcn/globals.css";` in src/styles.css. Then everything below is usable directly; `muten add <name>` only ejects a source.
4
4
 
5
+ > **Native primitives always win — for a checkbox / select / number / range / date / chart, use the native muten
6
+ > primitive, NOT a plugin part.** muten's core now ships these as primitives, so this plugin does NOT: write
7
+ > `Checkbox bind(agree)`, `Select bind(theme) options(System, Light, Dark) class("native-select")` (the `.native-select`
8
+ > class gives the native `<select>` the shadcn look), `Number bind(qty)`, `Range bind(vol)`, `Date bind(due)`,
9
+ > `Chart @data kind(bar) x(label) y(value)`. A part named the same as a primitive is unreachable (the primitive
10
+ > shadows it), so those parts were removed. For a *searchable* dropdown use the `Combobox` part.
11
+ > **The exact props of every part are in the header comment of `node_modules/@muten/shadcn/registry/<name>.muten` —
12
+ > read it before calling (the one-liners below are the catalog, not the API).**
13
+
14
+ ## Nova + the system kit
15
+
16
+ The newer half of the plugin is shadcn's **Nova** style plus a kit of generic, data-driven components (agenda,
17
+ inbox, order board, booking, app shell…). It is 1:1 with the reference artifact the bench page `plugins/playground`
18
+ shows. Setup, on top of the install above:
19
+
20
+ ```css
21
+ /* src/styles.css, after globals.css */
22
+ @import "@muten/shadcn/nova.css"; /* shadcn's Nova source, scoped under .style-nova */
23
+ @import "@muten/shadcn/kit.css"; /* muten adapters + the kit's layout and motion */
24
+ ```
25
+
26
+ ```html
27
+ <!-- index.html: the style class on <html>, and Geist -->
28
+ <html class="style-nova">
29
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&family=Geist+Mono:wght@400;500&display=swap">
30
+ ```
31
+
32
+ ```
33
+ # src/app.muten: once, in the shell (a shell cannot call plugin parts, so the Custom directly)
34
+ shell { Stack { Custom KitLayer class("cx-kit-host") slot } }
35
+ ```
36
+
37
+ `KitLayer` loads the kit core once: the icon sprite, the tooltip on anything with `data-name`, the Island, the one
38
+ adaptive modal (Dialog wide, Drawer on a phone) the kit's components share, and the wheels. Every component's exact
39
+ props are in the header comment of its `registry/<name>.muten`; the data shapes are documented there too.
40
+
41
+ | Group | Parts |
42
+ |---|---|
43
+ | Atoms | `Btn` (variant, size, tone), `Txt`, `Badge`/`StatusBadge`/`ToneBadge`/`Chip`, `Avatar`/`AvatarGroup`/`Who`, `Kbd`, `Spinner`, `Skeleton`, `Indicator`, `Separator`, `Progress` |
44
+ | Lists and cards | `Item…`, `Price`, `Card…` (with the action zone), `FixedCard`/`Row3`/`EmptyMini`, `StatCard`/`StatGrid`, `Spark` |
45
+ | Controls | `Switch`/`SwitchRow`, `Tabs`, `SegmentedControl`, `ChoiceList`, `Sortable`, `SaveButton`, `NavButton` |
46
+ | Fields | `Field…`, `Input`/`TextArea`, `InputGroup`/`SearchInput`, `MoneyField`, `PhoneField`, `InputOtp`, `PasswordField` |
47
+ | Notices | `Alert`, `Band`, `Island`, `Modal`/`ModalFooter`, `SettingsForm`/`DirtyBar` |
48
+ | Menus and content | `Combobox`, `RowMenu`, `Accordion`, `StoreQr` |
49
+ | Values | `ScaleSlider`, `RangeSlider`, `Slider`, `ColorPicker` |
50
+ | Collections | `TagInput`, `PaginationNav`, `VirtualList`, `Carousel`/`CarouselSlide` |
51
+ | Data | `TableView` (filters as data, chips, bulk), `OrderBoard`, `OrderCards` |
52
+ | Dates and files | `Booking`, `Calendar`, `DateField`, `TimeField`, `ImageUpload` |
53
+ | Structure | `PhoneShell`, `ShareButton`, `AppShell` (Sidebar, page header, detail Sheet, ⌘K) |
54
+ | System | `Agenda`, `NewAppointment`, `Messaging`, `Chatbot`, `BarChart`, `Checklist`, `Plans`, `CardField`, `MemberList`, `PermissionMatrix`, `StampCard`, `Bell`, `Queue`, `WeeklyHours` |
55
+ | Loading | `Skeletons(kind)`, `Loading(busy, kind) { … }`: content-shaped skeletons, a fade when the data lands |
56
+
57
+ Rules the kit keeps: the page owns the state and gets JSON back through actions; functions never travel as data
58
+ (a bot's answers are `{match, text}` rules); a skeleton only shows while there is nothing to show; no native
59
+ `<select>`, the wheels and menus instead.
60
+
5
61
  ## PLUG-AND-PLAY (zero class props)
6
62
  - **Btn**(variant, onClick) { slot } · **LinkBtn**(to, variant) { slot } · **Input**(value, placeholder)
7
63
  - **DataTable** @rows columns(a, b) - STYLED BY DEFAULT, no class needed.
8
64
  - + every Part / Custom below.
9
65
 
10
- ## Parts (64) - imported by plugins {}
66
+ ## Parts (62) - imported by plugins {}
11
67
 
12
68
  - **Card** - A surface with CardHeader / CardTitle / CardDescription / CardContent / CardFooter sub-components. · +CardHeader, CardTitle, CardDescription, CardContent, CardFooter
13
69
  - **Badge** - A small status descriptor. variant: default | secondary | destructive | outline.
@@ -22,7 +78,6 @@
22
78
  - **Pagination** - Page navigation with PaginationLink / Previous / Next / Ellipsis. · +PaginationLink, PaginationPrevious, PaginationNext, PaginationEllipsis
23
79
  - **Field** - A labelled form control: FieldLabel / FieldDescription / FieldError. · +FieldLabel, FieldDescription, FieldError
24
80
  - **Item** - A bordered row: ItemContent / ItemTitle / ItemDescription. · +ItemContent, ItemTitle, ItemDescription
25
- - **Checkbox** - A checkbox; the page owns the bool + the toggle action.
26
81
  - **Toggle** - A two-state button; the page owns the bool + the toggle action.
27
82
  - **ToggleGroup** - Single-select toolbar with ToggleGroupItem; page owns a text state. · +ToggleGroupItem
28
83
  - **RadioGroup** - Single choice with RadioGroupItem; page owns a text state. · +RadioGroupItem
@@ -37,7 +92,6 @@
37
92
  - **Sheet** - A panel that slides in from the right; page owns the open bool. · +SheetTitle, SheetDescription
38
93
  - **Drawer** - A panel that slides up from the bottom; page owns the open bool.
39
94
  - **HoverCard** - Richer content shown on hover (pure CSS, no state).
40
- - **Select** - A value picker with SelectItem; page owns the value text + open bool. · +SelectItem
41
95
  - **ScrollArea** - A scrollable region with styled scrollbars.
42
96
  - **Message** - Chat Message + Bubble + Marker (variant: sent | received). · +Bubble, Marker
43
97
  - **MessageScroller** - A scrollable column of chat messages.
@@ -74,14 +128,13 @@
74
128
  - **Input** - Plug-and-play text input (part Input wraps SearchField). `Input(value: q, placeholder: "...")` - value is two-way bound. For typed/validated fields use a Form.
75
129
  - **LinkBtn** - A navigation link styled as a button. `LinkBtn(to: "/signup", variant: "default") { Span "Get started" }`.
76
130
 
77
- ## Customs (21) - importable; some need a dep
131
+ ## Customs (20) - importable; some need a dep
78
132
 
79
133
  - **Slider** (`slider`) - A draggable range slider (Custom). Page owns the value number.
80
134
  - **InputOtp** (`input-otp`) - N single-character boxes synced to one value (Custom). Page owns the value text.
81
135
  - **Calendar** (`calendar`) - A month-grid date picker (Custom). Page owns the selected ISO date text.
82
136
  - **Toaster** (`toaster`) - Fixed toast notifications (Custom). Page bumps a trigger counter to fire one.
83
137
  - **Carousel** (`carousel`) - A slide carousel over a list (Custom). Page owns the slides list.
84
- - **Chart** (`chart`) - An SVG bar chart over a list of { label, value } (Custom).
85
138
  - **GradientBlinds** (`gradient-blinds`) · **needs npm: ogl** - Animated WebGL gradient + diagonal-blinds hero background that follows the cursor and fades into the page (needs ogl).
86
139
  - **Resizable** (`resizable`) - Two panels with a draggable splitter (Custom).
87
140
  - **ContextMenu** (`context-menu`) - Right-click an area to open a menu of items (Custom).
@@ -105,4 +158,6 @@
105
158
  - **table** - DataTable @rows columns(name, email, status) - STYLED BY DEFAULT (no class needed). `class("data-table")` still works as an explicit alias. Raw cells; for badge/formatted cells build with each + Stack.
106
159
  - **motion** - Page animations, all CSS + reduced-motion safe. Entrance: animate-fade-up|fade-in|scale-in|slide-in (+ d1..d6 stagger). Scroll: reveal|reveal-left|reveal-scale, and nav-scroll on a navbar. Hover/press: hover-lift, hover-glow, arrow-hover (nudges a trailing Icon), link-underline, press, float.
107
160
 
108
- ### Gotcha: a part can not be named after a primitive (Button/Link/Form/Image/SearchField/DataTable/Icon/Text/Title/Span) - hence Btn/Input/LinkBtn. `Part(...) class(...)` is a syntax error.
161
+ ### Gotcha: a part can not be named after a core primitive — the **primitive wins** and any same-named plugin part is unreachable on import. The primitives include `Button/Link/Form/Image/SearchField/DataTable/Icon/Text/Title/Span` (→ this plugin uses `Btn`/`Input`/`LinkBtn`) AND `Select/Checkbox/Number/Range/Date/Chart` (→ use those primitives directly, see the note at the top). If you write a part call and the oracle says `missing-prop: X is missing the required "bind"`, X is a primitive shadowing the part — switch to the primitive's API.
162
+
163
+ ### Gotcha: a **part takes NO trailing modifiers** — `Part(...) class(...)`, `Part(...) disabled when x`, `Part(...) on(...)` and `Part(...) aria(...)` are all syntax errors (a part call ends at its `)`/`{}`). When you need `class`/`disabled when`/`on`/`aria` on a control, use the **native primitive** (`Button "Save" -> save disabled when not valid class("btn btn-default")`), not the `Btn(...)` part.
package/README.md CHANGED
@@ -94,24 +94,77 @@ Display: **card** (Card / CardHeader / CardTitle / CardDescription / CardContent
94
94
  **alert** (Alert / AlertTitle / AlertDescription), **avatar**, **spinner**, **progress**, **empty**,
95
95
  **breadcrumb**, **pagination**, **field**, **item**.
96
96
 
97
- Stateful (the page owns the state, the part receives it - see the pattern below): **switch**, **checkbox**,
97
+ Stateful (the page owns the state, the part receives it - see the pattern below): **switch**,
98
98
  **toggle**, **toggle-group**, **radio-group**, **collapsible**, **accordion**, **tabs**.
99
99
 
100
100
  Overlays (the page owns an `open` bool): **dialog**, **alert-dialog**, **tooltip** (pure hover, no state),
101
- **dropdown-menu**, **popover**, **sheet**, **drawer**, **hover-card** (hover), **select**, **scroll-area**,
101
+ **dropdown-menu**, **popover**, **sheet**, **drawer**, **hover-card** (hover), **scroll-area**,
102
102
  **menubar**, **navigation-menu** (hover), **combobox**, **command**.
103
103
 
104
+ > **Not here on purpose:** checkbox / select / number / range / date / chart are **native muten primitives** now,
105
+ > so this plugin ships no part for them (a same-named part would be shadowed by the primitive). Use `Checkbox bind(x)`,
106
+ > `Select bind(x) options(a, b) class("native-select")`, `Number`/`Range`/`Date bind(x)`, `Chart @data kind(bar) …`.
107
+ > For a *searchable* dropdown, use **combobox**.
108
+
104
109
  Chat: **message** (Message / Bubble / Marker), **message-scroller**, **attachment**.
105
110
 
106
111
  ### Custom (eject-only - `muten add` copies a host `.js` into `src/components/`)
107
112
 
108
- The genuinely interactive 20%: **slider**, **input-otp**, **calendar**, **toaster**, **carousel**, **chart**,
109
- **resizable**, **context-menu**. Each is a thin muten part over a small vanilla-JS host you own and can edit.
113
+ The genuinely interactive 20%: **input-otp**, **toaster**, **carousel**, **resizable**, **context-menu** (+ more,
114
+ see AGENTS.md). Each is a thin muten part over a small vanilla-JS host you own and can edit. (A chart / slider /
115
+ date picker is **native** — `Chart`/`Range`/`Date` — not a Custom; don't `muten add` those.)
110
116
 
111
117
  `calendar` ships all the shadcn variants: `mode` (`single` / `range` / `multiple`), `months` (1-2 side by side),
112
118
  `caption` (`label` / `dropdown`). `selected` encodes the value (`"yyyy-mm-dd"`, `"from/to"`, or `"d1,d2,..."`).
113
119
  A **date picker** is just `Popover { Calendar … }`.
114
120
 
121
+ ## Nova + the system kit
122
+
123
+ The newer half of the plugin is shadcn's **Nova** style plus a kit of generic, data-driven components (agenda,
124
+ inbox, order board, booking, app shell…). It is 1:1 with the reference artifact the bench page `plugins/playground`
125
+ shows. Setup, on top of the install above:
126
+
127
+ ```css
128
+ /* src/styles.css, after globals.css */
129
+ @import "@muten/shadcn/nova.css"; /* shadcn's Nova source, scoped under .style-nova */
130
+ @import "@muten/shadcn/kit.css"; /* muten adapters + the kit's layout and motion */
131
+ ```
132
+
133
+ ```html
134
+ <!-- index.html: the style class on <html>, and Geist -->
135
+ <html class="style-nova">
136
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&family=Geist+Mono:wght@400;500&display=swap">
137
+ ```
138
+
139
+ ```
140
+ # src/app.muten: once, in the shell (a shell cannot call plugin parts, so the Custom directly)
141
+ shell { Stack { Custom KitLayer class("cx-kit-host") slot } }
142
+ ```
143
+
144
+ `KitLayer` loads the kit core once: the icon sprite, the tooltip on anything with `data-name`, the Island, the one
145
+ adaptive modal (Dialog wide, Drawer on a phone) the kit's components share, and the wheels. Every component's exact
146
+ props are in the header comment of its `registry/<name>.muten`; the data shapes are documented there too.
147
+
148
+ | Group | Parts |
149
+ |---|---|
150
+ | Atoms | `Btn` (variant, size, tone), `Txt`, `Badge`/`StatusBadge`/`ToneBadge`/`Chip`, `Avatar`/`AvatarGroup`/`Who`, `Kbd`, `Spinner`, `Skeleton`, `Indicator`, `Separator`, `Progress` |
151
+ | Lists and cards | `Item…`, `Price`, `Card…` (with the action zone), `FixedCard`/`Row3`/`EmptyMini`, `StatCard`/`StatGrid`, `Spark` |
152
+ | Controls | `Switch`/`SwitchRow`, `Tabs`, `SegmentedControl`, `ChoiceList`, `Sortable`, `SaveButton`, `NavButton` |
153
+ | Fields | `Field…`, `Input`/`TextArea`, `InputGroup`/`SearchInput`, `MoneyField`, `PhoneField`, `InputOtp`, `PasswordField` |
154
+ | Notices | `Alert`, `Band`, `Island`, `Modal`/`ModalFooter`, `SettingsForm`/`DirtyBar` |
155
+ | Menus and content | `Combobox`, `RowMenu`, `Accordion`, `StoreQr` |
156
+ | Values | `ScaleSlider`, `RangeSlider`, `Slider`, `ColorPicker` |
157
+ | Collections | `TagInput`, `PaginationNav`, `VirtualList`, `Carousel`/`CarouselSlide` |
158
+ | Data | `TableView` (filters as data, chips, bulk), `OrderBoard`, `OrderCards` |
159
+ | Dates and files | `Booking`, `Calendar`, `DateField`, `TimeField`, `ImageUpload` |
160
+ | Structure | `PhoneShell`, `ShareButton`, `AppShell` (Sidebar, page header, detail Sheet, ⌘K) |
161
+ | System | `Agenda`, `NewAppointment`, `Messaging`, `Chatbot`, `BarChart`, `Checklist`, `Plans`, `CardField`, `MemberList`, `PermissionMatrix`, `StampCard`, `Bell`, `Queue`, `WeeklyHours` |
162
+ | Loading | `Skeletons(kind)`, `Loading(busy, kind) { … }`: content-shaped skeletons, a fade when the data lands |
163
+
164
+ Rules the kit keeps: the page owns the state and gets JSON back through actions; functions never travel as data
165
+ (a bot's answers are `{match, text}` rules); a skeleton only shows while there is nothing to show; no native
166
+ `<select>`, the wheels and menus instead.
167
+
115
168
  ---
116
169
 
117
170
  ## The container / presentational pattern
package/globals.css CHANGED
@@ -175,6 +175,7 @@
175
175
  raw <svg> child - muten renders icons as iconify-icon). Icon sizing is the `.btn svg` rule below. */
176
176
  .btn { @apply inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium leading-none transition-all shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] active:scale-[0.97] aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 disabled:pointer-events-none disabled:opacity-50 h-8 px-3; }
177
177
  .btn-default { @apply bg-primary text-primary-foreground shadow-xs hover:bg-primary/90 active:bg-primary/80; }
178
+ .btn-primary { @apply bg-primary text-primary-foreground shadow-xs hover:bg-primary/90 active:bg-primary/80; } /* alias of btn-default — tolerate the near-universal `btn-primary` idiom */
178
179
  .btn-destructive { @apply bg-destructive text-white shadow-xs hover:bg-destructive/90 active:bg-destructive/80 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60; }
179
180
  .btn-outline { @apply border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground active:bg-accent/70 dark:bg-input/30 dark:border-input dark:hover:bg-input/50 dark:active:bg-input/70; }
180
181
  .btn-secondary { @apply bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80 active:bg-secondary/70; }
@@ -197,6 +198,20 @@
197
198
  .label { @apply text-sm font-medium leading-none; }
198
199
  .native-select { @apply flex h-8 w-full items-center rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs outline-none transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-destructive dark:bg-input/30 disabled:cursor-not-allowed disabled:opacity-50; }
199
200
 
201
+ /* ---- native primitives styled shadcn-flavored (muten core ships Checkbox/Number/Range/Date/Chart) ---- */
202
+ .mu-checkbox { @apply inline-flex items-center gap-2 text-sm; }
203
+ .mu-checkbox input, .mu-field-check { @apply size-4 rounded-[4px] border-input; accent-color: var(--primary); }
204
+ .mu-number, .mu-date { @apply flex h-8 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs outline-none transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 dark:bg-input/30; }
205
+ .mu-range { @apply w-full; accent-color: var(--primary); }
206
+ .mu-chart-bar, .mu-chart-dot, .mu-chart-slice { fill: var(--primary); }
207
+ .mu-chart-slice { stroke: var(--card); stroke-width: 2.5; }
208
+ .mu-chart-dot { stroke: var(--card); stroke-width: 2; }
209
+ .mu-chart-line { fill: none; stroke: var(--primary); stroke-width: 2.25; stroke-linecap: round; stroke-linejoin: round; }
210
+ .mu-chart-area { stroke: none; } /* fill comes from the inline accent→transparent gradient __chart draws */
211
+ .mu-chart-grid { stroke: var(--border); stroke-opacity: 0.55; }
212
+ .mu-chart-tick, .mu-chart-xlabel { fill: var(--muted-foreground); font-size: 10px; font-variant-numeric: tabular-nums; }
213
+ .mu-chart-total { fill: var(--foreground); font-size: 15px; font-weight: 650; font-variant-numeric: tabular-nums; }
214
+
200
215
  /* ---- Card ---- */
201
216
  .card { @apply bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm; }
202
217
  .card-header { @apply grid auto-rows-min items-start gap-1.5 px-6; }
@@ -746,6 +761,16 @@
746
761
  (the classic "call to action" micro-interaction). Respects reduced motion via the global rule below. ---- */
747
762
  .arrow-hover .mu-icon { @apply transition-transform duration-200; }
748
763
  .arrow-hover:hover .mu-icon:last-child { translate: 3px 0; }
764
+
765
+ /* ---- Touch targets. These components are sized for a mouse (h-8 = 32px); Apple HIG asks for >=44px and
766
+ Material for >=48dp before a finger hits reliably. `pointer: coarse` is the browser telling us there IS a
767
+ finger, so the SAME app adapts on a phone with no mobile build, no second plugin and no decision for the
768
+ author to make. Inside @layer components on purpose: a class("h-14") on the Button still wins.
769
+ Deliberately NOT everything h-8: `btn-xs`/`switch` are small by intent, and badges/avatars aren't targets. ---- */
770
+ @media (pointer: coarse) {
771
+ .btn, .input, .toggle, .select-trigger, .native-select { @apply h-11; }
772
+ .btn-sm { @apply h-10; }
773
+ }
749
774
  }
750
775
 
751
776
  @keyframes progress-indeterminate { 0% { left: -40%; } 100% { left: 100%; } }
@@ -762,8 +787,11 @@
762
787
  @keyframes mu-slide-in { from { opacity: 0; translate: -1.5rem 0; } to { opacity: 1; translate: 0 0; } }
763
788
  @keyframes mu-reveal-scale{ from { opacity: 0; scale: 0.92; translate: 0 1rem; } to { opacity: 1; scale: 1; translate: 0 0; } }
764
789
  /* nav pill: airy + shadowless at the top, settles + deepens its shadow once you scroll, and reverses smoothly
765
- when you return to the top (scroll-position driven, so "back to top" is free). */
766
- @keyframes mu-nav-scroll { from { scale: 1.015; box-shadow: 0 4px 12px -6px rgb(0 0 0 / 0.10); } to { scale: 0.98; box-shadow: 0 16px 36px -10px rgb(0 0 0 / 0.30); } }
790
+ when you return to the top (scroll-position driven, so "back to top" is free).
791
+ It scrubs the SHADOW ONLY. It used to scrub `scale: 1.015 → 0.98` as well, which resized the navbar by 3.5% of
792
+ its own width on every scroll — a visible jump on each landing, and blurred nav text for the whole animation.
793
+ A navbar is furniture: it may deepen, it must never change size. */
794
+ @keyframes mu-nav-scroll { from { box-shadow: 0 4px 12px -6px rgb(0 0 0 / 0.10); } to { box-shadow: 0 16px 36px -10px rgb(0 0 0 / 0.30); } }
767
795
  @keyframes mu-float { 0%, 100% { translate: 0 0; } 50% { translate: 0 -6px; } }
768
796
 
769
797
  @layer utilities {