@nurix/etna 0.20.37 → 0.20.39
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/data/catalog/rules/frontend.md +5 -5
- package/data/catalog/rules/pnpm.md +2 -2
- package/data/harness-index.json +1 -1
- package/data/harnesses/code/agents/brainstorm.md +5 -3
- package/data/harnesses/code/codex/agents/brainstorm.toml +5 -3
- package/data/harnesses/code/harness.json +2 -2
- package/data/harnesses/code/hooks/approved-packages.md +1 -2
- package/data/harnesses/code/rules/frontend.md +5 -5
- package/data/harnesses/code/rules/pnpm.md +2 -2
- package/data/harnesses/code/skills/boundary/references/packs/build-config-runtime.md +1 -1
- package/data/harnesses/code/skills/brainstorm/README.md +18 -45
- package/data/harnesses/code/skills/brainstorm/SKILL.md +105 -173
- package/data/harnesses/code/skills/brainstorm/references/doctrine.md +70 -141
- package/data/harnesses/code/skills/brainstorm/references/entry.md +70 -0
- package/data/harnesses/code/skills/brainstorm/references/harvest.md +85 -137
- package/data/harnesses/code/skills/brainstorm/references/session-schema.md +98 -135
- package/data/harnesses/code/skills/design/components/charts.md +121 -43
- package/data/harnesses/code/skills/design/components/collections.md +209 -41
- package/data/harnesses/code/skills/design/components/feedback.md +86 -25
- package/data/harnesses/code/skills/design/components/hooks.md +198 -12
- package/data/harnesses/code/skills/design/components/index.md +93 -71
- package/data/harnesses/code/skills/design/components/inputs.md +249 -157
- package/data/harnesses/code/skills/design/components/layout.md +98 -38
- package/data/harnesses/code/skills/design/components/media.md +46 -25
- package/data/harnesses/code/skills/design/components/motion.md +56 -46
- package/data/harnesses/code/skills/design/components/navigation.md +54 -15
- package/data/harnesses/code/skills/design/components/overlays.md +51 -41
- package/data/harnesses/code/skills/design/components/setup.md +84 -5
- package/data/harnesses/code/skills/design/components/typography.md +72 -22
- package/data/harnesses/code/skills/design/components/utils.md +47 -13
- package/data/harnesses/code/skills/design/data/chrome/board-column.md +12 -12
- package/data/harnesses/code/skills/design/data/chrome/data-table.md +6 -6
- package/data/harnesses/code/skills/design/data/chrome/side-panel.md +15 -15
- package/data/harnesses/code/skills/design/data/chrome/sidebar.md +25 -25
- package/data/harnesses/code/skills/design/data/chrome/stat-cards.md +22 -22
- package/data/harnesses/code/skills/design/data/chrome/topbar.md +12 -12
- package/data/harnesses/code/skills/design/references/emission.md +6 -6
- package/data/harnesses/code/skills/design/scripts/README-validator.md +20 -8
- package/data/harnesses/code/skills/design/scripts/validate-design-md.mjs +15 -10
- package/data/harnesses/delivery/agents/brainstorm.md +5 -3
- package/data/harnesses/delivery/codex/agents/brainstorm.toml +5 -3
- package/data/harnesses/delivery/harness.json +2 -2
- package/data/harnesses/delivery/skills/brainstorm/README.md +18 -45
- package/data/harnesses/delivery/skills/brainstorm/SKILL.md +105 -173
- package/data/harnesses/delivery/skills/brainstorm/references/doctrine.md +70 -141
- package/data/harnesses/delivery/skills/brainstorm/references/entry.md +70 -0
- package/data/harnesses/delivery/skills/brainstorm/references/harvest.md +85 -137
- package/data/harnesses/delivery/skills/brainstorm/references/session-schema.md +98 -135
- package/data/harnesses/etna/agents/brainstorm.md +5 -3
- package/data/harnesses/etna/codex/agents/brainstorm.toml +5 -3
- package/data/harnesses/etna/harness.json +2 -2
- package/data/harnesses/etna/skills/boundary/references/packs/build-config-runtime.md +1 -1
- package/data/harnesses/etna/skills/brainstorm/README.md +18 -45
- package/data/harnesses/etna/skills/brainstorm/SKILL.md +105 -173
- package/data/harnesses/etna/skills/brainstorm/references/doctrine.md +70 -141
- package/data/harnesses/etna/skills/brainstorm/references/entry.md +70 -0
- package/data/harnesses/etna/skills/brainstorm/references/harvest.md +85 -137
- package/data/harnesses/etna/skills/brainstorm/references/session-schema.md +98 -135
- package/data/harnesses/hr/harness.json +1 -1
- package/package.json +2 -2
|
@@ -2,51 +2,111 @@
|
|
|
2
2
|
|
|
3
3
|
> Generated reference (regen-owned; see [index.md](index.md)). Binds only under `primitives: nurix`.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Components: Accordion, AspectRatio, Block, Card, Carousel, Collapsible, Item, Resizable, Row, ScrollArea, Separator, SidePanel, Sortable, Spacer
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Each imports from its own subpath as one namespace, with its parts as dotted members, e.g. `import { Card } from "@nurix/components/block/card"` then `Card.Header`, `Card.Content`, `Card.Footer`. Parts swap their element through `render` — there is no `asChild` (Resizable's parts are the exception: they take no `render`).
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Block · Row · Spacer
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
The naked space primitives: `Block` (`block/block`) is a page region that stacks its children on the density gap and owns the region's insets; `Row` (`element/row`) owns only the gap between its children; `Spacer` (`element/spacer`) is placed empty space that pushes siblings apart. None of them draws anything — the dress is `className`.
|
|
12
12
|
|
|
13
|
-
**
|
|
14
|
-
**
|
|
15
|
-
**
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
**Block props:** `render` (root element, default `section` — `<header />`, `<footer />`, `<aside />`, `<main />`), `height` [hug|hero] (default `hug`; `hero` reserves a 300px masthead band), `shouldSettle` (a content-driven height change travels instead of snapping; outermost settling region only)
|
|
14
|
+
**Row props:** `gap` [none|sm|md|lg] (default `md`, on the `--density-gap-*` tokens), `align` [start|center|end|baseline] (default `center`), `hasFloor` (reserves one control height, so a toolbar row measures the same with or without its buttons), `render`
|
|
15
|
+
**Spacer props:** `render` only — no size, no content; `aria-hidden`, and it grows only inside a flex parent
|
|
16
|
+
|
|
17
|
+
- Insets live only on the Block: never pad a Row or Spacer inside it, never put margins on its children.
|
|
18
|
+
- Distribution is positional — a Spacer between the sides replaces `justify-between` and `mt-auto`. Never use it for a fixed distance; that is the parent's gap.
|
|
19
19
|
|
|
20
20
|
```tsx
|
|
21
|
-
<
|
|
22
|
-
<
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
</
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
21
|
+
<Block render={<header />} className="border-b bg-card">
|
|
22
|
+
<Row hasFloor>
|
|
23
|
+
<Breadcrumb />
|
|
24
|
+
<Spacer />
|
|
25
|
+
<Button>New</Button>
|
|
26
|
+
</Row>
|
|
27
|
+
</Block>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Card
|
|
31
|
+
|
|
32
|
+
The surfaced container (`block/card`): ring edge, elevation and density insets, with a header grid that grows an end column only when an action is present.
|
|
33
|
+
|
|
34
|
+
**Sub-components:** `Card.Header` (`hasDivider`), `Card.Header.Action` (pinned to the header's end column), `Card.Title`, `Card.Description`, `Card.Content`, `Card.Footer` (`hasDivider`)
|
|
35
|
+
|
|
36
|
+
- No `padding`/`radius`/`shadow` props: insets read the `--density-pad-*` tokens. Depth rides `className` as `shadow-(--elevation-N)` or `shadow-none`, which keeps the ring edge.
|
|
37
|
+
- `hasDivider` draws the hairline rule and the density inset on that side; a bare `border-b` / `border-t` class adds no inset.
|
|
38
|
+
- A Title mints an id; the root points `aria-labelledby` at it only while the root carries a role (`role`, or `render={<section />}` / `article` / `aside` / `form` / `nav` / `fieldset`).
|
|
39
|
+
- Full-bleed media is a direct `<img>` child of `Card`. A grid of clickable cards is `block/list` with `view="card"`; there is no action-area part.
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
<Card render={<section />}>
|
|
43
|
+
<Card.Header hasDivider>
|
|
44
|
+
<Card.Title render={<h2 />}>Billing</Card.Title>
|
|
45
|
+
<Card.Description>Plan and payment method</Card.Description>
|
|
46
|
+
<Card.Header.Action><Button variant="ghost" size="sm">Edit</Button></Card.Header.Action>
|
|
47
|
+
</Card.Header>
|
|
48
|
+
<Card.Content>{/* … */}</Card.Content>
|
|
49
|
+
<Card.Footer hasDivider><Button>Upgrade</Button></Card.Footer>
|
|
50
|
+
</Card>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Item
|
|
54
|
+
|
|
55
|
+
A list or menu row primitive (`element/item`): leading media, a title and description, trailing actions.
|
|
56
|
+
|
|
57
|
+
**Sub-components:** `Item.Media` (`variant` [default|icon|image]), `Item.Content`, `Item.Title`, `Item.Description`, `Item.Actions` (a `role="group"` labelled by the row's Title), `Item.Header`, `Item.Footer`, `Item.Group`, `Item.Separator`
|
|
58
|
+
**Item props:** `variant` [default|outline|muted], `inset` [default|sm], `side` [start|end] (`end` reverses the row), `render` (`render={<a href="…" />}` makes the whole row a link; an untyped `<button />` becomes `type="button"`)
|
|
59
|
+
|
|
60
|
+
- `Item.Media variant="image"` is what crops and sizes an `<img>`; `icon` is a bordered tile.
|
|
61
|
+
- `Item.Group` inserts no dividers and carries no list role — place `Item.Separator` yourself, and write `<Item.Group render={<ul />}>` with rows `render={<li />}` for list semantics.
|
|
62
|
+
- Data-driven rows with search, grouping or pagination are `block/list` with `Item` rows.
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
<Item variant="outline">
|
|
66
|
+
<Item.Media variant="icon"><Bell /></Item.Media>
|
|
67
|
+
<Item.Content>
|
|
68
|
+
<Item.Title>Deploy finished</Item.Title>
|
|
69
|
+
<Item.Description>web-app shipped to production.</Item.Description>
|
|
70
|
+
</Item.Content>
|
|
71
|
+
<Item.Actions><Button variant="ghost" size="sm">View</Button></Item.Actions>
|
|
72
|
+
</Item>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Sortable
|
|
76
|
+
|
|
77
|
+
Drag-to-reorder list over dnd-kit (`compound/sortable`), keyboard sortable, with a floating drag overlay. Optional peer family `sortable` — install `@dnd-kit/core`, `@dnd-kit/modifiers`, `@dnd-kit/sortable` and `@dnd-kit/utilities` yourself.
|
|
78
|
+
|
|
79
|
+
**Sub-components:** `Sortable.Content`, `Sortable.Item` (`value`, `isHandle` drags the whole row), `Sortable.ItemHandle` (the grip), `Sortable.Overlay` (the drag preview, portalled to `document.body` or a `container`)
|
|
80
|
+
**Props:** `value` / `defaultValue` / `onValueChange(value, details)` (an uncontrolled caller refuses a move with `details.cancel()`), `onValueCommitted`, `getItemValue` (stable unique id; required when `value` holds objects), `orientation` [vertical|horizontal|mixed] (default `vertical`), `strategy`, `activationConstraint` (`distance` px or `delay` ms), `hasGrabCursor` (default on), `disabled`, `labels`
|
|
81
|
+
|
|
82
|
+
- Also exported: `useSortableItem`, `arrayMove`, `arraySwap`, the list/rect strategies, the `restrictTo*` and snap modifiers, and the collision detectors.
|
|
83
|
+
- Skip `Sortable.Overlay` and a dragged item only shifts in place, with nothing following the pointer.
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
<Sortable value={items} onValueChange={setItems} getItemValue={(item) => item.id}>
|
|
87
|
+
<Sortable.Content>
|
|
88
|
+
{items.map((item) => (
|
|
89
|
+
<Sortable.Item key={item.id} value={item.id}><Sortable.ItemHandle />{item.name}</Sortable.Item>
|
|
90
|
+
))}
|
|
91
|
+
</Sortable.Content>
|
|
92
|
+
<Sortable.Overlay />
|
|
93
|
+
</Sortable>
|
|
36
94
|
```
|
|
37
95
|
|
|
38
96
|
## Other layout components
|
|
39
97
|
|
|
40
|
-
- `accordion` — Accordion,
|
|
41
|
-
- `
|
|
42
|
-
- `
|
|
43
|
-
- `
|
|
44
|
-
- `carousel` — Carousel
|
|
45
|
-
- `
|
|
46
|
-
- `
|
|
47
|
-
- `
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
98
|
+
- `compound/accordion` — `Accordion` with `Accordion.Item`, `.Header` (an `<h3>` by default; `render={<h4 />}` moves the level), `.Trigger`, `.Panel` (`hiddenUntilFound`, `keepMounted`); `value`/`defaultValue` are always arrays, `multiple` lets several stay open, `onValueChange` drives it from outside.
|
|
99
|
+
- `element/collapsible` — `Collapsible` with `Collapsible.Trigger` (`render` swaps the button), `.Panel` (unmounts when closed unless `keepMounted`; never give it a height class), `.Indicator` (turns on the trigger's `data-panel-open`); `open`/`defaultOpen`/`onOpenChange`.
|
|
100
|
+
- `block/side-panel` — `SidePanel` with `SidePanel.Trigger`, `SidePanel.Panel`: an in-flow region in a `flex` row that collapses to a rail and reflows its sibling; `side` [start|end] (default `end`), `open`/`onOpenChange`, `expandedWidth`/`collapsedWidth` (or the `--side-panel-expanded-width`/`--side-panel-collapsed-width` variables), `keepMounted`, `labels`.
|
|
101
|
+
- `block/resizable` — `Resizable` with `Resizable.Panel`, `Resizable.Handle` (`hasGrip`): draggable split panes inside a parent with a height; a numeric size is pixels and a string is a percentage (`defaultSize="30%"`), `orientation` [horizontal|vertical], `onLayoutCommitted` + `defaultLayout` persist the layout, `panelRef`/`groupRef` reach the imperative handles. Optional peer family `resizable` (`react-resizable-panels`).
|
|
102
|
+
- `compound/carousel` — `Carousel` with `Carousel.Content`, `.Item` (`basis-full` by default), `.Previous`, `.Next`; `value`/`defaultValue`/`onValueChange` (0-based snap index), `orientation`, `opts`, `setApi`, `labels`. `LoadingCarousel` is the ready-made tips strip (`data` tips with a stable `id`, `timeout`, `indicators` [progress|steps|none], `aspectRatio`, `textPlacement`). Optional peer family `carousel` (`embla-carousel-react`, `embla-carousel-autoplay`).
|
|
103
|
+
- `element/scroll-area` — `ScrollArea`: styled bars on both axes, each drawn only while its axis overflows; give it an explicit `h-*`/`max-h-*`, `hasFadeEdges` fades every edge with more content past it, and `aria-label` names the focusable viewport. Never pass `ScrollArea.Bar` as a child.
|
|
104
|
+
- `element/separator` — `Separator`: a hairline, `orientation` [horizontal|vertical] (vertical needs a bounded height); children render the labeled form, placed by `align` [start|center|end] (default `center`, ignored without children).
|
|
105
|
+
- `element/aspect-ratio` — `AspectRatio`: `ratio` is width / height (default `1`; a non-finite or non-positive ratio falls back to `1`), the child fills the box itself (`h-full w-full object-cover`), `render` swaps the element.
|
|
106
|
+
|
|
107
|
+
## Fallback-only concepts
|
|
108
|
+
|
|
109
|
+
No primitive ships for these; build them from the catalog's fallback spec, composed over the components above.
|
|
110
|
+
|
|
111
|
+
- `bento-grid` — an asymmetric CSS grid of `Card`s with spanning cells.
|
|
112
|
+
- `editable-card` — a `Card` whose `Card.Content` edits in place and whose `Card.Footer` commits.
|
|
@@ -2,65 +2,86 @@
|
|
|
2
2
|
|
|
3
3
|
> Generated reference (regen-owned; see [index.md](index.md)). Binds only under `primitives: nurix`.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Avatars, icons, images, the brand mark and a few media-adjacent controls; import each from its layer-prefixed subpath, e.g. `import { Avatar } from "@nurix/components/element/avatar"`.
|
|
6
6
|
|
|
7
7
|
## Avatar
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Profile image with an initials fallback and one stable accessible name, over Base UI's avatar. `AvatarGroup` stacks avatars into a facepile.
|
|
10
10
|
|
|
11
|
-
**Props:** `
|
|
11
|
+
**Props:** `label` (the one accessible name, `role="img"`; omit beside a visible name and the avatar is `aria-hidden`), `size` [xs|sm|default|lg] (24, 32, 36, 40px; default `default`)
|
|
12
12
|
|
|
13
|
-
**Sub-components:** `
|
|
13
|
+
**Sub-components:** `Avatar.Image`, `Avatar.Fallback` (shows while the image loads and after it errors), `Avatar.Badge` (`intent` [neutral|info|success|warning|danger], status dot painted from `--intent-*`), `AvatarGroup` (`variant` [default|bare] — `bare` drops the hover lift; `role="group"`, name it with `aria-label`), `AvatarGroup.Count`
|
|
14
14
|
|
|
15
15
|
```tsx
|
|
16
|
-
<Avatar size=
|
|
17
|
-
<
|
|
18
|
-
<
|
|
16
|
+
<Avatar label="Jane Doe, online" size="lg">
|
|
17
|
+
<Avatar.Image src={user.avatarUrl} alt="" />
|
|
18
|
+
<Avatar.Fallback>JD</Avatar.Fallback>
|
|
19
|
+
<Avatar.Badge intent="success" />
|
|
19
20
|
</Avatar>
|
|
20
21
|
```
|
|
21
22
|
|
|
22
23
|
## CopyButton
|
|
23
24
|
|
|
24
|
-
Click-to-copy button
|
|
25
|
+
Click-to-copy `Button` (`compound/copy-button`) that swaps its copy glyph for a check, publishes the outcome as `data-status` [success|error] and announces it.
|
|
25
26
|
|
|
26
|
-
**Props:** `value
|
|
27
|
+
**Props:** `value` (string, or a function resolved at click time), `onCopy(value)`, `onCopyError(error)`, `timeout` (ms the outcome holds; defaults to the `--hold-dwell` token, `Infinity` holds success), `labels` (`{ copy, copied, failed }`), plus Button's `variant` (default `ghost`), `intent`, `size` [xs|sm|default|lg] and `isIconOnly` (on when there are no `children`)
|
|
27
28
|
|
|
28
29
|
```tsx
|
|
29
|
-
<CopyButton value={
|
|
30
|
+
<CopyButton value={message.text} size="sm" />
|
|
30
31
|
```
|
|
31
32
|
|
|
32
|
-
##
|
|
33
|
+
## FilePreview
|
|
34
|
+
|
|
35
|
+
One file tile — a staged attachment or a persisted file (`compound/file-preview`). It renders state only; choosing and uploading the file is `compound/file-picker`.
|
|
33
36
|
|
|
34
|
-
|
|
37
|
+
**Sub-components:** `FilePreview.Group` (snap-scrolling strip), `FilePreview.Media`, `FilePreview.Content`, `FilePreview.Title`, `FilePreview.Description`, `FilePreview.Actions`, `FilePreview.Action`, `FilePreview.Trigger` (overlay button or `render` anchor), `FilePreview.Progress`; also `getFileTypeIcon({ type, name })`
|
|
35
38
|
|
|
36
|
-
**Props:** `
|
|
39
|
+
**Props:** root — `status` [idle|uploading|processing|error|success] (omit for a resting file; `idle` dashes the border, `error` tints it), `size` [default|sm|xs], `orientation` [horizontal|vertical], `variant` [default|bare]; Media — `type`, `name` (picks a mime-aware glyph when given no child), `variant="image"`; Progress — `value` (0–100, `null` indeterminate), `variant` [linear|circular|fill], `keepMounted` (otherwise it unmounts at 100)
|
|
37
40
|
|
|
38
41
|
```tsx
|
|
39
|
-
<
|
|
42
|
+
<FilePreview status={file.status} size="sm">
|
|
43
|
+
<FilePreview.Media type={file.type} name={file.name} />
|
|
44
|
+
<FilePreview.Content>
|
|
45
|
+
<FilePreview.Title>{file.name}</FilePreview.Title>
|
|
46
|
+
<FilePreview.Description>{formatBytes(file.size)}</FilePreview.Description>
|
|
47
|
+
</FilePreview.Content>
|
|
48
|
+
<FilePreview.Actions>
|
|
49
|
+
<FilePreview.Action aria-label={`Remove ${file.name}`} onClick={() => remove(file.id)}><XIcon /></FilePreview.Action>
|
|
50
|
+
</FilePreview.Actions>
|
|
51
|
+
</FilePreview>
|
|
40
52
|
```
|
|
41
53
|
|
|
42
|
-
##
|
|
54
|
+
## Icon
|
|
43
55
|
|
|
44
|
-
|
|
56
|
+
Draws a Lucide icon from a name held as data (`element/icon`) — a record field, a config value or an `IconPicker` (`compound/icon-picker`) pick. A fixed icon known at build time is a direct `lucide-react` import instead.
|
|
45
57
|
|
|
46
|
-
**Props:** `
|
|
58
|
+
**Props:** `value` (Lucide's kebab-case name, e.g. `"arrow-up-right"`), `size` (numeric px, default 24), `label` (standalone meaningful icon → `role="img"`; omit beside visible text), `fallback` (drawn for an unknown name; an empty box of the icon's size otherwise), `strokeWidth` (defaults to the `--edge-stroke` token)
|
|
47
59
|
|
|
48
60
|
```tsx
|
|
49
|
-
<
|
|
61
|
+
<Icon value={record.icon} size={16} />
|
|
50
62
|
```
|
|
51
63
|
|
|
52
|
-
##
|
|
64
|
+
## Image
|
|
53
65
|
|
|
54
|
-
|
|
66
|
+
Content photo or screenshot (`element/image`) with a skeleton while loading and a bordered placeholder (the `alt` text, or `labels.unavailable` — "Image unavailable") on error or an empty `src`, never the native broken-image glyph. A person's photo is `Avatar`.
|
|
55
67
|
|
|
56
|
-
**Props:** `
|
|
68
|
+
**Props:** `src`, `alt`, `width`/`height` (both together reserve the box via `aspect-ratio`), `fallback` (replaces the placeholder glyph and caption), `labels` (`{ unavailable }`), `variant` [default|bare] (`bare` drops its own radius, border and fill inside a framing host). Takes no `onClick` — a lightbox wraps it in a trigger.
|
|
57
69
|
|
|
58
70
|
```tsx
|
|
59
|
-
<
|
|
71
|
+
<Image src={attachment.src} alt={attachment.name} width={320} height={180} />
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Logo
|
|
75
|
+
|
|
76
|
+
Official NuPlay brand lockup (`element/logo`) — mark + wordmark, inline SVG.
|
|
77
|
+
|
|
78
|
+
**Props:** `variant` [blue-black|white-white|lime-white|blue-white] (fixed literal fills, named mark-then-wordmark; default `blue-black`, for light surfaces only), `height` (number = px; default 28px via `h-7`; width follows the aspect), `label` (accessible name, default `"NuPlay"`; pass `aria-hidden` beside the brand name in text). `fill` is not a prop — recolor through `variant`.
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
<Logo variant="white-white" height={20} />
|
|
60
82
|
```
|
|
61
83
|
|
|
62
84
|
## Other Components
|
|
63
85
|
|
|
64
|
-
- `
|
|
65
|
-
-
|
|
66
|
-
- `shine-border` — `ShineBorder`: absolutely-positioned animated gradient border overlay (parent needs `position: relative`); `borderWidth`, `duration` (seconds), `shineColor` (string or array, cycled through a radial gradient sweep)
|
|
86
|
+
- `lib/icons-data` — `iconsData`: `{ name, categories, tags }[]` over the Lucide set (~1,700 entries), for a custom icon search or browser; load it with a dynamic `import()`, keep only names present in the installed `lucide-react`, and render each match with `Icon`. A one-icon pick is `IconPicker` (`compound/icon-picker`), which takes these records as `data`.
|
|
87
|
+
- View switching (table/card and similar view-mode strips) has no dedicated component: compose a single-select `ToggleGroup` + `ToggleGroup.Item` (`compound/toggle-group`), guarding the `""` it publishes on deselect; reach for `Tabs` (`compound/tabs`) only when the pick also swaps a visible panel.
|
|
@@ -2,81 +2,91 @@
|
|
|
2
2
|
|
|
3
3
|
> Generated reference (regen-owned; see [index.md](index.md)). Binds only under `primitives: nurix`.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The effect tier (`effect/*`; the streaming cursor is a conversation surface, in [collections.md](collections.md)) plus the `element/animated-number` counter and the motion-aware `lib/slot`. Compose sparingly — decorative and low-frequency surfaces only; never on data or on actions users repeat dozens of times a day. Import each from its own subpath, e.g. `import { AnimatedList } from "@nurix/components/effect/animated-list"`.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Every effect times itself from the personality's motion ladder: durations follow the `pace` trait, and the caller periods below (seconds at neutral pace unless marked) scale with it. No effect takes a `transition`, `variants` or `initial` prop. Under `prefers-reduced-motion`, a zeroed ladder, or inside a `data-mode="inline"` collection, an effect goes still: a continuous effect renders its static frame and publishes `data-playing="false"` (it also pauses off screen and in a hidden tab), and a one-shot effect lands in its end state and publishes `data-reduced-motion`. Where an effect takes `as`, the value is a tag from the tier's closed motion tag table.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Animated numbers
|
|
10
10
|
|
|
11
|
-
- `
|
|
12
|
-
- `motion-primitives/sliding-number` — `SlidingNumber`: per-digit slot-machine roll; `value`, `padStart`, `decimalSeparator`
|
|
11
|
+
- `element/animated-number` — `AnimatedNumber`: rolling digits over static `Intl.NumberFormat` text on a `<data>` root (plain text through SSR, hydration and reduced motion — no layout shift, no flash of `0`); `value` (`null` or non-finite renders `fallback`), `format` (`Intl.NumberFormatOptions` minus two notations; default `{ notation: "standard", maximumFractionDigits: 0 }`), `locale`, `prefix`, `suffix`, `fallback`, `trend`, `digits`, `plugins` (`continuous`). The roll is timed by `pace`; there is no timing prop. `AnimatedNumber.Group` links counters that change together; `useIsSupported` is re-exported. **Optional peer:** `@number-flow/react` — install it or the subpath fails to resolve.
|
|
13
12
|
|
|
14
13
|
```tsx
|
|
15
|
-
<AnimatedNumber value={total}
|
|
14
|
+
<AnimatedNumber value={total} format={{ notation: "compact", maximumFractionDigits: 1 }} />
|
|
16
15
|
```
|
|
17
16
|
|
|
18
17
|
## Stagger entrance
|
|
19
18
|
|
|
20
|
-
- `
|
|
19
|
+
- `effect/animated-list` — `AnimatedList`: animates keyed children entering, leaving and reflowing; `animation` [slide|fade|scale] (default `slide`), `animate` (play the entrance on first mount), `as`, `itemAs`, `layout` [true|position]. Every child needs a stable `key`; a leaver pops out of the flow against the `relative` root. Above 50 children, items render as plain elements with no motion. `block/list` already wraps it.
|
|
21
20
|
|
|
22
21
|
```tsx
|
|
23
|
-
<
|
|
24
|
-
{items.map((item) => <
|
|
25
|
-
</
|
|
22
|
+
<AnimatedList className="space-y-2">
|
|
23
|
+
{items.map((item) => <Row key={item.id} item={item} />)}
|
|
24
|
+
</AnimatedList>
|
|
26
25
|
```
|
|
27
26
|
|
|
28
27
|
## Text effects
|
|
29
28
|
|
|
30
|
-
Per-character/word/line text animation — low-frequency surfaces only (empty states, onboarding, marketing-adjacent copy).
|
|
29
|
+
Per-character/word/line text animation — low-frequency surfaces only (empty states, onboarding, marketing-adjacent copy). Each member renders a `span` by default and takes a string child. `trigger` means one thing across the family: a `false → true` edge replays the effect.
|
|
31
30
|
|
|
32
|
-
- `
|
|
33
|
-
- `
|
|
34
|
-
- `
|
|
35
|
-
- `
|
|
31
|
+
- `effect/text-effects` — `TextEffect`: staggered reveal; `per` [word|char|line] (default `word`), `animation` [blur|fade-in-blur|scale|fade|slide] (default `fade`), `delay`, `speedReveal`, `speedSegment`, `trigger`, `onAnimationComplete`, `segmentWrapperClassName`. Prefer `per="word"` or `"line"` for long strings (above 50 segments, per-segment motion drops)
|
|
32
|
+
- `effect/text-effects` — `TextMorph`: cross-fades one short string into the next in place; change `children` in place, never force a new `key`
|
|
33
|
+
- `effect/text-effects` — `TextScramble`: decodes a string in from noise; `duration` (default `0.8`), `speed` (default `0.04`), `characterSet`, `trigger`, `onAnimationComplete`
|
|
34
|
+
- `effect/text-effects` — `TextShimmer`: continuous "still working" gradient sweep; `duration` (default `2`), `spread` (default `2`)
|
|
35
|
+
- `effect/text-effects` — `TypingAnimation`: types a string, or cycles `words`; `typeInterval` (default `0.1`), `deleteInterval` (default half `typeInterval`), `startDelay`, `holdDelay` (default `1`), `loop`, `start` [mount|view] (default `view`), `hasCursor` (default `true`), `isCursorBlinking` (default `true`), `cursorStyle` [line|block|underscore]
|
|
36
|
+
- `effect/dia-text-reveal` — `DiaTextReveal`: sweeps a colour band across a line, revealing it; `words` + `loop` rotate several strings, `colors` (band stops only — the text inherits its colour), `duration` (default `1.5`), `delay`, `holdDelay` (default `0.5`), `start` [mount|view|each-view] (default `view`), `hasFixedWidth`. The line is blank until the sweep passes
|
|
36
37
|
|
|
37
|
-
##
|
|
38
|
+
## Animated icons
|
|
39
|
+
|
|
40
|
+
- `effect/icons` — `AnimateIcon` plus 259 lucide-derived animated icons, each exported under its plain name and an `…Icon` alias (`Activity` / `ActivityIcon`, `ArrowDown` / `ArrowDownIcon`, …). Triggers sit on an icon or on an `AnimateIcon` wrapper that drives every icon inside it: `animateOnHover`, `animateOnTap`, `animateOnView` (`animateOnViewMargin`, `animateOnViewOnce`), or the boolean `animate` for an external trigger; `animation` names the variant (`default`, `default-loop`, … per icon), `loop`, `startDelay`, `holdDelay`, `persistOnAnimateEnd`, `completeOnStop`. Icon props: `size`, `label` (an unlabelled icon is `aria-hidden`). `AnimateIcon` drives only icons from this set — wrapping a plain `lucide-react` icon triggers nothing. A static icon is `lucide-react` directly; an icon from a stored name is `element/icon`.
|
|
38
41
|
|
|
39
|
-
|
|
42
|
+
## Morphing overlays
|
|
40
43
|
|
|
41
|
-
|
|
42
|
-
- `motion-primitives/morphing-popover` — `MorphingPopover` (`defaultOpen`/`open`/`onOpenChange`, `variants`) + `MorphingPopoverTrigger`, `MorphingPopoverContent`
|
|
44
|
+
The trigger morphs its own bounds into the popup (shared layout on the slow motion step, not a fade); under reduced motion the popup opens on the plain transition. Both are parts of the overlay families in [overlays.md](overlays.md):
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
<MorphingDialogTrigger>
|
|
47
|
-
<img src={thumb} alt="" />
|
|
48
|
-
</MorphingDialogTrigger>
|
|
49
|
-
<MorphingDialogContainer>
|
|
50
|
-
<MorphingDialogContent>
|
|
51
|
-
<MorphingDialogImage src={fullSize} alt="" />
|
|
52
|
-
</MorphingDialogContent>
|
|
53
|
-
</MorphingDialogContainer>
|
|
54
|
-
</MorphingDialog>
|
|
55
|
-
```
|
|
46
|
+
- `compound/dialog` — `Dialog.MorphTrigger`, in place of `Dialog.Trigger`; takes no `render` (style it with `className`)
|
|
47
|
+
- `element/popover` — `Popover.MorphTrigger`, in place of `Popover.Trigger`; takes no `render`
|
|
56
48
|
|
|
57
49
|
## Panel transitions
|
|
58
50
|
|
|
59
|
-
|
|
51
|
+
Swap between sibling panels, or a height-animated reveal.
|
|
60
52
|
|
|
61
|
-
- `
|
|
62
|
-
- `
|
|
63
|
-
- `
|
|
64
|
-
- `animate-ui/components/animate/tabs` — animated `Tabs`: sliding active-tab highlight over the primitive below; `variant` [solid|underline], `size` [sm|md|lg]
|
|
53
|
+
- `effect/transition-panel` — `TransitionPanel` + `TransitionPanel.Panel` (each with a `value`): shows the Panel matching `value` (controlled only — no `defaultValue` or `onValueChange`; an unmatched `value` renders nothing); `animation` [fade|slide|scale] (default `fade`). Slide direction follows Panel order; panels of different heights change the root's height at the swap
|
|
54
|
+
- `compound/tabs` — `Tabs.Contents` settles the panel box to the active panel's height and fades the entering panel in; reach for Tabs rather than pairing a hand-rolled tab strip with `TransitionPanel` ([navigation.md](navigation.md))
|
|
55
|
+
- `compound/accordion` / `element/collapsible` — `Accordion.Panel` and `Collapsible.Panel` open on their own measured height ([layout.md](layout.md))
|
|
65
56
|
|
|
66
57
|
## Decorative effects
|
|
67
58
|
|
|
68
|
-
Pointer-tracked washes and ambient loops — decorative chrome only, never load-bearing content.
|
|
59
|
+
Pointer-tracked washes, sliding highlights and ambient loops — decorative chrome only, never load-bearing content.
|
|
69
60
|
|
|
70
|
-
- `
|
|
71
|
-
- `
|
|
72
|
-
- `
|
|
73
|
-
- `
|
|
74
|
-
- `
|
|
61
|
+
- `effect/spotlight` — `Spotlight`: cursor-following radial glow, first child of a `relative overflow-hidden` parent; `diameter` (px, default `200`), `as` (`span` inside phrasing content). No spring prop — the trail follows `pace`
|
|
62
|
+
- `effect/shine-border` — `ShineBorder`: absolutely-positioned animated gradient border, placed as the direct first child of a `relative overflow-hidden` rounded card; `borderWidth` (px, defaults to `--edge-hairline`), `duration` (seconds, default 14), `colors` (gradient stops, default `["var(--primary)"]`).
|
|
63
|
+
- `effect/glow-effect` — `GlowEffect`: animated multi-colour halo, first child of a `relative` parent with the content in a later `relative` sibling; `animation` [rotate|pulse|breathe|colorShift|flowHorizontal|static] (default `rotate`), `colors`, `blur` [softest|soft|medium|strong|stronger|strongest|none] or a px number (default `medium`), `duration` (default `5`), `scale` (default `1`; raise it to bleed past the parent)
|
|
64
|
+
- `effect/grainient` — `Grainient`: WebGL2 animated grain gradient for a hero or empty-state background; `colors` (three stops, default `GRAINIENT_DEFAULT_COLORS`; token stops follow `.dark`), `timeSpeed` (default `0.25`), `warpSpeed`, `isGrainAnimated`, `maxFps` (default `30`), plus shader tuning (`colorBalance`, `warpStrength`, `warpFrequency`, `warpAmplitude`, `blendAngle`, `blendSoftness`, `rotationAmount`, `noiseScale`, `grainAmount`, `grainScale`, `contrast`, `gamma`, `saturation`, `centerX`, `centerY`, `zoom`). Override its root to `absolute inset-0` inside a `relative` parent; one instance per screen
|
|
65
|
+
- `effect/infinite-slider` — `InfiniteSlider`: seamless looping marquee that pauses on hover and focus within; `gap` (px, default `16`), `speed` (default `100`), `orientation` [horizontal|vertical], `isReversed`, `isPaused`, `as`. Children render twice — give each a stable `key` and keep `id`s and form controls out
|
|
66
|
+
- `effect/highlight` — `Highlight` + `Highlight.Item` (each with a string `value`): one box slides behind the item the host's `value` names (controlled only; `value={null}` shows none); `mode` [children|parent] (`parent` for mixed-size items), `exitDelay` (ms, default `200`), `boundsOffset`, `containerClassName`, `as`; root `className` and `style` paint the box (add `inset-0` in `children` mode). `useHighlightHover(restingValue)` returns `value` plus `getItemProps(id)` for a box that follows the pointer — paint it neutral (`bg-muted`), never the accent
|
|
75
67
|
|
|
76
|
-
|
|
68
|
+
```tsx
|
|
69
|
+
const hover = useHighlightHover(currentPage);
|
|
70
|
+
|
|
71
|
+
<Highlight value={hover.value} className="inset-0 rounded-md bg-muted">
|
|
72
|
+
{pages.map((page) => (
|
|
73
|
+
<Highlight.Item key={page.id} value={page.id} {...hover.getItemProps(page.id)}>
|
|
74
|
+
<a href={page.href}>{page.label}</a>
|
|
75
|
+
</Highlight.Item>
|
|
76
|
+
))}
|
|
77
|
+
</Highlight>
|
|
78
|
+
```
|
|
77
79
|
|
|
78
|
-
|
|
80
|
+
## Motion-aware slot
|
|
79
81
|
|
|
80
|
-
|
|
82
|
+
`Slot` (from `lib/slot`) — the motion-aware `asChild` slot: renders its single child element with the slot's props merged on (classes through `cn`, `style` merged with the slot's values winning, both refs kept), lifting the child onto a motion component so motion props reach a plain element. A non-element child renders nothing. `WithAsChild<Props>` is the matching props shape. Base UI parts compose through their `render` prop instead; `Slot` is for consumers building their own motion children.
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
<Slot whileHover={{ scale: 1.02 }} className="rounded-md">
|
|
86
|
+
<a href="/reports">Reports</a>
|
|
87
|
+
</Slot>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Dynamic toolbar
|
|
81
91
|
|
|
82
|
-
|
|
92
|
+
No primitive (`dynamic-toolbar`) — a toolbar that expands into a contextual input follows the plain-spec fallback in [index.md](index.md).
|
|
@@ -2,28 +2,67 @@
|
|
|
2
2
|
|
|
3
3
|
> Generated reference (regen-owned; see [index.md](index.md)). Binds only under `primitives: nurix`.
|
|
4
4
|
|
|
5
|
-
Components: Breadcrumb, Menubar,
|
|
5
|
+
Components: Breadcrumb, Menubar, NavigationMenu, Pagination, Sidebar, Tabs, VerticalIconBar
|
|
6
6
|
|
|
7
|
-
Each imports from its own subpath, with
|
|
7
|
+
Each imports from its own subpath as one namespace, with its parts as dotted members, e.g. `import { Tabs } from "@nurix/components/compound/tabs"` then `Tabs.List`, `Tabs.Trigger`, `Tabs.Content`.
|
|
8
8
|
|
|
9
9
|
## Sidebar
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Collapsible app shell: the shadcn primitives plus an opinionated kit, all as `Sidebar.*` members of `@nurix/components/block/sidebar`, with `useSidebar` beside it.
|
|
12
12
|
|
|
13
|
-
**Sub-components:** `
|
|
13
|
+
**Sub-components:** `Sidebar.Provider` (`defaultOpen`, `open`, `onOpenChange`, `openMobile`, `onOpenMobileChange`, `keyboardShortcut` [default `"b"`, `null` unbinds], `labels`), `Sidebar` (`side` [start|end], `variant` [sidebar|floating|inset], `collapsible` [offcanvas|icon|none], default `offcanvas`), `Sidebar.Trigger`, `.Rail`, `.Inset`, `.Input`, `.Header`, `.Content`, `.Footer`, `.Separator`, `.Group`, `.GroupLabel`, `.GroupAction`, `.GroupContent`, `.Menu`, `.MenuItem`, `.MenuButton`, `.MenuAction` (`isHoverRevealed`), `.MenuBadge`, `.MenuSkeleton` (`hasIcon`), `.MenuSub`, `.MenuSubItem`, `.MenuSubButton`. **Kit:** `Sidebar.Brand` (`logo`, `name`, `caption`, `href`), `Sidebar.Switcher` (`variant` [simple|rich], `side` [bottom|inline-end], `options`, `value`/`defaultValue`/`onValueChange`, `addAction`), `Sidebar.ItemGroup` (`variant` [list|tree|rich], `items`, `isCollapsible`, `hasCollapsibleItems`, `defaultExpandedIds`, `collapsedLabel` [hide|divider], `onShowMore`, `onItemClick`), `Sidebar.UserMenu` (`user`, `menuItems`), `Sidebar.CommandTrigger` (`collapsedTooltip`).
|
|
14
|
+
|
|
15
|
+
- `useSidebar()` returns `{ state, open, setOpen, openMobile, setOpenMobile, isMobile, toggleSidebar, panelId, labels }` and throws outside `Sidebar.Provider`.
|
|
16
|
+
- Page content is a sibling `Sidebar.Inset`, never a child of `Sidebar`. The sidebar stores nothing — persist open state through `defaultOpen` + `onOpenChange`.
|
|
17
|
+
- A file tree in the nav is `Sidebar.ItemGroup variant="tree"`; a footer card is a `Sidebar.Group` composed inside `Sidebar.Footer`.
|
|
14
18
|
|
|
15
19
|
```tsx
|
|
16
|
-
<
|
|
20
|
+
<Sidebar.Provider>
|
|
17
21
|
<Sidebar collapsible="icon">
|
|
18
|
-
<
|
|
19
|
-
<Switcher options={workspaces} />
|
|
20
|
-
</
|
|
21
|
-
<
|
|
22
|
-
<ItemGroup label="Platform"
|
|
23
|
-
</
|
|
24
|
-
<
|
|
25
|
-
<UserMenu user={user} />
|
|
26
|
-
</
|
|
22
|
+
<Sidebar.Header>
|
|
23
|
+
<Sidebar.Switcher options={workspaces} defaultValue={workspaces[0].id} />
|
|
24
|
+
</Sidebar.Header>
|
|
25
|
+
<Sidebar.Content>
|
|
26
|
+
<Sidebar.ItemGroup label="Platform" variant="tree" items={items} />
|
|
27
|
+
</Sidebar.Content>
|
|
28
|
+
<Sidebar.Footer>
|
|
29
|
+
<Sidebar.UserMenu user={user} menuItems={accountActions} />
|
|
30
|
+
</Sidebar.Footer>
|
|
31
|
+
<Sidebar.Rail />
|
|
27
32
|
</Sidebar>
|
|
28
|
-
</
|
|
33
|
+
<Sidebar.Inset><Sidebar.Trigger />{children}</Sidebar.Inset>
|
|
34
|
+
</Sidebar.Provider>
|
|
29
35
|
```
|
|
36
|
+
|
|
37
|
+
## Pagination
|
|
38
|
+
|
|
39
|
+
Pager over a page count (`compound/pagination`); `getPageRange(page, pageCount, siblingCount = 1)` returns the page window as numbers and `"ellipsis"` markers.
|
|
40
|
+
|
|
41
|
+
**Sub-components:** `Pagination.Content`, `.Item`, `.Link` (`value` or `isActive`, `href`), `.Previous`, `.Next`, `.First`, `.Last`, `.Ellipsis`; every control takes `size` [sm|default|lg], `isIconOnly`, `disabled`.
|
|
42
|
+
|
|
43
|
+
**Props:** `value`/`defaultValue`/`onValueChange(value, details)`, `pageCount`, `labels`
|
|
44
|
+
|
|
45
|
+
- A link takes `value` (the root holds the page) or `isActive` (a router owns it, with `href`), never both. In value mode the step controls disable at the ends; in router mode pass `disabled` yourself.
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
<Pagination value={page} pageCount={12} onValueChange={setPage}>
|
|
49
|
+
<Pagination.Content>
|
|
50
|
+
<Pagination.Item><Pagination.Previous /></Pagination.Item>
|
|
51
|
+
{getPageRange(page, 12).map((entry, index) => (
|
|
52
|
+
<Pagination.Item key={index}>
|
|
53
|
+
{entry === "ellipsis" ? <Pagination.Ellipsis /> : <Pagination.Link value={entry}>{entry}</Pagination.Link>}
|
|
54
|
+
</Pagination.Item>
|
|
55
|
+
))}
|
|
56
|
+
<Pagination.Item><Pagination.Next /></Pagination.Item>
|
|
57
|
+
</Pagination.Content>
|
|
58
|
+
</Pagination>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Other Components
|
|
62
|
+
|
|
63
|
+
- `compound/tabs` — `Tabs` with `Tabs.List` (`align` [start|justify], `activateOnFocus`), `Tabs.Trigger`, `Tabs.Content` (`keepMounted`), optional `Tabs.Contents` (height-settling, fading panel box); root `value`/`defaultValue`/`onValueChange`, `variant` [default|underline], `size` [sm|default|lg], `orientation`
|
|
64
|
+
- `compound/breadcrumb` — `Breadcrumb` with `Breadcrumb.Item` (`href`, `render`; the last item always renders as the current page); `maxItems` with `itemsBeforeCollapse`/`itemsAfterCollapse` (default 1 and 2) folds the middle behind an ellipsis menu; `separator`, `labels`
|
|
65
|
+
- `compound/navigation-menu` — `NavigationMenu` with `.List`, `.Item`, `.Trigger`, `.Content`, `.Link` (`isActive`, `closeOnClick`, `render`); a plain link takes `className={navigationMenuTriggerStyle({ size })}`; placement and `hasArrow` sit on the root, beside `orientation` and `labels.navigation`
|
|
66
|
+
- `compound/menubar` — `Menubar` with `.Menu`, `.Trigger`, `.Popup`, `.Item` (fires `onClick`, never `onSelect`), `.LinkItem`, `.CheckboxItem`, `.RadioGroup`/`.RadioItem`, `.Group`, `.Label`, `.Separator`, `.Sub`/`.SubTrigger`/`.SubPopup`, `.Shortcut` (display only, binds no key)
|
|
67
|
+
- `block/vertical-icon-bar` — `VerticalIconBar`: narrow always-icon rail; `items` (`{ value, label, icon, href?, render?, description?, badge?, disabled? }`), `value`/`defaultValue`/`onValueChange`, `width` (default `5rem`), `footer`, `labels.navigation`
|
|
68
|
+
- No nurix primitive: `navbar` (nearest composition `NavigationMenu`) and `stepper` — build both from the `index.md` fallback spec
|