@cueplusplus/ui 0.10.0 → 0.11.1
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/CHANGELOG.md +195 -0
- package/README.md +109 -3
- package/dist/chrome/index.d.ts +2 -1
- package/dist/chrome/index.js +3 -2
- package/dist/chrome/inspector.d.ts +61 -0
- package/dist/chrome/inspector.js +121 -0
- package/dist/elements/scroll-anchor.js +4 -2
- package/dist/forms/input.d.ts +12 -0
- package/dist/forms/textarea.d.ts +12 -0
- package/dist/forms/toggle.d.ts +6 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +5 -2
- package/dist/instruments/code-block.d.ts +35 -0
- package/dist/instruments/code-block.js +173 -0
- package/dist/instruments/index.d.ts +2 -1
- package/dist/instruments/index.js +2 -1
- package/dist/layout/bento.js +1 -1
- package/dist/layout/index.d.ts +2 -1
- package/dist/layout/index.js +2 -1
- package/dist/layout/preview.d.ts +110 -0
- package/dist/layout/preview.js +459 -0
- package/dist/primitives/chip.d.ts +1 -1
- package/manifest/components/activity-graph.json +2 -1
- package/manifest/components/agent-card.json +2 -1
- package/manifest/components/agent-pile.json +2 -1
- package/manifest/components/background-inbox.json +2 -1
- package/manifest/components/breadcrumb.json +2 -1
- package/manifest/components/chart-tooltip-content.json +2 -1
- package/manifest/components/checkpoint-history.json +2 -1
- package/manifest/components/code-block.json +106 -0
- package/manifest/components/code-diff.json +2 -1
- package/manifest/components/combobox.json +2 -1
- package/manifest/components/comparison-card.json +2 -1
- package/manifest/components/composer-attachment-chip.json +2 -1
- package/manifest/components/composer-context.json +2 -1
- package/manifest/components/composer-model-item.json +2 -1
- package/manifest/components/composer-person-item.json +2 -1
- package/manifest/components/computer-use.json +2 -1
- package/manifest/components/confidence-marker.json +2 -1
- package/manifest/components/context-breakdown.json +2 -1
- package/manifest/components/context-usage.json +2 -1
- package/manifest/components/conversation-search.json +2 -1
- package/manifest/components/cost-meter.json +2 -1
- package/manifest/components/day-separator.json +2 -1
- package/manifest/components/document-reference.json +2 -1
- package/manifest/components/elements-command-palette.json +2 -1
- package/manifest/components/elements-timeline.json +2 -1
- package/manifest/components/elicitation-form.json +2 -1
- package/manifest/components/file-tree.json +2 -1
- package/manifest/components/flow-graph.json +4 -2
- package/manifest/components/frac.json +1 -1
- package/manifest/components/group-bar.json +2 -1
- package/manifest/components/inline-citation.json +2 -1
- package/manifest/components/input.json +20 -0
- package/manifest/components/inspector.json +199 -0
- package/manifest/components/job-progress.json +2 -1
- package/manifest/components/log-viewer.json +2 -1
- package/manifest/components/map-answer.json +2 -1
- package/manifest/components/math-block.json +1 -1
- package/manifest/components/mcp-server-panel.json +2 -1
- package/manifest/components/memory-chips.json +2 -1
- package/manifest/components/message-actions.json +2 -1
- package/manifest/components/message-attachments.json +2 -1
- package/manifest/components/message-queue.json +2 -1
- package/manifest/components/message-timing.json +2 -1
- package/manifest/components/meter.json +1 -1
- package/manifest/components/model-picker.json +2 -1
- package/manifest/components/multi-select.json +2 -1
- package/manifest/components/onboarding.json +2 -1
- package/manifest/components/password-input.json +20 -0
- package/manifest/components/preview.json +202 -0
- package/manifest/components/prompt-library.json +2 -1
- package/manifest/components/queue-dock.json +2 -1
- package/manifest/components/quote-reply.json +2 -1
- package/manifest/components/reasoning-effort.json +2 -1
- package/manifest/components/reasoning-panel.json +2 -1
- package/manifest/components/regenerate-menu.json +2 -1
- package/manifest/components/research-report.json +2 -1
- package/manifest/components/retrieval-chunks.json +2 -1
- package/manifest/components/reviewable-diff.json +2 -1
- package/manifest/components/schedule-card.json +2 -1
- package/manifest/components/score-breakdown.json +2 -1
- package/manifest/components/scroll-anchor.json +2 -1
- package/manifest/components/search-input.json +20 -0
- package/manifest/components/segmented-control.json +2 -1
- package/manifest/components/settings-panel.json +2 -1
- package/manifest/components/shared-conversation.json +2 -1
- package/manifest/components/sources.json +2 -1
- package/manifest/components/speaker-identity.json +2 -1
- package/manifest/components/spec-sheet.json +2 -1
- package/manifest/components/spectrum-visualizer.json +2 -1
- package/manifest/components/stepper.json +2 -1
- package/manifest/components/streaming-text.json +2 -1
- package/manifest/components/sub.json +1 -1
- package/manifest/components/subagent-list.json +4 -2
- package/manifest/components/sup.json +1 -1
- package/manifest/components/swap-label.json +2 -1
- package/manifest/components/textarea.json +20 -0
- package/manifest/components/thread-list.json +2 -1
- package/manifest/components/thread-search.json +2 -1
- package/manifest/components/todo-list.json +2 -1
- package/manifest/components/toggle.json +10 -0
- package/manifest/components/tool-group.json +2 -1
- package/manifest/components/trace-waterfall.json +2 -1
- package/manifest/components/tree.json +2 -1
- package/manifest/components/universe-grid.json +2 -1
- package/manifest/components/usage-chart.json +2 -1
- package/manifest/components/voice-conversation.json +2 -1
- package/manifest/components/web-search.json +2 -1
- package/manifest/fixtures.json +670 -0
- package/manifest/manifest.json +125 -86
- package/manifest/tokens.json +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,200 @@
|
|
|
1
1
|
# @cueplusplus/ui
|
|
2
2
|
|
|
3
|
+
## 0.11.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 8ddd141: The manifest's fixture catalogue grows from 18 entries to 106, and 76 props across 74 components
|
|
8
|
+
now name one in `control.fixture`. A code generator, playground or agent reading
|
|
9
|
+
`manifest/components/<name>.json` now finds a named sample for props such as `TodoList.items`,
|
|
10
|
+
`CodeDiff.lines`, `Combobox.items` and `Breadcrumb.items`, where before it found nothing to fill
|
|
11
|
+
them with.
|
|
12
|
+
|
|
13
|
+
**Nothing to do.** No prop, type or export changed, and apart from the one fix at the end of this
|
|
14
|
+
note this release touches only the files under `manifest/`. `@cueplusplus/tokens` and `@cueplusplus/brand-tokens` move to 0.11.1 with it,
|
|
15
|
+
as one fixed family, and neither changes.
|
|
16
|
+
|
|
17
|
+
`manifest/fixtures.json` gains 88 entries:
|
|
18
|
+
|
|
19
|
+
- **Six short text fixtures** (kind `node`): `text.heading`, `text.count`, `text.total`,
|
|
20
|
+
`text.detail`, `text.author` and `text.time` — a heading, a figure, the figure it is out of, a
|
|
21
|
+
qualifier under a figure, an author's name and a clock time. Like `children.label` in 0.11.0,
|
|
22
|
+
they are for a playground or propSet to pick by hand, and no prop's `control.fixture` names them.
|
|
23
|
+
- **82 data fixtures** (71 `array`, 11 `opaque`), each a sample taken from its component's own
|
|
24
|
+
documentation specimen: todo items, diff hunks, trace spans, log lines, chart points, sources,
|
|
25
|
+
threads, models and the like. 75 of them list the printed type they fit in `accepts` —
|
|
26
|
+
`agent.todos` accepts `readonly TodoItem[]`, `layout.show-crumbs` accepts
|
|
27
|
+
`readonly BreadcrumbItem[]` — and every one of those 75 is now the `control.fixture` of at least
|
|
28
|
+
one prop. The other seven (`agent.subagent-progress`, `agents.window-start`,
|
|
29
|
+
`agents.window-end`, `chrome.expanded-front`, `composer.model-names`,
|
|
30
|
+
`knowledge.rig-dashboard`, `knowledge.trait-labels`) claim no type, so they are only ever picked
|
|
31
|
+
by hand.
|
|
32
|
+
|
|
33
|
+
An entry carries an id, a kind, a label and `accepts`, never the value itself. The values live with
|
|
34
|
+
the tools that render or export them: the docs playground, and the studio, whose bridge
|
|
35
|
+
`@cueplusplus/studio-mcp` exports each one as code from 0.1.1.
|
|
36
|
+
|
|
37
|
+
In `manifest/components/`, every change adds a `control.fixture` to a prop that had none, and no
|
|
38
|
+
existing one moved. `Combobox.items` and `MultiSelect.items` share `forms.fixture-types`, and
|
|
39
|
+
`FlowGraph` (`nodes`, `edges`) and `SubagentList` (`agents`, `summaryAgent`) gain two each.
|
|
40
|
+
`manifest.json` changes only in the SHA-256 of each record that changed.
|
|
41
|
+
|
|
42
|
+
Two records also correct the specimen code they embed:
|
|
43
|
+
|
|
44
|
+
- `meter.json` passed `paceTick={50}`, but `paceTick` is how far through the window you are, from
|
|
45
|
+
0 to 1, so the example drew no tick. It now passes `0.6`, labelled "60% of period elapsed".
|
|
46
|
+
- `math-block.json`, and `frac.json`, `sub.json` and `sup.json`, which embed the same specimen,
|
|
47
|
+
now write `visibleSteps={3}` instead of `visibleSteps={MATH.length}`. The count is the same, but
|
|
48
|
+
a tool that reads only literals can now read it.
|
|
49
|
+
|
|
50
|
+
One fix: `ScrollAnchor` (`@cueplusplus/ui/elements`) now stops its append timer once every message
|
|
51
|
+
has landed, where before the timer went on firing every 1.3 seconds for as long as the element was
|
|
52
|
+
mounted, though nothing on screen changed.
|
|
53
|
+
|
|
54
|
+
- @cueplusplus/tokens@0.11.1
|
|
55
|
+
|
|
56
|
+
## 0.11.0
|
|
57
|
+
|
|
58
|
+
### Minor Changes
|
|
59
|
+
|
|
60
|
+
- 8a41dcb: Three new components — `Preview`, `Inspector` and `CodeBlock`, each also exported from the root
|
|
61
|
+
barrel — plus a layout fix to `Bento.Tile` and newly documented `aria-label` and `placeholder`
|
|
62
|
+
props on the text inputs and `Toggle`.
|
|
63
|
+
|
|
64
|
+
**Nothing to do: every addition is a new export, and nothing that already compiled changed.** The
|
|
65
|
+
snippets below are fragments; each component has a full, copy-paste quick start in the package
|
|
66
|
+
README (`node_modules/@cueplusplus/ui/README.md`).
|
|
67
|
+
|
|
68
|
+
**`Preview`** (`@cueplusplus/ui/layout`) frames one component: a stage that can carry its own
|
|
69
|
+
theme, a slot for tools at the top right, and a footer. `label` is required, because the frame is
|
|
70
|
+
a `role="group"` named by it.
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import { Chip } from "@cueplusplus/ui";
|
|
74
|
+
import { Preview } from "@cueplusplus/ui/layout";
|
|
75
|
+
|
|
76
|
+
<Preview label="Chip preview" theme="terminal" density="compact" resizable>
|
|
77
|
+
<Chip tone="accent">Standby</Chip>
|
|
78
|
+
</Preview>;
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
- **The stage is a theme island; the chrome is not.** `theme`, `mode`, `density` and `font` land
|
|
82
|
+
on the stage and nowhere else. `tools`, `footer`, the resize grips and anything they open stay in
|
|
83
|
+
the page's scope. With none of the four set, the stage carries no attribute at all and inherits
|
|
84
|
+
the page.
|
|
85
|
+
- **Naming a theme does not load it.** The stage is scoped with `[data-theme="<name>"]`, so that
|
|
86
|
+
theme's stylesheet (`@cueplusplus/theme-<name>/theme.css`) must already be on the page.
|
|
87
|
+
- A stage `mode` with no `theme` restates the page's theme beside it, and a stage `theme` with no
|
|
88
|
+
`mode` repeats the page's mode, because a theme's light block is one compound selector. A stage
|
|
89
|
+
`density` names the nearest theme, as `<Density>` does.
|
|
90
|
+
- Overlays opened on the stage follow its theme, mode and density. A font pairing stops at the
|
|
91
|
+
stage: portals keep the page's. A stage that sets `theme` or `mode` also keeps the page's
|
|
92
|
+
`ThemeProvider` `overrides` off those overlays, so a popover matches the stage it opened from.
|
|
93
|
+
Inside a stage whose `mode` is `"dark"` or `"light"`, `useTheme().resolvedMode` reports that
|
|
94
|
+
mode; with `"system"` it reports the page's.
|
|
95
|
+
- Changing `theme`, `mode`, `density` or `font` keeps the specimen mounted, so its uncontrolled
|
|
96
|
+
state — a typed value, an open disclosure — survives the switch.
|
|
97
|
+
- The specimen sits centred on a dot grid. One wider than the stage keeps its start edge in view
|
|
98
|
+
and the frame scrolls to the rest. The stage reserves a minimum height before its specimen
|
|
99
|
+
loads, and with no `footer` its bottom corners follow the frame's rounded border.
|
|
100
|
+
- **The tools never cover the specimen.** With `tools`, the stage reserves their corner: it pads
|
|
101
|
+
its top by the tools' whole depth, measured in the page's density where the tools are drawn,
|
|
102
|
+
so a stage given a `density` of its own still clears them. The stage reserves this space only
|
|
103
|
+
when `tools` is set; a Preview without tools draws exactly the same markup.
|
|
104
|
+
|
|
105
|
+
`resizable` makes the stage resizable by pointer and keyboard:
|
|
106
|
+
|
|
107
|
+
- `resizable` (`true`, or `{ axis, minWidth, maxWidth, minHeight, maxHeight }`) adds a grip on
|
|
108
|
+
each axis, within 160–1280 × 96–960 px by default; `axis: "x"` or `"y"` keeps one. Each edge grip
|
|
109
|
+
is a focusable `separator` valued in pixels: arrow keys step 8 px, Shift+arrow 64 px, and
|
|
110
|
+
Home/End jump to the bounds. A corner grip drags both axes with the pointer, a double-click
|
|
111
|
+
resets an axis (the corner resets both), and a `W × H` readout shows while dragging.
|
|
112
|
+
- A resizable Preview fills its container's width. Its width bound in force is the smaller of
|
|
113
|
+
`maxWidth` and the frame's own width, re-measured with a `ResizeObserver`, so it stays inside a
|
|
114
|
+
grid track as the viewport changes; a frame narrower than `minWidth` lowers the floor with it,
|
|
115
|
+
and a width a reader chose comes back when the track widens again. The height is bounded by
|
|
116
|
+
`maxHeight` alone, and a taller stage grows the frame.
|
|
117
|
+
- An axis nobody has resized follows the stage's natural size live — a specimen that grows after
|
|
118
|
+
it loads, a track that widens, a Preview mounted hidden and shown later — and is drawn within the
|
|
119
|
+
same bounds its grip announces, so the first key press or drag starts from what is on screen.
|
|
120
|
+
- Without `resizable` there are no grips, and nothing is measured or observed. `Preview` is a
|
|
121
|
+
client component (`"use client"`).
|
|
122
|
+
|
|
123
|
+
**`Inspector`** (`@cueplusplus/ui/chrome`) is the layout of a settings panel, a properties sidebar
|
|
124
|
+
or a wrench menu: titled sections of label-and-control rows, with a footer. The controls are the
|
|
125
|
+
library's own.
|
|
126
|
+
|
|
127
|
+
```tsx
|
|
128
|
+
import { Inspector } from "@cueplusplus/ui/chrome";
|
|
129
|
+
|
|
130
|
+
<Inspector.Root>
|
|
131
|
+
<Inspector.Section label="Variants">
|
|
132
|
+
<Inspector.Row label="Size">
|
|
133
|
+
<SegmentedControl items={sizes} />
|
|
134
|
+
</Inspector.Row>
|
|
135
|
+
<Inspector.Row label="Label" htmlFor="label">
|
|
136
|
+
<Input id="label" />
|
|
137
|
+
</Inspector.Row>
|
|
138
|
+
</Inspector.Section>
|
|
139
|
+
<Inspector.Footer note="preset · primary" action={<Button>Reset</Button>} />
|
|
140
|
+
</Inspector.Root>;
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
- `Inspector.Section` takes a `label`, drawn as a `SectionHeader` and used as the group's name.
|
|
144
|
+
- `Inspector.Row` is one column until the Inspector itself is 18rem wide, then label beside
|
|
145
|
+
control. It is a container query, so a row follows the width of the popover or sidebar it sits
|
|
146
|
+
in, not the viewport's.
|
|
147
|
+
- **How a row names its control.** With `htmlFor`, the label is a `<label>` for that id. Without
|
|
148
|
+
it, the row lays its `label` on the control as `aria-label`, but only when the control is a
|
|
149
|
+
single element not already named by `aria-label` or `aria-labelledby`; text, lists and fragments
|
|
150
|
+
are left as they are. The row has no role of its own and never names itself, so a
|
|
151
|
+
`SegmentedControl`, which is already a group, is not announced twice.
|
|
152
|
+
- `Inspector.Footer` puts a quiet `note` at the start and one `action` at the end. A lone `action`
|
|
153
|
+
still sits at the end edge.
|
|
154
|
+
- Static markup — no hooks, no `"use client"` — so a server component can render it.
|
|
155
|
+
|
|
156
|
+
**`CodeBlock`** (`@cueplusplus/ui/instruments`) is a block of code with a caption and a copy
|
|
157
|
+
button, and no syntax-highlighter palette.
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
import { CodeBlock } from "@cueplusplus/ui/instruments";
|
|
161
|
+
|
|
162
|
+
<CodeBlock
|
|
163
|
+
label="JSX"
|
|
164
|
+
language="jsx"
|
|
165
|
+
code={'<Button variant="primary">Take cue</Button>'}
|
|
166
|
+
/>;
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
- `code` is printed verbatim, and the copy button copies exactly that. `label` is the caption and
|
|
170
|
+
defaults to the language. `language` defaults to `"tsx"` and lands on the `<pre>` as
|
|
171
|
+
`data-language`.
|
|
172
|
+
- `language="jsx"` adds emphasis in three inks the theme already has: tag names in `--cue-fg`,
|
|
173
|
+
attribute names in `--cue-fg-muted`, punctuation in `--cue-fg-subtle`. It reads string literals
|
|
174
|
+
whole, so a brace or a `<` inside a quoted string does not break it, and a `{…}` expression child
|
|
175
|
+
stays plain. Every other language prints plain.
|
|
176
|
+
- No directive: the copy button is its only client code, so a server page can render the rest.
|
|
177
|
+
|
|
178
|
+
**Changes to existing components:**
|
|
179
|
+
|
|
180
|
+
- **`Bento.Tile`**: a long `eyebrow` now truncates on one line instead of running under the tile's
|
|
181
|
+
`meta` and `action` in a narrow track. This is the only runtime change to an existing component.
|
|
182
|
+
- **`Input`** (and with it `PasswordInput` and `SearchInput`) and **`Textarea`** now declare
|
|
183
|
+
`aria-label` and `placeholder` in their props, and **`Toggle`** declares `aria-label`. This is
|
|
184
|
+
documentation only: all of them were already accepted as inherited HTML attributes and forwarded
|
|
185
|
+
to the element, so nothing you pass behaves differently. They now have rows in the props table
|
|
186
|
+
and in the manifest.
|
|
187
|
+
|
|
188
|
+
**Manifest.** `manifest/manifest.json` indexes the three new components, and
|
|
189
|
+
`manifest/components/{preview,inspector,code-block}.json` are new. The records for `input`,
|
|
190
|
+
`password-input`, `search-input`, `textarea` and `toggle` were regenerated with their new rows.
|
|
191
|
+
`manifest/fixtures.json` gains `children.label` ("A short label"), a one-word text fixture for a
|
|
192
|
+
playground or propSet to pick by hand; no prop's `control.fixture` names it.
|
|
193
|
+
|
|
194
|
+
### Patch Changes
|
|
195
|
+
|
|
196
|
+
- @cueplusplus/tokens@0.11.0
|
|
197
|
+
|
|
3
198
|
## 0.10.0
|
|
4
199
|
|
|
5
200
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -81,11 +81,11 @@ their own, so importing a button never pulls a charting library into your bundle
|
|
|
81
81
|
| `@cueplusplus/ui/primitives` | the leaves: buttons, chips, avatars, dots and the two loading shapes |
|
|
82
82
|
| `@cueplusplus/ui/forms` | everything a user types into, toggles, picks from or drags |
|
|
83
83
|
| `@cueplusplus/ui/overlays` | everything that floats: dialogs, sheets, menus, tooltips, the command palette |
|
|
84
|
-
| `@cueplusplus/ui/chrome` | console furniture: panels, rows, bars, tabs
|
|
85
|
-
| `@cueplusplus/ui/layout` | page structure: cards, stacks, grids, `Bento`, disclosure and the navigation shapes |
|
|
84
|
+
| `@cueplusplus/ui/chrome` | console furniture: panels, rows, bars, tabs, the tree outline and the `Inspector` layout |
|
|
85
|
+
| `@cueplusplus/ui/layout` | page structure: cards, stacks, grids, `Bento`, the `Preview` frame, disclosure and the navigation shapes |
|
|
86
86
|
| `@cueplusplus/ui/layout/carousel` | needs `embla-carousel-react` |
|
|
87
87
|
| `@cueplusplus/ui/layout/resizable` | needs `react-resizable-panels` |
|
|
88
|
-
| `@cueplusplus/ui/instruments` | the readouts: meters, sparklines, tables, logs and the two device frames |
|
|
88
|
+
| `@cueplusplus/ui/instruments` | the readouts: meters, sparklines, tables, logs, `CodeBlock` and the two device frames |
|
|
89
89
|
| `@cueplusplus/ui/instruments/data-table` | needs `@tanstack/react-table` |
|
|
90
90
|
| `@cueplusplus/ui/instruments/log-viewer` | needs `@tanstack/react-virtual`, `anser` |
|
|
91
91
|
| `@cueplusplus/ui/charts` | Recharts in this system's tokens, plus the categorical palette and the ramps; needs `recharts` |
|
|
@@ -108,6 +108,112 @@ Four stylesheet exports. `@cueplusplus/ui/styles.css` is always imported; the ot
|
|
|
108
108
|
imported only if you use what they paint — `@cueplusplus/ui/elements.css`,
|
|
109
109
|
`@cueplusplus/ui/flow.css` and `@cueplusplus/ui/elements/generative.css`.
|
|
110
110
|
|
|
111
|
+
## Showing a component: `Preview`, `Inspector`, `CodeBlock`
|
|
112
|
+
|
|
113
|
+
Three pieces for a page that shows components rather than only using them — a docs page, a design
|
|
114
|
+
review, a settings screen with a live sample. Each is exported from the root barrel as well as from
|
|
115
|
+
its group's subpath, and none needs an optional peer.
|
|
116
|
+
|
|
117
|
+
### `Preview` — one component on a stage
|
|
118
|
+
|
|
119
|
+
From `@cueplusplus/ui/layout`. A frame with a stage for the specimen, a `tools` slot at the top
|
|
120
|
+
right and a `footer`. `label` is required, because the frame is a `role="group"` named by it. The
|
|
121
|
+
stage can carry its own `theme`, `mode`, `density` and `font`; with none of them set it carries no
|
|
122
|
+
attribute and inherits the page.
|
|
123
|
+
|
|
124
|
+
**A stage `theme` needs that theme's stylesheet on the page.** Naming a theme does not load it: the
|
|
125
|
+
stage is scoped with `[data-theme="<name>"]`, so `@cueplusplus/theme-<name>/theme.css` has to be
|
|
126
|
+
imported like any other palette, or the stage paints the blank base with nothing erroring. The
|
|
127
|
+
example below shows `terminal` on a `cue` page, so both are imported and both are registered:
|
|
128
|
+
|
|
129
|
+
```css
|
|
130
|
+
/* app/globals.css */
|
|
131
|
+
@import "tailwindcss";
|
|
132
|
+
@import "@cueplusplus/ui/styles.css";
|
|
133
|
+
@import "@cueplusplus/theme-cue/theme.css";
|
|
134
|
+
@import "@cueplusplus/theme-terminal/theme.css";
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
import cue from "@cueplusplus/theme-cue";
|
|
139
|
+
import terminal from "@cueplusplus/theme-terminal";
|
|
140
|
+
import { Chip } from "@cueplusplus/ui";
|
|
141
|
+
import { Preview } from "@cueplusplus/ui/layout";
|
|
142
|
+
import { ThemeProvider } from "@cueplusplus/ui/system";
|
|
143
|
+
|
|
144
|
+
export default function ChipPage() {
|
|
145
|
+
return (
|
|
146
|
+
<ThemeProvider themes={[cue, terminal]} theme="cue" density="compact" mode="system">
|
|
147
|
+
<Preview label="Chip preview" theme="terminal" resizable footer="terminal · compact">
|
|
148
|
+
<Chip tone="accent">Standby</Chip>
|
|
149
|
+
</Preview>
|
|
150
|
+
</ThemeProvider>
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
- Only the stage changes theme. `tools`, `footer`, the resize grips and anything they open stay in
|
|
156
|
+
the page's theme, so the controls that drive a specimen always look like the page around them.
|
|
157
|
+
- `resizable` adds a grip per axis, 160–1280 × 96–960 px by default, that works by pointer and by
|
|
158
|
+
keyboard (arrows step 8 px, Shift+arrow 64 px). Pass `{ axis, minWidth, maxWidth, minHeight,
|
|
159
|
+
maxHeight }` to narrow it. A resizable Preview fills its container's width.
|
|
160
|
+
- It is a client component (`"use client"`).
|
|
161
|
+
|
|
162
|
+
### `Inspector` — the layout of a settings panel
|
|
163
|
+
|
|
164
|
+
From `@cueplusplus/ui/chrome`. Titled sections of label-and-control rows, then a footer — the shape
|
|
165
|
+
of a properties sidebar or a wrench menu. The controls are the library's own.
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
import { Button, Input, SegmentedControl } from "@cueplusplus/ui";
|
|
169
|
+
import { Inspector } from "@cueplusplus/ui/chrome";
|
|
170
|
+
|
|
171
|
+
const sizes = [
|
|
172
|
+
{ value: "sm", label: "Small" },
|
|
173
|
+
{ value: "md", label: "Medium" },
|
|
174
|
+
{ value: "lg", label: "Large" },
|
|
175
|
+
];
|
|
176
|
+
|
|
177
|
+
export function ButtonInspector() {
|
|
178
|
+
return (
|
|
179
|
+
<Inspector.Root>
|
|
180
|
+
<Inspector.Section label="Variants">
|
|
181
|
+
<Inspector.Row label="Size">
|
|
182
|
+
<SegmentedControl items={sizes} defaultValue="md" />
|
|
183
|
+
</Inspector.Row>
|
|
184
|
+
<Inspector.Row label="Label" htmlFor="button-label">
|
|
185
|
+
<Input id="button-label" defaultValue="Run cue" />
|
|
186
|
+
</Inspector.Row>
|
|
187
|
+
</Inspector.Section>
|
|
188
|
+
<Inspector.Footer note="preset · primary" action={<Button size="sm">Reset</Button>} />
|
|
189
|
+
</Inspector.Root>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
- A row names its control. With `htmlFor` the label is a `<label>` for that id; without it the row
|
|
195
|
+
lays `label` on the control as `aria-label`, unless the control already names itself.
|
|
196
|
+
- A row is one column until the Inspector is 18rem wide, then label beside control. It is a
|
|
197
|
+
container query, so it follows the popover or sidebar the Inspector sits in, not the viewport.
|
|
198
|
+
- `Inspector` itself has no hooks and no `"use client"`, so a server component can render it.
|
|
199
|
+
|
|
200
|
+
### `CodeBlock` — code with a caption and a copy button
|
|
201
|
+
|
|
202
|
+
From `@cueplusplus/ui/instruments`.
|
|
203
|
+
|
|
204
|
+
```tsx
|
|
205
|
+
import { CodeBlock } from "@cueplusplus/ui/instruments";
|
|
206
|
+
|
|
207
|
+
export function ButtonSource() {
|
|
208
|
+
return <CodeBlock label="button.tsx" language="jsx" code={'<Button variant="primary">Run cue</Button>'} />;
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
- `code` is printed verbatim, and the copy button copies exactly that. `label` is the caption and
|
|
213
|
+
defaults to the language; `language` defaults to `"tsx"`.
|
|
214
|
+
- There is no syntax-highlighter palette. `language="jsx"` picks out tag names, attribute names and
|
|
215
|
+
punctuation in three inks the theme already has; every other language prints plain.
|
|
216
|
+
|
|
111
217
|
## The machine-readable half
|
|
112
218
|
|
|
113
219
|
This package ships its own manifest: `@cueplusplus/ui/manifest.json` is an index of every
|
package/dist/chrome/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { AppShell, AppShellAsideProps, AppShellBarProps, AppShellBodyProps, AppS
|
|
|
6
6
|
import { EmptyState, EmptyStateProps } from "./empty-state.js";
|
|
7
7
|
import { Eyebrow, EyebrowProps } from "./eyebrow.js";
|
|
8
8
|
import { Footer, FooterProps } from "./footer.js";
|
|
9
|
+
import { Inspector, InspectorFooterProps, InspectorRootProps, InspectorRowProps, InspectorSectionProps } from "./inspector.js";
|
|
9
10
|
import { NavigationMenu, NavigationMenuContentProps, NavigationMenuItemProps, NavigationMenuLinkProps, NavigationMenuListProps, NavigationMenuRootProps, NavigationMenuTriggerProps, NavigationMenuViewportProps } from "./navigation-menu.js";
|
|
10
11
|
import { PageShell, PageShellProps, PageWidth } from "./page-shell.js";
|
|
11
12
|
import { Panel, PanelHeader, PanelHeaderProps, PanelProps } from "./panel.js";
|
|
@@ -19,4 +20,4 @@ import { ScrollableTabsList, ScrollableTabsListProps, Tabs, TabsListProps, TabsP
|
|
|
19
20
|
import { TitleBar, TitleBarProps } from "./title-bar.js";
|
|
20
21
|
import { Tree, TreeProps, TreeVisibility, TreeVisibilityToggle, TreeVisibilityToggleProps } from "./tree.js";
|
|
21
22
|
import { Toolbar, ToolbarButtonProps, ToolbarGroupProps, ToolbarRootProps, ToolbarSeparatorProps } from "./toolbar.js";
|
|
22
|
-
export { AppBar, type AppBarActionsProps, type AppBarBrandProps, type AppBarLinkProps, type AppBarNavProps, type AppBarRegister, type AppBarRootProps, type AppBarSeparatorProps, AppShell, type AppShellAsideProps, type AppShellBarProps, type AppShellBodyProps, type AppShellContentProps, type AppShellNavTriggerProps, type AppShellRootProps, type AppShellScrollerProps, type AppShellSidebarProps, type BarOverflow, EmptyState, type EmptyStateProps, Eyebrow, type EyebrowProps, Footer, type FooterProps, NavigationMenu, type NavigationMenuContentProps, type NavigationMenuItemProps, type NavigationMenuLinkProps, type NavigationMenuListProps, type NavigationMenuRootProps, type NavigationMenuTriggerProps, type NavigationMenuViewportProps, PageShell, type PageShellProps, type PageWidth, Panel, PanelHeader, type PanelHeaderProps, type PanelProps, Row, type RowProps, ScrollArea, type ScrollAreaOrientation, type ScrollAreaProps, type ScrollEdges, ScrollableTabsList, type ScrollableTabsListProps, SeamList, type SeamListProps, SectionHeader, type SectionHeaderProps, SegmentedControl, type SegmentedControlItem, type SegmentedControlProps, type SegmentedControlSize, StatusBar, type StatusBarGroupProps, type StatusBarItemProps, type StatusBarProminence, type StatusBarProps, type StatusBarTone, TAB_FADE_PX, TREE_GUIDE_GLYPHS, Tabs, type TabsListProps, type TabsPanelProps, type TabsRootProps, type TabsTabProps, TitleBar, type TitleBarProps, Toolbar, type ToolbarButtonProps, type ToolbarGroupProps, type ToolbarRootProps, type ToolbarSeparatorProps, Tree, type TreeGuide, type TreeItem, type TreeProps, type TreeRow, type TreeVisibility, TreeVisibilityToggle, type TreeVisibilityToggleProps, computeScrollEdges, edgeFadeMask, flattenTree, rowVariants };
|
|
23
|
+
export { AppBar, type AppBarActionsProps, type AppBarBrandProps, type AppBarLinkProps, type AppBarNavProps, type AppBarRegister, type AppBarRootProps, type AppBarSeparatorProps, AppShell, type AppShellAsideProps, type AppShellBarProps, type AppShellBodyProps, type AppShellContentProps, type AppShellNavTriggerProps, type AppShellRootProps, type AppShellScrollerProps, type AppShellSidebarProps, type BarOverflow, EmptyState, type EmptyStateProps, Eyebrow, type EyebrowProps, Footer, type FooterProps, Inspector, type InspectorFooterProps, type InspectorRootProps, type InspectorRowProps, type InspectorSectionProps, NavigationMenu, type NavigationMenuContentProps, type NavigationMenuItemProps, type NavigationMenuLinkProps, type NavigationMenuListProps, type NavigationMenuRootProps, type NavigationMenuTriggerProps, type NavigationMenuViewportProps, PageShell, type PageShellProps, type PageWidth, Panel, PanelHeader, type PanelHeaderProps, type PanelProps, Row, type RowProps, ScrollArea, type ScrollAreaOrientation, type ScrollAreaProps, type ScrollEdges, ScrollableTabsList, type ScrollableTabsListProps, SeamList, type SeamListProps, SectionHeader, type SectionHeaderProps, SegmentedControl, type SegmentedControlItem, type SegmentedControlProps, type SegmentedControlSize, StatusBar, type StatusBarGroupProps, type StatusBarItemProps, type StatusBarProminence, type StatusBarProps, type StatusBarTone, TAB_FADE_PX, TREE_GUIDE_GLYPHS, Tabs, type TabsListProps, type TabsPanelProps, type TabsRootProps, type TabsTabProps, TitleBar, type TitleBarProps, Toolbar, type ToolbarButtonProps, type ToolbarGroupProps, type ToolbarRootProps, type ToolbarSeparatorProps, Tree, type TreeGuide, type TreeItem, type TreeProps, type TreeRow, type TreeVisibility, TreeVisibilityToggle, type TreeVisibilityToggleProps, computeScrollEdges, edgeFadeMask, flattenTree, rowVariants };
|
package/dist/chrome/index.js
CHANGED
|
@@ -5,16 +5,17 @@ import { AppShell } from "./app-shell.js";
|
|
|
5
5
|
import { EmptyState } from "./empty-state.js";
|
|
6
6
|
import { Eyebrow } from "./eyebrow.js";
|
|
7
7
|
import { Footer } from "./footer.js";
|
|
8
|
+
import { SectionHeader } from "./section-header.js";
|
|
9
|
+
import { Inspector } from "./inspector.js";
|
|
8
10
|
import { NavigationMenu } from "./navigation-menu.js";
|
|
9
11
|
import { PageShell } from "./page-shell.js";
|
|
10
12
|
import { Panel, PanelHeader } from "./panel.js";
|
|
11
13
|
import { Row, SeamList, rowVariants } from "./row.js";
|
|
12
14
|
import { ScrollArea } from "./scroll-area.js";
|
|
13
|
-
import { SectionHeader } from "./section-header.js";
|
|
14
15
|
import { SegmentedControl } from "./segmented-control.js";
|
|
15
16
|
import { StatusBar } from "./status-bar.js";
|
|
16
17
|
import { ScrollableTabsList, Tabs } from "./tabs.js";
|
|
17
18
|
import { TitleBar } from "./title-bar.js";
|
|
18
19
|
import { Tree, TreeVisibilityToggle } from "./tree.js";
|
|
19
20
|
import { Toolbar } from "./toolbar.js";
|
|
20
|
-
export { AppBar, AppShell, EmptyState, Eyebrow, Footer, NavigationMenu, PageShell, Panel, PanelHeader, Row, ScrollArea, ScrollableTabsList, SeamList, SectionHeader, SegmentedControl, StatusBar, TAB_FADE_PX, TREE_GUIDE_GLYPHS, Tabs, TitleBar, Toolbar, Tree, TreeVisibilityToggle, computeScrollEdges, edgeFadeMask, flattenTree, rowVariants };
|
|
21
|
+
export { AppBar, AppShell, EmptyState, Eyebrow, Footer, Inspector, NavigationMenu, PageShell, Panel, PanelHeader, Row, ScrollArea, ScrollableTabsList, SeamList, SectionHeader, SegmentedControl, StatusBar, TAB_FADE_PX, TREE_GUIDE_GLYPHS, Tabs, TitleBar, Toolbar, Tree, TreeVisibilityToggle, computeScrollEdges, edgeFadeMask, flattenTree, rowVariants };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
//#region src/chrome/inspector.d.ts
|
|
3
|
+
interface InspectorRootProps extends React.ComponentPropsWithoutRef<"div"> {
|
|
4
|
+
/** The sections, then the footer. */
|
|
5
|
+
children?: React.ReactNode;
|
|
6
|
+
}
|
|
7
|
+
interface InspectorSectionProps extends React.ComponentPropsWithoutRef<"div"> {
|
|
8
|
+
/** The section's title — "Variants", "Stage". Drawn by a `SectionHeader` and read as the group's name. */
|
|
9
|
+
label: string;
|
|
10
|
+
/** The section's rows. */
|
|
11
|
+
children?: React.ReactNode;
|
|
12
|
+
}
|
|
13
|
+
interface InspectorRowProps extends React.ComponentPropsWithoutRef<"div"> {
|
|
14
|
+
/**
|
|
15
|
+
* What the control sets — "Size", "Theme". Drawn before it, and read as its
|
|
16
|
+
* name: a `<label>` for it when `htmlFor` is given, and otherwise laid on
|
|
17
|
+
* the control as `aria-label`, unless the control already names itself.
|
|
18
|
+
*/
|
|
19
|
+
label: string;
|
|
20
|
+
/** The control's `id`, when it takes one: the label then becomes a `<label>` for it. */
|
|
21
|
+
htmlFor?: string;
|
|
22
|
+
/** The control — one element, any of the library's own. A row names a single control. */
|
|
23
|
+
children?: React.ReactNode;
|
|
24
|
+
}
|
|
25
|
+
interface InspectorFooterProps extends React.ComponentPropsWithoutRef<"div"> {
|
|
26
|
+
/** A quiet line on the left: which preset this is, or that none matches. */
|
|
27
|
+
note?: React.ReactNode;
|
|
28
|
+
/** The footer's one action, on the right — by convention a small `Button`. */
|
|
29
|
+
action?: React.ReactNode;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The shape a settings panel, a properties sidebar and a wrench menu share:
|
|
33
|
+
* titled sections of label-and-control rows, with a footer.
|
|
34
|
+
*
|
|
35
|
+
* Layout and nothing else — the controls are the library's own. A section is
|
|
36
|
+
* a group headed by a `SectionHeader`; a row is a label then its control, one
|
|
37
|
+
* column in a narrow container and two from 18rem; the footer holds a quiet
|
|
38
|
+
* note and one action.
|
|
39
|
+
*
|
|
40
|
+
* **Static markup — no hooks, no `"use client"`**, so a server page can draw
|
|
41
|
+
* one. Labels are strings for the same reason: a row with no `htmlFor` lays its
|
|
42
|
+
* label on its control as `aria-label`, rather than pointing at an id nobody
|
|
43
|
+
* has generated. The row itself carries no role.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* <Inspector.Root>
|
|
47
|
+
* <Inspector.Section label="Variants">
|
|
48
|
+
* <Inspector.Row label="Size"><SegmentedControl items={sizes} /></Inspector.Row>
|
|
49
|
+
* <Inspector.Row label="Label" htmlFor="label"><Input id="label" /></Inspector.Row>
|
|
50
|
+
* </Inspector.Section>
|
|
51
|
+
* <Inspector.Footer note="preset · button-hero" action={<Button size="sm">Reset</Button>} />
|
|
52
|
+
* </Inspector.Root>
|
|
53
|
+
*/
|
|
54
|
+
declare const Inspector: {
|
|
55
|
+
Root: React.ForwardRefExoticComponent<InspectorRootProps & React.RefAttributes<HTMLDivElement>>;
|
|
56
|
+
Section: React.ForwardRefExoticComponent<InspectorSectionProps & React.RefAttributes<HTMLDivElement>>;
|
|
57
|
+
Row: React.ForwardRefExoticComponent<InspectorRowProps & React.RefAttributes<HTMLDivElement>>;
|
|
58
|
+
Footer: React.ForwardRefExoticComponent<InspectorFooterProps & React.RefAttributes<HTMLDivElement>>;
|
|
59
|
+
};
|
|
60
|
+
//#endregion
|
|
61
|
+
export { Inspector, InspectorFooterProps, InspectorRootProps, InspectorRowProps, InspectorSectionProps };
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { cn } from "../lib/cn.js";
|
|
2
|
+
import { SectionHeader } from "./section-header.js";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
//#region src/chrome/inspector.tsx
|
|
6
|
+
/** A size container, so a row's two columns depend on the inspector's width and not the page's. */
|
|
7
|
+
const ROOT_CLASS = "@container flex min-w-0 flex-col";
|
|
8
|
+
const SECTION_CLASS = "flex flex-col gap-(--cue-space-3) border-t border-border px-(--cue-space-4) py-(--cue-space-3) first:border-t-0";
|
|
9
|
+
/** Static literals: Tailwind scans source text, not computed strings. */
|
|
10
|
+
const ROW_CLASS = "grid grid-cols-1 gap-(--cue-space-2) @min-[18rem]:grid-cols-[6rem_minmax(0,1fr)] @min-[18rem]:items-center";
|
|
11
|
+
const LABEL_CLASS = "text-(length:--cue-text-ui) text-fg-muted";
|
|
12
|
+
const FOOTER_CLASS = "flex items-center justify-between gap-(--cue-space-3) border-t border-border px-(--cue-space-4) py-(--cue-space-3)";
|
|
13
|
+
const NOTE_CLASS = "min-w-0 truncate font-mono text-(length:--cue-text-label) text-fg-subtle";
|
|
14
|
+
/** `ms-auto` so a lone action still sits at the end edge: `space-between` alone puts a single flex child at the start. */
|
|
15
|
+
const FOOTER_ACTION_CLASS = "ms-auto";
|
|
16
|
+
/**
|
|
17
|
+
* A row's words, laid on its control as the control's own name.
|
|
18
|
+
*
|
|
19
|
+
* A row with no `htmlFor` has no id to point a `<label>` at, and generating one
|
|
20
|
+
* would take `useId` — a hook, and with it this module's place in a server
|
|
21
|
+
* component. So the control is cloned with `aria-label={label}`: cloning is not
|
|
22
|
+
* a hook, which is why `Bento.Tile` clones its `render` link the same way. A
|
|
23
|
+
* control that already names itself keeps its name. Anything that is not one
|
|
24
|
+
* element — text, a list, a fragment — is left as it is, because an
|
|
25
|
+
* `aria-label` on a fragment is an attribute on nothing.
|
|
26
|
+
*
|
|
27
|
+
* The row itself carries no role. A `SegmentedControl` is already a group, and
|
|
28
|
+
* a row that named itself a group with the same words would be two groups with
|
|
29
|
+
* one name, announced twice.
|
|
30
|
+
*/
|
|
31
|
+
function nameControl(control, label) {
|
|
32
|
+
if (!React.isValidElement(control) || control.type === React.Fragment) return control;
|
|
33
|
+
if (control.props["aria-label"] !== void 0 || control.props["aria-labelledby"] !== void 0) return control;
|
|
34
|
+
return React.cloneElement(control, { "aria-label": label });
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The shape a settings panel, a properties sidebar and a wrench menu share:
|
|
38
|
+
* titled sections of label-and-control rows, with a footer.
|
|
39
|
+
*
|
|
40
|
+
* Layout and nothing else — the controls are the library's own. A section is
|
|
41
|
+
* a group headed by a `SectionHeader`; a row is a label then its control, one
|
|
42
|
+
* column in a narrow container and two from 18rem; the footer holds a quiet
|
|
43
|
+
* note and one action.
|
|
44
|
+
*
|
|
45
|
+
* **Static markup — no hooks, no `"use client"`**, so a server page can draw
|
|
46
|
+
* one. Labels are strings for the same reason: a row with no `htmlFor` lays its
|
|
47
|
+
* label on its control as `aria-label`, rather than pointing at an id nobody
|
|
48
|
+
* has generated. The row itself carries no role.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* <Inspector.Root>
|
|
52
|
+
* <Inspector.Section label="Variants">
|
|
53
|
+
* <Inspector.Row label="Size"><SegmentedControl items={sizes} /></Inspector.Row>
|
|
54
|
+
* <Inspector.Row label="Label" htmlFor="label"><Input id="label" /></Inspector.Row>
|
|
55
|
+
* </Inspector.Section>
|
|
56
|
+
* <Inspector.Footer note="preset · button-hero" action={<Button size="sm">Reset</Button>} />
|
|
57
|
+
* </Inspector.Root>
|
|
58
|
+
*/
|
|
59
|
+
const Inspector = {
|
|
60
|
+
Root: React.forwardRef(function InspectorRoot({ className, children, ...elementProps }, ref) {
|
|
61
|
+
return /* @__PURE__ */ jsx("div", {
|
|
62
|
+
...elementProps,
|
|
63
|
+
ref,
|
|
64
|
+
"data-slot": "inspector",
|
|
65
|
+
className: cn(ROOT_CLASS, className),
|
|
66
|
+
children
|
|
67
|
+
});
|
|
68
|
+
}),
|
|
69
|
+
Section: React.forwardRef(function InspectorSection({ label, className, children, ...elementProps }, ref) {
|
|
70
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
71
|
+
...elementProps,
|
|
72
|
+
ref,
|
|
73
|
+
role: "group",
|
|
74
|
+
"aria-label": label,
|
|
75
|
+
"data-slot": "inspector-section",
|
|
76
|
+
className: cn(SECTION_CLASS, className),
|
|
77
|
+
children: [/* @__PURE__ */ jsx(SectionHeader, { label }), children]
|
|
78
|
+
});
|
|
79
|
+
}),
|
|
80
|
+
Row: React.forwardRef(function InspectorRow({ label, htmlFor, className, children, ...elementProps }, ref) {
|
|
81
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
82
|
+
...elementProps,
|
|
83
|
+
ref,
|
|
84
|
+
"data-slot": "inspector-row",
|
|
85
|
+
className: cn(ROW_CLASS, className),
|
|
86
|
+
children: [htmlFor === void 0 ? /* @__PURE__ */ jsx("span", {
|
|
87
|
+
"data-slot": "inspector-row-label",
|
|
88
|
+
className: LABEL_CLASS,
|
|
89
|
+
children: label
|
|
90
|
+
}) : /* @__PURE__ */ jsx("label", {
|
|
91
|
+
"data-slot": "inspector-row-label",
|
|
92
|
+
htmlFor,
|
|
93
|
+
className: LABEL_CLASS,
|
|
94
|
+
children: label
|
|
95
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
96
|
+
"data-slot": "inspector-row-control",
|
|
97
|
+
className: "min-w-0",
|
|
98
|
+
children: htmlFor === void 0 ? nameControl(children, label) : children
|
|
99
|
+
})]
|
|
100
|
+
});
|
|
101
|
+
}),
|
|
102
|
+
Footer: React.forwardRef(function InspectorFooter({ note, action, className, ...elementProps }, ref) {
|
|
103
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
104
|
+
...elementProps,
|
|
105
|
+
ref,
|
|
106
|
+
"data-slot": "inspector-footer",
|
|
107
|
+
className: cn(FOOTER_CLASS, className),
|
|
108
|
+
children: [note === void 0 ? null : /* @__PURE__ */ jsx("span", {
|
|
109
|
+
"data-slot": "inspector-footer-note",
|
|
110
|
+
className: NOTE_CLASS,
|
|
111
|
+
children: note
|
|
112
|
+
}), action === void 0 ? null : /* @__PURE__ */ jsx("span", {
|
|
113
|
+
"data-slot": "inspector-footer-action",
|
|
114
|
+
className: FOOTER_ACTION_CLASS,
|
|
115
|
+
children: action
|
|
116
|
+
})]
|
|
117
|
+
});
|
|
118
|
+
})
|
|
119
|
+
};
|
|
120
|
+
//#endregion
|
|
121
|
+
export { Inspector };
|
|
@@ -27,8 +27,9 @@ function ScrollAnchor({ messages, paused = false, onSettled, className, ...props
|
|
|
27
27
|
const [count, setCount] = useState(INITIAL_COUNT);
|
|
28
28
|
const [pinned, setPinned] = useState(true);
|
|
29
29
|
const [seenCount, setSeenCount] = useState(INITIAL_COUNT);
|
|
30
|
+
const settled = count >= messages.length;
|
|
30
31
|
useEffect(() => {
|
|
31
|
-
if (paused) return;
|
|
32
|
+
if (paused || settled) return;
|
|
32
33
|
if (reduced) {
|
|
33
34
|
setCount(messages.length);
|
|
34
35
|
return;
|
|
@@ -42,8 +43,9 @@ function ScrollAnchor({ messages, paused = false, onSettled, className, ...props
|
|
|
42
43
|
return () => clearInterval(id);
|
|
43
44
|
}, [
|
|
44
45
|
messages.length,
|
|
46
|
+
reduced,
|
|
45
47
|
paused,
|
|
46
|
-
|
|
48
|
+
settled
|
|
47
49
|
]);
|
|
48
50
|
useEffect(() => {
|
|
49
51
|
if (count >= messages.length && pinned) onSettled?.();
|
package/dist/forms/input.d.ts
CHANGED
|
@@ -10,6 +10,18 @@ interface InputProps extends Omit<Input.Props, "className" | "size"> {
|
|
|
10
10
|
* attribute (a character count), which nothing in a token-driven layout wants.
|
|
11
11
|
*/
|
|
12
12
|
size?: FormControlSize;
|
|
13
|
+
/**
|
|
14
|
+
* Accessible name for the input, when no `FieldLabel` names it. Declared here
|
|
15
|
+
* rather than left to the inherited attribute so the props table carries the
|
|
16
|
+
* row: a bare input outside a `Field` has no other way to be named.
|
|
17
|
+
*/
|
|
18
|
+
"aria-label"?: string;
|
|
19
|
+
/**
|
|
20
|
+
* An example of what goes in the field, shown while it is empty. Not a name:
|
|
21
|
+
* it disappears on the first keystroke, so pair it with `aria-label` or a
|
|
22
|
+
* `FieldLabel`. Declared for the props-table row, as `aria-label` is above.
|
|
23
|
+
*/
|
|
24
|
+
placeholder?: string;
|
|
13
25
|
}
|
|
14
26
|
/**
|
|
15
27
|
* The single-line text control.
|
package/dist/forms/textarea.d.ts
CHANGED
|
@@ -5,6 +5,18 @@ interface TextareaProps extends React.ComponentPropsWithoutRef<"textarea"> {
|
|
|
5
5
|
className?: string;
|
|
6
6
|
/** Visible rows before the box starts scrolling. Defaults to `3`. */
|
|
7
7
|
rows?: number;
|
|
8
|
+
/**
|
|
9
|
+
* Accessible name for the textarea, when no `FieldLabel` names it. Declared
|
|
10
|
+
* here rather than left to the inherited attribute so the props table carries
|
|
11
|
+
* the row: a bare textarea outside a `Field` has no other way to be named.
|
|
12
|
+
*/
|
|
13
|
+
"aria-label"?: string;
|
|
14
|
+
/**
|
|
15
|
+
* An example of what goes in the box, shown while it is empty. Not a name:
|
|
16
|
+
* it disappears on the first keystroke, so pair it with `aria-label` or a
|
|
17
|
+
* `FieldLabel`. Declared for the props-table row, as `aria-label` is above.
|
|
18
|
+
*/
|
|
19
|
+
placeholder?: string;
|
|
8
20
|
}
|
|
9
21
|
/**
|
|
10
22
|
* The multi-line text control.
|
package/dist/forms/toggle.d.ts
CHANGED
|
@@ -18,6 +18,12 @@ interface ToggleProps extends Omit<Toggle.Props, "className"> {
|
|
|
18
18
|
icon?: React.ElementType;
|
|
19
19
|
/** The label. Leave it off for an icon-only toggle — and then pass `aria-label`. */
|
|
20
20
|
children?: React.ReactNode;
|
|
21
|
+
/**
|
|
22
|
+
* Accessible name. An icon-only toggle has no text to be named by, so this is
|
|
23
|
+
* its name; declared here rather than left to the inherited attribute so the
|
|
24
|
+
* props table carries the row the sentence above tells a caller to pass.
|
|
25
|
+
*/
|
|
26
|
+
"aria-label"?: string;
|
|
21
27
|
}
|
|
22
28
|
/**
|
|
23
29
|
* A two-state button: solo, mute, snap-to-grid, "show hidden".
|