@sableui/react 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +73 -0
- package/bin/sable-lint.mjs +5 -1
- package/dist/{_contract-CkqXDVww.d.ts → _contract-CDa9-NdB.d.ts} +47 -1
- package/dist/blocks/wallet-block.js +2 -2
- package/dist/components/app-shell/app-shell-frame.js +16 -0
- package/dist/components/app-shell/app-shell-main.js +12 -0
- package/dist/components/app-shell/app-shell.js +28 -4
- package/dist/components/app-shell/app-shell.meta.js +88 -4
- package/dist/components/area-chart/area-chart.meta.js +6 -1
- package/dist/components/attachment/attachment.meta.js +2 -1
- package/dist/components/attachment/attachment.variants.js +1 -1
- package/dist/components/badge/badge.meta.js +8 -1
- package/dist/components/badge/badge.variants.js +7 -7
- package/dist/components/banner/banner.meta.js +6 -1
- package/dist/components/banner/banner.variants.js +5 -5
- package/dist/components/bar-chart/bar-chart.meta.js +6 -1
- package/dist/components/caret-menu/caret-menu.js +5 -6
- package/dist/components/chat-composer/chat-composer.meta.js +2 -2
- package/dist/components/chat-composer/chat-composer.variants.js +1 -1
- package/dist/components/color-field/color-field.js +6 -8
- package/dist/components/combobox/combobox.js +27 -5
- package/dist/components/combobox/combobox.meta.js +10 -2
- package/dist/components/command-menu/command-menu.js +14 -3
- package/dist/components/command-menu/command-menu.meta.js +9 -1
- package/dist/components/date-picker/date-picker.meta.js +2 -2
- package/dist/components/feedback/feedback.js +1 -1
- package/dist/components/feedback/feedback.meta.js +2 -1
- package/dist/components/gradient-art/gradient-art.js +8 -5
- package/dist/components/gradient-art/gradient-art.meta.js +35 -2
- package/dist/components/input/input.meta.js +11 -3
- package/dist/components/input-group/input-group.js +1 -1
- package/dist/components/input-group/input-group.meta.js +1 -1
- package/dist/components/line-chart/line-chart.meta.js +6 -1
- package/dist/components/menu/menu.js +1 -1
- package/dist/components/meter/meter.js +53 -7
- package/dist/components/meter/meter.meta.js +51 -4
- package/dist/components/meter/meter.variants.js +43 -7
- package/dist/components/note/note.meta.js +5 -1
- package/dist/components/note/note.variants.js +4 -4
- package/dist/components/number-field/number-field.meta.js +2 -2
- package/dist/components/otp-field/otp-field.meta.js +2 -2
- package/dist/components/panel-group/panel-group.js +5 -8
- package/dist/components/pie-chart/pie-chart.meta.js +6 -1
- package/dist/components/radar-chart/radar-chart.meta.js +6 -1
- package/dist/components/radial-chart/radial-chart.meta.js +6 -1
- package/dist/components/search-input/search-input.meta.js +11 -3
- package/dist/components/segmented-bar/segmented-bar.meta.js +8 -1
- package/dist/components/segmented-bar/segmented-bar.variants.js +7 -7
- package/dist/components/select/select.js +1 -1
- package/dist/components/select/select.meta.js +2 -2
- package/dist/components/sheet/sheet.js +5 -4
- package/dist/components/sidebar/sidebar.js +16 -1
- package/dist/components/sidebar/sidebar.meta.js +7 -2
- package/dist/components/sparkline/sparkline.meta.js +8 -1
- package/dist/components/status-dot/status-dot.meta.js +8 -1
- package/dist/components/status-dot/status-dot.variants.js +7 -7
- package/dist/components/stepper/stepper.meta.js +2 -1
- package/dist/components/stepper/stepper.variants.js +1 -1
- package/dist/components/table/table.meta.js +4 -4
- package/dist/components/textarea/textarea.js +5 -0
- package/dist/components/textarea/textarea.meta.js +3 -3
- package/dist/file-hashes.json +91 -88
- package/dist/foundations/accessibility.js +5 -0
- package/dist/index.d.ts +132 -24
- package/dist/index.js +9 -1
- package/dist/lib/chart/types.js +8 -8
- package/dist/lib/chart/use-arrival.js +5 -4
- package/dist/lib/field-shell.js +1 -1
- package/dist/lib/highlight-glide.js +6 -6
- package/dist/lib/scrub-gesture.js +6 -6
- package/dist/lib/use-caret-trigger.js +11 -18
- package/dist/lib/use-match-highlight.js +69 -0
- package/dist/lib/use-smooth-wheel.js +10 -8
- package/dist/presets/index.d.ts +13 -2
- package/dist/presets/index.js +17 -1
- package/dist/styles.css +100 -0
- package/dist/{theme-provider-CdSicAad.d.ts → theme-provider-BydfM5Z0.d.ts} +1 -1
- package/dist/themes/_contract.js +14 -0
- package/dist/themes/atelier/atelier.css +18 -0
- package/dist/themes/atelier/index.d.ts +1 -1
- package/dist/themes/contrast.js +48 -1
- package/dist/themes/ember/ember.css +18 -0
- package/dist/themes/ember/index.d.ts +1 -1
- package/dist/themes/index.d.ts +2 -2
- package/dist/themes/meridian/index.d.ts +1 -1
- package/dist/themes/meridian/meridian.css +18 -0
- package/dist/themes/poppy/index.d.ts +1 -1
- package/dist/themes/poppy/poppy.css +18 -0
- package/dist/themes/prism/index.d.ts +1 -1
- package/dist/themes/prism/prism.css +18 -0
- package/dist/themes/sable/index.d.ts +1 -1
- package/dist/themes/sable/sable.css +18 -0
- package/dist/themes/verdant/index.d.ts +1 -1
- package/dist/themes/verdant/verdant.css +18 -0
- package/llms/blocks/wallet-block.md +5 -4
- package/llms/components/app-shell.md +72 -3
- package/llms/components/area-chart.md +1 -1
- package/llms/components/attachment.md +1 -1
- package/llms/components/badge.md +1 -1
- package/llms/components/banner.md +1 -1
- package/llms/components/bar-chart.md +1 -1
- package/llms/components/chat-composer.md +1 -1
- package/llms/components/combobox.md +2 -1
- package/llms/components/command-menu.md +3 -2
- package/llms/components/date-picker.md +1 -1
- package/llms/components/feedback.md +1 -1
- package/llms/components/gradient-art.md +28 -1
- package/llms/components/input-group.md +1 -1
- package/llms/components/input.md +4 -2
- package/llms/components/line-chart.md +1 -1
- package/llms/components/meter.md +33 -4
- package/llms/components/note.md +1 -1
- package/llms/components/number-field.md +1 -1
- package/llms/components/otp-field.md +1 -1
- package/llms/components/pie-chart.md +1 -1
- package/llms/components/radar-chart.md +1 -1
- package/llms/components/radial-chart.md +1 -1
- package/llms/components/search-input.md +20 -2
- package/llms/components/segmented-bar.md +1 -1
- package/llms/components/select.md +1 -1
- package/llms/components/sidebar.md +3 -2
- package/llms/components/sparkline.md +1 -1
- package/llms/components/status-dot.md +1 -1
- package/llms/components/stepper.md +1 -1
- package/llms/components/table.md +2 -2
- package/llms/components/textarea.md +2 -2
- package/llms/foundations/accessibility.md +1 -0
- package/llms/reference/token-intent.md +22 -2
- package/llms/reference/utilities.md +5 -2
- package/llms-full.txt +222 -49
- package/llms.txt +2 -2
- package/package.json +1 -1
- package/registry.json +396 -57
- package/scripts/lint-rules.mjs +6 -3
|
@@ -11,7 +11,12 @@ var meterMeta = {
|
|
|
11
11
|
"capacity",
|
|
12
12
|
"limit",
|
|
13
13
|
"password strength",
|
|
14
|
-
"level"
|
|
14
|
+
"level",
|
|
15
|
+
"segmented",
|
|
16
|
+
"tick bar",
|
|
17
|
+
"score",
|
|
18
|
+
"credits",
|
|
19
|
+
"spend limit"
|
|
15
20
|
],
|
|
16
21
|
usage: {
|
|
17
22
|
description: "Use Meter to show a static measurement against a known maximum \u2014 storage used, seats taken, API quota, password strength. It is announced as a meter, not a progress bar, so a screen-reader user hears a level rather than a task underway.",
|
|
@@ -36,6 +41,15 @@ var meterMeta = {
|
|
|
36
41
|
{
|
|
37
42
|
guidance: "do",
|
|
38
43
|
description: 'Use shape="ring" when the reading is a score that belongs in a small, glanceable spot on a card. It is the same measurement drawn as a circular gauge, not a different component.'
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
guidance: "do",
|
|
47
|
+
description: "Use `segments` (a tick bar, \u25AE\u25AE\u25AE\u25AE\u25AE\u25AE\u25AF\u25AF\u25AF\u25AF) for a discrete budget, score or quota read at a glance \u2014 a spend limit, credits left, an ICP lead score, months of data coverage. Pick a count that matches the unit when there is one (10 for a score out of 10, 12 for months) and otherwise size it to the track: a tick reads as a tick when it is taller than it is wide, about one per 8px of track (40 across a card row, 20 in a narrow table cell). Any reading above min shows at least one tick."
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
guidance: "dont",
|
|
51
|
+
description: "Do not segment a fine-grained continuous value where the exact proportion matters (disk at 73.4%) \u2014 ticks round it to the nearest mark; use the continuous bar. And do not use a tick bar for a task in flight or steps completed: that is Progress, or a Stepper for named steps.",
|
|
52
|
+
instead: ["Progress"]
|
|
39
53
|
}
|
|
40
54
|
],
|
|
41
55
|
anatomy: [
|
|
@@ -47,7 +61,7 @@ var meterMeta = {
|
|
|
47
61
|
{
|
|
48
62
|
name: "MeterIndicator",
|
|
49
63
|
required: true,
|
|
50
|
-
description: "The fill, sized from value and coloured by tone."
|
|
64
|
+
description: "The fill, sized from value and coloured by tone. Not used with `segments`: the track draws its ticks instead."
|
|
51
65
|
},
|
|
52
66
|
{
|
|
53
67
|
name: "MeterLabel",
|
|
@@ -105,6 +119,11 @@ var meterMeta = {
|
|
|
105
119
|
type: "boolean",
|
|
106
120
|
description: "Print the value in the ring's centre (formatted like MeterValue)."
|
|
107
121
|
},
|
|
122
|
+
{
|
|
123
|
+
name: "segments",
|
|
124
|
+
type: "number",
|
|
125
|
+
description: 'Draw the bar as this many separate ticks instead of a continuous fill (a quota, score or spend limit). Filled ticks = round(share \xD7 N), at least one for any reading above min, none at min. Ticks take the tone; empty ones sit on the rail colour. The segmented track has its own, taller sm / md / lg ladder. Bar only: ignored for shape="ring".'
|
|
126
|
+
},
|
|
108
127
|
{
|
|
109
128
|
name: "strokeWidth",
|
|
110
129
|
type: "number",
|
|
@@ -131,7 +150,7 @@ var meterMeta = {
|
|
|
131
150
|
{
|
|
132
151
|
name: "MeterTrack",
|
|
133
152
|
type: "Base UI Track props + className + size",
|
|
134
|
-
description: "The rail. Rendered automatically when Meter has no children; renders a MeterIndicator by default."
|
|
153
|
+
description: "The rail. Rendered automatically when Meter has no children; renders a MeterIndicator by default \u2014 or, when the Meter has `segments`, its row of ticks (children are not rendered then)."
|
|
135
154
|
},
|
|
136
155
|
{
|
|
137
156
|
name: "MeterIndicator",
|
|
@@ -157,11 +176,16 @@ var meterMeta = {
|
|
|
157
176
|
tokensUsed: [
|
|
158
177
|
"secondary",
|
|
159
178
|
"primary",
|
|
179
|
+
"tone-3",
|
|
160
180
|
"success",
|
|
161
181
|
"tone-warning",
|
|
162
182
|
"destructive",
|
|
163
183
|
"foreground",
|
|
164
|
-
"muted-foreground"
|
|
184
|
+
"muted-foreground",
|
|
185
|
+
"destructive-mark",
|
|
186
|
+
"success-mark",
|
|
187
|
+
"tone-warning-mark",
|
|
188
|
+
"tone-3-mark"
|
|
165
189
|
],
|
|
166
190
|
motion: [
|
|
167
191
|
{
|
|
@@ -182,6 +206,12 @@ var meterMeta = {
|
|
|
182
206
|
part: "MeterIndicator",
|
|
183
207
|
why: "Width and colour ease on the motion tokens (no recipe animates width) when the reading changes \u2014 freeing space after a delete visibly shrinks the bar, so the user sees the cause and effect rather than a different bar."
|
|
184
208
|
},
|
|
209
|
+
{
|
|
210
|
+
slot: "transition",
|
|
211
|
+
recipe: "custom",
|
|
212
|
+
part: "MeterTrack (segments)",
|
|
213
|
+
why: "With segments, the fill runs through the ticks from the edge it is leaving \u2014 left to right as it grows, right to left as it shrinks \u2014 each tick easing its colour on the fast token after a stagger that is a share of the slow token (a full sweep is one slow duration) \xD7 --motion-expressive. Every tick switching at once would read as a different bar, not the same budget moving; `subtle` lands them together and off is instant."
|
|
214
|
+
},
|
|
185
215
|
{
|
|
186
216
|
slot: "activity",
|
|
187
217
|
recipe: "none",
|
|
@@ -212,6 +242,23 @@ var meterMeta = {
|
|
|
212
242
|
</div>
|
|
213
243
|
<MeterTrack />
|
|
214
244
|
</Meter>`
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
label: "Segmented spend limit",
|
|
248
|
+
code: `<Meter value={1240} max={2000} segments={40} getAriaValueText={() => "\u20AC1,240 of \u20AC2,000 spent this month"}>
|
|
249
|
+
<div className="mb-2 flex flex-wrap items-center justify-between gap-x-3 gap-y-1">
|
|
250
|
+
<MeterLabel>Monthly spend limit</MeterLabel>
|
|
251
|
+
<MeterValue>{() => "\u20AC1,240 / \u20AC2,000"}</MeterValue>
|
|
252
|
+
</div>
|
|
253
|
+
<MeterTrack />
|
|
254
|
+
</Meter>`
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
label: "Segmented score cell",
|
|
258
|
+
code: `<div className="flex items-center gap-3">
|
|
259
|
+
<Meter value={8} max={10} segments={10} size="sm" tone="success" className="w-24" aria-label="ICP score" getAriaValueText={(_, v) => \`\${v} out of 10\`} />
|
|
260
|
+
<span className="text-mono-sm text-foreground">8/10</span>
|
|
261
|
+
</div>`
|
|
215
262
|
},
|
|
216
263
|
{
|
|
217
264
|
label: "Tones",
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
// src/components/meter/meter.variants.ts
|
|
2
2
|
import { cva } from "class-variance-authority";
|
|
3
|
+
var meterToneFill = {
|
|
4
|
+
primary: "bg-primary",
|
|
5
|
+
"3": "bg-tone-3-mark",
|
|
6
|
+
success: "bg-success-mark",
|
|
7
|
+
warning: "bg-tone-warning-mark",
|
|
8
|
+
destructive: "bg-destructive-mark"
|
|
9
|
+
};
|
|
3
10
|
var meterIndicatorVariants = cva(
|
|
4
11
|
"h-full rounded-full transition-[width,background-color] duration-(--motion-duration-slow) ease-decelerate",
|
|
5
12
|
{
|
|
6
13
|
variants: {
|
|
7
|
-
tone:
|
|
8
|
-
primary: "bg-primary",
|
|
9
|
-
"3": "bg-tone-3",
|
|
10
|
-
success: "bg-success",
|
|
11
|
-
warning: "bg-tone-warning",
|
|
12
|
-
destructive: "bg-destructive"
|
|
13
|
-
}
|
|
14
|
+
tone: meterToneFill
|
|
14
15
|
},
|
|
15
16
|
defaultVariants: {
|
|
16
17
|
tone: "primary"
|
|
@@ -29,6 +30,39 @@ var meterTrackVariants = cva("relative w-full overflow-hidden rounded-full bg-se
|
|
|
29
30
|
size: "md"
|
|
30
31
|
}
|
|
31
32
|
});
|
|
33
|
+
var meterSegmentedTrackVariants = cva("flex w-full gap-0.5", {
|
|
34
|
+
variants: {
|
|
35
|
+
size: {
|
|
36
|
+
sm: "h-3",
|
|
37
|
+
md: "h-4",
|
|
38
|
+
lg: "h-5"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
defaultVariants: {
|
|
42
|
+
size: "md"
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
var meterTickVariants = cva(
|
|
46
|
+
// The corner follows the theme's smallest radius but stops at half a spacing
|
|
47
|
+
// step: a tick is a few px wide, and at the full radius-xs (4px in most
|
|
48
|
+
// themes) it rounded into a pill and the row read as a string of beads.
|
|
49
|
+
"h-full min-w-0 flex-1 rounded-[min(var(--radius-xs),--spacing(0.5))] transition-[background-color] duration-(--motion-duration-fast) ease-standard",
|
|
50
|
+
{
|
|
51
|
+
variants: {
|
|
52
|
+
tone: { primary: "", "3": "", success: "", warning: "", destructive: "" },
|
|
53
|
+
filled: { true: "", false: "bg-secondary" }
|
|
54
|
+
},
|
|
55
|
+
compoundVariants: Object.keys(meterToneFill).map((tone) => ({
|
|
56
|
+
tone,
|
|
57
|
+
filled: true,
|
|
58
|
+
class: meterToneFill[tone]
|
|
59
|
+
})),
|
|
60
|
+
defaultVariants: {
|
|
61
|
+
tone: "primary",
|
|
62
|
+
filled: false
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
);
|
|
32
66
|
var meterRingValueVariants = cva("absolute inset-0 flex items-center justify-center text-foreground", {
|
|
33
67
|
variants: {
|
|
34
68
|
size: {
|
|
@@ -57,5 +91,7 @@ export {
|
|
|
57
91
|
meterIndicatorVariants,
|
|
58
92
|
meterRingValueVariants,
|
|
59
93
|
meterRingVariants,
|
|
94
|
+
meterSegmentedTrackVariants,
|
|
95
|
+
meterTickVariants,
|
|
60
96
|
meterTrackVariants
|
|
61
97
|
};
|
|
@@ -5,10 +5,10 @@ var noteVariants = cva(
|
|
|
5
5
|
{
|
|
6
6
|
variants: {
|
|
7
7
|
tone: {
|
|
8
|
-
info: "border-tone-info/30 bg-tone-info/10",
|
|
9
|
-
warning: "border-tone-warning/30 bg-tone-warning/10",
|
|
10
|
-
success: "border-success/30 bg-success/10",
|
|
11
|
-
destructive: "border-destructive/30 bg-destructive/10",
|
|
8
|
+
info: "border-tone-info-mark/30 bg-tone-info-mark/10",
|
|
9
|
+
warning: "border-tone-warning-mark/30 bg-tone-warning-mark/10",
|
|
10
|
+
success: "border-success-mark/30 bg-success-mark/10",
|
|
11
|
+
destructive: "border-destructive-mark/30 bg-destructive-mark/10",
|
|
12
12
|
neutral: "border-border bg-muted/40"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
@@ -107,14 +107,11 @@ function PanelResizer({
|
|
|
107
107
|
const delta = side === "left" ? ev.clientX - startX : startX - ev.clientX;
|
|
108
108
|
onWidthChange(startWidth + delta);
|
|
109
109
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
window.addEventListener("pointermove", onMove);
|
|
116
|
-
window.addEventListener("pointerup", onUp);
|
|
117
|
-
window.addEventListener("pointercancel", onUp);
|
|
110
|
+
const drag = new AbortController();
|
|
111
|
+
const { signal } = drag;
|
|
112
|
+
window.addEventListener("pointermove", onMove, { signal });
|
|
113
|
+
window.addEventListener("pointerup", () => drag.abort(), { signal });
|
|
114
|
+
window.addEventListener("pointercancel", () => drag.abort(), { signal });
|
|
118
115
|
}
|
|
119
116
|
function onKeyDown(e) {
|
|
120
117
|
const grow = side === "left" ? "ArrowRight" : "ArrowLeft";
|
|
@@ -168,7 +168,12 @@ var pieChartMeta = {
|
|
|
168
168
|
"popover",
|
|
169
169
|
"popover-foreground",
|
|
170
170
|
"foreground",
|
|
171
|
-
"background"
|
|
171
|
+
"background",
|
|
172
|
+
"tone-warning-mark",
|
|
173
|
+
"tone-info-mark",
|
|
174
|
+
"tone-1-mark",
|
|
175
|
+
"tone-2-mark",
|
|
176
|
+
"tone-3-mark"
|
|
172
177
|
],
|
|
173
178
|
motion: [
|
|
174
179
|
{
|
|
@@ -162,7 +162,12 @@ var radarChartMeta = {
|
|
|
162
162
|
"popover",
|
|
163
163
|
"popover-foreground",
|
|
164
164
|
"foreground",
|
|
165
|
-
"background"
|
|
165
|
+
"background",
|
|
166
|
+
"tone-warning-mark",
|
|
167
|
+
"tone-info-mark",
|
|
168
|
+
"tone-1-mark",
|
|
169
|
+
"tone-2-mark",
|
|
170
|
+
"tone-3-mark"
|
|
166
171
|
],
|
|
167
172
|
motion: [
|
|
168
173
|
{
|
|
@@ -174,7 +174,12 @@ var radialChartMeta = {
|
|
|
174
174
|
"popover",
|
|
175
175
|
"popover-foreground",
|
|
176
176
|
"foreground",
|
|
177
|
-
"background"
|
|
177
|
+
"background",
|
|
178
|
+
"tone-warning-mark",
|
|
179
|
+
"tone-info-mark",
|
|
180
|
+
"tone-1-mark",
|
|
181
|
+
"tone-2-mark",
|
|
182
|
+
"tone-3-mark"
|
|
178
183
|
],
|
|
179
184
|
motion: [
|
|
180
185
|
{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/components/search-input/search-input.meta.ts
|
|
2
2
|
var searchInputMeta = {
|
|
3
3
|
name: "SearchInput",
|
|
4
|
-
summary: "Styled search field with a leading magnifier and a clearable X. Soft-square (rounded-sm),
|
|
4
|
+
summary: "Styled search field with a leading magnifier and a clearable X. Soft-square (rounded-sm), the theme's field surface, 2px focus ring; the clear button appears only when there is a value.",
|
|
5
5
|
status: "stable",
|
|
6
6
|
keywords: [
|
|
7
7
|
"search",
|
|
@@ -24,6 +24,10 @@ var searchInputMeta = {
|
|
|
24
24
|
guidance: "do",
|
|
25
25
|
description: "When a button stands in for search (a header trigger that opens CommandMenu with \u2318K), use CommandMenuTrigger. It wears this field's shell from the same source, so the two cannot drift; a hand-styled button already did once, into a borderless chip that matched neither the field nor a button."
|
|
26
26
|
},
|
|
27
|
+
{
|
|
28
|
+
guidance: "do",
|
|
29
|
+
description: "Light the query in the results it filters with `useMatchHighlight(query)` \u2014 a callback ref for the results container, with `selector` to keep it to titles. It paints on the `highlight` pair without wrapping matches in `<mark>`, the same paint Combobox and CommandMenu use for their rows."
|
|
30
|
+
},
|
|
27
31
|
{
|
|
28
32
|
guidance: "dont",
|
|
29
33
|
description: "Do not use SearchInput as a command palette; use CommandMenu for global commands, opened from the header by CommandMenuTrigger. A SearchInput that opens a dialog on focus is a text box you cannot type in."
|
|
@@ -91,8 +95,8 @@ var searchInputMeta = {
|
|
|
91
95
|
}
|
|
92
96
|
],
|
|
93
97
|
tokensUsed: [
|
|
94
|
-
"
|
|
95
|
-
"
|
|
98
|
+
"field-border",
|
|
99
|
+
"field",
|
|
96
100
|
"foreground",
|
|
97
101
|
"muted-foreground",
|
|
98
102
|
"ring",
|
|
@@ -144,6 +148,10 @@ var searchInputMeta = {
|
|
|
144
148
|
label: "Uncontrolled, sized as a whole",
|
|
145
149
|
code: '<Field label="Search posts"><SearchInput defaultValue="roadmap" className="max-w-80" /></Field>'
|
|
146
150
|
},
|
|
151
|
+
{
|
|
152
|
+
label: "Highlighting matches in the results",
|
|
153
|
+
code: 'const [q, setQ] = useState("")\nconst results = useMatchHighlight<HTMLUListElement>(q, { selector: "[data-title]" })\nconst shown = posts.filter((post) => post.title.toLowerCase().includes(q.trim().toLowerCase()))\n\n<SearchInput value={q} onValueChange={setQ} placeholder="Search posts" />\n<ul ref={results}>\n {shown.map((post) => (\n <li key={post.id}><span data-title>{post.title}</span></li>\n ))}\n</ul>'
|
|
154
|
+
},
|
|
147
155
|
{
|
|
148
156
|
label: "Disabled",
|
|
149
157
|
code: '<SearchInput disabled placeholder="Search" />'
|
|
@@ -71,7 +71,14 @@ var segmentedBarMeta = {
|
|
|
71
71
|
"muted-foreground",
|
|
72
72
|
"success",
|
|
73
73
|
"tone-warning",
|
|
74
|
-
"destructive"
|
|
74
|
+
"destructive",
|
|
75
|
+
"destructive-mark",
|
|
76
|
+
"success-mark",
|
|
77
|
+
"tone-warning-mark",
|
|
78
|
+
"tone-info-mark",
|
|
79
|
+
"tone-1-mark",
|
|
80
|
+
"tone-2-mark",
|
|
81
|
+
"tone-3-mark"
|
|
75
82
|
],
|
|
76
83
|
motion: [
|
|
77
84
|
{
|
|
@@ -5,15 +5,15 @@ var segmentedBarSegmentVariants = cva(
|
|
|
5
5
|
{
|
|
6
6
|
variants: {
|
|
7
7
|
tone: {
|
|
8
|
-
"1": "bg-tone-1",
|
|
9
|
-
"2": "bg-tone-2",
|
|
10
|
-
"3": "bg-tone-3",
|
|
11
|
-
info: "bg-tone-info",
|
|
8
|
+
"1": "bg-tone-1-mark",
|
|
9
|
+
"2": "bg-tone-2-mark",
|
|
10
|
+
"3": "bg-tone-3-mark",
|
|
11
|
+
info: "bg-tone-info-mark",
|
|
12
12
|
primary: "bg-primary",
|
|
13
13
|
neutral: "bg-muted-foreground",
|
|
14
|
-
success: "bg-success",
|
|
15
|
-
warning: "bg-tone-warning",
|
|
16
|
-
destructive: "bg-destructive"
|
|
14
|
+
success: "bg-success-mark",
|
|
15
|
+
warning: "bg-tone-warning-mark",
|
|
16
|
+
destructive: "bg-destructive-mark"
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
19
|
defaultVariants: {
|
|
@@ -72,7 +72,7 @@ function SelectTrigger({
|
|
|
72
72
|
className: cn(
|
|
73
73
|
`flex w-full items-center justify-between ${tier.body} text-foreground motion-interactive`,
|
|
74
74
|
mobileTier,
|
|
75
|
-
size === "xs" ? cn("h-(--control-xs) gap-1 px-1.5", FIELD_SHELL_XS) : "h-(--control-md) gap-2 rounded-sm border border-
|
|
75
|
+
size === "xs" ? cn("h-(--control-xs) gap-1 px-1.5", FIELD_SHELL_XS) : "h-(--control-md) gap-2 rounded-sm border border-field-border bg-field px-3",
|
|
76
76
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
77
77
|
"data-[popup-open]:ring-2 data-[popup-open]:ring-ring",
|
|
78
78
|
// Invalid like every other field: Base UI marks the trigger
|
|
@@ -61,11 +61,12 @@ function useKeyboardInset(enabled) {
|
|
|
61
61
|
Math.abs(viewport.scale - 1) > 0.01 ? 0 : Math.max(0, Math.round(window.innerHeight - viewport.height - viewport.offsetTop))
|
|
62
62
|
);
|
|
63
63
|
measure();
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
const listeners = new AbortController();
|
|
65
|
+
const { signal } = listeners;
|
|
66
|
+
viewport.addEventListener("resize", measure, { signal });
|
|
67
|
+
viewport.addEventListener("scroll", measure, { signal });
|
|
66
68
|
return () => {
|
|
67
|
-
|
|
68
|
-
viewport.removeEventListener("scroll", measure);
|
|
69
|
+
listeners.abort();
|
|
69
70
|
setInset(0);
|
|
70
71
|
};
|
|
71
72
|
}, [enabled]);
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { cn } from "../../lib/cn.js";
|
|
11
11
|
import { HighlightGlide } from "../../lib/highlight-glide.js";
|
|
12
12
|
import { motionAttribute } from "../../motion/MotionProvider.js";
|
|
13
|
+
import { useAppShellFrame } from "../app-shell/app-shell-frame.js";
|
|
13
14
|
import { RAIL_ROW_INLINE, sideNavItemIconVariants, sideNavItemVariants } from "../side-nav/side-nav.variants.js";
|
|
14
15
|
import { SimpleTooltip } from "../tooltip/index.js";
|
|
15
16
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -27,6 +28,8 @@ var SIDEBAR_VARIANT = {
|
|
|
27
28
|
app: "hidden lg:flex lg:sticky lg:top-0 lg:h-[calc(100vh-var(--dock-height,0px))] lg:self-start",
|
|
28
29
|
inline: "flex h-full"
|
|
29
30
|
};
|
|
31
|
+
var INSET_RAIL = "lg:h-auto lg:self-stretch";
|
|
32
|
+
var INSET_RAIL_SURFACE = "lg:border-r-0 lg:[--sidebar:var(--shell-ground)]";
|
|
30
33
|
var SIDEBAR_INK = [
|
|
31
34
|
"[--background:var(--sidebar)] [--sable-surface-bg:var(--sidebar)]",
|
|
32
35
|
"[--foreground:var(--sidebar-foreground)]",
|
|
@@ -54,6 +57,7 @@ function Sidebar({
|
|
|
54
57
|
}) {
|
|
55
58
|
const [hasCollapsed, setHasCollapsed] = useState(collapsed);
|
|
56
59
|
if (collapsed && !hasCollapsed) setHasCollapsed(true);
|
|
60
|
+
const inset = useAppShellFrame() === "inset";
|
|
57
61
|
return /* @__PURE__ */ jsx(SidebarContext.Provider, { value: { collapsed, icons, reopened: hasCollapsed && !collapsed }, children: /* @__PURE__ */ jsx(
|
|
58
62
|
"aside",
|
|
59
63
|
{
|
|
@@ -61,6 +65,7 @@ function Sidebar({
|
|
|
61
65
|
"data-collapsed": collapsed || void 0,
|
|
62
66
|
"data-variant": variant,
|
|
63
67
|
"data-surface": surface,
|
|
68
|
+
"data-frame": inset ? "inset" : void 0,
|
|
64
69
|
className: cn(
|
|
65
70
|
"shrink-0 flex-col bg-sidebar text-sidebar-foreground",
|
|
66
71
|
// The rail is its own surface. Anything placed in it that inks with
|
|
@@ -71,8 +76,11 @@ function Sidebar({
|
|
|
71
76
|
// a theme names --sidebar-muted-foreground.
|
|
72
77
|
// On the page surface the rail is separated by space and its
|
|
73
78
|
// content, not a rule and a tonal step.
|
|
74
|
-
|
|
79
|
+
// In an inset AppShell the rail is the ground itself, so from lg its border
|
|
80
|
+
// goes too: the gap around the main panel is the divider.
|
|
81
|
+
surface === "rail" ? cn("border-r border-sidebar-border", inset && INSET_RAIL_SURFACE, SIDEBAR_INK) : PAGE_INK,
|
|
75
82
|
SIDEBAR_VARIANT[variant],
|
|
83
|
+
inset && INSET_RAIL,
|
|
76
84
|
"w-[var(--sidebar-width,16rem)] data-[collapsed]:w-[var(--sidebar-width-collapsed,4rem)]",
|
|
77
85
|
// Collapsing eases the width (`motion-size`, expressive) rather than
|
|
78
86
|
// jumping 192px in one frame. It reflows the page beside the rail for
|
|
@@ -164,11 +172,18 @@ function SidebarFooter({
|
|
|
164
172
|
className,
|
|
165
173
|
...props
|
|
166
174
|
}) {
|
|
175
|
+
const inset = useAppShellFrame() === "inset";
|
|
167
176
|
return /* @__PURE__ */ jsx(
|
|
168
177
|
"div",
|
|
169
178
|
{
|
|
170
179
|
className: cn(
|
|
171
180
|
"flex flex-col gap-1 border-t border-sidebar-border px-3 py-4",
|
|
181
|
+
// In an inset shell the rail has no edge of its own (the gap is the
|
|
182
|
+
// divider), so a full-width rule ran out into that gap and stopped on
|
|
183
|
+
// nothing. Inset to the content column it spans what the rows span:
|
|
184
|
+
// the padding becomes margin, so the rule shortens and nothing inside
|
|
185
|
+
// moves.
|
|
186
|
+
inset && "lg:mx-3 lg:px-0",
|
|
172
187
|
className
|
|
173
188
|
),
|
|
174
189
|
...props
|
|
@@ -24,6 +24,10 @@ var sidebarMeta = {
|
|
|
24
24
|
guidance: "do",
|
|
25
25
|
description: `Set surface="page" when a full-width top bar sits above the rail. A theme's tinted or dark rail is for a full-height rail that frames the app.`
|
|
26
26
|
},
|
|
27
|
+
{
|
|
28
|
+
guidance: "do",
|
|
29
|
+
description: `Keep surface="rail" inside AppShell frame="inset": the rail's tint becomes the ground the main panel floats on. Do not add a border-r class back \u2014 the gap is the divider.`
|
|
30
|
+
},
|
|
27
31
|
{
|
|
28
32
|
guidance: "dont",
|
|
29
33
|
description: "Do not use Sidebar for page-local settings, filters, or temporary action groups."
|
|
@@ -76,7 +80,7 @@ var sidebarMeta = {
|
|
|
76
80
|
name: "surface",
|
|
77
81
|
type: '"rail" | "page"',
|
|
78
82
|
default: '"rail"',
|
|
79
|
-
description: `Which surface the rail is painted on. "rail" is its own --sidebar-* surface with a border \u2014 right for a full-height rail that frames the app, which a theme may tint or paint dark. "page" uses the page's surface and ink with no border \u2014 use it when a full-width header sits above the rail, where a tinted column starting under a page-coloured bar reads as pasted on. Use it instead of overriding bg-/text- classes, which the rail's re-pointed tokens defeat.`
|
|
83
|
+
description: `Which surface the rail is painted on. "rail" is its own --sidebar-* surface with a border \u2014 right for a full-height rail that frames the app, which a theme may tint or paint dark. "page" uses the page's surface and ink with no border \u2014 use it when a full-width header sits above the rail, where a tinted column starting under a page-coloured bar reads as pasted on. Use it instead of overriding bg-/text- classes, which the rail's re-pointed tokens defeat. In AppShell's sidebar slot with frame="inset", the rail's surface is also the shell's ground: from lg a "rail" rail drops its border (the gap around the main panel divides them) and either surface stretches to the shell's body row instead of sizing to the viewport. AppShell signals this to its sidebar slot only, so a Sidebar elsewhere in the page is unaffected.`
|
|
80
84
|
},
|
|
81
85
|
{
|
|
82
86
|
name: "motion",
|
|
@@ -146,7 +150,8 @@ var sidebarMeta = {
|
|
|
146
150
|
"sidebar-border",
|
|
147
151
|
"sidebar-accent",
|
|
148
152
|
"sidebar-accent-foreground",
|
|
149
|
-
"sidebar-ring"
|
|
153
|
+
"sidebar-ring",
|
|
154
|
+
"shell-ground"
|
|
150
155
|
],
|
|
151
156
|
variants: {
|
|
152
157
|
variant: ["app", "inline"]
|
|
@@ -106,7 +106,14 @@ var sparklineMeta = {
|
|
|
106
106
|
"tone-warning",
|
|
107
107
|
"muted-foreground",
|
|
108
108
|
"success",
|
|
109
|
-
"destructive"
|
|
109
|
+
"destructive",
|
|
110
|
+
"destructive-mark",
|
|
111
|
+
"success-mark",
|
|
112
|
+
"tone-warning-mark",
|
|
113
|
+
"tone-info-mark",
|
|
114
|
+
"tone-1-mark",
|
|
115
|
+
"tone-2-mark",
|
|
116
|
+
"tone-3-mark"
|
|
110
117
|
],
|
|
111
118
|
motion: [
|
|
112
119
|
{
|
|
@@ -83,7 +83,14 @@ var statusDotMeta = {
|
|
|
83
83
|
"tone-info",
|
|
84
84
|
"tone-1",
|
|
85
85
|
"tone-2",
|
|
86
|
-
"destructive"
|
|
86
|
+
"destructive",
|
|
87
|
+
"destructive-mark",
|
|
88
|
+
"success-mark",
|
|
89
|
+
"tone-warning-mark",
|
|
90
|
+
"tone-info-mark",
|
|
91
|
+
"tone-1-mark",
|
|
92
|
+
"tone-2-mark",
|
|
93
|
+
"tone-3-mark"
|
|
87
94
|
],
|
|
88
95
|
a11y: [
|
|
89
96
|
"Rendered aria-hidden \u2014 purely decorative. Convey status in adjacent text, not color alone.",
|
|
@@ -4,13 +4,13 @@ var statusDotVariants = cva("inline-block shrink-0 rounded-full", {
|
|
|
4
4
|
variants: {
|
|
5
5
|
tone: {
|
|
6
6
|
neutral: "bg-muted-foreground",
|
|
7
|
-
"3": "bg-tone-3",
|
|
8
|
-
success: "bg-success",
|
|
9
|
-
warning: "bg-tone-warning",
|
|
10
|
-
info: "bg-tone-info",
|
|
11
|
-
"1": "bg-tone-1",
|
|
12
|
-
"2": "bg-tone-2",
|
|
13
|
-
destructive: "bg-destructive",
|
|
7
|
+
"3": "bg-tone-3-mark",
|
|
8
|
+
success: "bg-success-mark",
|
|
9
|
+
warning: "bg-tone-warning-mark",
|
|
10
|
+
info: "bg-tone-info-mark",
|
|
11
|
+
"1": "bg-tone-1-mark",
|
|
12
|
+
"2": "bg-tone-2-mark",
|
|
13
|
+
destructive: "bg-destructive-mark",
|
|
14
14
|
// A palette family paints from the slot its data-palette scope fills.
|
|
15
15
|
red: "bg-palette-dot",
|
|
16
16
|
orange: "bg-palette-dot",
|
|
@@ -24,7 +24,7 @@ var stepperDotVariants = cva(
|
|
|
24
24
|
complete: "bg-primary",
|
|
25
25
|
current: "bg-[var(--sable-surface-bg,var(--background))] ring-[0.1875em] ring-primary ring-inset",
|
|
26
26
|
upcoming: "bg-border-strong",
|
|
27
|
-
error: "bg-destructive"
|
|
27
|
+
error: "bg-destructive-mark"
|
|
28
28
|
}
|
|
29
29
|
},
|
|
30
30
|
defaultVariants: {
|
|
@@ -100,13 +100,13 @@ var tableMeta = {
|
|
|
100
100
|
},
|
|
101
101
|
{
|
|
102
102
|
name: "TableHead",
|
|
103
|
-
type: 'ComponentPropsWithRef<"th">',
|
|
104
|
-
description: "A column header cell (th) in muted label styling."
|
|
103
|
+
type: 'ComponentPropsWithRef<"th"> & { numeric?: boolean }',
|
|
104
|
+
description: "A column header cell (th) in muted label styling. `numeric` marks a number column: end-aligned, tabular figures \u2014 set it on the column's cells too."
|
|
105
105
|
},
|
|
106
106
|
{
|
|
107
107
|
name: "TableCell",
|
|
108
|
-
type: 'ComponentPropsWithRef<"td">',
|
|
109
|
-
description: "A data cell (td)."
|
|
108
|
+
type: 'ComponentPropsWithRef<"td"> & { numeric?: boolean }',
|
|
109
|
+
description: "A data cell (td). `numeric` end-aligns it with tabular figures, matching its column's header."
|
|
110
110
|
},
|
|
111
111
|
{
|
|
112
112
|
name: "TableCaption",
|
|
@@ -23,6 +23,11 @@ function Textarea({
|
|
|
23
23
|
// already lost the invalid ring Input shows on focus.
|
|
24
24
|
FIELD_SHELL,
|
|
25
25
|
FIELD_INVALID,
|
|
26
|
+
// Text being edited must not rewrap above the caret. `text-wrap-style`
|
|
27
|
+
// inherits, so a field inside a `text-pretty` or `text-balance` block
|
|
28
|
+
// would re-break every earlier line on each keystroke; `stable` is
|
|
29
|
+
// what an editing surface asks for. Longhand only: the wrap mode stays.
|
|
30
|
+
"[text-wrap-style:stable]",
|
|
26
31
|
autoResize && "field-sizing-content resize-none",
|
|
27
32
|
tier.body,
|
|
28
33
|
density === "comfortable" && MOBILE_FIELD_TIER,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/components/textarea/textarea.meta.ts
|
|
2
2
|
var textareaMeta = {
|
|
3
3
|
name: "Textarea",
|
|
4
|
-
summary: "Styled native multi-line text control. Soft-square,
|
|
4
|
+
summary: "Styled native multi-line text control. Soft-square, the theme's field surface, --ring focus, and an aria-invalid destructive error state.",
|
|
5
5
|
status: "stable",
|
|
6
6
|
keywords: [
|
|
7
7
|
"textarea",
|
|
@@ -75,8 +75,8 @@ var textareaMeta = {
|
|
|
75
75
|
}
|
|
76
76
|
],
|
|
77
77
|
tokensUsed: [
|
|
78
|
-
"
|
|
79
|
-
"
|
|
78
|
+
"field-border",
|
|
79
|
+
"field",
|
|
80
80
|
"foreground",
|
|
81
81
|
"muted-foreground",
|
|
82
82
|
"ring",
|