@sableui/react 0.13.1 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -2
- package/CHANGELOG.md +132 -0
- package/CONTRIBUTING.md +7 -5
- package/DESIGN.md +8 -3
- package/bin/sable.mjs +17 -1
- package/dist/blocks/approval-block.js +93 -0
- package/dist/blocks/approval-block.meta.js +23 -0
- package/dist/blocks/index.d.ts +17 -2
- package/dist/blocks/index.js +4 -0
- package/dist/components/accordion/accordion.meta.js +10 -3
- package/dist/components/area-chart/area-chart.meta.js +10 -3
- package/dist/components/attachment/attachment.meta.js +26 -0
- package/dist/components/badge/badge.meta.js +2 -1
- package/dist/components/banner/banner.meta.js +4 -2
- package/dist/components/bar-chart/bar-chart.meta.js +11 -4
- package/dist/components/bottom-nav/bottom-nav.js +3 -1
- package/dist/components/bottom-nav/bottom-nav.meta.js +32 -0
- package/dist/components/breadcrumbs/breadcrumbs.meta.js +26 -0
- package/dist/components/button/button.js +21 -4
- package/dist/components/button/button.meta.js +7 -7
- package/dist/components/button-group/button-group.meta.js +2 -1
- package/dist/components/calendar/calendar.js +18 -1
- package/dist/components/calendar/calendar.meta.js +38 -0
- package/dist/components/carousel/carousel.js +6 -4
- package/dist/components/carousel/carousel.meta.js +42 -0
- package/dist/components/chat-composer/chat-composer.js +21 -21
- package/dist/components/chat-composer/chat-composer.meta.js +38 -0
- package/dist/components/chat-composer/use-eased-growth.js +70 -0
- package/dist/components/checkbox/checkbox-mark.js +8 -1
- package/dist/components/checkbox/checkbox.js +3 -1
- package/dist/components/checkbox/checkbox.meta.js +34 -1
- package/dist/components/checkbox-card/checkbox-card.js +3 -0
- package/dist/components/checkbox-card/checkbox-card.meta.js +32 -0
- package/dist/components/code-block/code-block.js +14 -3
- package/dist/components/code-block/code-block.meta.js +28 -1
- package/dist/components/collapsible/collapsible.meta.js +34 -1
- package/dist/components/color-field/color-field.meta.js +26 -0
- package/dist/components/combobox/combobox.meta.js +48 -2
- package/dist/components/command-menu/command-menu.js +8 -3
- package/dist/components/command-menu/command-menu.meta.js +44 -3
- package/dist/components/confirm-button/confirm-button.js +179 -0
- package/dist/components/confirm-button/confirm-button.meta.js +143 -0
- package/dist/components/confirm-button/index.js +7 -0
- package/dist/components/context-card/context-card.meta.js +2 -1
- package/dist/components/data-table/data-table.js +6 -2
- package/dist/components/data-table/data-table.meta.js +32 -0
- package/dist/components/dialog/dialog.meta.js +6 -3
- package/dist/components/disclosure-picker/disclosure-picker.meta.js +2 -1
- package/dist/components/entity/entity.meta.js +26 -0
- package/dist/components/feedback/feedback.js +113 -47
- package/dist/components/feedback/feedback.meta.js +49 -4
- package/dist/components/inline-status/inline-status.meta.js +2 -1
- package/dist/components/input-group/input-group.meta.js +27 -1
- package/dist/components/line-chart/line-chart.meta.js +10 -3
- package/dist/components/menu/menu.meta.js +2 -1
- package/dist/components/menubar/menubar.meta.js +2 -1
- package/dist/components/meter/meter.meta.js +2 -1
- package/dist/components/middle-truncate/middle-truncate.meta.js +1 -1
- package/dist/components/note/note.meta.js +34 -1
- package/dist/components/notification-badge/notification-badge.js +17 -5
- package/dist/components/notification-badge/notification-badge.meta.js +34 -2
- package/dist/components/number-ticker/index.js +7 -0
- package/dist/components/number-ticker/number-ticker.js +246 -0
- package/dist/components/number-ticker/number-ticker.meta.js +159 -0
- package/dist/components/otp-field/otp-field.js +23 -3
- package/dist/components/otp-field/otp-field.meta.js +23 -2
- package/dist/components/page-loader/page-loader.meta.js +2 -1
- package/dist/components/panel-group/panel-group.meta.js +26 -0
- package/dist/components/panel-section/panel-section.js +37 -10
- package/dist/components/panel-section/panel-section.meta.js +32 -0
- package/dist/components/pie-chart/pie-chart.js +20 -11
- package/dist/components/pie-chart/pie-chart.meta.js +17 -4
- package/dist/components/pill/pill.meta.js +34 -1
- package/dist/components/popover/popover.meta.js +4 -2
- package/dist/components/progress/progress.meta.js +2 -1
- package/dist/components/radar-chart/radar-chart.js +4 -3
- package/dist/components/radar-chart/radar-chart.meta.js +10 -3
- package/dist/components/radial-chart/radial-chart.js +22 -22
- package/dist/components/radial-chart/radial-chart.meta.js +17 -4
- package/dist/components/radio/radio.meta.js +28 -1
- package/dist/components/radio-card/radio-card.meta.js +38 -0
- package/dist/components/relative-time/relative-time.meta.js +32 -0
- package/dist/components/scroller/scroller.meta.js +32 -0
- package/dist/components/scrub-field/scrub-field.meta.js +32 -0
- package/dist/components/search-input/search-input.js +9 -7
- package/dist/components/search-input/search-input.meta.js +26 -0
- package/dist/components/segmented-bar/segmented-bar.meta.js +2 -1
- package/dist/components/select/select.meta.js +4 -2
- package/dist/components/sheet/sheet.meta.js +4 -2
- package/dist/components/show-more/show-more.js +1 -4
- package/dist/components/show-more/show-more.meta.js +38 -0
- package/dist/components/side-nav/side-nav.js +21 -1
- package/dist/components/side-nav/side-nav.meta.js +34 -1
- package/dist/components/side-nav/side-nav.variants.js +3 -1
- package/dist/components/sidebar/sidebar.js +31 -8
- package/dist/components/sidebar/sidebar.meta.js +38 -0
- package/dist/components/skeleton/skeleton.meta.js +2 -1
- package/dist/components/slider/slider.meta.js +26 -0
- package/dist/components/sparkline/sparkline.js +7 -4
- package/dist/components/sparkline/sparkline.meta.js +9 -2
- package/dist/components/spinner/spinner.meta.js +2 -1
- package/dist/components/stepper/stepper.meta.js +4 -2
- package/dist/components/switch/switch.meta.js +2 -1
- package/dist/components/table/table.meta.js +28 -1
- package/dist/components/tabs/tabs.js +27 -8
- package/dist/components/tabs/tabs.meta.js +50 -5
- package/dist/components/theme-selector/theme-selector.meta.js +32 -0
- package/dist/components/theme-switcher/theme-switcher.js +4 -1
- package/dist/components/theme-switcher/theme-switcher.meta.js +42 -0
- package/dist/components/thinking-orb/thinking-orb.meta.js +4 -2
- package/dist/components/toast/toast.meta.js +2 -1
- package/dist/components/toggle/toggle.js +28 -5
- package/dist/components/toggle/toggle.meta.js +46 -3
- package/dist/components/tool-call/index.js +8 -0
- package/dist/components/tool-call/tool-call.js +117 -0
- package/dist/components/tool-call/tool-call.meta.js +147 -0
- package/dist/components/tool-call/tool-call.variants.js +33 -0
- package/dist/components/toolbar/toolbar.meta.js +2 -1
- package/dist/components/tooltip/index.js +3 -1
- package/dist/components/tooltip/tooltip.js +84 -0
- package/dist/components/tooltip/tooltip.meta.js +18 -2
- package/dist/components/tree/tree.js +71 -6
- package/dist/components/tree/tree.meta.js +32 -0
- package/dist/components/video/video.meta.js +32 -0
- package/dist/file-hashes.json +139 -122
- package/dist/foundations/motion.js +49 -3
- package/dist/index.d.ts +616 -46
- package/dist/index.js +4 -1
- package/dist/lib/chart/cartesian.js +9 -10
- package/dist/lib/chart/chart-center.js +30 -0
- package/dist/lib/chart/chart-frame.js +15 -8
- package/dist/lib/chart/dim.js +13 -0
- package/dist/lib/chart/format.js +7 -1
- package/dist/lib/chart/motion.js +6 -4
- package/dist/lib/highlight-glide.js +68 -10
- package/dist/lib/taxonomy.js +3 -0
- package/dist/{meta-DVG8ceze.d.ts → meta-DX5r5wQL.d.ts} +8 -0
- package/dist/motion/MotionProvider.js +45 -3
- package/dist/motion/Reveal.js +1 -1
- package/dist/motion/TextReveal.js +1 -1
- package/dist/motion/index.js +15 -2
- package/dist/motion/useAutoSize.js +42 -0
- package/dist/motion/useShake.js +25 -0
- package/dist/patterns/index.d.ts +1 -1
- package/dist/styles.css +298 -5
- package/llms/blocks/approval-block.md +128 -0
- package/llms/components/accordion.md +4 -3
- package/llms/components/area-chart.md +4 -3
- package/llms/components/attachment.md +7 -0
- package/llms/components/badge.md +1 -1
- package/llms/components/banner.md +2 -2
- package/llms/components/bar-chart.md +5 -4
- package/llms/components/bottom-nav.md +8 -0
- package/llms/components/breadcrumbs.md +7 -0
- package/llms/components/button-group.md +1 -1
- package/llms/components/button.md +6 -6
- package/llms/components/calendar.md +9 -0
- package/llms/components/carousel.md +17 -0
- package/llms/components/chat-composer.md +9 -0
- package/llms/components/checkbox-card.md +8 -0
- package/llms/components/checkbox.md +9 -1
- package/llms/components/code-block.md +8 -0
- package/llms/components/collapsible.md +9 -1
- package/llms/components/color-field.md +7 -0
- package/llms/components/combobox.md +12 -2
- package/llms/components/command-menu.md +12 -3
- package/llms/components/confirm-button.md +92 -0
- package/llms/components/context-card.md +1 -1
- package/llms/components/data-table.md +8 -0
- package/llms/components/dialog.md +3 -3
- package/llms/components/disclosure-picker.md +1 -1
- package/llms/components/entity.md +7 -0
- package/llms/components/feedback.md +22 -3
- package/llms/components/inline-status.md +1 -1
- package/llms/components/input-group.md +8 -1
- package/llms/components/line-chart.md +4 -3
- package/llms/components/menu.md +1 -1
- package/llms/components/menubar.md +1 -1
- package/llms/components/meter.md +1 -1
- package/llms/components/middle-truncate.md +1 -1
- package/llms/components/note.md +9 -1
- package/llms/components/notification-badge.md +10 -2
- package/llms/components/number-ticker.md +86 -0
- package/llms/components/otp-field.md +15 -1
- package/llms/components/page-loader.md +1 -1
- package/llms/components/panel-group.md +7 -0
- package/llms/components/panel-section.md +8 -0
- package/llms/components/pie-chart.md +6 -4
- package/llms/components/pill.md +9 -1
- package/llms/components/popover.md +2 -2
- package/llms/components/progress.md +1 -1
- package/llms/components/radar-chart.md +4 -3
- package/llms/components/radial-chart.md +6 -4
- package/llms/components/radio-card.md +9 -0
- package/llms/components/radio.md +8 -1
- package/llms/components/relative-time.md +8 -0
- package/llms/components/scroller.md +8 -0
- package/llms/components/scrub-field.md +8 -0
- package/llms/components/search-input.md +7 -0
- package/llms/components/segmented-bar.md +1 -1
- package/llms/components/select.md +2 -2
- package/llms/components/sheet.md +2 -2
- package/llms/components/show-more.md +9 -0
- package/llms/components/side-nav.md +9 -1
- package/llms/components/sidebar.md +9 -0
- package/llms/components/skeleton.md +1 -1
- package/llms/components/slider.md +7 -0
- package/llms/components/sparkline.md +3 -2
- package/llms/components/spinner.md +1 -1
- package/llms/components/stepper.md +2 -2
- package/llms/components/switch.md +1 -1
- package/llms/components/table.md +8 -1
- package/llms/components/tabs.md +22 -4
- package/llms/components/theme-selector.md +8 -0
- package/llms/components/theme-switcher.md +17 -0
- package/llms/components/thinking-orb.md +2 -2
- package/llms/components/toast.md +1 -1
- package/llms/components/toggle.md +20 -3
- package/llms/components/tool-call.md +115 -0
- package/llms/components/toolbar.md +1 -1
- package/llms/components/tooltip.md +12 -2
- package/llms/components/tree.md +8 -0
- package/llms/components/video.md +8 -0
- package/llms/foundations/motion.md +48 -3
- package/llms/reference/utilities.md +23 -1
- package/llms/tasks/reviewing-motion.md +14 -0
- package/llms-full.txt +1004 -98
- package/llms.txt +16 -11
- package/package.json +1 -1
- package/registry.json +2708 -187
- package/targets/ios.json +27 -0
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
// src/components/pie-chart/pie-chart.tsx
|
|
4
4
|
import { useId } from "react";
|
|
5
|
-
import {
|
|
5
|
+
import { ChartCenter } from "../../lib/chart/chart-center.js";
|
|
6
|
+
import { ChartFrame, chartMotion } from "../../lib/chart/chart-frame.js";
|
|
6
7
|
import { ChartLegend } from "../../lib/chart/chart-legend.js";
|
|
7
8
|
import { ChartTooltipContent } from "../../lib/chart/chart-tooltip.js";
|
|
8
|
-
import {
|
|
9
|
+
import { FILL_HOVER, dimmed } from "../../lib/chart/dim.js";
|
|
10
|
+
import { categoryText, chartFormatters } from "../../lib/chart/format.js";
|
|
9
11
|
import { arcPath, polar } from "../../lib/chart/geometry.js";
|
|
10
12
|
import { DRAW_DURATION, morphTransition, pathStyle } from "../../lib/chart/motion.js";
|
|
11
13
|
import {
|
|
@@ -30,7 +32,8 @@ function PieChart({
|
|
|
30
32
|
tooltip = true,
|
|
31
33
|
valueFormatter,
|
|
32
34
|
locale,
|
|
33
|
-
|
|
35
|
+
motion,
|
|
36
|
+
animate,
|
|
34
37
|
activeIndex,
|
|
35
38
|
defaultActiveIndex,
|
|
36
39
|
onActiveIndexChange
|
|
@@ -52,6 +55,7 @@ function PieChart({
|
|
|
52
55
|
});
|
|
53
56
|
});
|
|
54
57
|
const tooltipOptions = typeof tooltip === "object" ? tooltip : {};
|
|
58
|
+
const level = chartMotion(motion, animate);
|
|
55
59
|
const ratio = donut === true ? 0.6 : typeof donut === "number" ? Math.min(0.9, Math.max(0, donut)) : 0;
|
|
56
60
|
const geometry = (size) => {
|
|
57
61
|
const margin = labels === "outside" ? 30 : 8;
|
|
@@ -105,7 +109,7 @@ function PieChart({
|
|
|
105
109
|
className: cn("h-64", className),
|
|
106
110
|
count: data.length,
|
|
107
111
|
interactive: tooltip !== false,
|
|
108
|
-
|
|
112
|
+
motion: level,
|
|
109
113
|
activeIndex,
|
|
110
114
|
defaultActiveIndex,
|
|
111
115
|
onActiveIndexChange,
|
|
@@ -117,6 +121,10 @@ function PieChart({
|
|
|
117
121
|
rows: data.map((_, i) => [styles[i].label, ...keys.map((_2, r) => fmt.full(rings[r][i].v))])
|
|
118
122
|
},
|
|
119
123
|
legend: legend ?? labels === "none" ? /* @__PURE__ */ jsx(ChartLegend, { items: names.map((n, i) => ({ key: n, label: styles[i].label, color: styles[i].color, icon: styles[i].icon })) }) : null,
|
|
124
|
+
overlay: centerLabel && ratio > 0 ? ({ size }) => {
|
|
125
|
+
const g = geometry(size);
|
|
126
|
+
return /* @__PURE__ */ jsx(ChartCenter, { center: centerLabel, x: g.cx, y: g.cy, locale, motion: level });
|
|
127
|
+
} : void 0,
|
|
120
128
|
children: ({ size, activeIndex: active }) => {
|
|
121
129
|
const g = geometry(size);
|
|
122
130
|
const maskId = `${uid}-sweep`;
|
|
@@ -148,8 +156,13 @@ function PieChart({
|
|
|
148
156
|
d,
|
|
149
157
|
strokeWidth: separator ? 2 : 0,
|
|
150
158
|
strokeLinejoin: "round",
|
|
151
|
-
className: cn(separator && "stroke-(--sable-surface-bg,var(--background))"
|
|
152
|
-
style: {
|
|
159
|
+
className: cn(separator && "stroke-(--sable-surface-bg,var(--background))"),
|
|
160
|
+
style: {
|
|
161
|
+
...pathStyle(d),
|
|
162
|
+
// Stepped back toward the surface rather than faded (see lib/chart/dim).
|
|
163
|
+
fill: active != null && active !== i ? dimmed(styles[i].color, 60) : styles[i].color,
|
|
164
|
+
transition: `${morphTransition()}, ${FILL_HOVER}`
|
|
165
|
+
}
|
|
153
166
|
},
|
|
154
167
|
`${r}-${names[i]}`
|
|
155
168
|
);
|
|
@@ -175,11 +188,7 @@ function PieChart({
|
|
|
175
188
|
},
|
|
176
189
|
`l-${names[i]}`
|
|
177
190
|
);
|
|
178
|
-
}) : null
|
|
179
|
-
centerLabel && g.inner > 0 ? /* @__PURE__ */ jsxs("text", { x: g.cx, y: g.cy, textAnchor: "middle", className: "[[data-reveal=out]_&]:opacity-0", style: { transition: morphTransition() }, children: [
|
|
180
|
-
/* @__PURE__ */ jsx("tspan", { x: g.cx, dy: "0.35em", className: "fill-foreground text-heading-2 tabular-nums", children: centerValueText(centerLabel.value, locale) }),
|
|
181
|
-
centerLabel.label ? /* @__PURE__ */ jsx("tspan", { x: g.cx, dy: "1.9em", className: "fill-muted-foreground text-caption", children: centerLabel.label }) : null
|
|
182
|
-
] }) : null
|
|
191
|
+
}) : null
|
|
183
192
|
] });
|
|
184
193
|
}
|
|
185
194
|
}
|
|
@@ -127,11 +127,18 @@ var pieChartMeta = {
|
|
|
127
127
|
default: "runtime locale",
|
|
128
128
|
description: "BCP 47 locale for default number and date formatting."
|
|
129
129
|
},
|
|
130
|
+
{
|
|
131
|
+
name: "motion",
|
|
132
|
+
type: '"full" | "subtle" | "off"',
|
|
133
|
+
default: '"full"',
|
|
134
|
+
description: "How much motion this component uses: `full` (default) inherits the app's policy, `subtle` keeps feedback and drops the flourish, `off` stills it. It can only turn motion down \u2014 it never overrides a reader's reduce-motion setting. The sweep, the slice morph and the rolling centre number are the flourish; the hover pull-out and dim are the feedback `subtle` keeps."
|
|
135
|
+
},
|
|
130
136
|
{
|
|
131
137
|
name: "animate",
|
|
132
138
|
type: "boolean",
|
|
133
139
|
default: "true",
|
|
134
|
-
description:
|
|
140
|
+
description: 'Sweep the slices in clockwise when the chart scrolls into view. `animate={false}` is `motion="subtle"`.',
|
|
141
|
+
deprecated: 'motion="subtle" (what animate={false} now maps to: no arrival, hover kept) or motion="off"'
|
|
135
142
|
},
|
|
136
143
|
{
|
|
137
144
|
name: "activeIndex",
|
|
@@ -168,19 +175,25 @@ var pieChartMeta = {
|
|
|
168
175
|
slot: "arrival",
|
|
169
176
|
recipe: "custom",
|
|
170
177
|
part: "Slices",
|
|
171
|
-
why:
|
|
178
|
+
why: 'Once on screen the slices are revealed by a mask that sweeps clockwise from 12 o\'clock \u2014 the whole is read as it fills. On the motion tokens; reduced motion shows the finished chart. The arrival is expressive: it plays at the full motion level only, so `motion="subtle"` (or a subtle app policy) shows the finished chart while hover feedback stays.'
|
|
172
179
|
},
|
|
173
180
|
{
|
|
174
181
|
slot: "response",
|
|
175
182
|
recipe: "none",
|
|
176
183
|
part: "Active slice",
|
|
177
|
-
why: "The hovered slice pulls outward and the rest dim at once; the geometry change itself eases (see transition)."
|
|
184
|
+
why: "The hovered slice pulls outward and the rest dim at once (mixed toward the surface, not faded); the geometry change itself eases (see transition). Essential: `subtle` keeps it."
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
slot: "transition",
|
|
188
|
+
recipe: "custom",
|
|
189
|
+
part: "Centre value",
|
|
190
|
+
why: "A numeric centre value rolls to its new total digit by digit (NumberTicker) when the data changes, so the headline is seen moving with the slices instead of being found different afterwards. Expressive: under `subtle` it updates in place."
|
|
178
191
|
},
|
|
179
192
|
{
|
|
180
193
|
slot: "transition",
|
|
181
194
|
recipe: "custom",
|
|
182
195
|
part: "Slices",
|
|
183
|
-
why: "Geometry eases from the old shape to the new one through a CSS `d` transition on the motion tokens (no recipe animates path geometry); browsers without `d` transitions update in place."
|
|
196
|
+
why: "Geometry eases from the old shape to the new one through a CSS `d` transition on the motion tokens (no recipe animates path geometry); browsers without `d` transitions update in place. Expressive, like the arrival: under `subtle` new data swaps in place."
|
|
184
197
|
},
|
|
185
198
|
{
|
|
186
199
|
slot: "activity",
|
|
@@ -24,7 +24,8 @@ var pillMeta = {
|
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
guidance: "dont",
|
|
27
|
-
description: "Do not use Pill as a static label. A pressable-looking chip that does nothing is the most common cause of dead clicks in a filter row \u2014 that is a Badge."
|
|
27
|
+
description: "Do not use Pill as a static label. A pressable-looking chip that does nothing is the most common cause of dead clicks in a filter row \u2014 that is a Badge.",
|
|
28
|
+
instead: ["Badge"]
|
|
28
29
|
},
|
|
29
30
|
{
|
|
30
31
|
guidance: "dont",
|
|
@@ -97,6 +98,38 @@ var pillMeta = {
|
|
|
97
98
|
"muted-foreground",
|
|
98
99
|
"foreground"
|
|
99
100
|
],
|
|
101
|
+
motion: [
|
|
102
|
+
{
|
|
103
|
+
slot: "arrival",
|
|
104
|
+
recipe: "none",
|
|
105
|
+
part: "Root",
|
|
106
|
+
why: "Pills arrive with the filter row or the content they annotate. A chip that animated in alone would read as a filter someone just added."
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
slot: "response",
|
|
110
|
+
recipe: "motion-interactive",
|
|
111
|
+
part: "Root",
|
|
112
|
+
why: "The hover wash eases, so sweeping the pointer along a filter row reads as one cursor moving rather than chips flashing in turn."
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
slot: "response",
|
|
116
|
+
recipe: "motion-press",
|
|
117
|
+
part: "Root",
|
|
118
|
+
why: "A pill often toggles a filter that takes a moment to reach the results; the settle on press confirms the click landed before they change."
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
slot: "transition",
|
|
122
|
+
recipe: "motion-interactive",
|
|
123
|
+
part: "Root",
|
|
124
|
+
why: "`selected` lifts the chip onto its selected surface on the same ease, so toggling reads as this chip changing state, not a different chip appearing in its place."
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
slot: "activity",
|
|
128
|
+
recipe: "none",
|
|
129
|
+
part: "Root",
|
|
130
|
+
why: "A chip is a choice, not a process. If applying it is slow, the results show it."
|
|
131
|
+
}
|
|
132
|
+
],
|
|
100
133
|
a11y: [
|
|
101
134
|
'Renders a native <button type="button"> for focus and keyboard activation.',
|
|
102
135
|
"Selected state is exposed via aria-pressed."
|
|
@@ -22,11 +22,13 @@ var popoverMeta = {
|
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
guidance: "dont",
|
|
25
|
-
description: "Do not use Popover for blocking confirmations, long forms, or critical information."
|
|
25
|
+
description: "Do not use Popover for blocking confirmations, long forms, or critical information.",
|
|
26
|
+
instead: ["Dialog"]
|
|
26
27
|
},
|
|
27
28
|
{
|
|
28
29
|
guidance: "dont",
|
|
29
|
-
description: "Do not put a form that can fail validation inside one. A popover dismisses on outside click, which discards what the user typed with no warning \u2014 that is a Dialog."
|
|
30
|
+
description: "Do not put a form that can fail validation inside one. A popover dismisses on outside click, which discards what the user typed with no warning \u2014 that is a Dialog.",
|
|
31
|
+
instead: ["Dialog"]
|
|
30
32
|
}
|
|
31
33
|
],
|
|
32
34
|
anatomy: [
|
|
@@ -26,7 +26,8 @@ var progressMeta = {
|
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
28
|
guidance: "dont",
|
|
29
|
-
description: "Do not use a determinate Progress for an unknown duration. A bar that sits at 90% is worse than a Spinner, because it makes a promise about time that you cannot keep."
|
|
29
|
+
description: "Do not use a determinate Progress for an unknown duration. A bar that sits at 90% is worse than a Spinner, because it makes a promise about time that you cannot keep.",
|
|
30
|
+
instead: ["Spinner"]
|
|
30
31
|
}
|
|
31
32
|
],
|
|
32
33
|
anatomy: [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/components/radar-chart/radar-chart.tsx
|
|
4
|
-
import { ChartFrame } from "../../lib/chart/chart-frame.js";
|
|
4
|
+
import { ChartFrame, chartMotion } from "../../lib/chart/chart-frame.js";
|
|
5
5
|
import { ChartLegend } from "../../lib/chart/chart-legend.js";
|
|
6
6
|
import { ChartTooltipContent } from "../../lib/chart/chart-tooltip.js";
|
|
7
7
|
import { approxTextWidth, categoryText, chartFormatters } from "../../lib/chart/format.js";
|
|
@@ -29,7 +29,8 @@ function RadarChart({
|
|
|
29
29
|
tooltip = true,
|
|
30
30
|
valueFormatter,
|
|
31
31
|
locale,
|
|
32
|
-
|
|
32
|
+
motion,
|
|
33
|
+
animate,
|
|
33
34
|
activeIndex,
|
|
34
35
|
defaultActiveIndex,
|
|
35
36
|
onActiveIndexChange
|
|
@@ -80,7 +81,7 @@ function RadarChart({
|
|
|
80
81
|
className: cn("h-72", className),
|
|
81
82
|
count: n,
|
|
82
83
|
interactive: tooltip !== false,
|
|
83
|
-
animate,
|
|
84
|
+
motion: chartMotion(motion, animate),
|
|
84
85
|
activeIndex,
|
|
85
86
|
defaultActiveIndex,
|
|
86
87
|
onActiveIndexChange,
|
|
@@ -121,11 +121,18 @@ var radarChartMeta = {
|
|
|
121
121
|
default: "runtime locale",
|
|
122
122
|
description: "BCP 47 locale for default number and date formatting."
|
|
123
123
|
},
|
|
124
|
+
{
|
|
125
|
+
name: "motion",
|
|
126
|
+
type: '"full" | "subtle" | "off"',
|
|
127
|
+
default: '"full"',
|
|
128
|
+
description: "How much motion this component uses: `full` (default) inherits the app's policy, `subtle` keeps feedback and drops the flourish, `off` stills it. It can only turn motion down \u2014 it never overrides a reader's reduce-motion setting. The polygons growing in and morphing are the flourish; the hover highlight is the feedback `subtle` keeps."
|
|
129
|
+
},
|
|
124
130
|
{
|
|
125
131
|
name: "animate",
|
|
126
132
|
type: "boolean",
|
|
127
133
|
default: "true",
|
|
128
|
-
description:
|
|
134
|
+
description: 'Grow the polygons from the centre when the chart scrolls into view. `animate={false}` is `motion="subtle"`.',
|
|
135
|
+
deprecated: 'motion="subtle" (what animate={false} now maps to: no arrival, hover kept) or motion="off"'
|
|
129
136
|
},
|
|
130
137
|
{
|
|
131
138
|
name: "activeIndex",
|
|
@@ -162,7 +169,7 @@ var radarChartMeta = {
|
|
|
162
169
|
slot: "arrival",
|
|
163
170
|
recipe: "custom",
|
|
164
171
|
part: "Polygon",
|
|
165
|
-
why:
|
|
172
|
+
why: 'Once on screen each polygon grows from the centre and fades in, series staggered, on the emphasized easing. On the motion tokens; reduced motion shows the finished chart. The arrival is expressive: it plays at the full motion level only, so `motion="subtle"` (or a subtle app policy) shows the finished chart while hover feedback stays.'
|
|
166
173
|
},
|
|
167
174
|
{
|
|
168
175
|
slot: "response",
|
|
@@ -174,7 +181,7 @@ var radarChartMeta = {
|
|
|
174
181
|
slot: "transition",
|
|
175
182
|
recipe: "custom",
|
|
176
183
|
part: "Polygon",
|
|
177
|
-
why: "Geometry eases from the old shape to the new one through a CSS `d` transition on the motion tokens (no recipe animates path geometry); browsers without `d` transitions update in place."
|
|
184
|
+
why: "Geometry eases from the old shape to the new one through a CSS `d` transition on the motion tokens (no recipe animates path geometry); browsers without `d` transitions update in place. Expressive, like the arrival: under `subtle` new data swaps in place."
|
|
178
185
|
},
|
|
179
186
|
{
|
|
180
187
|
slot: "activity",
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/components/radial-chart/radial-chart.tsx
|
|
4
|
-
import {
|
|
4
|
+
import { ChartCenter } from "../../lib/chart/chart-center.js";
|
|
5
|
+
import { ChartFrame, chartMotion } from "../../lib/chart/chart-frame.js";
|
|
5
6
|
import { ChartLegend } from "../../lib/chart/chart-legend.js";
|
|
6
7
|
import { ChartTooltipContent } from "../../lib/chart/chart-tooltip.js";
|
|
7
|
-
import {
|
|
8
|
+
import { STROKE_HOVER, dimmed } from "../../lib/chart/dim.js";
|
|
9
|
+
import { categoryText, chartFormatters } from "../../lib/chart/format.js";
|
|
8
10
|
import { polar, strokeArcPath } from "../../lib/chart/geometry.js";
|
|
9
|
-
import { drawTransition,
|
|
11
|
+
import { drawTransition, pathStyle, stagger } from "../../lib/chart/motion.js";
|
|
10
12
|
import {
|
|
11
13
|
categoryStyle,
|
|
12
14
|
numberValue
|
|
@@ -30,7 +32,8 @@ function RadialChart({
|
|
|
30
32
|
tooltip = true,
|
|
31
33
|
valueFormatter,
|
|
32
34
|
locale,
|
|
33
|
-
|
|
35
|
+
motion,
|
|
36
|
+
animate,
|
|
34
37
|
activeIndex,
|
|
35
38
|
defaultActiveIndex,
|
|
36
39
|
onActiveIndexChange
|
|
@@ -45,6 +48,7 @@ function RadialChart({
|
|
|
45
48
|
const start = -span / 2 + (sweep >= 360 ? span / 2 : 0);
|
|
46
49
|
const tooltipOptions = typeof tooltip === "object" ? tooltip : {};
|
|
47
50
|
const gauge = sweep < 360;
|
|
51
|
+
const level = chartMotion(motion, animate);
|
|
48
52
|
const geometry = (size) => {
|
|
49
53
|
const outer = gauge ? Math.min(size.width / 2, size.height * (sweep <= 180 ? 0.92 : 0.6)) - 8 : Math.min(size.width, size.height) / 2 - 8;
|
|
50
54
|
const cx = size.width / 2;
|
|
@@ -102,7 +106,7 @@ function RadialChart({
|
|
|
102
106
|
className: cn("h-64", className),
|
|
103
107
|
count: data.length,
|
|
104
108
|
interactive: tooltip !== false,
|
|
105
|
-
|
|
109
|
+
motion: level,
|
|
106
110
|
activeIndex,
|
|
107
111
|
defaultActiveIndex,
|
|
108
112
|
onActiveIndexChange,
|
|
@@ -114,6 +118,10 @@ function RadialChart({
|
|
|
114
118
|
rows: data.map((_, i) => [styles[i].label, fmt.full(values[i])])
|
|
115
119
|
},
|
|
116
120
|
legend: legend ?? !labels ? /* @__PURE__ */ jsx(ChartLegend, { items: names.map((n, i) => ({ key: n, label: styles[i].label, color: styles[i].color, icon: styles[i].icon })) }) : null,
|
|
121
|
+
overlay: centerLabel ? ({ size }) => {
|
|
122
|
+
const g = geometry(size);
|
|
123
|
+
return gauge && sweep <= 180 ? /* @__PURE__ */ jsx(ChartCenter, { center: centerLabel, x: g.cx, y: g.cy - 6, placement: "gauge", locale, motion: level }) : /* @__PURE__ */ jsx(ChartCenter, { center: centerLabel, x: g.cx, y: g.cy, locale, motion: level });
|
|
124
|
+
} : void 0,
|
|
117
125
|
children: ({ size, activeIndex: active }) => {
|
|
118
126
|
const g = geometry(size);
|
|
119
127
|
const ringCount = stacked ? 1 : data.length;
|
|
@@ -140,8 +148,14 @@ function RadialChart({
|
|
|
140
148
|
fill: "none",
|
|
141
149
|
strokeWidth: g.thickness,
|
|
142
150
|
strokeLinecap: stacked ? "butt" : "round",
|
|
143
|
-
className:
|
|
144
|
-
style: {
|
|
151
|
+
className: "[stroke-dasharray:1] [stroke-dashoffset:0] [[data-reveal=out]_&]:[stroke-dashoffset:1]",
|
|
152
|
+
style: {
|
|
153
|
+
...pathStyle(d),
|
|
154
|
+
// Stepped back toward the surface rather than faded: a faded ring
|
|
155
|
+
// lets its muted track show through and turns muddy (lib/chart/dim).
|
|
156
|
+
stroke: active != null && active !== a.i ? dimmed(styles[a.i].color, 60) : styles[a.i].color,
|
|
157
|
+
transition: `${drawTransition(stagger(a.i, 90))}, ${STROKE_HOVER}`
|
|
158
|
+
}
|
|
145
159
|
},
|
|
146
160
|
names[a.i]
|
|
147
161
|
);
|
|
@@ -149,21 +163,7 @@ function RadialChart({
|
|
|
149
163
|
labels && !stacked ? arcs.map((a) => {
|
|
150
164
|
const [x, y] = polar(g.cx, g.cy, radiusOf(g, a.ring), start);
|
|
151
165
|
return /* @__PURE__ */ jsx("text", { x: x - 8, y, dy: "0.32em", textAnchor: "end", className: "fill-muted-foreground text-caption", children: styles[a.i].label }, `l${a.i}`);
|
|
152
|
-
}) : null
|
|
153
|
-
centerLabel ? /* @__PURE__ */ jsxs(
|
|
154
|
-
"text",
|
|
155
|
-
{
|
|
156
|
-
x: g.cx,
|
|
157
|
-
y: gauge && sweep <= 180 ? g.cy - 6 : g.cy,
|
|
158
|
-
textAnchor: "middle",
|
|
159
|
-
className: "[[data-reveal=out]_&]:opacity-0",
|
|
160
|
-
style: { transition: morphTransition() },
|
|
161
|
-
children: [
|
|
162
|
-
/* @__PURE__ */ jsx("tspan", { x: g.cx, dy: gauge && sweep <= 180 ? centerLabel.label ? "-1.4em" : "0" : "0.35em", className: "fill-foreground text-heading-2 tabular-nums", children: centerValueText(centerLabel.value, locale) }),
|
|
163
|
-
centerLabel.label ? /* @__PURE__ */ jsx("tspan", { x: g.cx, dy: gauge && sweep <= 180 ? "1.6em" : "1.9em", className: "fill-muted-foreground text-caption", children: centerLabel.label }) : null
|
|
164
|
-
]
|
|
165
|
-
}
|
|
166
|
-
) : null
|
|
166
|
+
}) : null
|
|
167
167
|
] });
|
|
168
168
|
}
|
|
169
169
|
}
|
|
@@ -133,11 +133,18 @@ var radialChartMeta = {
|
|
|
133
133
|
default: "runtime locale",
|
|
134
134
|
description: "BCP 47 locale for default number and date formatting."
|
|
135
135
|
},
|
|
136
|
+
{
|
|
137
|
+
name: "motion",
|
|
138
|
+
type: '"full" | "subtle" | "off"',
|
|
139
|
+
default: '"full"',
|
|
140
|
+
description: "How much motion this component uses: `full` (default) inherits the app's policy, `subtle` keeps feedback and drops the flourish, `off` stills it. It can only turn motion down \u2014 it never overrides a reader's reduce-motion setting. The draw-on, the ring morph and the rolling centre number are the flourish; the hover dim is the feedback `subtle` keeps."
|
|
141
|
+
},
|
|
136
142
|
{
|
|
137
143
|
name: "animate",
|
|
138
144
|
type: "boolean",
|
|
139
145
|
default: "true",
|
|
140
|
-
description:
|
|
146
|
+
description: 'Draw the rings round from their start when the chart scrolls into view. `animate={false}` is `motion="subtle"`.',
|
|
147
|
+
deprecated: 'motion="subtle" (what animate={false} now maps to: no arrival, hover kept) or motion="off"'
|
|
141
148
|
},
|
|
142
149
|
{
|
|
143
150
|
name: "activeIndex",
|
|
@@ -174,19 +181,25 @@ var radialChartMeta = {
|
|
|
174
181
|
slot: "arrival",
|
|
175
182
|
recipe: "custom",
|
|
176
183
|
part: "Ring",
|
|
177
|
-
why:
|
|
184
|
+
why: 'Once on screen each ring draws round from its start (stroke-dashoffset on a round-capped arc), staggered outside in. On the motion tokens; reduced motion shows the finished chart. The arrival is expressive: it plays at the full motion level only, so `motion="subtle"` (or a subtle app policy) shows the finished chart while hover feedback stays.'
|
|
178
185
|
},
|
|
179
186
|
{
|
|
180
187
|
slot: "response",
|
|
181
188
|
recipe: "none",
|
|
182
189
|
part: "Active ring",
|
|
183
|
-
why: "The hovered ring stays full strength and the others dim at once."
|
|
190
|
+
why: "The hovered ring stays full strength and the others dim at once \u2014 mixed toward the surface rather than faded, so a dimmed ring stays solid over its track instead of turning muddy. Essential: `subtle` keeps it."
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
slot: "transition",
|
|
194
|
+
recipe: "custom",
|
|
195
|
+
part: "Centre value",
|
|
196
|
+
why: "A numeric centre value rolls to its new total digit by digit (NumberTicker) when the data changes, so the headline is seen moving with the rings instead of being found different afterwards. Expressive: under `subtle` it updates in place."
|
|
184
197
|
},
|
|
185
198
|
{
|
|
186
199
|
slot: "transition",
|
|
187
200
|
recipe: "custom",
|
|
188
201
|
part: "Ring",
|
|
189
|
-
why: "Geometry eases from the old shape to the new one through a CSS `d` transition on the motion tokens (no recipe animates path geometry); browsers without `d` transitions update in place."
|
|
202
|
+
why: "Geometry eases from the old shape to the new one through a CSS `d` transition on the motion tokens (no recipe animates path geometry); browsers without `d` transitions update in place. Expressive, like the arrival: under `subtle` new data swaps in place."
|
|
190
203
|
},
|
|
191
204
|
{
|
|
192
205
|
slot: "activity",
|
|
@@ -22,7 +22,8 @@ var radioMeta = {
|
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
guidance: "dont",
|
|
25
|
-
description: "Do not use Radio for independent toggles or multiple selection; use Checkbox or Switch."
|
|
25
|
+
description: "Do not use Radio for independent toggles or multiple selection; use Checkbox or Switch.",
|
|
26
|
+
instead: ["Checkbox", "Switch"]
|
|
26
27
|
},
|
|
27
28
|
{
|
|
28
29
|
guidance: "dont",
|
|
@@ -66,6 +67,32 @@ var radioMeta = {
|
|
|
66
67
|
}
|
|
67
68
|
],
|
|
68
69
|
tokensUsed: ["input", "card", "primary", "ring"],
|
|
70
|
+
motion: [
|
|
71
|
+
{
|
|
72
|
+
slot: "arrival",
|
|
73
|
+
recipe: "none",
|
|
74
|
+
part: "Root",
|
|
75
|
+
why: "Radios arrive with the form they belong to. Animating each one in turns a question into a title sequence."
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
slot: "response",
|
|
79
|
+
recipe: "motion-interactive",
|
|
80
|
+
part: "Root",
|
|
81
|
+
why: "The ring's edge and focus ring ease, so arrowing through a group \u2014 which moves the selection with focus \u2014 reads as one choice moving down the list."
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
slot: "transition",
|
|
85
|
+
recipe: "motion-interactive",
|
|
86
|
+
part: "Indicator",
|
|
87
|
+
why: "The dot grows from the centre on a spring and shrinks out of the radio being left. A group's selection moves from one option to another, and the paired grow and shrink is what makes it read as moving rather than two dots blinking."
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
slot: "activity",
|
|
91
|
+
recipe: "none",
|
|
92
|
+
part: "Root",
|
|
93
|
+
why: "A radio commits instantly. A slow write belongs to the surrounding form's pending state, not the control."
|
|
94
|
+
}
|
|
95
|
+
],
|
|
69
96
|
a11y: [
|
|
70
97
|
"Base UI provides the radiogroup/radio roles, aria-checked, hidden native inputs, and roving tabindex.",
|
|
71
98
|
"Arrow keys move and select between items; Space selects the focused item; Tab enters/leaves the group.",
|
|
@@ -122,6 +122,44 @@ var radioCardMeta = {
|
|
|
122
122
|
"tone-info",
|
|
123
123
|
"tone-warning"
|
|
124
124
|
],
|
|
125
|
+
motion: [
|
|
126
|
+
{
|
|
127
|
+
slot: "arrival",
|
|
128
|
+
recipe: "none",
|
|
129
|
+
part: "Root",
|
|
130
|
+
why: "Cards arrive with the form. A plan picker that animated each card in would delay the choice it exists to make."
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
slot: "response",
|
|
134
|
+
recipe: "motion-interactive",
|
|
135
|
+
part: "Root",
|
|
136
|
+
why: "The edge steps toward the ring colour on hover, eased. On a card-sized target a hard snap across the whole border reads as the layout flickering."
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
slot: "response",
|
|
140
|
+
recipe: "motion-press",
|
|
141
|
+
part: "Root",
|
|
142
|
+
why: "The settle on press confirms a click anywhere in the card \u2014 the radio is small, and without it a click in the card's body can feel like it missed the control."
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
slot: "transition",
|
|
146
|
+
recipe: "motion-interactive",
|
|
147
|
+
part: "Root",
|
|
148
|
+
why: "Checking eases the tone ring and wash onto the new card as the old one releases, so the choice reads as moving between cards rather than two cards repainting."
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
slot: "transition",
|
|
152
|
+
recipe: "motion-interactive",
|
|
153
|
+
part: "Indicator",
|
|
154
|
+
why: "The radio dot grows in on a spring, the same mark as Radio, so a card and a plain radio confirm a choice the same way."
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
slot: "activity",
|
|
158
|
+
recipe: "none",
|
|
159
|
+
part: "Root",
|
|
160
|
+
why: "A choice commits instantly. A slow write belongs to the surrounding form's pending state."
|
|
161
|
+
}
|
|
162
|
+
],
|
|
125
163
|
a11y: [
|
|
126
164
|
"Base UI provides the radiogroup/radio roles, aria-checked, hidden native inputs, and roving tabindex.",
|
|
127
165
|
"Arrow keys move and select between cards; Space selects the focused card; Tab enters/leaves the group.",
|
|
@@ -54,6 +54,38 @@ var relativeTimeMeta = {
|
|
|
54
54
|
}
|
|
55
55
|
],
|
|
56
56
|
tokensUsed: ["popover", "popover-foreground", "border", "ring"],
|
|
57
|
+
motion: [
|
|
58
|
+
{
|
|
59
|
+
slot: "arrival",
|
|
60
|
+
recipe: "none",
|
|
61
|
+
part: "Root",
|
|
62
|
+
why: "It is a word in a line of text and arrives with that line."
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
slot: "response",
|
|
66
|
+
recipe: "none",
|
|
67
|
+
part: "Root",
|
|
68
|
+
why: "The only hover change on the timestamp is a dotted underline, and text-decoration-line is discrete: CSS cannot tween it, so a transition here would animate nothing and imply the snap had been handled."
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
slot: "response",
|
|
72
|
+
recipe: "motion-pop",
|
|
73
|
+
part: "Tooltip",
|
|
74
|
+
why: "The pointer's real answer is the absolute time, which arrives in a Tooltip on its own fast pop. That short entrance is what makes the full date read as belonging to the word under the cursor."
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
slot: "transition",
|
|
78
|
+
recipe: "none",
|
|
79
|
+
part: "Root",
|
|
80
|
+
why: "The label does not tick: it is computed when the component renders, so it never changes in front of the reader. A timestamp rolling from one minute to two would pull the eye off the content it dates."
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
slot: "activity",
|
|
84
|
+
recipe: "none",
|
|
85
|
+
part: "Root",
|
|
86
|
+
why: "A timestamp has nothing to wait for."
|
|
87
|
+
}
|
|
88
|
+
],
|
|
57
89
|
a11y: [
|
|
58
90
|
"Renders a semantic <time> element with a machine-readable dateTime (ISO) attribute.",
|
|
59
91
|
"The <time> carries tabIndex=0 (it is not focusable natively), so the absolute time \u2014 exposed via Base UI's Tooltip, which opens on keyboard focus as well as hover and wires aria-describedby \u2014 is reachable from the keyboard.",
|
|
@@ -92,6 +92,38 @@ var scrollerMeta = {
|
|
|
92
92
|
wheelScroll: ["true", "false"]
|
|
93
93
|
},
|
|
94
94
|
tokensUsed: ["ring"],
|
|
95
|
+
motion: [
|
|
96
|
+
{
|
|
97
|
+
slot: "arrival",
|
|
98
|
+
recipe: "none",
|
|
99
|
+
part: "Root",
|
|
100
|
+
why: "It is a region, not an event; its content arrives with whatever fills it."
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
slot: "response",
|
|
104
|
+
recipe: "motion-interactive",
|
|
105
|
+
part: "Viewport",
|
|
106
|
+
why: "The region is focusable so the keyboard can scroll it, and its focus ring eases in like any control's. It is the one sign the region, not the page, now takes the arrow keys."
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
slot: "response",
|
|
110
|
+
recipe: "custom",
|
|
111
|
+
part: "Scrollbar",
|
|
112
|
+
why: "The vertical bar (`scrollbar-quiet`) stays hidden until the region is hovered, focused or scrolled, then fades its thumb in on the motion tokens. A bar that appeared in one frame would flash every time the pointer crossed the list."
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
slot: "transition",
|
|
116
|
+
recipe: "none",
|
|
117
|
+
part: "Edge fade",
|
|
118
|
+
why: "The edge fades switch on and off as you scroll, in the frame the content is already moving, so the change is carried by the scroll itself. They are a mask gradient, which CSS cannot interpolate without registered custom properties."
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
slot: "activity",
|
|
122
|
+
recipe: "none",
|
|
123
|
+
part: "Root",
|
|
124
|
+
why: "A scroll region does no work of its own. Content still loading inside it brings its own Skeleton or Spinner."
|
|
125
|
+
}
|
|
126
|
+
],
|
|
95
127
|
a11y: [
|
|
96
128
|
"The edge fades are a CSS mask-image on the scrolling element, not overlay elements \u2014 there is nothing in the DOM to intercept a pointer or be read by assistive tech, and the content under a fade stays fully interactive.",
|
|
97
129
|
'Two boxes: a chrome box carrying `className` (border, background, radius, sizing) and, inside it, the element that actually scrolls and carries the fade mask. They are split because a `mask-image` applies to its element\'s own border \u2014 so with both on one box, a bordered Scroller watched its frame dissolve at the scrolling edge. The axis is published as `data-orientation`, not `aria-orientation`, which is invalid on `role="group"`.',
|
|
@@ -99,6 +99,38 @@ var scrubFieldMeta = {
|
|
|
99
99
|
{ name: "disabled", type: "boolean", description: "Disables typing and scrubbing." },
|
|
100
100
|
{ name: "id", type: "string", description: "Input id, for a PropertyRow's htmlFor." }
|
|
101
101
|
],
|
|
102
|
+
motion: [
|
|
103
|
+
{
|
|
104
|
+
slot: "arrival",
|
|
105
|
+
recipe: "none",
|
|
106
|
+
part: "Root",
|
|
107
|
+
why: "It arrives with the inspector row it sits in."
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
slot: "response",
|
|
111
|
+
recipe: "motion-interactive",
|
|
112
|
+
part: "Root",
|
|
113
|
+
why: "The shell eases its focus ring like every field, so tabbing through a column of numbers shows where the keyboard is without flicker."
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
slot: "response",
|
|
117
|
+
recipe: "motion-interactive",
|
|
118
|
+
part: "Handle",
|
|
119
|
+
why: "The handle's ink brightens while the field is hovered. It is the only sign that the icon or prefix can be dragged, which nobody would guess from a label."
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
slot: "transition",
|
|
123
|
+
recipe: "none",
|
|
124
|
+
part: "Value",
|
|
125
|
+
why: "The number follows the drag pixel for pixel. Easing it \u2014 or rolling it with a NumberTicker \u2014 would show a value the pointer has already left, in a control whose whole point is precision."
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
slot: "activity",
|
|
129
|
+
recipe: "none",
|
|
130
|
+
part: "Root",
|
|
131
|
+
why: "Scrubbing is synchronous; there is nothing to wait for."
|
|
132
|
+
}
|
|
133
|
+
],
|
|
102
134
|
a11y: [
|
|
103
135
|
"The input carries the accessible name via `label`; the glyph is aria-hidden because it is decorative.",
|
|
104
136
|
"Every scrub gesture is reachable from the keyboard: ArrowUp/ArrowDown step by `step`, Shift+Arrow by ten steps.",
|