@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.
- package/AGENTS.md +61 -6
- package/README.md +57 -4
- package/globals.css +30 -2
- package/kit.css +2763 -0
- package/motion.css +79 -0
- package/nova.css +1387 -0
- package/package.json +10 -2
- package/registry/accordion.muten +11 -10
- package/registry/agenda.js +35 -0
- package/registry/agenda.muten +10 -0
- package/registry/alert-dialog.muten +9 -12
- package/registry/alert.muten +8 -8
- package/registry/app-shell.js +9 -0
- package/registry/app-shell.muten +12 -0
- package/registry/attachment.muten +13 -9
- package/registry/avatar.muten +24 -5
- package/registry/badge.muten +23 -8
- package/registry/band.muten +16 -0
- package/registry/bar-chart.muten +7 -0
- package/registry/bell.muten +3 -0
- package/registry/bento.muten +6 -9
- package/registry/booking.js +21 -0
- package/registry/booking.muten +13 -0
- package/registry/breadcrumb.muten +9 -7
- package/registry/button-group.muten +13 -4
- package/registry/button.muten +21 -8
- package/registry/calendar.js +28 -93
- package/registry/calendar.muten +9 -8
- package/registry/canvas-viewport.js +12 -5
- package/registry/canvas-viewport.muten +9 -9
- package/registry/card-field.muten +4 -0
- package/registry/card.muten +12 -8
- package/registry/carousel.js +5 -36
- package/registry/carousel.muten +12 -5
- package/registry/chatbot.muten +9 -0
- package/registry/checklist.muten +6 -0
- package/registry/choice-list.muten +16 -0
- package/registry/code.js +14 -12
- package/registry/code.muten +6 -7
- package/registry/collapsible.muten +14 -10
- package/registry/color-picker.js +460 -41
- package/registry/color-picker.muten +7 -6
- package/registry/combobox.js +5 -0
- package/registry/combobox.muten +6 -23
- package/registry/command-palette.muten +8 -12
- package/registry/command.js +32 -0
- package/registry/command.muten +32 -11
- package/registry/context-menu.muten +9 -8
- package/registry/count-up.muten +5 -10
- package/registry/date-field.js +5 -0
- package/registry/date-field.muten +7 -0
- package/registry/device-frame.muten +8 -0
- package/registry/dialog.muten +6 -12
- package/registry/dirty-bar.js +19 -0
- package/registry/dirty-bar.muten +13 -0
- package/registry/drawer.muten +6 -11
- package/registry/dropdown-menu.muten +37 -13
- package/registry/empty.muten +11 -7
- package/registry/feature-grid.muten +10 -12
- package/registry/feature-rows.muten +12 -8
- package/registry/field-behavior.js +33 -0
- package/registry/field-behavior.muten +9 -0
- package/registry/field.muten +26 -7
- package/registry/file-input.js +36 -21
- package/registry/file-input.muten +8 -7
- package/registry/fixed-card.muten +25 -0
- package/registry/folder-picker.js +13 -15
- package/registry/folder-picker.muten +5 -8
- package/registry/gradient-blinds.muten +6 -13
- package/registry/hover-card.muten +7 -9
- package/registry/image-upload.js +5 -0
- package/registry/image-upload.muten +8 -0
- package/registry/indicator.muten +5 -0
- package/registry/input-group.muten +27 -4
- package/registry/input-otp.js +8 -35
- package/registry/input-otp.muten +6 -6
- package/registry/input.muten +8 -7
- package/registry/inspector.muten +13 -15
- package/registry/island.js +7 -0
- package/registry/island.muten +5 -0
- package/registry/item.muten +20 -7
- package/registry/kbd.muten +3 -3
- package/registry/kit/board.js +300 -0
- package/registry/kit/collections.js +148 -0
- package/registry/kit/core.js +989 -0
- package/registry/kit/dates.js +106 -0
- package/registry/kit/menus.js +90 -0
- package/registry/kit/overlays.js +114 -0
- package/registry/kit/paint.js +211 -0
- package/registry/kit/qrcode.js +2291 -0
- package/registry/kit/structure.js +393 -0
- package/registry/kit/table.js +198 -0
- package/registry/kit/values.js +179 -0
- package/registry/kit-layer.js +2 -0
- package/registry/kit-layer.muten +5 -0
- package/registry/kit-skeleton.js +24 -0
- package/registry/kit-skeleton.muten +16 -0
- package/registry/kit-widget.js +79 -0
- package/registry/kit-widget.muten +4 -0
- package/registry/link-btn.muten +9 -7
- package/registry/live-stack.js +29 -0
- package/registry/live-stack.muten +7 -0
- package/registry/logo-cloud.muten +6 -11
- package/registry/member-list.muten +6 -0
- package/registry/menubar.muten +10 -14
- package/registry/message-scroller.js +12 -0
- package/registry/message-scroller.muten +8 -4
- package/registry/message.muten +27 -10
- package/registry/messaging.muten +11 -0
- package/registry/modal-behavior.js +56 -0
- package/registry/modal-behavior.muten +4 -0
- package/registry/modal.muten +29 -0
- package/registry/money-field.js +5 -0
- package/registry/money-field.muten +7 -0
- package/registry/nav-button.muten +14 -0
- package/registry/navigation-menu.muten +16 -14
- package/registry/navpill.muten +15 -9
- package/registry/new-appointment.js +8 -0
- package/registry/new-appointment.muten +10 -0
- package/registry/number-field.js +34 -24
- package/registry/number-field.muten +8 -6
- package/registry/order-board.js +6 -0
- package/registry/order-board.muten +21 -0
- package/registry/overlay-behavior.js +13 -0
- package/registry/overlay-behavior.muten +4 -0
- package/registry/pagination-nav.js +6 -0
- package/registry/pagination-nav.muten +8 -0
- package/registry/pagination.muten +12 -9
- package/registry/password-field.muten +3 -0
- package/registry/permission-matrix.muten +6 -0
- package/registry/phone-field.js +5 -0
- package/registry/phone-field.muten +7 -0
- package/registry/phone-shell.js +7 -0
- package/registry/phone-shell.muten +9 -0
- package/registry/pill.muten +6 -5
- package/registry/plans.muten +4 -0
- package/registry/popover.muten +16 -9
- package/registry/pricing.muten +21 -21
- package/registry/progress.muten +5 -5
- package/registry/queue.muten +3 -0
- package/registry/radio-group.muten +16 -8
- package/registry/range-slider.js +9 -24
- package/registry/range-slider.muten +4 -5
- package/registry/resizable.js +34 -27
- package/registry/resizable.muten +16 -5
- package/registry/roving-behavior.js +16 -0
- package/registry/roving-behavior.muten +3 -0
- package/registry/row-menu.js +5 -0
- package/registry/row-menu.muten +5 -0
- package/registry/save-button.muten +11 -0
- package/registry/scale-slider.js +7 -0
- package/registry/scale-slider.muten +9 -0
- package/registry/scroll-area.muten +8 -4
- package/registry/segmented-control.muten +8 -8
- package/registry/separator.muten +3 -3
- package/registry/share-button.js +7 -0
- package/registry/share-button.muten +10 -0
- package/registry/sheet.muten +6 -10
- package/registry/sidebar.muten +23 -15
- package/registry/skeleton.muten +6 -4
- package/registry/slider.js +73 -27
- package/registry/slider.muten +6 -6
- package/registry/sortable-behavior.js +43 -0
- package/registry/sortable-behavior.muten +2 -0
- package/registry/sortable-list.js +10 -26
- package/registry/sortable-list.muten +6 -7
- package/registry/sortable.muten +15 -0
- package/registry/spark.js +14 -0
- package/registry/spark.muten +3 -0
- package/registry/spinner.muten +4 -3
- package/registry/split-button.muten +12 -10
- package/registry/stamp-card.muten +7 -0
- package/registry/stat-band.muten +6 -9
- package/registry/stat.muten +23 -0
- package/registry/status-bar.muten +7 -6
- package/registry/stepper.muten +17 -14
- package/registry/store-qr.js +5 -0
- package/registry/store-qr.muten +5 -0
- package/registry/swatch.muten +8 -8
- package/registry/switch.muten +14 -6
- package/registry/table-view.muten +10 -0
- package/registry/tabs-behavior.js +27 -0
- package/registry/tabs-behavior.muten +3 -0
- package/registry/tabs.muten +19 -10
- package/registry/tag-input.js +4 -27
- package/registry/tag-input.muten +6 -6
- package/registry/text.muten +7 -0
- package/registry/time-field.js +5 -0
- package/registry/time-field.muten +6 -0
- package/registry/timeline.muten +14 -14
- package/registry/toaster.js +34 -22
- package/registry/toaster.muten +10 -8
- package/registry/toggle-group.muten +11 -6
- package/registry/toggle.muten +8 -5
- package/registry/toolbar.muten +11 -6
- package/registry/tooltip.muten +6 -9
- package/registry/tree-view.js +27 -7
- package/registry/tree-view.muten +8 -13
- package/registry/vector-field.muten +9 -8
- package/registry/virtual-list.js +5 -0
- package/registry/virtual-list.muten +6 -0
- package/registry/weekly-hours.muten +4 -0
- package/registry/wordline.muten +6 -0
- package/registry/zoom-control.muten +9 -9
- package/registry.json +868 -424
- package/themes/bloom.css +53 -0
- package/themes/editorial.css +65 -0
- package/themes/noir.css +54 -0
- package/registry/chart.js +0 -34
- package/registry/chart.muten +0 -7
- package/registry/checkbox.muten +0 -8
- package/registry/context-menu.js +0 -34
- 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 (
|
|
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 (
|
|
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
|
|
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**,
|
|
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), **
|
|
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%: **
|
|
109
|
-
|
|
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
|
-
|
|
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 {
|