@justanarthur/modo-ui 0.6.0-canary.6 → 0.6.0-canary.8
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/DESIGN.md +8 -2
- package/README.md +87 -13
- package/components/AI/input-message/examples.mdx +34 -28
- package/components/AI/input-message/index.tsx +2 -0
- package/components/accordion/examples.mdx +41 -35
- package/components/badge/examples.mdx +30 -26
- package/components/button/examples.mdx +47 -43
- package/components/card/examples.mdx +135 -129
- package/components/copy/examples.mdx +50 -44
- package/components/inputs/checkbox/examples.mdx +34 -30
- package/components/inputs/color-picker/examples.mdx +39 -31
- package/components/inputs/combobox/examples.mdx +135 -125
- package/components/inputs/date-time/date-picker/examples.mdx +107 -97
- package/components/inputs/date-time/date-range-picker/examples.mdx +37 -33
- package/components/inputs/field/examples.mdx +58 -54
- package/components/inputs/file-dropzone/examples.mdx +15 -13
- package/components/inputs/input/examples.mdx +44 -13
- package/components/inputs/number-input/examples.mdx +18 -14
- package/components/inputs/select/examples.mdx +94 -84
- package/components/inputs/slider/examples.mdx +13 -11
- package/components/inputs/switch/examples.mdx +33 -31
- package/components/inputs/textarea/examples.mdx +39 -33
- package/components/navigation/pagination/examples.mdx +22 -16
- package/components/navigation/sidebar/examples.mdx +14 -8
- package/components/navigation/tabs/index.tsx +1 -1
- package/components/overlays/dropdown/examples.mdx +176 -168
- package/components/overlays/popover/examples.mdx +46 -40
- package/components/table/examples.mdx +45 -41
- package/dist/base.css +44 -0
- package/dist/blocks/sidebar-app/index.js +12 -11
- package/dist/components/AI/input-message/index.js +5 -4
- package/dist/components/accordion/index.js +3 -2
- package/dist/components/avatar/index.js +3 -2
- package/dist/components/badge/index.js +3 -2
- package/dist/components/button/index.js +3 -2
- package/dist/components/card/index.js +3 -2
- package/dist/components/copy/index.js +4 -3
- package/dist/components/inputs/checkbox/index.js +3 -2
- package/dist/components/inputs/color-picker/index.js +5 -4
- package/dist/components/inputs/combobox/index.js +5 -4
- package/dist/components/inputs/date-time/calendar/index.js +4 -3
- package/dist/components/inputs/date-time/date-picker/index.js +12 -11
- package/dist/components/inputs/date-time/date-range-picker/index.js +12 -11
- package/dist/components/inputs/date-time/duration-picker/index.js +11 -10
- package/dist/components/inputs/date-time/month-picker/index.js +10 -9
- package/dist/components/inputs/date-time/time-picker/index.js +11 -10
- package/dist/components/inputs/field/index.js +5 -4
- package/dist/components/inputs/file-dropzone/index.js +5 -4
- package/dist/components/inputs/input/index.js +4 -3
- package/dist/components/inputs/number-input/index.js +5 -4
- package/dist/components/inputs/radio/index.js +3 -2
- package/dist/components/inputs/search/index.js +7 -6
- package/dist/components/inputs/select/index.js +5 -4
- package/dist/components/inputs/slider/index.js +3 -2
- package/dist/components/inputs/switch/index.js +3 -2
- package/dist/components/inputs/textarea/index.js +4 -3
- package/dist/components/navigation/navigation-menu/index.js +4 -3
- package/dist/components/navigation/pagination/index.js +9 -8
- package/dist/components/navigation/sidebar/index.js +9 -8
- package/dist/components/navigation/tabs/index.js +3 -2
- package/dist/components/navigation/tabs-subtle/index.js +3 -2
- package/dist/components/overlays/alert-dialog/index.js +5 -4
- package/dist/components/overlays/command/index.js +6 -5
- package/dist/components/overlays/context-menu/index.js +6 -5
- package/dist/components/overlays/dialog/index.js +4 -3
- package/dist/components/overlays/dropdown/index.js +5 -4
- package/dist/components/overlays/popover/index.js +3 -2
- package/dist/components/overlays/preview-card/index.js +3 -2
- package/dist/components/overlays/sheet/index.js +5 -4
- package/dist/components/overlays/toast/index.js +4 -3
- package/dist/components/overlays/tooltip/index.js +3 -2
- package/dist/docs/index.d.ts +83 -0
- package/dist/docs/index.js +288 -0
- package/dist/docs/vite.d.ts +31 -0
- package/dist/docs/vite.js +45 -0
- package/dist/index.js +56 -55
- package/dist/lib/field-classes.d.ts +6 -1
- package/dist/lib/field-classes.js +3 -2
- package/dist/lib/focus-ring.js +3 -2
- package/dist/lib/scroll-column.js +3 -2
- package/dist/lib/shape-context.js +2 -1
- package/dist/lib/shape-radius.d.ts +19 -0
- package/dist/lib/shape-radius.js +6 -0
- package/dist/preset.d.ts +1 -0
- package/dist/preset.js +1 -0
- package/dist/primitives/code/index.js +4 -3
- package/dist/primitives/craft/index.js +4 -3
- package/dist/primitives/fluid-hover/index.js +3 -2
- package/dist/primitives/morph/index.js +4 -3
- package/dist/primitives/motion/index.js +4 -3
- package/dist/primitives/scroll-area/index.js +3 -2
- package/dist/primitives/skeleton/index.js +3 -2
- package/dist/shared/{components-59my5pwr.js → components-1kab3j44.js} +4 -4
- package/dist/shared/{components-47226105.js → components-2c64r8c9.js} +5 -5
- package/dist/shared/{components-vbh98t9d.js → components-2syq4mwc.js} +3 -3
- package/dist/shared/{components-dg6s5gjg.js → components-3ydr2fqe.js} +3 -3
- package/dist/shared/{components-z9n19fyk.js → components-4nck8acq.js} +1 -1
- package/dist/shared/{components-q4z71n18.js → components-5012r6gr.js} +2 -2
- package/dist/shared/{components-621xezcz.js → components-5sxjeh6h.js} +2 -2
- package/dist/shared/{components-pmfszv7a.js → components-5tzhqbcw.js} +2 -2
- package/dist/shared/{components-60atskhp.js → components-5y5shqfd.js} +1 -1
- package/dist/shared/{components-kr40s3z0.js → components-6b0zb8z3.js} +1 -1
- package/dist/shared/{components-c96k4gfs.js → components-6gk118w3.js} +2 -2
- package/dist/shared/{components-78x40gee.js → components-71nbt03m.js} +14 -1
- package/dist/shared/{components-52ngsgca.js → components-7zkhz3r8.js} +1 -1
- package/dist/shared/{components-02c81nsv.js → components-8mt5bsv6.js} +1 -1
- package/dist/shared/{components-nd1baxp1.js → components-8rb25gbe.js} +2 -2
- package/dist/shared/{components-ep3d57kp.js → components-8v644a0s.js} +4 -4
- package/dist/shared/{components-1edyddfg.js → components-9j9abkct.js} +3 -3
- package/dist/shared/{components-4swzve2d.js → components-9sttq78t.js} +1 -1
- package/dist/shared/{components-2c0qcfx4.js → components-av5t26rc.js} +1 -1
- package/dist/shared/{components-k57dtvgp.js → components-b94t6qtj.js} +3 -3
- package/dist/shared/{components-2z48g4fp.js → components-ctqmge8t.js} +2 -1
- package/dist/shared/{components-vqqapw72.js → components-cwg1d0w6.js} +1 -1
- package/dist/shared/{components-mpw667rb.js → components-dyae0y7h.js} +1 -1
- package/dist/shared/{components-35tmfjtw.js → components-ej4r7wmj.js} +2 -2
- package/dist/shared/{components-bwy8775y.js → components-eqze3y30.js} +5 -3
- package/dist/shared/{components-3qssegme.js → components-fejdzvqc.js} +5 -5
- package/dist/shared/{components-pd42emw3.js → components-ft3zdc79.js} +2 -2
- package/dist/shared/components-gx4h5rbb.js +40 -0
- package/dist/shared/{components-c6cz9nw6.js → components-gyt7my41.js} +3 -3
- package/dist/shared/{components-6zng858q.js → components-hdzrqqpx.js} +3 -1
- package/dist/shared/{components-zj640a90.js → components-jymmaevv.js} +3 -3
- package/dist/shared/{components-aj7f4v4v.js → components-khspp26b.js} +2 -2
- package/dist/shared/{components-b92nqk44.js → components-km7fhgbk.js} +1 -1
- package/dist/shared/{components-y1w3a6wx.js → components-mattt5jp.js} +2 -2
- package/dist/shared/{components-43brg0gv.js → components-mpa2y6x8.js} +4 -4
- package/dist/shared/{components-wktrrb4m.js → components-pt5ftm4p.js} +1 -1
- package/dist/shared/{components-t7c6c4t4.js → components-px2zm7dc.js} +1 -1
- package/dist/shared/{components-v0nz1m4t.js → components-qqcmtrbv.js} +1 -1
- package/dist/shared/{components-0rpek9d8.js → components-r7q1zm7r.js} +2 -2
- package/dist/shared/{components-n155gkhr.js → components-rpw4md2b.js} +2 -2
- package/dist/shared/{components-72w4ge68.js → components-rtadhd9j.js} +1 -1
- package/dist/shared/{components-nv4awn05.js → components-s8yqk2dc.js} +1 -1
- package/dist/shared/{components-wwd363me.js → components-skfd7kff.js} +1 -1
- package/dist/shared/{components-daqy7ydp.js → components-t2a3qmy9.js} +2 -2
- package/dist/shared/{components-030n1m1v.js → components-t50hrswb.js} +2 -2
- package/dist/shared/{components-jkctvwz9.js → components-t5pk5nmc.js} +1 -1
- package/dist/shared/{components-49bsynbw.js → components-vc864c51.js} +1 -1
- package/dist/shared/{components-d7nhksd0.js → components-vkwq2k96.js} +1 -1
- package/dist/shared/{components-64c8kvmt.js → components-w0xq6q9k.js} +3 -3
- package/dist/shared/{components-8nwsqjn8.js → components-wbbckbw8.js} +1 -1
- package/dist/shared/{components-hx4a4cvm.js → components-wqrvqq5p.js} +3 -3
- package/dist/shared/{components-96sd8h9m.js → components-xjkdvnbg.js} +1 -1
- package/dist/shared/{components-hpe3avtw.js → components-xqszvkj4.js} +3 -3
- package/dist/shared/{components-tjtjmjjr.js → components-y1qvbawa.js} +1 -1
- package/dist/shared/{components-9n43qf8y.js → components-z0bqtvcp.js} +5 -5
- package/dist/shared/{components-khcnzj3g.js → components-z6dfqtyt.js} +3 -3
- package/dist/styles.css +46 -1
- package/dist/tailwind.css +1 -0
- package/dist/tokens/colors.css +6 -0
- package/dist/tokens.css +6 -0
- package/docs/chrome.css +120 -0
- package/docs/chrome.tsx +283 -0
- package/docs/index.ts +9 -0
- package/docs/vite.ts +85 -0
- package/lib/field-classes.ts +7 -1
- package/lib/shape-context.tsx +16 -2
- package/lib/shape-radius.ts +67 -0
- package/package.json +26 -2
- package/preset.ts +1 -0
- package/primitives/craft/examples.mdx +22 -18
- package/primitives/morph/examples.mdx +11 -7
- package/primitives/scroll-area/index.tsx +4 -0
package/DESIGN.md
CHANGED
|
@@ -67,6 +67,8 @@ colors:
|
|
|
67
67
|
image-edge-dark: "rgb(255 255 255 / 0.1)"
|
|
68
68
|
progress-track: "color-mix(in oklab, oklch(0.205 0 0) 10%, transparent)"
|
|
69
69
|
progress-track-dark: "color-mix(in oklab, oklch(0.97 0 0) 10%, transparent)"
|
|
70
|
+
well: "oklch(0.967 0.001 286.375)"
|
|
71
|
+
well-dark: "oklch(0 0 0 / 0.25)"
|
|
70
72
|
surface-1: "oklch(0.985 0 0)"
|
|
71
73
|
surface-2: "oklch(0.991 0 0)"
|
|
72
74
|
surface-3: "oklch(1 0 0)"
|
|
@@ -284,7 +286,7 @@ components:
|
|
|
284
286
|
padding: 24px
|
|
285
287
|
width: 400px
|
|
286
288
|
tabs-list:
|
|
287
|
-
backgroundColor: "{colors.
|
|
289
|
+
backgroundColor: "{colors.well}"
|
|
288
290
|
rounded: "{rounded.xl}"
|
|
289
291
|
height: "{spacing.control}"
|
|
290
292
|
padding: 4px
|
|
@@ -357,7 +359,11 @@ Two text colors, a greyscale ground, one blue.
|
|
|
357
359
|
button (until `--primary-foreground` is re-pointed) and the tooltip (`text-background`).
|
|
358
360
|
- **Surfaces (`bg-surface-1` … `bg-surface-8`)** — the elevation ladder (see Elevation & Depth). Prefer a
|
|
359
361
|
surface level over `card`/`background` for anything that floats or nests.
|
|
360
|
-
- **Muted (`bg-muted`)** — a
|
|
362
|
+
- **Muted (`bg-muted`)** — a sunken fill: a field's hover wash, a queued row. In dark it is surface 2, so
|
|
363
|
+
it never carries a track: it would vanish on a card or the inset.
|
|
364
|
+
- **Well (`bg-well`)** — the recessed track under a segmented control's indicator (the tabs list). Light is
|
|
365
|
+
muted; dark is black at 25%, which darkens whatever it sits on, so the track reads on the page, a card
|
|
366
|
+
and the inset alike.
|
|
361
367
|
- **Accent (`bg-accent`)** — the secondary button and the switch's off track. `selected` is a firmer
|
|
362
368
|
grey for persistent selection fills.
|
|
363
369
|
- **Hover / Active (`bg-hover`, `bg-active`)** — translucent overlays (black 4% / 7% in light, white 6% /
|
package/README.md
CHANGED
|
@@ -106,7 +106,7 @@ Every vendored file opens with a plain `/* */` header. The header names the
|
|
|
106
106
|
upstream path and commit, carries the MIT notice, and lists every local
|
|
107
107
|
modification. The vendored code below the header keeps upstream's formatting.
|
|
108
108
|
Files written for this port (`preset.ts`, `uno.config.ts`, `vite.ts`, `index.ts`,
|
|
109
|
-
`scripts/build-css.ts`, `
|
|
109
|
+
`scripts/build-css.ts`, `docs/*`,
|
|
110
110
|
`lib/use-controllable-state.ts`, `primitives/code/index.tsx`, `primitives/craft/*`, the morph files
|
|
111
111
|
in `lib/` (`use-morph.ts`, `reduced-motion.ts`, `morph-layers.tsx`, `morph-part.tsx`, `goo-indicator.tsx`,
|
|
112
112
|
`slot.ts`) and `primitives/morph/index.tsx`, `blocks/sidebar-app/index.tsx`,
|
|
@@ -137,13 +137,13 @@ positioning) are ported.
|
|
|
137
137
|
| `DESIGN.md` | The design language in Google's [DESIGN.md](https://github.com/google-labs-code/design.md) format: the tokens as front matter, the rules as prose. Agents building here follow the `modo-ui` skill (`.claude/skills/modo-ui` at the repo root). |
|
|
138
138
|
| `tokens/*.css` | Colors, typography (`--font-sans`, `--text-*`), motion (`--duration-*`), radius and spacing. Shipped per group as `dist/tokens/*.css` (`./tokens/*`). |
|
|
139
139
|
| `base.css` | Theme switching, base styles, focus fallback, scrollbars, shimmer/spinner keyframes and `.scroll-fade`. Shipped in the package. The inline `code` chip applies only inside the docs shell, `data-modo="prose"` and `.modo-prose`. |
|
|
140
|
-
| `global.css` | The docs site's stylesheet (`modo.config.ts` `css`): imports `base.css`, then
|
|
140
|
+
| `global.css` | The docs site's stylesheet (`modo.config.ts` `css`): imports `base.css`, then `docs/chrome.css`. |
|
|
141
141
|
| `preset.ts` | The UnoCSS preset (theme and token utilities), shipped as `@justanarthur/modo-ui/unocss`. |
|
|
142
|
-
| `uno.config.ts`, `vite.ts` | The UnoCSS setup of the docs site and the prebuilt CSS (see below). |
|
|
142
|
+
| `uno.config.ts`, `vite.ts` | The UnoCSS setup of the docs site and the prebuilt CSS (see below); `vite.ts` also applies the docs chrome's `docsTheme` plugin. |
|
|
143
143
|
| `index.ts`, `bunup.config.ts`, `scripts/build-css.ts` | The package build: `bun run build` writes the components, their types and the stylesheets to `dist/`. The docs site builds with `bun run build:docs` into `docs-dist/`. |
|
|
144
144
|
| `scripts/exports.ts`, `scripts/use-client.ts`, `scripts/check-singletons.ts` | Packaging around that build. `exports.ts` (first step of `bun run build`) writes one `./lib/<name>` export per `lib/` module into `package.json`, plus `./components/*/variants` and `./blocks/*/variants` for the items' server-callable `variants.ts` entries; commit the `package.json` it leaves. `use-client.ts` (after bunup) puts `"use client"` on the emitted modules that render, call a hook or create a context, or use a binding from one; pure helpers (`cn`, class tables, springs, `variants.ts`) and re-export entries stay directive-free so a React Server Component can call them (`--list` prints the split). `check-singletons.ts` (`bun run check:dist`) checks that every React context and the `toast()` manager exist once in `dist/`, and that every entry has its `.d.ts`. `typesVersions` in `package.json` maps every public subpath to `dist/**/*.d.ts`, so `moduleResolution: node` consumers do not type-check the shipped source. |
|
|
145
145
|
| `lib/` | FF's shared system files (upstream `lib/`, `hooks/` and the fluid-hover highlight, flat, upstream names), imported relatively by items. modo only scans the tier folders, so it never mistakes them for items. |
|
|
146
|
-
| `
|
|
146
|
+
| `docs/` | The docs chrome, shipped: `chrome.tsx` (the `Button`, `Link`, `Icon`, `Select` and `DocsNav` shell-slot adapters and the `ThemeSwitcher` panel item, re-exported by `index.ts` as `@justanarthur/modo-ui/docs`), `chrome.css` (the inset layout and the look of the chrome, `@justanarthur/modo-ui/docs/chrome.css`) and `vite.ts` (`docsTheme`, the pre-paint theme controller, `@justanarthur/modo-ui/docs/vite`). `modo.config.ts` picks the slots by export name (`./docs#DocsNav`); another design system documented with modo points at the same module by package specifier (see **The docs chrome, for another design system**). The barrel (`index.ts`) never imports it, `bun run check:dist` fails if it does. |
|
|
147
147
|
| `primitives/<id>/` | FF's "System" pages: `index.tsx` (component + TSDoc prose) and `examples.mdx`, pulled in by `@example {@include ./examples.mdx}`. |
|
|
148
148
|
| `components/[<group>/]<id>/` | FF's "Components" pages, same shape. The `AI/`, `inputs/` (with `inputs/date-time/`), `navigation/` and `overlays/` group folders become sidebar sub-groups and overview sections; the core display items stay ungrouped. |
|
|
149
149
|
| `blocks/<id>/` | Compositions of several items, same shape: `sidebar-app`, FF's sidebar preset `sa1FQfCxH6` as an app shell, with the header and footer blocks it is built from beside it. |
|
|
@@ -158,7 +158,8 @@ positioning) are ported.
|
|
|
158
158
|
| `lib/springs.ts` | `lib/springs.ts` | `goo` tier added (the morph engine's goo: 250ms to land, bounce 0.15, a 200ms spring back); `exitFallbackMs` also reads a spring exit's `visualDuration` |
|
|
159
159
|
| `lib/font-weight.ts` | — | not ported: its `fontWeights` became the `--weight-*` tokens in `tokens/typography.css` (the `weight-*` utilities) |
|
|
160
160
|
| `lib/popup.ts` | `lib/popup.ts` | `popupMotionClass` dropped (unused since the popups morph) |
|
|
161
|
-
| `lib/shape-context.tsx` | `lib/shape-context.tsx` | `"use client"` dropped |
|
|
161
|
+
| `lib/shape-context.tsx` | `lib/shape-context.tsx` | `"use client"` dropped; `--shape-input-radius` is published through `claimShapeRadius` and given back on unmount |
|
|
162
|
+
| — (new) | `lib/shape-radius.ts` | Local addition: the stack of `ShapeProvider` claims on `--shape-input-radius` (`<html>`), so an unmounting provider restores the one below it or the page's own value; plain data, tested without a DOM |
|
|
162
163
|
| `lib/size-context.tsx` | `lib/size-context.tsx` | `"use client"` dropped; `SizeProvider` moved to `primitives/sizes` (the documented item), with `SizeContext` exported for it; `sizeMap`, `typeScale` and their types moved to `size-scale.ts` and re-exported |
|
|
163
164
|
| `lib/size-context.tsx` (`sizeMap`, `typeScale`) | `lib/size-scale.ts` | The ladder's plain data, split out so server code can read it (no JSX, hooks or contexts); `sizeMap` text classes → `text-body` / `text-body-compact` |
|
|
164
165
|
| `lib/icon-context.tsx` | `lib/icon-context.tsx` | `"use client"` dropped; `size`/`strokeWidth` widened to `number \| string` for lucide v1 + React 18 types |
|
|
@@ -292,17 +293,17 @@ only what is specific to it:
|
|
|
292
293
|
| — | `registry/blocks/sidebar-app/inset-topbar.tsx` | `blocks/sidebar-app/inset-topbar.tsx` | the trigger's peek-time fade dropped (the sidebar opens on hover in flow, so the trigger stays) |
|
|
293
294
|
| — | `registry/default/lib/sidebar-menu-grid.ts` | `blocks/sidebar-app/menu-grid.ts` | the width reads `--anchor-width` only; the `-ml-1` shift dropped (it would move the morph surface's content off its background) |
|
|
294
295
|
|
|
295
|
-
`Select` in `
|
|
296
|
+
`Select` in `docs/chrome.tsx` is not an item: modo's docs chrome renders its Select slot
|
|
296
297
|
with a flat `value` / `onChange` / `options` contract
|
|
297
298
|
(`lib/src/lib/slots.tsx`), and this adapter maps it onto
|
|
298
299
|
`Select.Trigger` / `Select.Content` / `Select.Item` so the chrome runs on the
|
|
299
300
|
design system's own Select. The
|
|
300
301
|
`components/inputs/select` item keeps the upstream API untouched.
|
|
301
302
|
|
|
302
|
-
`DocsNav` in `
|
|
303
|
+
`DocsNav` in `docs/chrome.tsx` is the chrome's Sidebar slot, pinned as
|
|
303
304
|
`shell.Sidebar` (by name alone modo would adopt the documented `Sidebar`, an
|
|
304
305
|
app shell that needs its provider). Each aside is an inset `Sidebar` with its
|
|
305
|
-
own provider, and `
|
|
306
|
+
own provider, and `docs/chrome.css` turns the content between them into the inset
|
|
306
307
|
card (the lib's grid columns become `auto`, so they follow the sidebars' width
|
|
307
308
|
springs). Each provider has `openOnHover`, and its `Sidebar.Trigger` sits in
|
|
308
309
|
the card's corner: the trigger, `[` for the nav and `]` for the panel, switch
|
|
@@ -315,7 +316,7 @@ below xl. A section of links is a collapsible `Sidebar.Group` with one
|
|
|
315
316
|
highlight melt from link to link; a panel section (Theme) keeps its control
|
|
316
317
|
under the group label.
|
|
317
318
|
|
|
318
|
-
`ThemeSwitcher` in `
|
|
319
|
+
`ThemeSwitcher` in `docs/chrome.tsx` is not an item either: it is the `Theme` entry in
|
|
319
320
|
`modo.config.ts` `panel.items`, a `Select` of Light / Dark / System (each row
|
|
320
321
|
with its icon, the trigger showing the active one) that reads and sets
|
|
321
322
|
`window.__uiTheme` and re-reads it on `ui:themechange`. All switching logic lives in the pre-paint controller
|
|
@@ -323,6 +324,75 @@ described under **Tailwind → UnoCSS**, so the control holds no theme state of
|
|
|
323
324
|
its own. `demo/scripts/run-design-systems.ts` appends its own `Switcher` panel
|
|
324
325
|
item to whatever a design system declares, so both show up under the runner.
|
|
325
326
|
|
|
327
|
+
The chrome's own elements (the corner triggers, the panel section's gutter) are
|
|
328
|
+
styled in `docs/chrome.css` through `data-modo-ui` attributes, not utility
|
|
329
|
+
classes: nothing in `docs/` needs a UnoCSS or Tailwind scan, so a host with
|
|
330
|
+
either generator loads the same file. `Button` and `Link` are pinned too, so a
|
|
331
|
+
design system with items of those names but another prop shape is not matched
|
|
332
|
+
by name (modo would warn on every start).
|
|
333
|
+
|
|
334
|
+
### The docs chrome, for another design system
|
|
335
|
+
|
|
336
|
+
A design system documented with modo (an `@utegsk/ui`-style package that
|
|
337
|
+
depends on `@justanarthur/modo-ui`) gets the same sidebars, inset card layout,
|
|
338
|
+
panel and Theme switcher as this site by pointing its `modo.config.ts` at the
|
|
339
|
+
shipped module. A `shell` / `panel` value may be a package specifier (the
|
|
340
|
+
viewer resolves it from the project root through the package's `exports`, the
|
|
341
|
+
`source` file first), which needs an `@justanarthur/modo` release after
|
|
342
|
+
0.9.0-canary.0; with an older viewer keep a one-line local re-export instead
|
|
343
|
+
(`export * from '@justanarthur/modo-ui/docs'` in a `docs/shell.tsx`, and point
|
|
344
|
+
the slots at `./docs/shell.tsx#DocsNav`).
|
|
345
|
+
|
|
346
|
+
```ts
|
|
347
|
+
// modo.config.ts
|
|
348
|
+
import { defineConfig } from '@justanarthur/modo/config'
|
|
349
|
+
|
|
350
|
+
export default defineConfig({
|
|
351
|
+
name: 'My DS',
|
|
352
|
+
css: './docs.css',
|
|
353
|
+
vite: './vite.mjs',
|
|
354
|
+
shell: {
|
|
355
|
+
Button: '@justanarthur/modo-ui/docs#Button',
|
|
356
|
+
Link: '@justanarthur/modo-ui/docs#Link',
|
|
357
|
+
Select: '@justanarthur/modo-ui/docs#Select',
|
|
358
|
+
Icon: '@justanarthur/modo-ui/docs#Icon',
|
|
359
|
+
Sidebar: '@justanarthur/modo-ui/docs#DocsNav',
|
|
360
|
+
},
|
|
361
|
+
panel: { items: [{ label: 'Theme', component: '@justanarthur/modo-ui/docs#ThemeSwitcher' }] },
|
|
362
|
+
})
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
```css
|
|
366
|
+
/* docs.css: the package stylesheet (or base.css with your own utilities), then the chrome */
|
|
367
|
+
@import "@justanarthur/modo-ui/styles.css";
|
|
368
|
+
@import "@justanarthur/modo-ui/docs/chrome.css";
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
```js
|
|
372
|
+
// vite.mjs: plain JS, Node loads it as is. Add your own plugins (Tailwind, UnoCSS) beside docsTheme.
|
|
373
|
+
import { docsTheme } from '@justanarthur/modo-ui/docs/vite'
|
|
374
|
+
|
|
375
|
+
export default config => {
|
|
376
|
+
config.plugins = [...(config.plugins ?? []), docsTheme({ storageKey: 'my-ds-theme' })]
|
|
377
|
+
return config
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
- `chrome.css` also loads by itself, as the stylesheet beside the slot module,
|
|
382
|
+
when modo bundles `@justanarthur/modo-ui/docs` from its source; the explicit
|
|
383
|
+
`@import` fixes where it sits in your cascade and is the one to rely on.
|
|
384
|
+
- `docsTheme` puts `.light` / `.dark` on `<html>` before first paint and
|
|
385
|
+
exposes `window.__uiTheme` for `ThemeSwitcher`; `storageKey` (default
|
|
386
|
+
`modo-ui-theme`) keeps two sites on one origin apart.
|
|
387
|
+
- The panel's narrow-screen behavior (below xl the panel is a drawer, opened on
|
|
388
|
+
hover or with `]`, never a strip above the content) comes with `chrome.css`.
|
|
389
|
+
A stylesheet that re-implements the layout instead of importing it can
|
|
390
|
+
recreate the lib's `grid-template-rows: auto` strip: a viewport-tall blank
|
|
391
|
+
row with the Theme select behind it.
|
|
392
|
+
- `lucide-react` (the `Icon` slot) is already a dependency of the package;
|
|
393
|
+
the docs entry adds no other. `@justanarthur/modo-ui` itself must be a
|
|
394
|
+
dependency of the host: modo resolves the specifier from the project root.
|
|
395
|
+
|
|
326
396
|
## Tier mapping
|
|
327
397
|
|
|
328
398
|
The tiers mirror the FF docs navigation. FF's "System" pages become
|
|
@@ -371,7 +441,7 @@ No ported file imports any of them.
|
|
|
371
441
|
|
|
372
442
|
The files only they, or the FF docs site's nav, use are left out too:
|
|
373
443
|
`mobile-drawer`, `nav-item`, `nav-menu`, `lib/theme-context.tsx` (the
|
|
374
|
-
`ThemeSwitcher` panel item and vite.ts's pre-paint controller take its
|
|
444
|
+
`ThemeSwitcher` panel item and docs/vite.ts's pre-paint controller take its
|
|
375
445
|
place) and the blocks other than the sidebar's (`queued-stack`,
|
|
376
446
|
`dialog-sidebar`). Inside kept files, the same rule removed
|
|
377
447
|
`SURFACE_HOVER_BG`, `SURFACE_HOVER_SHADOW` and `surfaceHoverClasses` from
|
|
@@ -398,7 +468,8 @@ prebuilt `styles.css`, and turns `preset.ts` into `tailwind.css`.
|
|
|
398
468
|
|
|
399
469
|
- **Dark mode.** `dark: 'class'` produces `.dark .dark\:x`, the same "inside a
|
|
400
470
|
`.dark` ancestor" contract as FF's `@custom-variant dark (&:is(.dark *))`.
|
|
401
|
-
modo ships no theme of its own, so `vite.ts
|
|
471
|
+
modo ships no theme of its own, so `docsTheme` (`docs/vite.ts`, applied by
|
|
472
|
+
`vite.ts`) injects a small controller into
|
|
402
473
|
`index.html` (`transformIndexHtml`, `head-prepend`). Before first paint it
|
|
403
474
|
puts `light` or `dark` on `<html>` — the stored preference, or the OS one
|
|
404
475
|
under `system` — which is also what flips every `light-dark()` token through
|
|
@@ -411,7 +482,10 @@ prebuilt `styles.css`, and turns `preset.ts` into `tailwind.css`.
|
|
|
411
482
|
`global.css` (and the `base.css` it imports) and fixes the order of the
|
|
412
483
|
layer its `@layer base` rules join.
|
|
413
484
|
`vite.ts` is loaded by Node with type stripping, so it may only use erasable
|
|
414
|
-
TypeScript
|
|
485
|
+
TypeScript, names the `.ts` extension of the one relative module it imports
|
|
486
|
+
(`./docs/vite.ts`) and hands `uno.config.ts` to UnoCSS by absolute path.
|
|
487
|
+
`docs/vite.ts` ships built (`dist/docs/vite.js`): Node never strips types
|
|
488
|
+
from a file under `node_modules`.
|
|
415
489
|
- **Colors.** Theme colors point at the CSS variables directly (for example
|
|
416
490
|
`accent: 'var(--accent)'`, `surface.1..8`). wind4 applies opacity modifiers
|
|
417
491
|
to `var()` colors with `color-mix(in srgb, …)`, so `bg-accent/12` works on
|
|
@@ -435,7 +509,7 @@ prebuilt `styles.css`, and turns `preset.ts` into `tailwind.css`.
|
|
|
435
509
|
after the reset, so utilities (in `default`) still win. This is the same
|
|
436
510
|
arrangement as Tailwind's base/utilities split.
|
|
437
511
|
- **Content.** UnoCSS scans `{lib,primitives,components,blocks}/**/*.{ts,tsx,mdx}`
|
|
438
|
-
|
|
512
|
+
from disk (`content.filesystem`, and the same
|
|
439
513
|
globs in `content.pipeline.include`, since the default pipeline skips
|
|
440
514
|
`.ts`). Two reasons:
|
|
441
515
|
- modo serves items pre-bundled, so the sources never pass through Vite's
|
|
@@ -2,7 +2,9 @@ import InputMessage from './index'
|
|
|
2
2
|
import Button from '../../button'
|
|
3
3
|
import { ChevronDown, Plus } from 'lucide-react'
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# Basics
|
|
6
|
+
|
|
7
|
+
## Basic
|
|
6
8
|
|
|
7
9
|
No props at all: the composer keeps its own draft, grows as you type and
|
|
8
10
|
clears itself on Enter.
|
|
@@ -11,7 +13,31 @@ clears itself on Enter.
|
|
|
11
13
|
<InputMessage />
|
|
12
14
|
</div>
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
## Send Handler
|
|
17
|
+
|
|
18
|
+
`onSend` receives the trimmed text and the attached files; an uncontrolled
|
|
19
|
+
composer clears its own draft afterwards. The handler here is an empty
|
|
20
|
+
arrow — in an app it is where the message joins the transcript.
|
|
21
|
+
|
|
22
|
+
<div className="w-full max-w-xl">
|
|
23
|
+
<InputMessage
|
|
24
|
+
onSend={() => {}}
|
|
25
|
+
placeholder="Press Enter to send. Shift+Enter for newline."
|
|
26
|
+
/>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
## Disabled
|
|
30
|
+
|
|
31
|
+
Dims the panel to 50% and drops pointer events — textarea, send button and
|
|
32
|
+
drag-and-drop all go inert.
|
|
33
|
+
|
|
34
|
+
<div className="w-full max-w-xl">
|
|
35
|
+
<InputMessage defaultValue="This composer is disabled" disabled />
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
# Content
|
|
39
|
+
|
|
40
|
+
## Suggestions
|
|
15
41
|
|
|
16
42
|
The ghost placeholder renders with a Tab keycap — Tab fills it into the
|
|
17
43
|
composer. ArrowDown/ArrowUp walk the list below (focus stays in the
|
|
@@ -30,7 +56,7 @@ shows a ↓ hint until a row is highlighted. Typing collapses the list.
|
|
|
30
56
|
/>
|
|
31
57
|
</div>
|
|
32
58
|
|
|
33
|
-
|
|
59
|
+
## Attachments
|
|
34
60
|
|
|
35
61
|
`defaultFiles` seeds the composer and turns attachment behavior on: drop a
|
|
36
62
|
PNG, JPEG or PDF anywhere on the panel, or use the render-fn slot's
|
|
@@ -52,7 +78,7 @@ for its × button.
|
|
|
52
78
|
/>
|
|
53
79
|
</div>
|
|
54
80
|
|
|
55
|
-
|
|
81
|
+
## Queued messages
|
|
56
82
|
|
|
57
83
|
`defaultStatus="streaming"` plus `defaultQueue` runs the composer as if a
|
|
58
84
|
response were in flight: the send button is a Queue action, so a typed
|
|
@@ -71,7 +97,9 @@ response, and that streaming→idle edge dispatches the row at the top.
|
|
|
71
97
|
/>
|
|
72
98
|
</div>
|
|
73
99
|
|
|
74
|
-
#
|
|
100
|
+
# Slots
|
|
101
|
+
|
|
102
|
+
## Left Slot Only
|
|
75
103
|
|
|
76
104
|
`leftSlot` takes the bottom-left action area — an attach button, a model
|
|
77
105
|
switcher, a mode toggle.
|
|
@@ -86,7 +114,7 @@ switcher, a mode toggle.
|
|
|
86
114
|
/>
|
|
87
115
|
</div>
|
|
88
116
|
|
|
89
|
-
|
|
117
|
+
## Right Slot Only
|
|
90
118
|
|
|
91
119
|
`rightSlot` sits in the bottom-right, just before the built-in send
|
|
92
120
|
button.
|
|
@@ -100,25 +128,3 @@ button.
|
|
|
100
128
|
}
|
|
101
129
|
/>
|
|
102
130
|
</div>
|
|
103
|
-
|
|
104
|
-
# Send Handler
|
|
105
|
-
|
|
106
|
-
`onSend` receives the trimmed text and the attached files; an uncontrolled
|
|
107
|
-
composer clears its own draft afterwards. The handler here is an empty
|
|
108
|
-
arrow — in an app it is where the message joins the transcript.
|
|
109
|
-
|
|
110
|
-
<div className="w-full max-w-xl">
|
|
111
|
-
<InputMessage
|
|
112
|
-
onSend={() => {}}
|
|
113
|
-
placeholder="Press Enter to send. Shift+Enter for newline."
|
|
114
|
-
/>
|
|
115
|
-
</div>
|
|
116
|
-
|
|
117
|
-
# Disabled
|
|
118
|
-
|
|
119
|
-
Dims the panel to 50% and drops pointer events — textarea, send button and
|
|
120
|
-
drag-and-drop all go inert.
|
|
121
|
-
|
|
122
|
-
<div className="w-full max-w-xl">
|
|
123
|
-
<InputMessage defaultValue="This composer is disabled" disabled />
|
|
124
|
-
</div>
|
|
@@ -924,6 +924,8 @@ const InputMessage = forwardRef<HTMLDivElement, InputMessageProps>(
|
|
|
924
924
|
if (!clickToFocus || disabled) return
|
|
925
925
|
const target = e.target as HTMLElement
|
|
926
926
|
if (target === textareaRef.current) return
|
|
927
|
+
// A press in a popup portalled out of the box reaches it through the React tree only.
|
|
928
|
+
if (!e.currentTarget.contains(target)) return
|
|
927
929
|
if (target.closest('button, a, input, select, textarea, [contenteditable], [role="button"], [data-im-queue]')) {
|
|
928
930
|
return
|
|
929
931
|
}
|
|
@@ -2,7 +2,9 @@ import Accordion from './index'
|
|
|
2
2
|
import Button from '../button'
|
|
3
3
|
import { ArrowRight } from 'lucide-react'
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# Basics
|
|
6
|
+
|
|
7
|
+
## Standalone
|
|
6
8
|
|
|
7
9
|
A single collapsible item with its own hover state.
|
|
8
10
|
|
|
@@ -15,7 +17,7 @@ A single collapsible item with its own hover state.
|
|
|
15
17
|
</Accordion.Item>
|
|
16
18
|
</Accordion>
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
## Single Expand
|
|
19
21
|
|
|
20
22
|
Multiple items with fluid hover — only one can be expanded at a time.
|
|
21
23
|
|
|
@@ -50,7 +52,7 @@ Multiple items with fluid hover — only one can be expanded at a time.
|
|
|
50
52
|
</Accordion.Item>
|
|
51
53
|
</Accordion.Group>
|
|
52
54
|
|
|
53
|
-
|
|
55
|
+
## Multi Expand
|
|
54
56
|
|
|
55
57
|
Multiple items with fluid hover — several can be expanded at once.
|
|
56
58
|
|
|
@@ -75,34 +77,7 @@ Multiple items with fluid hover — several can be expanded at once.
|
|
|
75
77
|
</Accordion.Item>
|
|
76
78
|
</Accordion.Group>
|
|
77
79
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
With `highlight="trigger"` an expanded item holds no tint — the fill
|
|
81
|
-
scopes to the row and waits for hover. Suits dense panels, where a block
|
|
82
|
-
per open item reads as a second layer.
|
|
83
|
-
|
|
84
|
-
<Accordion.Group type="single" collapsible defaultValue="item-1" highlight="trigger">
|
|
85
|
-
<Accordion.Item value="item-1" index={0}>
|
|
86
|
-
<Accordion.Trigger>Expanded, but not tinted</Accordion.Trigger>
|
|
87
|
-
<Accordion.Content>
|
|
88
|
-
The panel reads as part of the page rather than a filled block.
|
|
89
|
-
</Accordion.Content>
|
|
90
|
-
</Accordion.Item>
|
|
91
|
-
<Accordion.Item value="item-2" index={1}>
|
|
92
|
-
<Accordion.Trigger>Hover any row</Accordion.Trigger>
|
|
93
|
-
<Accordion.Content>
|
|
94
|
-
The fill follows your cursor instead of marking a state.
|
|
95
|
-
</Accordion.Content>
|
|
96
|
-
</Accordion.Item>
|
|
97
|
-
<Accordion.Item value="item-3" index={2}>
|
|
98
|
-
<Accordion.Trigger>Compare with the sections above</Accordion.Trigger>
|
|
99
|
-
<Accordion.Content>
|
|
100
|
-
Those hold a block across the row and its panel while open.
|
|
101
|
-
</Accordion.Content>
|
|
102
|
-
</Accordion.Item>
|
|
103
|
-
</Accordion.Group>
|
|
104
|
-
|
|
105
|
-
# Morph
|
|
80
|
+
## Morph
|
|
106
81
|
|
|
107
82
|
Each panel drips out of the row where it was pressed (its middle, from the keyboard) and widens into the item, its content revealed by the same shape; closing folds it back into the row. The rows below ride its bottom edge.
|
|
108
83
|
|
|
@@ -130,7 +105,36 @@ Each panel drips out of the row where it was pressed (its middle, from the keybo
|
|
|
130
105
|
</Accordion.Item>
|
|
131
106
|
</Accordion.Group>
|
|
132
107
|
|
|
133
|
-
#
|
|
108
|
+
# Variants
|
|
109
|
+
|
|
110
|
+
## Row highlight
|
|
111
|
+
|
|
112
|
+
With `highlight="trigger"` an expanded item holds no tint — the fill
|
|
113
|
+
scopes to the row and waits for hover. Suits dense panels, where a block
|
|
114
|
+
per open item reads as a second layer.
|
|
115
|
+
|
|
116
|
+
<Accordion.Group type="single" collapsible defaultValue="item-1" highlight="trigger">
|
|
117
|
+
<Accordion.Item value="item-1" index={0}>
|
|
118
|
+
<Accordion.Trigger>Expanded, but not tinted</Accordion.Trigger>
|
|
119
|
+
<Accordion.Content>
|
|
120
|
+
The panel reads as part of the page rather than a filled block.
|
|
121
|
+
</Accordion.Content>
|
|
122
|
+
</Accordion.Item>
|
|
123
|
+
<Accordion.Item value="item-2" index={1}>
|
|
124
|
+
<Accordion.Trigger>Hover any row</Accordion.Trigger>
|
|
125
|
+
<Accordion.Content>
|
|
126
|
+
The fill follows your cursor instead of marking a state.
|
|
127
|
+
</Accordion.Content>
|
|
128
|
+
</Accordion.Item>
|
|
129
|
+
<Accordion.Item value="item-3" index={2}>
|
|
130
|
+
<Accordion.Trigger>Compare with the sections above</Accordion.Trigger>
|
|
131
|
+
<Accordion.Content>
|
|
132
|
+
Those hold a block across the row and its panel while open.
|
|
133
|
+
</Accordion.Content>
|
|
134
|
+
</Accordion.Item>
|
|
135
|
+
</Accordion.Group>
|
|
136
|
+
|
|
137
|
+
## Without the goo
|
|
134
138
|
|
|
135
139
|
`effect="morph"` grows the same shape with no liquid neck to its row; `tier="moderate"` runs the goo on the quicker, critically damped spring.
|
|
136
140
|
|
|
@@ -149,7 +153,7 @@ Each panel drips out of the row where it was pressed (its middle, from the keybo
|
|
|
149
153
|
</Accordion.Item>
|
|
150
154
|
</Accordion.Group>
|
|
151
155
|
|
|
152
|
-
|
|
156
|
+
## Without the chevron
|
|
153
157
|
|
|
154
158
|
`icon={false}` drops the glyph at the row's end, for a row whose own content says it opens. A component passed as `icon` replaces the chevron and turns a quarter turn on open, so give it a right-pointing glyph.
|
|
155
159
|
|
|
@@ -174,7 +178,9 @@ Each panel drips out of the row where it was pressed (its middle, from the keybo
|
|
|
174
178
|
</Accordion.Item>
|
|
175
179
|
</Accordion.Group>
|
|
176
180
|
|
|
177
|
-
#
|
|
181
|
+
# Composition
|
|
182
|
+
|
|
183
|
+
## Rich headers
|
|
178
184
|
|
|
179
185
|
By default the trigger renders its label twice: a hidden semibold copy reserves the width, so the label gets heavier on open without moving. A header made of components would be duplicated in the DOM, so `weightShift={false}` renders it once and leaves the weight to its content. `contentClassName` is merged over the inner row's inset, padding and muted body text: the first panel below turns its text to full strength, the second takes a wider inset and the caption size. The label lives inside the trigger `<button>`, so build it from phrasing content (spans, as below), never a `div`-based header. Text that fixes its own colour stays that colour when the item opens: the chevron, the highlight and the open tint are what signal the state.
|
|
180
186
|
|
|
@@ -203,7 +209,7 @@ By default the trigger renders its label twice: a hidden semibold copy reserves
|
|
|
203
209
|
</Accordion.Item>
|
|
204
210
|
</Accordion.Group>
|
|
205
211
|
|
|
206
|
-
|
|
212
|
+
## Your own trigger
|
|
207
213
|
|
|
208
214
|
`asChild` (or `render`) makes your element the trigger, so a Button, a link-styled control or anything else can open the item. It is rendered as it is: the row's label copy, the chevron and the row padding are not added, so the element brings its own content and look. Base UI still wires `aria-expanded`, `aria-controls`, `data-panel-open` and the keys onto it, so style the open state with `data-[panel-open]`.
|
|
209
215
|
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import Badge from './index'
|
|
2
2
|
import ChangeDemo from './change-demo'
|
|
3
3
|
|
|
4
|
-
#
|
|
4
|
+
# Variants
|
|
5
|
+
|
|
6
|
+
## Solid
|
|
5
7
|
|
|
6
8
|
The default variant: a tinted background in the badge's color.
|
|
7
9
|
|
|
@@ -13,7 +15,7 @@ The default variant: a tinted background in the badge's color.
|
|
|
13
15
|
<Badge color="rose">Poetry</Badge>
|
|
14
16
|
</div>
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
## Dot
|
|
17
19
|
|
|
18
20
|
`variant="dot"` keeps a neutral bordered badge and shows the color as an
|
|
19
21
|
indicator dot.
|
|
@@ -26,7 +28,7 @@ indicator dot.
|
|
|
26
28
|
<Badge variant="dot" color="rose">Poetry</Badge>
|
|
27
29
|
</div>
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
## Outline
|
|
30
32
|
|
|
31
33
|
`variant="outline"` is the dot badge's neutral frame without the dot: a label
|
|
32
34
|
that carries no status.
|
|
@@ -37,22 +39,7 @@ that carries no status.
|
|
|
37
39
|
<Badge variant="outline" size="compact">Archived</Badge>
|
|
38
40
|
</div>
|
|
39
41
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
Hosts with a shadcn-style badge map its variants onto a hue: default and
|
|
43
|
-
secondary → `gray`, destructive → `red`, success → `green`, outline →
|
|
44
|
-
`variant="outline"`. The tint stays a wash with foreground text, never a solid
|
|
45
|
-
fill.
|
|
46
|
-
|
|
47
|
-
<div className="flex flex-wrap items-center gap-2">
|
|
48
|
-
<Badge color="gray">Default</Badge>
|
|
49
|
-
<Badge color="gray">Secondary</Badge>
|
|
50
|
-
<Badge color="red">Destructive</Badge>
|
|
51
|
-
<Badge color="green">Success</Badge>
|
|
52
|
-
<Badge variant="outline">Outline</Badge>
|
|
53
|
-
</div>
|
|
54
|
-
|
|
55
|
-
# Colors
|
|
42
|
+
## Colors
|
|
56
43
|
|
|
57
44
|
All seventeen palette colors, solid and dot.
|
|
58
45
|
|
|
@@ -73,18 +60,24 @@ All seventeen palette colors, solid and dot.
|
|
|
73
60
|
</div>
|
|
74
61
|
</div>
|
|
75
62
|
|
|
76
|
-
#
|
|
63
|
+
# Usage
|
|
77
64
|
|
|
78
|
-
|
|
79
|
-
|
|
65
|
+
## Status mapping
|
|
66
|
+
|
|
67
|
+
Hosts with a shadcn-style badge map its variants onto a hue: default and
|
|
68
|
+
secondary → `gray`, destructive → `red`, success → `green`, outline →
|
|
69
|
+
`variant="outline"`. The tint stays a wash with foreground text, never a solid
|
|
70
|
+
fill.
|
|
80
71
|
|
|
81
72
|
<div className="flex flex-wrap items-center gap-2">
|
|
82
|
-
<Badge
|
|
83
|
-
<Badge
|
|
84
|
-
<Badge
|
|
73
|
+
<Badge color="gray">Default</Badge>
|
|
74
|
+
<Badge color="gray">Secondary</Badge>
|
|
75
|
+
<Badge color="red">Destructive</Badge>
|
|
76
|
+
<Badge color="green">Success</Badge>
|
|
77
|
+
<Badge variant="outline">Outline</Badge>
|
|
85
78
|
</div>
|
|
86
79
|
|
|
87
|
-
|
|
80
|
+
## Changes
|
|
88
81
|
|
|
89
82
|
Press a button. A new label springs the badge to its new width while the
|
|
90
83
|
text crossfades, a new color fades in, and the dot slides in or out with
|
|
@@ -118,3 +111,14 @@ the variant. `ChangeDemo` is a docs stage: a Badge that steps through its
|
|
|
118
111
|
]}
|
|
119
112
|
/>
|
|
120
113
|
</div>
|
|
114
|
+
|
|
115
|
+
## Compact
|
|
116
|
+
|
|
117
|
+
`size="compact"` steps the badge down the size ladder (20px tall, 11px
|
|
118
|
+
text) for dense rows and table cells.
|
|
119
|
+
|
|
120
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
121
|
+
<Badge size="compact" color="blue">History</Badge>
|
|
122
|
+
<Badge size="compact" variant="dot" color="green">Philosophy</Badge>
|
|
123
|
+
<Badge size="compact">Draft</Badge>
|
|
124
|
+
</div>
|