@muten/shadcn 0.1.14 → 0.2.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 +88 -1
- package/globals.css +1 -0
- package/kit.css +329 -124
- package/motion.css +3 -0
- package/package.json +1 -1
- package/registry/accordion.muten +3 -3
- package/registry/agenda.js +19 -16
- package/registry/agenda.muten +10 -10
- package/registry/alert-dialog.muten +2 -2
- package/registry/alert.muten +1 -1
- package/registry/app-shell.muten +1 -1
- package/registry/attachment.muten +1 -1
- package/registry/avatar.muten +4 -4
- package/registry/badge.muten +14 -3
- package/registry/band.muten +2 -2
- package/registry/bar-chart.muten +2 -2
- package/registry/bio-play.muten +2 -2
- package/registry/booking-play.muten +5 -5
- package/registry/booking.muten +2 -2
- package/registry/breadcrumb.muten +4 -4
- package/registry/button.muten +9 -7
- package/registry/calendar.js +15 -10
- package/registry/calendar.muten +1 -1
- package/registry/card.muten +1 -1
- package/registry/carousel.muten +1 -1
- package/registry/chat-play.muten +8 -8
- package/registry/chatbot.muten +5 -4
- package/registry/checklist.muten +1 -1
- package/registry/choice-list.muten +3 -3
- package/registry/code.js +10 -4
- package/registry/collapsible.muten +2 -2
- package/registry/color-picker.js +37 -36
- package/registry/color-picker.muten +1 -1
- package/registry/combobox.js +1 -1
- package/registry/combobox.muten +2 -2
- package/registry/command-palette.muten +2 -2
- package/registry/command.js +1 -1
- package/registry/command.muten +7 -7
- package/registry/context-menu.muten +3 -3
- package/registry/count-up.js +33 -31
- package/registry/count-up.muten +6 -4
- package/registry/date-field.js +1 -1
- package/registry/date-field.muten +3 -3
- package/registry/day-plan.muten +5 -5
- package/registry/device-frame.muten +3 -3
- package/registry/dialog.muten +1 -1
- package/registry/dirty-bar.js +2 -2
- package/registry/dirty-bar.muten +3 -3
- package/registry/drawer.muten +1 -1
- package/registry/dropdown-menu.muten +4 -4
- package/registry/empty.muten +1 -1
- package/registry/feature-grid.muten +1 -1
- package/registry/feature-rows.muten +2 -2
- package/registry/field-behavior.js +13 -3
- package/registry/field-behavior.muten +3 -3
- package/registry/field.muten +5 -5
- package/registry/file-input.js +8 -4
- package/registry/file-input.muten +3 -3
- package/registry/fixed-card.muten +4 -4
- package/registry/folder-picker.js +6 -2
- package/registry/folder-picker.muten +2 -2
- package/registry/heatmap.muten +5 -5
- package/registry/image-upload.js +1 -1
- package/registry/image-upload.muten +2 -2
- package/registry/inbox-play.muten +5 -5
- package/registry/indicator.muten +1 -1
- package/registry/info-table.muten +1 -1
- package/registry/input-group.muten +11 -11
- package/registry/input-otp.muten +2 -2
- package/registry/input.muten +1 -1
- package/registry/inspector.muten +2 -2
- package/registry/item.muten +2 -2
- package/registry/kit/board.js +36 -34
- package/registry/kit/collections.js +24 -24
- package/registry/kit/core.js +197 -114
- package/registry/kit/dates.js +29 -27
- package/registry/kit/i18n.js +172 -0
- package/registry/kit/menus.js +14 -13
- package/registry/kit/overlays.js +7 -2
- package/registry/kit/structure.js +66 -61
- package/registry/kit/table.js +19 -17
- package/registry/kit/values.js +36 -28
- package/registry/kit-skeleton.muten +1 -1
- package/registry/kit-widget.js +9 -4
- package/registry/lang-scope.js +8 -0
- package/registry/lang-scope.muten +5 -0
- package/registry/legal-doc.muten +5 -5
- package/registry/link-btn.muten +1 -1
- package/registry/list-motion.js +46 -0
- package/registry/list-motion.muten +4 -0
- package/registry/live-stack.muten +2 -2
- package/registry/logo-cloud.muten +2 -2
- package/registry/marketing.muten +7 -7
- package/registry/member-list.muten +2 -2
- package/registry/menubar.muten +3 -3
- package/registry/message-scroller.muten +3 -3
- package/registry/message.muten +9 -9
- package/registry/messaging.muten +1 -1
- package/registry/modal.muten +4 -4
- package/registry/money-field.js +1 -1
- package/registry/money-field.muten +2 -2
- package/registry/nav-button.muten +4 -4
- package/registry/navigation-menu.muten +4 -4
- package/registry/navpill.muten +6 -6
- package/registry/new-appointment.js +1 -1
- package/registry/new-appointment.muten +4 -4
- package/registry/number-field.js +6 -4
- package/registry/number-field.muten +1 -1
- package/registry/order-board.js +1 -1
- package/registry/order-board.muten +2 -2
- package/registry/order-play.muten +4 -4
- package/registry/pagination-nav.js +1 -1
- package/registry/pagination-nav.muten +3 -3
- package/registry/pagination.muten +4 -4
- package/registry/password-field.muten +2 -2
- package/registry/permission-matrix.muten +4 -4
- package/registry/phone-bar.muten +6 -6
- package/registry/phone-field.js +1 -1
- package/registry/phone-field.muten +1 -1
- package/registry/phone-shell.js +1 -1
- package/registry/pill.muten +2 -2
- package/registry/plans.muten +1 -1
- package/registry/popover.muten +2 -2
- package/registry/pricing.muten +4 -4
- package/registry/product-play.muten +3 -3
- package/registry/progress.muten +3 -3
- package/registry/queue.muten +1 -1
- package/registry/radio-group.muten +1 -1
- package/registry/rank-item.muten +4 -4
- package/registry/resizable.muten +1 -1
- package/registry/row-menu.js +1 -1
- package/registry/row-menu.muten +2 -2
- package/registry/save-button.muten +5 -5
- package/registry/scale-slider.js +1 -1
- package/registry/scale-slider.muten +2 -2
- package/registry/screen-tour.muten +1 -1
- package/registry/share-bar.muten +2 -2
- package/registry/share-button.muten +4 -4
- package/registry/sheet.muten +1 -1
- package/registry/sidebar.muten +12 -6
- package/registry/site-footer.muten +6 -6
- package/registry/sortable-behavior.js +67 -20
- package/registry/sortable-list.js +3 -1
- package/registry/sortable-list.muten +2 -2
- package/registry/sortable.muten +5 -4
- package/registry/spinner.muten +2 -2
- package/registry/split-button.muten +2 -2
- package/registry/stacked-bars.js +3 -3
- package/registry/stacked-bars.muten +2 -2
- package/registry/stamp-card.muten +2 -2
- package/registry/stat-band.muten +3 -3
- package/registry/stat.muten +3 -3
- package/registry/status-bar.muten +2 -2
- package/registry/stepper.muten +4 -4
- package/registry/store-qr.js +1 -1
- package/registry/store-qr.muten +2 -2
- package/registry/swatch.muten +1 -1
- package/registry/switch.muten +8 -7
- package/registry/table-view.muten +3 -3
- package/registry/tabs-behavior.js +9 -1
- package/registry/tabs.muten +2 -2
- package/registry/tag-input.js +1 -1
- package/registry/tag-input.muten +2 -2
- package/registry/text.muten +2 -2
- package/registry/time-field.js +1 -1
- package/registry/time-field.muten +3 -3
- package/registry/timeline.muten +4 -4
- package/registry/toaster.muten +2 -2
- package/registry/toggle-group.muten +1 -1
- package/registry/toggle.muten +3 -3
- package/registry/toolbar.muten +4 -4
- package/registry/tooltip.muten +2 -2
- package/registry/tree-view.js +38 -25
- package/registry/tree-view.muten +1 -1
- package/registry/veil.muten +1 -1
- package/registry/virtual-list.js +1 -1
- package/registry/virtual-list.muten +2 -2
- package/registry/virtual-window.js +4 -4
- package/registry/virtual-window.muten +2 -2
- package/registry/wordline.muten +1 -1
- package/registry/zoom-control.muten +1 -1
- package/registry.json +22 -2
package/AGENTS.md
CHANGED
|
@@ -124,6 +124,93 @@ Rules the kit keeps: the page owns the state and gets JSON back through actions;
|
|
|
124
124
|
(a bot's answers are `{match, text}` rules); a skeleton only shows while there is nothing to show; no native
|
|
125
125
|
`<select>`, the wheels and menus instead.
|
|
126
126
|
|
|
127
|
+
## Motion: one rhythm for the whole library
|
|
128
|
+
|
|
129
|
+
Every component moves with the same tokens, so a store, a tool and a wellness app built on the kit feel like one
|
|
130
|
+
family. The tokens live in kit.css `:root`; a component **never writes its own curve or duration**. Live reference:
|
|
131
|
+
the bench page `/motion`.
|
|
132
|
+
|
|
133
|
+
| Token | Value | For |
|
|
134
|
+
|---|---|---|
|
|
135
|
+
| `--ease-out` | `cubic-bezier(.23, 1, .32, 1)` | anything entering or appearing |
|
|
136
|
+
| `--ease-in-out` | `cubic-bezier(.77, 0, .175, 1)` | something moving on screen, a panel leaving |
|
|
137
|
+
| `--ease-drawer` | `cubic-bezier(.32, .72, 0, 1)` | a sheet or drawer sliding in |
|
|
138
|
+
| `--t-press` | 100 ms | a control giving under the press |
|
|
139
|
+
| `--t-micro` | 150 ms | tooltip, a check, an icon swap |
|
|
140
|
+
| `--t-pop` | 180 ms | menu, popover, select |
|
|
141
|
+
| `--t-move` | 240 ms | tab pill, switch, a fold, a list row, a value travelling |
|
|
142
|
+
| `--t-modal` | 240 ms | a dialog entering |
|
|
143
|
+
| `--t-sheet` | 380 ms | a sheet or drawer entering |
|
|
144
|
+
|
|
145
|
+
Rules (they are what makes the components plug and play):
|
|
146
|
+
- **It comes built in.** Use the part and it already moves; the page writes no CSS and picks no duration.
|
|
147
|
+
- **Leaving is faster than entering**, about 0.6 to 0.7 of it (`calc(var(--t-modal) * .62)`): the thing going is no longer what matters.
|
|
148
|
+
- **A hover never animates and never moves the element.** Rows, menu items, nav links and buttons change colour instantly; a `translateY` on hover blinks on the element's edge. See «Hover never blinks» in the muten-design skill.
|
|
149
|
+
- **Keyboard actions do not animate** (⌘K, arrows). What is seen a hundred times a day moves less, not more.
|
|
150
|
+
- **The first paint does not animate.** What moves is what changed because the person did something or a datum arrived (e.g. tab panels only slide once the person switched tabs: `data-tabs-moved`).
|
|
151
|
+
- **Nesting does not double.** A dialog that enters with a list inside: only the dialog enters.
|
|
152
|
+
- **A skin never touches motion.** Skins change colour, type and corners; the rhythm stays.
|
|
153
|
+
- **Reduce motion lives in one place:** under `prefers-reduced-motion` the duration tokens drop to 1 ms.
|
|
154
|
+
- **A state change is a transition, never an animation.** A CSS `animation` on a state (`:checked`, `[data-state]`) replays on the first paint and every time its node is moved (a row reordered), which reads as a flicker; a `transition` only runs when the state changes. Keep `animation` for something appearing (with `data-kit-live`) or leaving.
|
|
155
|
+
- **Check what Nova already animates before adding motion.** A kit part sits on Nova's CSS (its own transitions, positions in %, colours per state); a second animation on top fights it. Nothing that runs together may change the reference it is measured from: a `scale` whose `transform-origin` flips with the state threw the switch thumb outside its track for a frame. Film it (press AND release, both ways) before calling it done.
|
|
156
|
+
- **Select a state by its value, never by the attribute alone.** muten writes every `data()` attribute always (`data-loading="false"`), so `[data-loading]` matches every Btn: a `position: relative` there pulled the dialogs' absolute close button into the flow and broke every modal. Write `[data-loading="true"]`, and check a generic rule against Dialog, Sheet and a form before calling it done.
|
|
157
|
+
- **Never take a floating panel out of the top layer to bring it back:** a menu reopened while it is still closing vanished for a frame. Raise it once (`place()` does).
|
|
158
|
+
|
|
159
|
+
The pieces that make it plug and play (use them, never re-invent them):
|
|
160
|
+
- **Tokens** in kit.css `:root`; from script, `ms('--t-move')` / `ease('--ease-out')` in kit/core.js (WAAPI cannot read `var()`; they read the live tokens, so reduce motion and skins apply).
|
|
161
|
+
- **`data-kit-live` on `<html>`** (set by kit/core.js once the page has painted): an entrance written as `:root[data-kit-live] .x { @starting-style { … } }` plays for what appears later and never on the first paint.
|
|
162
|
+
- **`ListMotion`** (inside every `ItemGroup`): rows of an `each` open their place, leave closing their gap, moves are not entrances, and a whole page swapped only fades (no height jump).
|
|
163
|
+
- **`.cx-swap-in`**: wrap a label or icon that changes to say what happened (Copiar → Copiado, copy → check); it grows in from its middle out of a short blur.
|
|
164
|
+
- **muten's `.mu-leave`** (with `--mu-h`): what a `when` takes away can close its gap (the Alert does).
|
|
165
|
+
- A Custom's returned function is its **updater** (called with new inputs), not a cleanup: return nothing unless it updates.
|
|
166
|
+
|
|
167
|
+
Done (October 2026): the tokens; every ease-out curve on `--ease-out` (CSS and the kit's WAAPI) and the drawer on
|
|
168
|
+
`--ease-drawer`; popover / dropdown / context menu / menubar / hover card on `--t-pop`; tooltip on `--t-micro`,
|
|
169
|
+
instant after the first; dialog (in from 6 px lower at 97 %, out faster) and its overlay; sheet (drawer curve in,
|
|
170
|
+
shorter in-out out); tabs (pill on `--t-move`, panel in from the side you went, only after a switch); accordion /
|
|
171
|
+
collapsible; switch (track and thumb together, the thumb stretches on press); checkbox (fills, the check grows in);
|
|
172
|
+
Btn `loading` (keeps its width, the content fades, the spinner comes in centred); SaveButton labels; every copy
|
|
173
|
+
feedback (`.cx-swap-in`); CountUp with rolling digits (roll "view" | "change") and StatCard's value rolling on change;
|
|
174
|
+
list rows (ListMotion in ItemGroup); Loading's content landing out of a blur; Alert entering / leaving; calendar
|
|
175
|
+
months and years sliding toward the arrow; bar chart bars on the tokens; the bell's nudge when unread goes up; the
|
|
176
|
+
AppShell section fade; Sortable / SortableList with a ghost of the row where it will land (rows slide apart, the row settles onto the ghost, Escape puts it back); progress bars; the sidebar fold; instant hovers.
|
|
177
|
+
Also done: sheet content arriving a moment after the panel, one row after another; the command palette with no
|
|
178
|
+
animation (it is opened from the keyboard); navigation menu / menubar swapping the panel in place between menus; the
|
|
179
|
+
Combobox on the tokens; shakes (OTP, island, a field turning invalid) on translate, never on the layout; timeline and
|
|
180
|
+
vertical stepper steps changing on the move token (and new timeline steps through ListMotion); heatmap cells and the
|
|
181
|
+
share bar travelling on the tokens; the SidebarTrigger.
|
|
182
|
+
Deliberately different from the proposal: a Btn that loads keeps its width (nothing beside it moves) instead of its
|
|
183
|
+
width travelling; the checkbox's check grows in instead of being drawn (it is a background image); a page turned by
|
|
184
|
+
Pagination fades in place (ListMotion) instead of sliding, since the rows are the page's, not the nav's.
|
|
185
|
+
To do: badge counts rolling (put a CountUp in it); the fixed durations still written in kit/board.js,
|
|
186
|
+
structure.js, table.js, kit-widget.js and stacked-bars.js (curves already on the token); TableView's own row
|
|
187
|
+
animation on the tokens. The number field does not roll: it is an input, its value must stay editable.
|
|
188
|
+
|
|
189
|
+
## Language: written in English, speaks the language it is in
|
|
190
|
+
|
|
191
|
+
Every word the library writes is English in the code, and the English text is its key; kit/i18n.js holds the other
|
|
192
|
+
languages (Spanish today) as dictionaries from that text: `t(lang, 'Page {0} of {1}', 2, 9)`, `'One item | {0} items'`.
|
|
193
|
+
A piece speaks the language of its nearest `lang` (a container's attribute, else `<html lang>`), English when there is
|
|
194
|
+
none. Change a `lang` with the page open and what is on screen says it again in the new one (no reload).
|
|
195
|
+
|
|
196
|
+
- **An app with its own i18n changes nothing.** It already sets `<html lang>` (Storio does, from its language pill), so
|
|
197
|
+
the library follows the app's language. Its own texts passed to a part (a label, a title) are never touched.
|
|
198
|
+
- **A part of the page in another language:** `LangScope(lang: shopLang) { … }` (the public store in the shop's language).
|
|
199
|
+
- **A Custom takes `lang` in its inputs** (KitWidget, Agenda, Calendar, ColorPicker…), which wins over the page's.
|
|
200
|
+
- **Writing a new piece:** English text through `t()`/`T()` in JS; in a .muten, the English text plus its mark
|
|
201
|
+
(`data(tr: …)` text, `trl` aria-label, `trn` tooltip, `trp` placeholder, `trt` title; values for {0}… in `tra`,
|
|
202
|
+
split by «|»). Add the Spanish to kit/i18n.js under the piece's group. Months and days: `kit.words(lang)`; currency and
|
|
203
|
+
country names: `Intl.DisplayNames`. A Custom that renders once paints through `core.relang(el, inputs, paint)` so a
|
|
204
|
+
language change repaints it.
|
|
205
|
+
- muten cannot interpolate inside `aria(label: "…")`: a label with a value is a mark (`trl` + `tra`) or set from JS.
|
|
206
|
+
|
|
207
|
+
Before Storio moves to this version (it is on 0.1.15, still all Spanish):
|
|
208
|
+
- Nothing to do for the app: `<html lang="es">` keeps everything Spanish, and with the app in English the library now
|
|
209
|
+
follows it (before, its own words stayed Spanish).
|
|
210
|
+
- The public store (book.muten) speaks `shopLang`, not the app's language: wrap it in `LangScope(lang: shopLang)` (and
|
|
211
|
+
the Design / Store previews in `LangScope(lang: previewLang)`), or the library's words there follow the visitor's.
|
|
212
|
+
- Check one screen of each in English and in Spanish: agenda, messaging, money and phone fields, the store's booking.
|
|
213
|
+
|
|
127
214
|
## PLUG-AND-PLAY (zero class props)
|
|
128
215
|
- **Btn**(variant, onClick) { slot } · **LinkBtn**(to, variant) { slot } · **Input**(value, placeholder)
|
|
129
216
|
- **DataTable** @rows columns(a, b) - STYLED BY DEFAULT, no class needed.
|
|
@@ -222,7 +309,7 @@ Rules the kit keeps: the page owns the state and gets JSON back through actions;
|
|
|
222
309
|
- **textarea** - class("textarea") · label: class("label") · native select: class("native-select")
|
|
223
310
|
- **typography** - Title "Docs" h1 class("prose-h1") (prose-h1..h4 · prose-p|lead|large|small|muted|blockquote|code|list)
|
|
224
311
|
- **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.
|
|
225
|
-
- **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.
|
|
312
|
+
- **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. hover-lift carries an invisible strip under the lifted card so a pointer on its bottom edge does not make it blink; it fails on an element with overflow hidden (a Card clips it), so lift such a card with its shadow only. Never add a colour transition to a hover on a row, menu item, nav link or button: the kit's hover there is instant on purpose (a fade blinks when the pointer sweeps a list).
|
|
226
313
|
|
|
227
314
|
### 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.
|
|
228
315
|
|
package/globals.css
CHANGED
|
@@ -807,6 +807,7 @@
|
|
|
807
807
|
/* hover-lift - a card floats up + deepens its shadow on hover (the classic interactive-card feel) */
|
|
808
808
|
.hover-lift { transition: translate 300ms var(--mu-ease), box-shadow 300ms var(--mu-ease); }
|
|
809
809
|
.hover-lift:hover { @apply -translate-y-1 shadow-xl; }
|
|
810
|
+
.hover-lift:hover::after { content: ""; position: absolute; left: 0; right: 0; top: calc(100% - 2px); height: 10px; } /* fills the gap it lifts from: no blinking hover on its bottom edge */
|
|
810
811
|
|
|
811
812
|
/* ── Micro-interactions (drop the class on any node) ── */
|
|
812
813
|
/* link-underline - an underline that grows from the left on hover; perfect for nav links */
|