@misoto22/design 0.7.0 → 0.8.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 +87 -0
- package/CLAUDE.md +1 -0
- package/README.md +50 -5
- package/bin/misoto22-design.mjs +59 -13
- package/dist/agent/Accordion.md +24 -1
- package/dist/agent/Alert.md +23 -1
- package/dist/agent/AppShell.md +30 -2
- package/dist/agent/ArchitectureFigure.md +25 -2
- package/dist/agent/AreaChart.md +27 -2
- package/dist/agent/Article.md +26 -3
- package/dist/agent/AspectRatio.md +57 -0
- package/dist/agent/Avatar.md +25 -5
- package/dist/agent/Badge.md +22 -1
- package/dist/agent/BarChart.md +29 -2
- package/dist/agent/BarList.md +27 -1
- package/dist/agent/BigNumber.md +26 -2
- package/dist/agent/BoxPlot.md +24 -1
- package/dist/agent/Breadcrumb.md +24 -2
- package/dist/agent/BulletChart.md +23 -1
- package/dist/agent/Button.md +25 -1
- package/dist/agent/Calendar.md +37 -3
- package/dist/agent/Card.md +24 -2
- package/dist/agent/Checkbox.md +23 -2
- package/dist/agent/Code.md +50 -0
- package/dist/agent/CodeBlock.md +74 -0
- package/dist/agent/Collapsible.md +22 -1
- package/dist/agent/Combobox.md +29 -3
- package/dist/agent/Command.md +25 -2
- package/dist/agent/ComposedChart.md +26 -2
- package/dist/agent/ContextMenu.md +37 -4
- package/dist/agent/DataflowFigure.md +22 -1
- package/dist/agent/DatePicker.md +34 -6
- package/dist/agent/DescriptionList.md +68 -0
- package/dist/agent/Diagram.md +27 -3
- package/dist/agent/DiagramCanvas.md +24 -1
- package/dist/agent/DiagramExportMenu.md +29 -3
- package/dist/agent/DiagramInspector.md +23 -1
- package/dist/agent/DiagramLegend.md +22 -1
- package/dist/agent/DiagramMinimap.md +24 -4
- package/dist/agent/DiagramToolbar.md +23 -1
- package/dist/agent/Dialog.md +26 -3
- package/dist/agent/DropdownMenu.md +45 -6
- package/dist/agent/EmptyState.md +26 -1
- package/dist/agent/ErrorState.md +27 -2
- package/dist/agent/Facet.md +25 -1
- package/dist/agent/Field.md +45 -4
- package/dist/agent/FigureBand.md +24 -1
- package/dist/agent/FloatingIconButton.md +23 -1
- package/dist/agent/FunnelChart.md +23 -1
- package/dist/agent/Heading.md +64 -0
- package/dist/agent/Heatmap.md +25 -1
- package/dist/agent/Histogram.md +26 -2
- package/dist/agent/Input.md +22 -1
- package/dist/agent/Kbd.md +19 -1
- package/dist/agent/LifecycleFigure.md +22 -1
- package/dist/agent/LineChart.md +26 -2
- package/dist/agent/LinkArrow.md +20 -1
- package/dist/agent/Markdown.md +68 -0
- package/dist/agent/NativeSelect.md +23 -2
- package/dist/agent/NavItem.md +21 -1
- package/dist/agent/Pagination.md +28 -2
- package/dist/agent/PieChart.md +26 -2
- package/dist/agent/Popover.md +23 -1
- package/dist/agent/Progress.md +27 -3
- package/dist/agent/RadarChart.md +26 -2
- package/dist/agent/RadialChart.md +26 -3
- package/dist/agent/RadioGroup.md +23 -2
- package/dist/agent/SankeyChart.md +25 -2
- package/dist/agent/ScatterChart.md +27 -2
- package/dist/agent/ScrollArea.md +24 -3
- package/dist/agent/SearchableMenu.md +23 -1
- package/dist/agent/Select.md +29 -3
- package/dist/agent/Separator.md +28 -4
- package/dist/agent/SequenceFigure.md +23 -1
- package/dist/agent/Sheet.md +25 -2
- package/dist/agent/Skeleton.md +24 -2
- package/dist/agent/Slider.md +27 -4
- package/dist/agent/Sparkline.md +23 -1
- package/dist/agent/Spinner.md +24 -2
- package/dist/agent/StatusDot.md +20 -1
- package/dist/agent/StatusPill.md +28 -2
- package/dist/agent/Steps.md +24 -1
- package/dist/agent/Switch.md +21 -1
- package/dist/agent/Table.md +26 -3
- package/dist/agent/Tabs.md +24 -2
- package/dist/agent/Tag.md +40 -9
- package/dist/agent/Text.md +65 -0
- package/dist/agent/Textarea.md +20 -1
- package/dist/agent/Timestamp.md +64 -0
- package/dist/agent/Toast.md +26 -2
- package/dist/agent/ToggleGroup.md +24 -2
- package/dist/agent/Toolbar.md +71 -0
- package/dist/agent/Tooltip.md +23 -1
- package/dist/agent/TreemapChart.md +24 -1
- package/dist/agent/WaterfallChart.md +24 -1
- package/dist/agent/WorkflowFigure.md +24 -2
- package/dist/agent/catalog.json +5602 -745
- package/dist/agent/index.md +13 -4
- package/dist/article.css +16 -4
- package/dist/charts/AreaChart/AreaChart.d.ts +9 -2
- package/dist/charts/AreaChart/AreaChart.js +12 -13
- package/dist/charts/AreaChart/AreaChart.js.map +1 -1
- package/dist/charts/BarChart/BarChart.d.ts +14 -3
- package/dist/charts/BarChart/BarChart.js +20 -12
- package/dist/charts/BarChart/BarChart.js.map +1 -1
- package/dist/charts/BarList/BarList.d.ts +9 -1
- package/dist/charts/BarList/BarList.js +9 -1
- package/dist/charts/BarList/BarList.js.map +1 -1
- package/dist/charts/BigNumber/BigNumber.d.ts +19 -3
- package/dist/charts/BigNumber/BigNumber.js +25 -5
- package/dist/charts/BigNumber/BigNumber.js.map +1 -1
- package/dist/charts/BoxPlot/BoxPlot.js +4 -2
- package/dist/charts/BoxPlot/BoxPlot.js.map +1 -1
- package/dist/charts/BulletChart/BulletChart.js +28 -7
- package/dist/charts/BulletChart/BulletChart.js.map +1 -1
- package/dist/charts/ComposedChart/ComposedChart.d.ts +9 -2
- package/dist/charts/ComposedChart/ComposedChart.js +10 -10
- package/dist/charts/ComposedChart/ComposedChart.js.map +1 -1
- package/dist/charts/FunnelChart/FunnelChart.d.ts +7 -2
- package/dist/charts/FunnelChart/FunnelChart.js +6 -16
- package/dist/charts/FunnelChart/FunnelChart.js.map +1 -1
- package/dist/charts/Heatmap/Heatmap.d.ts +17 -3
- package/dist/charts/Heatmap/Heatmap.js +20 -11
- package/dist/charts/Heatmap/Heatmap.js.map +1 -1
- package/dist/charts/Histogram/Histogram.d.ts +24 -1
- package/dist/charts/Histogram/Histogram.js +43 -11
- package/dist/charts/Histogram/Histogram.js.map +1 -1
- package/dist/charts/LineChart/LineChart.d.ts +9 -2
- package/dist/charts/LineChart/LineChart.js +11 -12
- package/dist/charts/LineChart/LineChart.js.map +1 -1
- package/dist/charts/PieChart/PieChart.d.ts +15 -3
- package/dist/charts/PieChart/PieChart.js +14 -6
- package/dist/charts/PieChart/PieChart.js.map +1 -1
- package/dist/charts/RadarChart/RadarChart.d.ts +15 -3
- package/dist/charts/RadarChart/RadarChart.js +11 -9
- package/dist/charts/RadarChart/RadarChart.js.map +1 -1
- package/dist/charts/RadialChart/RadialChart.d.ts +22 -4
- package/dist/charts/RadialChart/RadialChart.js +28 -6
- package/dist/charts/RadialChart/RadialChart.js.map +1 -1
- package/dist/charts/SankeyChart/SankeyChart.d.ts +16 -4
- package/dist/charts/SankeyChart/SankeyChart.js +14 -6
- package/dist/charts/SankeyChart/SankeyChart.js.map +1 -1
- package/dist/charts/ScatterChart/ScatterChart.d.ts +24 -3
- package/dist/charts/ScatterChart/ScatterChart.js +21 -15
- package/dist/charts/ScatterChart/ScatterChart.js.map +1 -1
- package/dist/charts/Sparkline/Sparkline.js +5 -3
- package/dist/charts/Sparkline/Sparkline.js.map +1 -1
- package/dist/charts/TreemapChart/TreemapChart.d.ts +7 -2
- package/dist/charts/TreemapChart/TreemapChart.js +20 -11
- package/dist/charts/TreemapChart/TreemapChart.js.map +1 -1
- package/dist/charts/WaterfallChart/WaterfallChart.js +4 -2
- package/dist/charts/WaterfallChart/WaterfallChart.js.map +1 -1
- package/dist/charts/lib/export.d.ts +1 -0
- package/dist/charts/lib/figure.d.ts +21 -1
- package/dist/charts/lib/figure.js +5 -2
- package/dist/charts/lib/figure.js.map +1 -1
- package/dist/charts/lib/scale.d.ts +23 -0
- package/dist/charts/lib/scale.js +13 -0
- package/dist/charts/lib/scale.js.map +1 -0
- package/dist/charts/lib/selection.d.ts +20 -0
- package/dist/charts/lib/selection.js +18 -0
- package/dist/charts/lib/selection.js.map +1 -0
- package/dist/charts/lib/toolbar.d.ts +1 -0
- package/dist/components/Accordion/Accordion.js +8 -1
- package/dist/components/Accordion/Accordion.js.map +1 -1
- package/dist/components/AppShell/AppShell.d.ts +6 -0
- package/dist/components/AppShell/AppShell.js +34 -4
- package/dist/components/AppShell/AppShell.js.map +1 -1
- package/dist/components/Article/Article.d.ts +11 -4
- package/dist/components/Article/Article.js +13 -0
- package/dist/components/Article/Article.js.map +1 -1
- package/dist/components/AspectRatio/AspectRatio.d.ts +46 -0
- package/dist/components/AspectRatio/AspectRatio.js +33 -0
- package/dist/components/AspectRatio/AspectRatio.js.map +1 -0
- package/dist/components/Avatar/Avatar.d.ts +12 -3
- package/dist/components/Avatar/Avatar.js +6 -1
- package/dist/components/Avatar/Avatar.js.map +1 -1
- package/dist/components/Breadcrumb/Breadcrumb.d.ts +6 -0
- package/dist/components/Breadcrumb/Breadcrumb.js +15 -0
- package/dist/components/Breadcrumb/Breadcrumb.js.map +1 -1
- package/dist/components/Button/Button.js +14 -0
- package/dist/components/Button/Button.js.map +1 -1
- package/dist/components/Calendar/Calendar.d.ts +29 -3
- package/dist/components/Calendar/Calendar.js +60 -12
- package/dist/components/Calendar/Calendar.js.map +1 -1
- package/dist/components/Card/Card.d.ts +6 -0
- package/dist/components/Card/Card.js +1 -1
- package/dist/components/Card/Card.js.map +1 -1
- package/dist/components/Checkbox/Checkbox.d.ts +5 -2
- package/dist/components/Checkbox/Checkbox.js +12 -2
- package/dist/components/Checkbox/Checkbox.js.map +1 -1
- package/dist/components/Code/Code.d.ts +30 -0
- package/dist/components/Code/Code.js +21 -0
- package/dist/components/Code/Code.js.map +1 -0
- package/dist/components/CodeBlock/CodeBlock.d.ts +141 -0
- package/dist/components/CodeBlock/CodeBlock.js +123 -0
- package/dist/components/CodeBlock/CodeBlock.js.map +1 -0
- package/dist/components/Collapsible/Collapsible.js +10 -2
- package/dist/components/Collapsible/Collapsible.js.map +1 -1
- package/dist/components/Combobox/Combobox.d.ts +15 -1
- package/dist/components/Combobox/Combobox.js +25 -5
- package/dist/components/Combobox/Combobox.js.map +1 -1
- package/dist/components/Command/Command.d.ts +4 -2
- package/dist/components/Command/Command.js +13 -1
- package/dist/components/Command/Command.js.map +1 -1
- package/dist/components/ContextMenu/ContextMenu.d.ts +30 -5
- package/dist/components/ContextMenu/ContextMenu.js +32 -2
- package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
- package/dist/components/DatePicker/DatePicker.d.ts +36 -4
- package/dist/components/DatePicker/DatePicker.js +55 -12
- package/dist/components/DatePicker/DatePicker.js.map +1 -1
- package/dist/components/DescriptionList/DescriptionList.d.ts +73 -0
- package/dist/components/DescriptionList/DescriptionList.js +35 -0
- package/dist/components/DescriptionList/DescriptionList.js.map +1 -0
- package/dist/components/Diagram/Diagram.d.ts +8 -3
- package/dist/components/Diagram/Diagram.js +82 -10
- package/dist/components/Diagram/Diagram.js.map +1 -1
- package/dist/components/Dialog/Dialog.d.ts +18 -3
- package/dist/components/Dialog/Dialog.js +20 -2
- package/dist/components/Dialog/Dialog.js.map +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.d.ts +49 -11
- package/dist/components/DropdownMenu/DropdownMenu.js +32 -2
- package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
- package/dist/components/EmptyState/EmptyState.d.ts +25 -1
- package/dist/components/EmptyState/EmptyState.js +3 -1
- package/dist/components/EmptyState/EmptyState.js.map +1 -1
- package/dist/components/ErrorState/ErrorState.d.ts +22 -1
- package/dist/components/ErrorState/ErrorState.js +11 -2
- package/dist/components/ErrorState/ErrorState.js.map +1 -1
- package/dist/components/Field/Field.d.ts +70 -3
- package/dist/components/Field/Field.js +53 -12
- package/dist/components/Field/Field.js.map +1 -1
- package/dist/components/Field/field-control.d.ts +31 -0
- package/dist/components/Field/field-control.js +12 -0
- package/dist/components/Field/field-control.js.map +1 -0
- package/dist/components/FloatingIconButton/FloatingIconButton.js +2 -0
- package/dist/components/FloatingIconButton/FloatingIconButton.js.map +1 -1
- package/dist/components/Heading/Heading.d.ts +62 -0
- package/dist/components/Heading/Heading.js +44 -0
- package/dist/components/Heading/Heading.js.map +1 -0
- package/dist/components/Markdown/Markdown.d.ts +139 -0
- package/dist/components/Markdown/Markdown.js +135 -0
- package/dist/components/Markdown/Markdown.js.map +1 -0
- package/dist/components/Markdown/inline.d.ts +29 -0
- package/dist/components/Markdown/inline.js +74 -0
- package/dist/components/Markdown/inline.js.map +1 -0
- package/dist/components/Markdown/nodes.d.ts +65 -0
- package/dist/components/Markdown/nodes.js +1 -0
- package/dist/components/Markdown/nodes.js.map +1 -0
- package/dist/components/Markdown/parse.d.ts +24 -0
- package/dist/components/Markdown/parse.js +110 -0
- package/dist/components/Markdown/parse.js.map +1 -0
- package/dist/components/Markdown/slug.d.ts +15 -0
- package/dist/components/Markdown/slug.js +7 -0
- package/dist/components/Markdown/slug.js.map +1 -0
- package/dist/components/NativeSelect/NativeSelect.d.ts +6 -0
- package/dist/components/NativeSelect/NativeSelect.js +2 -3
- package/dist/components/NativeSelect/NativeSelect.js.map +1 -1
- package/dist/components/Pagination/Pagination.d.ts +24 -1
- package/dist/components/Pagination/Pagination.js +6 -3
- package/dist/components/Pagination/Pagination.js.map +1 -1
- package/dist/components/Progress/Progress.d.ts +17 -5
- package/dist/components/Progress/Progress.js +18 -6
- package/dist/components/Progress/Progress.js.map +1 -1
- package/dist/components/RadioGroup/RadioGroup.d.ts +6 -0
- package/dist/components/RadioGroup/RadioGroup.js +11 -1
- package/dist/components/RadioGroup/RadioGroup.js.map +1 -1
- package/dist/components/ScrollArea/ScrollArea.d.ts +15 -0
- package/dist/components/ScrollArea/ScrollArea.js +2 -2
- package/dist/components/ScrollArea/ScrollArea.js.map +1 -1
- package/dist/components/SearchableMenu/SearchableMenu.d.ts +11 -2
- package/dist/components/SearchableMenu/SearchableMenu.js +24 -2
- package/dist/components/SearchableMenu/SearchableMenu.js.map +1 -1
- package/dist/components/Select/Select.d.ts +18 -2
- package/dist/components/Select/Select.js +20 -3
- package/dist/components/Select/Select.js.map +1 -1
- package/dist/components/Separator/Separator.d.ts +21 -3
- package/dist/components/Separator/Separator.js +9 -1
- package/dist/components/Separator/Separator.js.map +1 -1
- package/dist/components/Sheet/Sheet.d.ts +3 -0
- package/dist/components/Sheet/Sheet.js +11 -2
- package/dist/components/Sheet/Sheet.js.map +1 -1
- package/dist/components/Skeleton/Skeleton.d.ts +8 -1
- package/dist/components/Skeleton/Skeleton.js +1 -1
- package/dist/components/Skeleton/Skeleton.js.map +1 -1
- package/dist/components/Slider/Slider.d.ts +21 -3
- package/dist/components/Slider/Slider.js +54 -27
- package/dist/components/Slider/Slider.js.map +1 -1
- package/dist/components/Spinner/Spinner.d.ts +8 -0
- package/dist/components/Spinner/Spinner.js +3 -2
- package/dist/components/Spinner/Spinner.js.map +1 -1
- package/dist/components/StatusPill/StatusPill.d.ts +5 -0
- package/dist/components/StatusPill/StatusPill.js +6 -0
- package/dist/components/StatusPill/StatusPill.js.map +1 -1
- package/dist/components/Table/Table.d.ts +6 -0
- package/dist/components/Table/Table.js +3 -1
- package/dist/components/Table/Table.js.map +1 -1
- package/dist/components/Tag/Tag.d.ts +68 -9
- package/dist/components/Tag/Tag.js +50 -10
- package/dist/components/Tag/Tag.js.map +1 -1
- package/dist/components/Text/Text.d.ts +62 -0
- package/dist/components/Text/Text.js +30 -0
- package/dist/components/Text/Text.js.map +1 -0
- package/dist/components/Timestamp/Timestamp.d.ts +59 -0
- package/dist/components/Timestamp/Timestamp.js +56 -0
- package/dist/components/Timestamp/Timestamp.js.map +1 -0
- package/dist/components/Toast/Toast.d.ts +9 -1
- package/dist/components/Toast/Toast.js +27 -4
- package/dist/components/Toast/Toast.js.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroup.d.ts +6 -1
- package/dist/components/ToggleGroup/ToggleGroup.js +11 -1
- package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -1
- package/dist/components/Toolbar/Toolbar.d.ts +55 -0
- package/dist/components/Toolbar/Toolbar.js +43 -0
- package/dist/components/Toolbar/Toolbar.js.map +1 -0
- package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.d.ts +6 -0
- package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.js +48 -8
- package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.js.map +1 -1
- package/dist/diagrams/DataflowFigure/DataflowFigure.js +21 -2
- package/dist/diagrams/DataflowFigure/DataflowFigure.js.map +1 -1
- package/dist/diagrams/DiagramCanvas/DiagramCanvas.d.ts +14 -0
- package/dist/diagrams/DiagramCanvas/DiagramCanvas.js +14 -7
- package/dist/diagrams/DiagramCanvas/DiagramCanvas.js.map +1 -1
- package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.d.ts +38 -4
- package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.js +14 -16
- package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.js.map +1 -1
- package/dist/diagrams/DiagramInspector/DiagramInspector.js +2 -2
- package/dist/diagrams/DiagramInspector/DiagramInspector.js.map +1 -1
- package/dist/diagrams/DiagramMinimap/DiagramMinimap.d.ts +23 -7
- package/dist/diagrams/DiagramMinimap/DiagramMinimap.js +45 -18
- package/dist/diagrams/DiagramMinimap/DiagramMinimap.js.map +1 -1
- package/dist/diagrams/LifecycleFigure/LifecycleFigure.js +44 -12
- package/dist/diagrams/LifecycleFigure/LifecycleFigure.js.map +1 -1
- package/dist/diagrams/SequenceFigure/SequenceFigure.js +35 -5
- package/dist/diagrams/SequenceFigure/SequenceFigure.js.map +1 -1
- package/dist/diagrams/WorkflowFigure/WorkflowFigure.d.ts +3 -1
- package/dist/diagrams/WorkflowFigure/WorkflowFigure.js +76 -28
- package/dist/diagrams/WorkflowFigure/WorkflowFigure.js.map +1 -1
- package/dist/diagrams/index.d.ts +1 -0
- package/dist/diagrams/index.js +10 -0
- package/dist/diagrams/index.js.map +1 -1
- package/dist/diagrams/lib/dev.d.ts +61 -0
- package/dist/diagrams/lib/dev.js +96 -0
- package/dist/diagrams/lib/dev.js.map +1 -0
- package/dist/diagrams/lib/frame.d.ts +48 -7
- package/dist/diagrams/lib/frame.js +17 -2
- package/dist/diagrams/lib/frame.js.map +1 -1
- package/dist/diagrams/lib/wires.js.map +1 -1
- package/dist/diagrams/spec.d.ts +64 -12
- package/dist/index.d.ts +16 -4
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/keyframes.css +57 -3
- package/dist/lib/overlay-container.d.ts +14 -4
- package/dist/lib/overlay-container.js.map +1 -1
- package/dist/lib/warn.d.ts +73 -0
- package/dist/lib/warn.js +38 -0
- package/dist/lib/warn.js.map +1 -0
- package/dist/semantic.css +17 -6
- package/dist/styles.css +1 -1
- package/dist/tokens.css +20 -2
- package/dist/tokens.d.ts +1 -1
- package/dist/tokens.js +39 -36
- package/dist/tokens.json +39 -36
- package/llms.txt +35 -0
- package/package.json +5 -2
- package/skills/misoto22-design/evals/evals.json +84 -0
- package/skills/misoto22-design/rules/a11y.md +55 -3
- package/skills/misoto22-design/rules/forms.md +5 -0
package/dist/agent/RadioGroup.md
CHANGED
|
@@ -4,10 +4,31 @@ A set of mutually exclusive choices.
|
|
|
4
4
|
|
|
5
5
|
- Group: Forms
|
|
6
6
|
- Import: `import { RadioGroup } from '@misoto22/design'`
|
|
7
|
-
- Version: 0.
|
|
7
|
+
- Version: 0.8.0
|
|
8
8
|
- Docs: https://ui.misoto22.com/components/radio-group/
|
|
9
9
|
- Related: checkbox, select
|
|
10
10
|
|
|
11
|
+
## Anatomy
|
|
12
|
+
|
|
13
|
+
- **Group** (required) — A <div role="radiogroup"> stacking its options. Being a div is why the label above it names the group by being pointed AT — aria-labelledby, not htmlFor — and why the words do not click through.
|
|
14
|
+
- **Row** (required) — The <label> RadioGroupItem wraps around control and words. It is the click target — a bare 18px circle is below every pointer-target guideline — and it is the only source of the option’s accessible name.
|
|
15
|
+
- **Circle** (required) — The 18px control itself, its border turning --accent when chosen.
|
|
16
|
+
- **Dot** — The 10px --accent fill inside the circle, present only on the chosen option.
|
|
17
|
+
|
|
18
|
+
## Best practices
|
|
19
|
+
|
|
20
|
+
### Do
|
|
21
|
+
|
|
22
|
+
- Name the group. Inside a Field its label does it, through aria-labelledby; standing alone it needs its own aria-label, and without either the group is announced as three unlabelled radios.
|
|
23
|
+
- Set defaultValue or value. Selection follows focus here, so a group that starts empty commits an answer the moment anybody arrows into it — including a reader who was only passing through on the way to the next field.
|
|
24
|
+
- Add an explicit “None” or “Any” option when the answer is genuinely optional: there is no way back to nothing once a radio is chosen, neither by clicking it again nor from the keyboard.
|
|
25
|
+
|
|
26
|
+
### Don’t
|
|
27
|
+
|
|
28
|
+
- Do not hang an expensive effect on onValueChange. Every arrow press commits, so a group whose options fetch or navigate fires once per key on the way past the ones nobody wanted.
|
|
29
|
+
- Do not reach past RadioGroupItem to the Radix primitive or hand-roll the row: selection-follows-focus is implemented in this item’s own focus handler, not upstream, so a hand-rolled one moves the outline and selects nothing.
|
|
30
|
+
- Do not disable one option to mean “not available here”: the roving focus skips it entirely, so a keyboard reader never learns the option exists. Say why in the Field’s hint and leave the option out.
|
|
31
|
+
|
|
11
32
|
## Accessibility
|
|
12
33
|
|
|
13
34
|
- One tab stop for the whole group; the arrow keys move between options, per the ARIA radiogroup pattern.
|
|
@@ -20,7 +41,7 @@ A set of mutually exclusive choices.
|
|
|
20
41
|
|
|
21
42
|
## RadioGroup
|
|
22
43
|
|
|
23
|
-
A set of mutually exclusive choices. Radix owns the roving tabindex, so the whole group is ONE tab stop and the arrow keys move between options — which is what the ARIA radiogroup pattern requires and what a stack of hand-rolled `<input type="radio">` wrappers usually gets wrong.
|
|
44
|
+
A set of mutually exclusive choices. Radix owns the roving tabindex, so the whole group is ONE tab stop and the arrow keys move between options — which is what the ARIA radiogroup pattern requires and what a stack of hand-rolled `<input type="radio">` wrappers usually gets wrong. Inside a `Field` the group takes its name from that label, by pointing back at it: the root is a `<div role="radiogroup">` and `<label for>` does not bind to one, so the words above it click through no more than a `<legend>` does. Standing alone, it still needs an `aria-label` of its own — an unnamed group is three unlabelled radios.
|
|
24
45
|
|
|
25
46
|
Also accepts: `ComponentProps<typeof RadioGroupPrimitive.Root>`.
|
|
26
47
|
|
|
@@ -4,7 +4,7 @@ Where a quantity goes as it moves through stages.
|
|
|
4
4
|
|
|
5
5
|
- Group: Charts
|
|
6
6
|
- Import: `import { SankeyChart } from '@misoto22/design/charts'`
|
|
7
|
-
- Version: 0.
|
|
7
|
+
- Version: 0.8.0
|
|
8
8
|
- Docs: https://ui.misoto22.com/components/sankey-chart/
|
|
9
9
|
- Related: bar-chart
|
|
10
10
|
|
|
@@ -12,6 +12,27 @@ Where a quantity goes as it moves through stages.
|
|
|
12
12
|
|
|
13
13
|
A funnel, a budget, an energy or traffic breakdown. The only chart here whose data is a graph rather than a table.
|
|
14
14
|
|
|
15
|
+
## Anatomy
|
|
16
|
+
|
|
17
|
+
- **Figure frame** (required) — ChartFigure’s <figure>, named by title, with the diagram inside one ChartContainer.
|
|
18
|
+
- **Node rectangles** (required) — The root’s own node renderer. A node whose name is in config is painted from its gradient; one that is not falls back to currentColor, so it is drawn plainly rather than lost.
|
|
19
|
+
- **Node labels** — <SankeyChart.NodeLabel>, composed inside <SankeyChart.Node>, and entirely opt-in. Leave it out and NOTHING on the diagram is named — there is no legend here, so the names exist only in the tooltip and in the hidden table.
|
|
20
|
+
- **Flow bands** — <SankeyChart.Link>. gradient fades the source’s colour into the target’s and is the variant that actually reads as flow; solid gives up colour entirely and lets the node rectangles carry identity.
|
|
21
|
+
- **Hidden data table** (required) — The sr-only table lists the LINKS — from, to, value — rather than the nodes, because a table of node totals loses every from-and-to the diagram exists to state.
|
|
22
|
+
|
|
23
|
+
## Best practices
|
|
24
|
+
|
|
25
|
+
### Do
|
|
26
|
+
|
|
27
|
+
- Treat the nodes array as an addressing table. A link’s source and target are INDEXES into it, so inserting a node at the front silently re-points every link at a different pair — and the layout still renders, which is why this belongs in a test rather than in an eyeball.
|
|
28
|
+
- Compose <SankeyChart.Node> with a <SankeyChart.NodeLabel> inside it. Names are opt-in and there is no legend to fall back on, so a sankey without labels is a set of anonymous grey bands.
|
|
29
|
+
- Keep the flows conserved, or give the shortfall a node of its own with a name. Band width is the only arithmetic on screen, and a node that quietly loses eight percent simply reads as a smaller node.
|
|
30
|
+
|
|
31
|
+
### Don’t
|
|
32
|
+
|
|
33
|
+
- Do not reach for it when the quantity only narrows along one path. That is a FunnelChart; a sankey spends its whole layout budget on splits that are not there.
|
|
34
|
+
- Do not put twenty nodes in one column. nodePadding is 10px and the layout distributes what is left, so past a dozen a node rectangle is a few pixels tall and a label centred on it has nowhere to sit.
|
|
35
|
+
|
|
15
36
|
## Accessibility
|
|
16
37
|
|
|
17
38
|
- title is required. The hidden table lists the FLOWS rather than the nodes — a table of node totals would lose every “from → to” the diagram exists to show.
|
|
@@ -38,10 +59,12 @@ Where a quantity goes as it moves through stages — the shape for a funnel, a b
|
|
|
38
59
|
- `sort` — `boolean` default `true`. Lets the layout reorder nodes for the fewest crossings.
|
|
39
60
|
- `align` — `'left' | 'justify'` default `'justify'`. How nodes are placed along the flow axis.
|
|
40
61
|
- `verticalAlign` — `'justify' | 'top'` default `'justify'`. How nodes are distributed within a column.
|
|
41
|
-
- `defaultSelectedNode` — `string | null` default `null`. The node lit on first render. Selecting one dims every flow it does not touch.
|
|
62
|
+
- `defaultSelectedNode` — `string | null` default `null`. The node lit on first render, when the chart keeps its own selection. Selecting one dims every flow it does not touch.
|
|
63
|
+
- `selectedNode` — `string | null`. The selected node, driven from outside. Give this and the chart follows it; leave it undefined and the chart keeps its own, starting from `defaultSelectedNode`.
|
|
42
64
|
- `onSelectionChange` — `(selection: { name: string; value: number } | null) => void`. Fires when the selection changes, and with null when it is cleared.
|
|
43
65
|
- `isLoading` — `boolean` default `false`. Swaps the marks for an animated skeleton, keeping the measured height so the page does not jump when the data lands.
|
|
44
66
|
- `hideDataTable` — `boolean` default `false`. Drops the hidden table view. Only correct when the page prints the data itself.
|
|
67
|
+
- `empty` — `ChartEmptyProps | false`. What the chart shows when it has nothing to draw. `false` keeps the empty plot, for a chart whose emptiness is itself the reading.
|
|
45
68
|
|
|
46
69
|
## Types
|
|
47
70
|
|
|
@@ -4,7 +4,7 @@ Two measures against each other, one mark per observation.
|
|
|
4
4
|
|
|
5
5
|
- Group: Charts
|
|
6
6
|
- Import: `import { ScatterChart } from '@misoto22/design/charts'`
|
|
7
|
-
- Version: 0.
|
|
7
|
+
- Version: 0.8.0
|
|
8
8
|
- Docs: https://ui.misoto22.com/components/scatter-chart/
|
|
9
9
|
- Related: line-chart, heatmap
|
|
10
10
|
|
|
@@ -12,6 +12,28 @@ Two measures against each other, one mark per observation.
|
|
|
12
12
|
|
|
13
13
|
Correlation, clustering, outliers — the questions that do not survive being bucketed into a bar. The only chart here whose x axis is a number rather than a category.
|
|
14
14
|
|
|
15
|
+
## Anatomy
|
|
16
|
+
|
|
17
|
+
- **Figure frame** (required) — ChartFigure’s <figure>, with isLoading and an empty state. Emptiness is read from the declared table rows, for the same reason the table is declared at all: the observations live on each <Scatter>, and the root cannot see them.
|
|
18
|
+
- **Numeric axes** (required) — <ScatterChart.XAxis> and <ScatterChart.YAxis>, both type="number" by default. The only chart in the group whose horizontal axis is a measurement rather than a category.
|
|
19
|
+
- **Clouds** (required) — <ScatterChart.Scatter>, one per series, each carrying its OWN data array rather than reading the root’s. Six mark shapes, and a solid mark takes a 1px --chart-surface ring so two coincident observations stay countable.
|
|
20
|
+
- **Size channel** — <ScatterChart.ZAxis>, range [40, 400] by default. That range is in AREA, not radius: doubling a radius quadruples the ink, which is how a bubble chart usually lies.
|
|
21
|
+
- **Crosshair** — The tooltip’s cursor, a pair of rules rather than one band. A scatter point is located by two coordinates and a single vertical cursor answers half of that.
|
|
22
|
+
- **Declared table** — table is a PROP here, not inferred. Scatter data lives on each series, so there are no rows on the root to read off — and passing nothing ships a figure with no table at all.
|
|
23
|
+
|
|
24
|
+
## Best practices
|
|
25
|
+
|
|
26
|
+
### Do
|
|
27
|
+
|
|
28
|
+
- Declare table. It is the one chart in the group whose hidden table cannot be derived, so omitting it fails silently: the figure renders, is named, and has no numbers behind it.
|
|
29
|
+
- Separate series by shape before anything else. Circle against cross stays legible where two steps of grey do not, and shape survives overprinting and forced colours — where every --series-* token becomes CanvasText and a lightness step is gone.
|
|
30
|
+
- Reach for variant="outline" or shape="ring" on a dense cloud. A hollow mark shows what is under it; a solid one at two thousand points is a silhouette of the densest region and nothing else.
|
|
31
|
+
|
|
32
|
+
### Don’t
|
|
33
|
+
|
|
34
|
+
- Do not vary size between series to mean something. size is a flat radius in pixels, so it encodes nothing while looking exactly as if it does; <ScatterChart.ZAxis> is the only path that maps a value to a mark’s area.
|
|
35
|
+
- Past three series shape stops separating them — circle, cross and triangle are distinct, and a fourth glyph is a diamond most readers see as a rotated square. Small multiples on shared axes is the answer, not a fourth mark.
|
|
36
|
+
|
|
15
37
|
## Accessibility
|
|
16
38
|
|
|
17
39
|
- title is required. The table view is declared rather than inferred: scatter data lives on each series, so there is no single set of rows to read off the root.
|
|
@@ -32,9 +54,12 @@ Two measures against each other, one mark per observation — the shape for "is
|
|
|
32
54
|
- `children` (required) — `ReactNode`. The composed parts — axes, grid, tooltip, legend, and the marks themselves.
|
|
33
55
|
- `className` — `string`. Merged onto the figure, last, so a call site can size or space it.
|
|
34
56
|
- `chartProps` — `ComponentProps<typeof RechartsScatterChart>`. Escape hatch onto the raw Recharts chart element.
|
|
35
|
-
- `defaultSelectedDataKey` — `string | null` default `null`. The series lit on first render
|
|
57
|
+
- `defaultSelectedDataKey` — `string | null` default `null`. The series lit on first render, when the chart keeps its own selection.
|
|
58
|
+
- `selectedDataKey` — `string | null`. The selected series, driven from outside. Give this and the chart follows it; leave it undefined and the chart keeps its own, starting from `defaultSelectedDataKey`.
|
|
36
59
|
- `onSelectionChange` — `(selectedDataKey: string | null) => void`. Fires when the selection changes, and with null when it is cleared.
|
|
37
60
|
- `table` — `ScatterTable | false`. The rows behind the hidden table view, with the fields to print. Scatter data lives on each `<Scatter>` rather than on the root, so unlike every other chart here the table cannot be inferred — it is declared.
|
|
61
|
+
- `isLoading` — `boolean` default `false`. Swaps the marks for an animated skeleton, keeping the measured height so the page does not jump when the data lands.
|
|
62
|
+
- `empty` — `ChartEmptyProps | false`. What the chart shows when it has nothing to draw. `false` keeps the empty plot, for a chart whose emptiness is itself the reading. Read from the declared `table` rows, for the same reason the table is declared: the observations live on each `<Scatter>`, and the root cannot see them.
|
|
38
63
|
|
|
39
64
|
## Types
|
|
40
65
|
|
package/dist/agent/ScrollArea.md
CHANGED
|
@@ -4,7 +4,7 @@ A box that scrolls, with a scrollbar that looks the same everywhere.
|
|
|
4
4
|
|
|
5
5
|
- Group: Surfaces
|
|
6
6
|
- Import: `import { ScrollArea } from '@misoto22/design'`
|
|
7
|
-
- Version: 0.
|
|
7
|
+
- Version: 0.8.0
|
|
8
8
|
- Docs: https://ui.misoto22.com/components/scroll-area/
|
|
9
9
|
- Related: table
|
|
10
10
|
|
|
@@ -12,10 +12,31 @@ A box that scrolls, with a scrollbar that looks the same everywhere.
|
|
|
12
12
|
|
|
13
13
|
A bounded panel — a long option list, a log. For page-level or prose scroll the scroll-slim utility is lighter and needs no component.
|
|
14
14
|
|
|
15
|
+
## Anatomy
|
|
16
|
+
|
|
17
|
+
- **Root** (required) — The bounded box, and where className lands. It is overflow-hidden and has no size of its own, so the height you give it here is the only thing that decides whether anything scrolls at all.
|
|
18
|
+
- **Viewport** (required) — The element that actually scrolls, and the one carrying role="region", tabIndex 0 and label. Radix hides the platform’s scrollbar on it and sets the axis WITHOUT a bar to overflow: hidden. It is positioned, so an absolutely-positioned descendant travels with the content instead of hanging still over it.
|
|
19
|
+
- **Bar** — One per orientation: an 8px track with a pill thumb at --rule-2, and touch-none — a finger scrolls the content, not the bar. It is drawn only while the pointer is inside the region and fades some 600ms after scrolling stops.
|
|
20
|
+
- **Corner** — The square where two bars meet, which exists only at orientation="both" — the default.
|
|
21
|
+
|
|
22
|
+
## Best practices
|
|
23
|
+
|
|
24
|
+
### Do
|
|
25
|
+
|
|
26
|
+
- Give it a height. With none, the root is as tall as its content, nothing ever overflows, and all the component added to the page was a keyboard stop.
|
|
27
|
+
- Narrow orientation only when clipping the other axis is the thing you meant. Both axes scroll by default, because the axis without a bar is set to overflow: hidden — what is past that edge is not merely unmarked, it is unreachable by every key and every gesture, with the content perfectly well rendered.
|
|
28
|
+
- Pass type="always" when the content ends flush at the boundary: the platform scrollbar is hidden and ours is not drawn until the pointer is inside, so at rest nothing on the screen says the box scrolls.
|
|
29
|
+
|
|
30
|
+
### Don’t
|
|
31
|
+
|
|
32
|
+
- Do not build a drag-to-scroll affordance over it — the thumb is deliberately touch-none and the viewport is a real overflow container, so touch dragging, momentum and the wheel are already the platform’s and behave as the reader expects.
|
|
33
|
+
- Do not nest one inside another on the same axis: the inner viewport consumes the wheel until it reaches its own end, so a reader aiming at the outer list moves the inner one instead.
|
|
34
|
+
|
|
15
35
|
## Accessibility
|
|
16
36
|
|
|
17
37
|
- The viewport stays focusable. A scrollable region whose contents are not focusable has nothing to Tab to, so everything past the fold does not exist without a mouse.
|
|
18
38
|
- label is required, because an unnamed keyboard stop announces "group" and nothing else.
|
|
39
|
+
- Both axes scroll unless a caller narrows orientation, so content wider than the box stays reachable rather than being clipped without a bar.
|
|
19
40
|
|
|
20
41
|
## Keyboard
|
|
21
42
|
|
|
@@ -24,12 +45,12 @@ A bounded panel — a long option list, a log. For page-level or prose scroll th
|
|
|
24
45
|
|
|
25
46
|
## ScrollArea
|
|
26
47
|
|
|
27
|
-
A box that scrolls, with a scrollbar that looks the same on every platform. The reason to reach for this over `overflow-auto` is not the scrollbar — it is that Radix keeps the viewport focusable and the bar operable, which a bare overflow container does not. A scrollable region whose contents are not themselves focusable is unreachable by keyboard: there is nothing to Tab to, so everything past the fold does not exist without a mouse. For a page-level or prose scroll, the `scroll-slim` utility is lighter and needs no component. This is for a bounded panel: a long option list, a log, a sidebar that outgrows its column.
|
|
48
|
+
A box that scrolls, with a scrollbar that looks the same on every platform. The reason to reach for this over `overflow-auto` is not the scrollbar — it is that Radix keeps the viewport focusable and the bar operable, which a bare overflow container does not. A scrollable region whose contents are not themselves focusable is unreachable by keyboard: there is nothing to Tab to, so everything past the fold does not exist without a mouse. For a page-level or prose scroll, the `scroll-slim` utility is lighter and needs no component. This is for a bounded panel: a long option list, a log, a sidebar that outgrows its column. Both axes scroll unless a caller says otherwise. The old vertical default read as a statement about which bar to draw and was in fact a statement about which half of the content existed: Radix sets the viewport's overflow from the mounted bars, so the axis without one was `hidden` and everything past it was unreachable — silently, and with the content perfectly well rendered.
|
|
28
49
|
|
|
29
50
|
### Props
|
|
30
51
|
|
|
31
52
|
- `label` (required) — `string`. Names the region. Required, and not decoration: a scroll container is a keyboard stop, and an unnamed stop announces "group" and nothing else.
|
|
32
|
-
- `orientation` — `'vertical' | 'horizontal' | 'both'` default `'
|
|
53
|
+
- `orientation` — `'vertical' | 'horizontal' | 'both'` default `'both'`. Which axes get a bar — and therefore which axes scroll at all. Radix sets the viewport's overflow from the bars that are mounted, so an axis without one is `hidden`: what is past that edge is not merely unmarked, it is unreachable by every key and every gesture. `both` is the default for that reason. Narrow it only when clipping the other axis is the thing you meant.
|
|
33
54
|
|
|
34
55
|
Also accepts: `ComponentProps<typeof ScrollAreaPrimitive.Root>`.
|
|
35
56
|
|
|
@@ -4,7 +4,7 @@ A menu of actions you can type into.
|
|
|
4
4
|
|
|
5
5
|
- Group: Overlays
|
|
6
6
|
- Import: `import { SearchableMenu } from '@misoto22/design'`
|
|
7
|
-
- Version: 0.
|
|
7
|
+
- Version: 0.8.0
|
|
8
8
|
- Docs: https://ui.misoto22.com/components/searchable-menu/
|
|
9
9
|
- Related: dropdown-menu, command, combobox
|
|
10
10
|
|
|
@@ -12,6 +12,28 @@ A menu of actions you can type into.
|
|
|
12
12
|
|
|
13
13
|
A DropdownMenu past about a dozen rows stops being scannable, and nesting submenus makes it worse. This is the same list with a filter over it. Not a Command palette: that is page-level and modal; this is anchored to a control.
|
|
14
14
|
|
|
15
|
+
## Anatomy
|
|
16
|
+
|
|
17
|
+
- **Trigger** (required) — A pill button built here rather than a Button: --control-h-sm tall, hairline bordered, with a chevron. Its accessible name is label, not the children you passed as its text.
|
|
18
|
+
- **Panel** (required) — A Popover with its padding removed and a flat 16rem width, so the filter and the list run edge to edge inside it. Not modal — this is a Popover, not a Dialog.
|
|
19
|
+
- **Filter** (required) — The Command input. Focus lands here on open and stays there; the highlight moves under it through aria-activedescendant.
|
|
20
|
+
- **Rows** — One per MenuAction, as listbox options. shortcut prints as a Kbd at the end of the row, destructive paints it --danger, and selecting one closes the menu before running onSelect.
|
|
21
|
+
- **Empty state** — emptyMessage, shown when the filter matches nothing. Say what would match rather than “no results”.
|
|
22
|
+
|
|
23
|
+
## Best practices
|
|
24
|
+
|
|
25
|
+
### Do
|
|
26
|
+
|
|
27
|
+
- Give an action keywords for the word a reader reaches for that the label does not print — “download” for Export, “bin” for Delete. The label’s own text is lifted into the filter for you; a label built only from elements prints none, and development warns SEARCHABLE_MENU_LABEL_UNREADABLE rather than shipping a row nothing matches.
|
|
28
|
+
- Make label the trigger’s visible text. It is set as aria-label on the trigger and overrides the children, so a button reading “Status” under a label of “Row actions” is announced as something the reader cannot say aloud (WCAG 2.5.3).
|
|
29
|
+
- Keep actions that share a group next to each other in the array: groups are built by walking the list and extending only the LAST one, so the same group name appearing again after other rows produces a second heading with identical text.
|
|
30
|
+
|
|
31
|
+
### Don’t
|
|
32
|
+
|
|
33
|
+
- It is a Popover underneath, so it is not modal: the page behind still scrolls while the filter is open and the panel is re-anchored as it does. A surface that should hold the page still is CommandDialog.
|
|
34
|
+
- className lands on the TRIGGER, not on the panel — the panel is a flat 16rem with no prop that widens it, so a long label wraps to a second line instead of the box growing to take it.
|
|
35
|
+
- The trigger is --control-h-sm — 36px comfortable, 30px under data-density="compact" — which is below the 44px pointer target (WCAG 2.5.5), and it is not the system Button, so variant and size do not reach it.
|
|
36
|
+
|
|
15
37
|
## Accessibility
|
|
16
38
|
|
|
17
39
|
- Inside a bounded frame — a device preview, an embedded console — wrap the subtree in `<OverlayContainer container={el}>`. The panel then renders into that element and collides with its edges instead of the viewport’s, and inherits the `dir` and `data-density` set there.
|
package/dist/agent/Select.md
CHANGED
|
@@ -4,7 +4,7 @@ A choice from a list, styled the whole way down.
|
|
|
4
4
|
|
|
5
5
|
- Group: Forms
|
|
6
6
|
- Import: `import { Select } from '@misoto22/design'`
|
|
7
|
-
- Version: 0.
|
|
7
|
+
- Version: 0.8.0
|
|
8
8
|
- Docs: https://ui.misoto22.com/components/select/
|
|
9
9
|
- Related: combobox, native-select, field
|
|
10
10
|
|
|
@@ -12,12 +12,34 @@ A choice from a list, styled the whole way down.
|
|
|
12
12
|
|
|
13
13
|
Up to roughly a dozen options. Past that a Combobox wins, because a list nobody can filter is slower to scan than one you can type into.
|
|
14
14
|
|
|
15
|
+
## Anatomy
|
|
16
|
+
|
|
17
|
+
- **Trigger** (required) — A <button role="combobox"> on CONTROL_BASE, so it matches the Input beside it exactly. It is named by the label and by its own value together, and carries the chevron that turns over while the panel is open.
|
|
18
|
+
- **Value** — The chosen item’s text, or placeholder in --ink-3-aa when nothing is chosen. It truncates, and it is the half of the accessible name that says what was picked.
|
|
19
|
+
- **Panel** — Portalled, at least as wide as the trigger and at most 18rem tall, with a scroll chevron appearing at each end once the list is longer than that.
|
|
20
|
+
- **Item** — One option. The 3.5 tick box is always drawn and only the tick inside it appears, so choosing does not shunt every label sideways; data-highlighted is the fill, the tick is the chosen one.
|
|
21
|
+
- **Group heading** — SelectLabel — a mono eyebrow inside a SelectGroup. It is a heading, not an option, which is the difference between it and a disabled item used as a divider.
|
|
22
|
+
|
|
23
|
+
## Best practices
|
|
24
|
+
|
|
25
|
+
### Do
|
|
26
|
+
|
|
27
|
+
- Pass name when the value has to survive a submit. The trigger is a <button>; Radix renders the hidden native <select> that carries the value only when the control is inside a <form>, and only a named one sends anything.
|
|
28
|
+
- Pick one spelling of invalid. The trigger reads the invalid prop and aria-invalid alike, including the one a Field sets from error, so setting both is two sources of truth for one border.
|
|
29
|
+
- Divide long lists with SelectGroup and SelectLabel rather than a disabled item used as a heading: a disabled item is still an option, so a screen reader counts it and announces the list as one longer than it is.
|
|
30
|
+
|
|
31
|
+
### Don’t
|
|
32
|
+
|
|
33
|
+
- Inside a Field with a label, the label prop here is not announced — the field’s words name the trigger — so a label that disagrees with the one above it is dead text nobody will ever hear.
|
|
34
|
+
- Do not lean on the closed trigger to show a long option: it truncates to keep the field’s height, so the end of the value is only readable with the panel open.
|
|
35
|
+
- Do not point contentClassName at the trigger. className is the trigger; contentClassName is the panel, and confusing them is how a select gets a 18rem-wide dropdown over the thing it is choosing for.
|
|
36
|
+
|
|
15
37
|
## Accessibility
|
|
16
38
|
|
|
17
39
|
- Inside a bounded frame — a device preview, an embedded console — wrap the subtree in `<OverlayContainer container={el}>`. The panel then renders into that element and collides with its edges instead of the viewport’s, and inherits the `dir` and `data-density` set there.
|
|
18
40
|
- The option list is ours, so it does not change typeface, spacing and selection colour the moment it opens — which is what a native select does.
|
|
19
41
|
- The keyboard contract is the platform's: typeahead, arrows, Home and End, Escape to close without choosing.
|
|
20
|
-
- label is required
|
|
42
|
+
- label is required, and it is announced WITH the value: the trigger reads "Region, Australia", because a value is not a name and a name without the value is not the answer. Inside a Field the FIELD’s label supplies the name half — the trigger’s aria-labelledby points at that label and at the value — and the label prop here is neither rendered nor announced, so one that disagrees with the words above it is text nobody will hear.
|
|
21
43
|
|
|
22
44
|
## Keyboard
|
|
23
45
|
|
|
@@ -40,11 +62,15 @@ A choice from a list, styled the whole way down. The option list is ours — dra
|
|
|
40
62
|
### Props
|
|
41
63
|
|
|
42
64
|
- `contentClassName` — `string`. Classes for the option PANEL, not the trigger. `className` styles the trigger, which is the common case. This exists for the uncommon one: a select inside a bounded surface, where the default 18rem of list would cover the thing the reader is choosing for — a year picker over its own calendar, say.
|
|
43
|
-
- `label` (required) — `string`. Names the control. Required — the trigger shows a value, and a value is not a name.
|
|
65
|
+
- `label` (required) — `string`. Names the control. Required — the trigger shows a value, and a value is not a name. It is announced together with the value, not instead of it: the trigger is named by the label and by its own text, so a reader hears "Region, Australia". Inside a `Field` with a label, that label is used and this one is not repeated.
|
|
44
66
|
- `placeholder` — `string` default `'Select…'`.
|
|
45
67
|
- `invalid` — `boolean`. Paints the resting border with `--danger` and reflects `aria-invalid`.
|
|
46
68
|
- `disabled` — `boolean`.
|
|
47
69
|
- `className` — `string`.
|
|
70
|
+
- `id` — `string`. The TRIGGER's id — the element a label points at. A `Field` sets it.
|
|
71
|
+
- `aria-describedby` — `string`. Ids of the copy describing the control. A `Field` sets it from hint, error and description.
|
|
72
|
+
- `aria-invalid` — `boolean | 'true' | 'false'`. The spelling a form library sets; read together with `invalid`.
|
|
73
|
+
- `aria-required` — `boolean`. Announced on the trigger. A `Field` sets it from `required`.
|
|
48
74
|
- `children` (required) — `ReactNode`. `SelectItem`s, optionally wrapped in `SelectGroup` with a `SelectLabel`.
|
|
49
75
|
|
|
50
76
|
Also accepts: `ComponentProps<typeof SelectPrimitive.Root>`.
|
package/dist/agent/Separator.md
CHANGED
|
@@ -1,29 +1,52 @@
|
|
|
1
1
|
# Separator
|
|
2
2
|
|
|
3
|
-
A rule, in the three weights a monochrome page needs.
|
|
3
|
+
A rule, in the three weights a monochrome page needs — with words in it when the break has something to say.
|
|
4
4
|
|
|
5
5
|
- Group: Display
|
|
6
6
|
- Import: `import { Separator } from '@misoto22/design'`
|
|
7
|
-
- Version: 0.
|
|
7
|
+
- Version: 0.8.0
|
|
8
8
|
- Docs: https://ui.misoto22.com/components/separator/
|
|
9
9
|
|
|
10
10
|
## When to reach for it
|
|
11
11
|
|
|
12
|
-
Hairline between rows, edge between blocks, hard under a masthead.
|
|
12
|
+
Hairline between rows, edge between blocks, hard under a masthead. label puts words in the break: "or continue with", "Older".
|
|
13
|
+
|
|
14
|
+
## Anatomy
|
|
15
|
+
|
|
16
|
+
- **Rule** (required) — One <div>. A pixel on its cross axis and 100% on its main axis, so it takes the width — or the height — of whatever contains it, and nothing else.
|
|
17
|
+
- **Ink** (required) — The only thing weight changes: --rule inside a block, --rule-2 between blocks, --rule-hard under a masthead. The hard one is not a darker grey, it is --ink itself.
|
|
18
|
+
- **Label** — label, horizontal only. It changes the construction rather than the styling: the rule is drawn TWICE, one aria-hidden piece either side of the words in mono-meta at --ink-3-aa, and the gap between them is a gap.
|
|
19
|
+
|
|
20
|
+
## Best practices
|
|
21
|
+
|
|
22
|
+
### Do
|
|
23
|
+
|
|
24
|
+
- Give a vertical separator a height. It is h-full, which against a parent with no height of its own resolves to zero — the element renders, occupies nothing, and reads as a component that failed to load.
|
|
25
|
+
- Pass decorative={false} when the rule is the only thing dividing two sections a screen reader should hear as distinct: that is what swaps role="none" for role="separator" and sets aria-orientation with it.
|
|
26
|
+
- Use label rather than building "or continue with" out of two Separators and a span. The two rules are drawn for you and neither of them needs to know the ground it is on.
|
|
27
|
+
|
|
28
|
+
### Don’t
|
|
29
|
+
|
|
30
|
+
- Do not pick the weight by eye. The three are ordered, so a hard rule between two table rows tells the reader the table ended there.
|
|
31
|
+
- Do not hand-tune a fourth grey through className. Three named weights are the whole set, and the names exist because a monochrome page drifts into five slightly different rules the moment one of them is chosen by feel.
|
|
32
|
+
- Do not lay the label over a single rule with a background colour to punch a hole in it. That version has to be told the ground it is sitting on, and a --paper notch on a --stone card reads as a rendering bug.
|
|
13
33
|
|
|
14
34
|
## Accessibility
|
|
15
35
|
|
|
16
36
|
- role="none" by default. A rule that only groups things visually must not be announced.
|
|
37
|
+
- With a label, the words are the content and the two rules are aria-hidden decoration — so decorative no longer applies, and nothing announces a separator over the top of the text.
|
|
38
|
+
- A label on a vertical rule is ignored rather than silently redrawn as a horizontal bar: there is no sensible place for words inside a one-pixel column.
|
|
17
39
|
|
|
18
40
|
## Separator
|
|
19
41
|
|
|
20
|
-
A rule. In a monochrome system the rule does the work colour would otherwise do, so it has three weights rather than one: hairline between rows, edge between blocks, hard under a masthead. Picking by name keeps a page from drifting into five hand-tuned greys.
|
|
42
|
+
A rule, with or without words in it. In a monochrome system the rule does the work colour would otherwise do, so it has three weights rather than one: hairline between rows, edge between blocks, hard under a masthead. Picking by name keeps a page from drifting into five hand-tuned greys. **On the label.** "or continue with" was two Separators and a span at every call site, and the usual one-element version — text laid over a single rule with a background to punch a hole in it — needs to know the ground it is sitting on. Get that wrong and the notch is `--paper` on a card that is `--stone`, which reads as a rendering bug. So there is no ground: the rule is drawn twice, one piece either side of the label, and the gap is a gap. It is correct on any surface without being told which one it is on.
|
|
21
43
|
|
|
22
44
|
### Props
|
|
23
45
|
|
|
24
46
|
- `orientation` — `'horizontal' | 'vertical'` default `'horizontal'`.
|
|
25
47
|
- `weight` — `'hairline' | 'edge' | 'hard'` default `'hairline'`. `hairline` divides rows inside one block; `edge` divides one block from the next.
|
|
26
48
|
- `decorative` — `boolean` default `true`. A rule that only groups things visually is decoration and must not be announced. Set `false` when the rule genuinely separates two sections a screen reader should hear as distinct.
|
|
49
|
+
- `label` — `ReactNode`. Words in the break — "or continue with", "Older". Horizontal only, and it changes the construction rather than the styling: see the note on the component. `decorative` no longer applies, because the label is content and the two rules beside it are decoration either way.
|
|
27
50
|
|
|
28
51
|
Also accepts: `HTMLAttributes<HTMLDivElement>`.
|
|
29
52
|
|
|
@@ -32,4 +55,5 @@ Also accepts: `HTMLAttributes<HTMLDivElement>`.
|
|
|
32
55
|
```tsx
|
|
33
56
|
<Separator weight="hard" />
|
|
34
57
|
<Separator orientation="vertical" className="h-4" />
|
|
58
|
+
<Separator label="or continue with" />
|
|
35
59
|
```
|
|
@@ -4,7 +4,7 @@ A call chain over time: who asks whom, in what order, and what comes back.
|
|
|
4
4
|
|
|
5
5
|
- Group: Diagrams
|
|
6
6
|
- Import: `import { SequenceFigure } from '@misoto22/design/diagrams'`
|
|
7
|
-
- Version: 0.
|
|
7
|
+
- Version: 0.8.0
|
|
8
8
|
- Docs: https://ui.misoto22.com/components/sequence-figure/
|
|
9
9
|
- Related: workflow-figure, architecture-figure
|
|
10
10
|
|
|
@@ -12,6 +12,28 @@ A call chain over time: who asks whom, in what order, and what comes back.
|
|
|
12
12
|
|
|
13
13
|
The only figure whose vertical axis means something. A message carries an explicit y, so two calls eight units apart happened together and two two hundred apart did not.
|
|
14
14
|
|
|
15
|
+
## Anatomy
|
|
16
|
+
|
|
17
|
+
- **Figure shell** (required) — The frame around the picture. What a trace hands it is a message list, and it is published in the order the messages array is written — which is the only ordering a reader who cannot see the axis is given.
|
|
18
|
+
- **Participant head** (required) — A 148-unit plate per participant at the top of its column, in the order the participants array puts them. meta.column_fit: "spread" widens every column to the widest name instead of holding the fixed width.
|
|
19
|
+
- **Lifeline** (required) — A hairline dropped from each head to below the last thing on the axis. A hairline and not a rule, because it is the axis: seven lifelines at message weight is seven vertical lines competing with twelve horizontal ones.
|
|
20
|
+
- **Message** (required) — A horizontal line at its own y, inset from both lifelines so the arrowhead lands clear of the axis, with the wording on a mask above it. A return is dashed AND takes an open head — two signals, because the reply is what a reader picks out of a dense trace.
|
|
21
|
+
- **Activation bar** — A narrow bar on a lifeline from one y to another: who is BUSY. It is the fact a sequence diagram carries that a list of calls does not, and one bar overlapping another is the reason to draw the picture at all.
|
|
22
|
+
- **Segment band** — A dashed rule across the whole figure with a mono caption on a masked patch — request, fallback, response. A caption rather than a tinted panel, because a second ground inside the figure would sit under every message label’s mask.
|
|
23
|
+
|
|
24
|
+
## Best practices
|
|
25
|
+
|
|
26
|
+
### Do
|
|
27
|
+
|
|
28
|
+
- Author the messages in ascending y. The picture reads the axis and the summary list beside it iterates the array, so a message written out of order is drawn at one point in the exchange and read aloud at another.
|
|
29
|
+
- Reach for meta.column_fit: "spread" when a participant’s name is longer than the fixed column. The plate wraps to two lines and ellipsises whatever still does not fit, and shortening the name to make it fit is not a repair — the name is the data.
|
|
30
|
+
- Space the messages by what actually happened. Nothing normalises y, so eight units between two calls reads as together and two hundred reads as a wait; an evenly spaced list is tidier and says something the trace does not.
|
|
31
|
+
|
|
32
|
+
### Don’t
|
|
33
|
+
|
|
34
|
+
- A message naming a participant that participants does not declare leaves the picture and the summary list together — there is no column to draw it between, and a text equivalent reporting a call the picture cannot show is two halves of one figure disagreeing. Development prints DIAGRAM_EDGE_DANGLING with both ends, which is now the only place that message is reported at all.
|
|
35
|
+
- This figure ASSERTS order. Three calls a service makes concurrently, given three y values because they had to be given something, are a picture claiming the second waited for the first — an activation bar or a segment caption is where "these overlap" belongs.
|
|
36
|
+
|
|
15
37
|
## Accessibility
|
|
16
38
|
|
|
17
39
|
- Return messages are dashed AND take an open arrowhead — two signals, because the reply is what a reader most often needs to pick out of a dense trace.
|
package/dist/agent/Sheet.md
CHANGED
|
@@ -4,7 +4,7 @@ A panel docked to an edge of the viewport.
|
|
|
4
4
|
|
|
5
5
|
- Group: Overlays
|
|
6
6
|
- Import: `import { Sheet } from '@misoto22/design'`
|
|
7
|
-
- Version: 0.
|
|
7
|
+
- Version: 0.8.0
|
|
8
8
|
- Docs: https://ui.misoto22.com/components/sheet/
|
|
9
9
|
- Related: dialog, popover
|
|
10
10
|
|
|
@@ -12,6 +12,29 @@ A panel docked to an edge of the viewport.
|
|
|
12
12
|
|
|
13
13
|
A modal that needs room — a filter panel, a detail view. It IS a Dialog, docked; the sides are named in reading order, so `end` is the right in English and the left in Arabic.
|
|
14
14
|
|
|
15
|
+
## Anatomy
|
|
16
|
+
|
|
17
|
+
- **Scrim** (required) — The same --scrim at --z-overlay that Dialog uses — the same component, in fact, so the page behind is inert and scroll-locked exactly as it is under a dialog.
|
|
18
|
+
- **Panel** (required) — The docked box. start and end are a min(24rem, 92vw) column at full height; top and bottom are a full-width band capped at 85vh. A flex column that scrolls itself.
|
|
19
|
+
- **Title** (required) — title, typed as required rather than optional — there is no unnamed-sheet path to fall into, only a hidden-title one via hideTitle.
|
|
20
|
+
- **Description** — description, under the title, sharing the wrapper that hideTitle hides.
|
|
21
|
+
- **Close** (required) — The X in the top-end corner. Unlike Dialog there is no showClose to turn it off, so every sheet has one whichever edge it is docked to.
|
|
22
|
+
|
|
23
|
+
## Best practices
|
|
24
|
+
|
|
25
|
+
### Do
|
|
26
|
+
|
|
27
|
+
- Reach for a Sheet over a Dialog when the content is a list or a form long enough to scroll: it gets the full height of the viewport rather than Dialog’s 32rem by 85vh box, and the reader keeps the page edge as an anchor.
|
|
28
|
+
- Use top or bottom when the content is wide and short — a filter bar, a date range. start and end are a 24rem column, and a table pushed into one wraps into a ribbon.
|
|
29
|
+
- Name the sides start and end rather than reaching for left and right: each edge has its own literal class string carrying its own rtl: variant, so end arrives from the right in English and the left in Arabic with no second code path.
|
|
30
|
+
- Wrap the cancelling control in SheetClose so the close runs through Radix — a sheet closed by your own state setter leaves focus inside a panel that is no longer on the page.
|
|
31
|
+
|
|
32
|
+
### Don’t
|
|
33
|
+
|
|
34
|
+
- Do not re-declare the travel in className. The panel carries data-m22-animated, which removes its transform outright under reduced motion; a second transform of your own only gets the universal floor, so it still arrives — a hundredth of a millisecond later, from wherever you put it.
|
|
35
|
+
- An OverlayContainer whose element is not positioned docks the sheet to the wrong box: naming a container switches the panel from fixed to absolute, so an unpositioned container sends it to the nearest positioned ancestor rather than to the frame.
|
|
36
|
+
- It is a modal dialog, so the page behind is scroll-locked and pointer-inert: this is not the home for a filter panel the reader is meant to work alongside. That is a Popover, or a column in the layout.
|
|
37
|
+
|
|
15
38
|
## Accessibility
|
|
16
39
|
|
|
17
40
|
- Shares Dialog’s focus trap, Escape handling and scroll lock rather than reproducing them — a second focus trap is a second one to get wrong.
|
|
@@ -32,7 +55,7 @@ Radix Dialog root, trigger and close — a sheet IS a dialog, docked.
|
|
|
32
55
|
|
|
33
56
|
## SheetContent
|
|
34
57
|
|
|
35
|
-
A panel docked to an edge of the viewport. It is a modal dialog — Radix's, so the focus trap, the escape key, the scroll lock and the `aria-modal` wiring are the same ones `Dialog` gets. The only differences are where it sits and which way it arrives, which is why this shares that implementation rather than reproducing it: a second focus trap is a second focus trap to get wrong. The title is required, visible or not. A modal with no accessible name drops a screen reader into an unnamed region with no way back out.
|
|
58
|
+
A panel docked to an edge of the viewport. It is a modal dialog — Radix's, so the focus trap, the escape key, the scroll lock and the `aria-modal` wiring are the same ones `Dialog` gets. The only differences are where it sits and which way it arrives, which is why this shares that implementation rather than reproducing it: a second focus trap is a second focus trap to get wrong. The title is required, visible or not. A modal with no accessible name drops a screen reader into an unnamed region with no way back out. Portals into the element an enclosing `OverlayContainer` names, docking to that element's edge rather than the viewport's when there is one.
|
|
36
59
|
|
|
37
60
|
### Props
|
|
38
61
|
|
package/dist/agent/Skeleton.md
CHANGED
|
@@ -4,7 +4,7 @@ The shape of the page, before the page.
|
|
|
4
4
|
|
|
5
5
|
- Group: Feedback
|
|
6
6
|
- Import: `import { Skeleton } from '@misoto22/design'`
|
|
7
|
-
- Version: 0.
|
|
7
|
+
- Version: 0.8.0
|
|
8
8
|
- Docs: https://ui.misoto22.com/components/skeleton/
|
|
9
9
|
- Related: spinner, empty-state
|
|
10
10
|
|
|
@@ -12,6 +12,28 @@ The shape of the page, before the page.
|
|
|
12
12
|
|
|
13
13
|
A wait the reader would otherwise think was a broken page. A shape that describes what is coming beats a dot that describes nothing.
|
|
14
14
|
|
|
15
|
+
## Anatomy
|
|
16
|
+
|
|
17
|
+
- **Frame** (required) — SkeletonPage: the div carrying role="status", aria-busy="true" and the single pulse. It is the only part that speaks and the only part that moves — the shapes inside it do neither.
|
|
18
|
+
- **Label** (required) — The sr-only sentence inside the frame, from the required label prop. Every shape is aria-hidden, so this one sentence is the entire loading state for a screen reader.
|
|
19
|
+
- **Fill** — Skeleton itself: a --stone rectangle one line tall — h-3 — and, being a div, already full width. Height is the one dimension the element does not have on its own, so that is the one the base supplies; anything in className replaces it.
|
|
20
|
+
- **Line, Block and Circle** — The three presets over that fill. SkeletonLine is a 12px pill and takes its width from the caller, SkeletonBlock only sets --radius-sm, and SkeletonCircle is a fixed 36px round.
|
|
21
|
+
- **Paragraph** — SkeletonText: three lines by default, the last at 62% so it ends mid-measure the way prose does rather than squaring off into a table.
|
|
22
|
+
|
|
23
|
+
## Best practices
|
|
24
|
+
|
|
25
|
+
### Do
|
|
26
|
+
|
|
27
|
+
- Wrap the shapes in SkeletonPage even when there is only one bar. The role, the aria-busy and the pulse all live on the frame, so parts used loose are aria-hidden, silent and completely still — a grey rectangle that never resolves.
|
|
28
|
+
- Give every Skeleton the height of the thing it stands in for. The base falls back to one line, so a block left unsized is no longer invisible — it is a 12px bar where a 160px plate is about to land, and the page jumps by the difference.
|
|
29
|
+
- Make whatever replaces the skeleton announce itself or take focus. aria-busy never flips to false here — the frame is unmounted, not updated — so the end of the wait is the disappearance of the only thing that was speaking.
|
|
30
|
+
|
|
31
|
+
### Don’t
|
|
32
|
+
|
|
33
|
+
- Do not add animate-pulse to a part. The frame already animates opacity and a second ramp on a child multiplies with it, so the part beats at a rate the shape around it does not. Reduced motion is not the reason it is wrong: the rule in keyframes.css is a universal floor on animation-duration and transition-duration, so a hand-written Tailwind animation is clamped along with everything else. data-m22-animated is a component asserting its motion is decorative, not the mechanism that does the cancelling.
|
|
34
|
+
- Do not nest one SkeletonPage inside another. Each is a role="status" region with its own sr-only sentence, so a page assembled from two skeleton sections announces two loading messages and marks two regions busy for a single wait.
|
|
35
|
+
- Do not carry a skeleton between screens unedited. SkeletonCircle is 36px and SkeletonLine is 12px tall whatever they stand in for, so a copied avatar mount and a copied heading are two guaranteed reflows the moment the real content lands.
|
|
36
|
+
|
|
15
37
|
## Accessibility
|
|
16
38
|
|
|
17
39
|
- One live region on the wrapper; every shape inside it is aria-hidden.
|
|
@@ -19,7 +41,7 @@ A wait the reader would otherwise think was a broken page. A shape that describe
|
|
|
19
41
|
|
|
20
42
|
## Skeleton
|
|
21
43
|
|
|
22
|
-
The fill every skeleton part is drawn from: `--stone`,
|
|
44
|
+
The fill every skeleton part is drawn from: `--stone`, at the height of one line until something says otherwise. Deliberately NOT a shimmer. A shimmer sweeps a highlight across the shape, which implies a light source; the White Reset has none, so the sweep reads as a bug rather than as loading. The whole page breathes together instead — see `SkeletonPage`, which owns the single pulse. `h-3` is a default rather than a design. A `<div>` is already full width, so height was the one dimension a caller could omit and get nothing for — a bare `<Skeleton />` was a zero-height box, which is not a small skeleton but an absent one. Twelve pixels is the height `SkeletonLine` already chose, and any class the caller passes replaces it.
|
|
23
45
|
|
|
24
46
|
Also accepts: `HTMLAttributes<HTMLDivElement>`.
|
|
25
47
|
|
package/dist/agent/Slider.md
CHANGED
|
@@ -4,14 +4,37 @@ A value chosen along a range.
|
|
|
4
4
|
|
|
5
5
|
- Group: Forms
|
|
6
6
|
- Import: `import { Slider } from '@misoto22/design'`
|
|
7
|
-
- Version: 0.
|
|
7
|
+
- Version: 0.8.0
|
|
8
8
|
- Docs: https://ui.misoto22.com/components/slider/
|
|
9
9
|
- Related: progress
|
|
10
10
|
|
|
11
|
+
## Anatomy
|
|
12
|
+
|
|
13
|
+
- **Track** (required) — A 1px rule in --stone that thickens to 1.5 when the pointer is anywhere over the control, not only over the thumb.
|
|
14
|
+
- **Range** — The --accent fill from the minimum to the thumb, or between the two thumbs of a range.
|
|
15
|
+
- **Thumb** — One per entry in the value array — so the number of thumbs comes from the value, not from a prop, and a slider given neither value nor defaultValue falls back to the primitive’s own default of one thumb at the minimum. Each is a 16px circle with an invisible 44px hit area from a before pseudo-element.
|
|
16
|
+
- **Value readout** — Only with showValue: a mono row above the track, the names on the start edge and the formatted values on the end, each joined by an en dash and in the thumbs’ own order — so a two-ended range reads “Minimum – Maximum” over “10 – 90”.
|
|
17
|
+
|
|
18
|
+
## Best practices
|
|
19
|
+
|
|
20
|
+
### Do
|
|
21
|
+
|
|
22
|
+
- Pass defaultValue or value whenever there is more than one end to it. The thumb count comes from that array, so a price filter left to the default is a single thumb sitting at the minimum.
|
|
23
|
+
- Pass an array of two names for a two-thumb range: every thumb after the first falls back to names[0], so both ends of a price filter otherwise announce themselves as “Minimum”.
|
|
24
|
+
- Put an Input beside it when the exact number matters. A slider cannot be typed into, and someone who needs 37 rather than roughly 40 is dragging a 16px thumb across a hundred steps to get it.
|
|
25
|
+
|
|
26
|
+
### Don’t
|
|
27
|
+
|
|
28
|
+
- format becomes each thumb’s aria-valuetext, which REPLACES the number rather than decorating it — so a formatter that rounds hard or drops the unit is what a screen reader gets instead of the value.
|
|
29
|
+
- Do not disable a slider to make it read-only: the whole control dims and stops taking the pointer, and Radix drops the thumb out of the tab order, so the value becomes unreachable rather than uneditable.
|
|
30
|
+
- Do not pass two names to a one-thumb slider: the heading prints one name per THUMB, so the second is drawn nowhere and announced nowhere.
|
|
31
|
+
- A Field’s label above it does not name it and does not click through: the role is on the THUMB and the root is a <span>, so the label prop here is the only name a reader hears. The hint and the error do reach the thumb.
|
|
32
|
+
|
|
11
33
|
## Accessibility
|
|
12
34
|
|
|
13
35
|
- label is required. A thumb that announces "42" and nothing else leaves a screen reader user with a number and no idea what it measures.
|
|
14
36
|
- A 44px hit area sits invisibly around the 16px thumb.
|
|
37
|
+
- format is announced as aria-valuetext, so a thumb showing “$1,200” says that rather than 1200.
|
|
15
38
|
- Arrows step, Page keys jump, Home and End reach the ends.
|
|
16
39
|
|
|
17
40
|
## Keyboard
|
|
@@ -22,13 +45,13 @@ A value chosen along a range.
|
|
|
22
45
|
|
|
23
46
|
## Slider
|
|
24
47
|
|
|
25
|
-
A value chosen along a range. Radix owns the keyboard contract — arrows step, Page keys jump, Home and End reach the ends — and the ARIA that reports the value. What is here is the look, and the labelling, which is the part a slider most often gets wrong: a thumb that announces "42" and nothing else leaves a screen reader user with a number and no idea what it measures. A 44px hit area sits invisibly around the 16px thumb, because a thumb sized for the design is well under any pointer-target guideline.
|
|
48
|
+
A value chosen along a range. Radix owns the keyboard contract — arrows step, Page keys jump, Home and End reach the ends — and the ARIA that reports the value. What is here is the look, and the labelling, which is the part a slider most often gets wrong: a thumb that announces "42" and nothing else leaves a screen reader user with a number and no idea what it measures. A 44px hit area sits invisibly around the 16px thumb, because a thumb sized for the design is well under any pointer-target guideline. Inside a `Field`, the hint, the error and the requirement land on the THUMB, which is the element carrying `role="slider"` — on the root they would sit on a `<span>` with no role and announce nothing. The NAME still comes from `label` here: a field's label above a slider points at that same roleless root, so it neither names the control nor clicks through to it.
|
|
26
49
|
|
|
27
50
|
### Props
|
|
28
51
|
|
|
29
52
|
- `label` (required) — `string | [string, string]`. Names the control. Required: a slider with no name announces only a number, and a number with no noun is not information. A range slider (two thumbs) needs one name per thumb — pass an array.
|
|
30
|
-
- `showValue` — `boolean` default `false`. Prints the current value beside the label.
|
|
31
|
-
- `format` — `(value: number) => string
|
|
53
|
+
- `showValue` — `boolean` default `false`. Prints the current value beside the label. A two-thumb range prints both names and both values, in the same order — the heading used to print the first name over a pair of numbers, which read as "Minimum" over "10 – 90".
|
|
54
|
+
- `format` — `(value: number) => string`. Renders the value with a unit or a currency, e.g. `(n) => n + '%'`. Reaches assistive tech as well as the readout: it becomes each thumb's `aria-valuetext`, so a thumb showing "$1,200" announces that rather than the bare number. Left off, the platform announces the value itself.
|
|
32
55
|
|
|
33
56
|
Also accepts: `ComponentProps<typeof SliderPrimitive.Root>`.
|
|
34
57
|
|
package/dist/agent/Sparkline.md
CHANGED
|
@@ -4,7 +4,7 @@ A run of numbers at the size of a word.
|
|
|
4
4
|
|
|
5
5
|
- Group: Data
|
|
6
6
|
- Import: `import { Sparkline } from '@misoto22/design/charts'`
|
|
7
|
-
- Version: 0.
|
|
7
|
+
- Version: 0.8.0
|
|
8
8
|
- Docs: https://ui.misoto22.com/components/sparkline/
|
|
9
9
|
- Related: line-chart, table
|
|
10
10
|
|
|
@@ -12,6 +12,28 @@ A run of numbers at the size of a word.
|
|
|
12
12
|
|
|
13
13
|
In a table cell, beside a figure, at the end of a row. When the trend needs reading precisely it wants a LineChart and its own space.
|
|
14
14
|
|
|
15
|
+
## Anatomy
|
|
16
|
+
|
|
17
|
+
- **Inline row** (required) — An inline-flex span, full width with 8px of gap, so the run sits in a table cell or beside a figure without breaking the line it is on.
|
|
18
|
+
- **Plot** (required) — One svg role="img" over a 0–100 by 0–100 viewBox with preserveAspectRatio="none", so it stretches to whatever width the container gives it. height, 28px by default, is the only fixed dimension.
|
|
19
|
+
- **Mark** (required) — The path, its area fill, or the bars — variant picks one. The stroke is drawn with non-scaling-stroke, which is what keeps the line the same weight in a narrow cell and a wide one after the box has been stretched to fit.
|
|
20
|
+
- **Last point** — A 2px dot on the final reading, from showLast, on the line and area variants. The bars variant carries the end of the run in its own last bar and draws no dot.
|
|
21
|
+
- **Printed value** — value, in mono tabular figures after the plot. It is also what the accessible name says after the label, and it is the only figure this component ever prints.
|
|
22
|
+
- **Too-short state** — What renders in place of the whole plot when fewer than two finite numbers survive: the label and “not enough data”, as one line of mono meta text.
|
|
23
|
+
|
|
24
|
+
## Best practices
|
|
25
|
+
|
|
26
|
+
### Do
|
|
27
|
+
|
|
28
|
+
- Pass value whenever a figure matters. The plot has no axis and no scale, so it carries shape and nothing else, and value is both the one number printed and the reading appended to the accessible name. Left out, that name falls back to the last point through toLocaleString — the raw number, without the unit, the currency or the rounding the row beside it uses.
|
|
29
|
+
- Pin domain across any two that will be read against each other. Each run is normalised into the same fixed box from its OWN min and max, so the highest point always touches the top edge and the lowest always the floor: a series moving between 4 and 6 and a series moving between 400 and 900 draw the same silhouette, and the difference between them is drawn nowhere.
|
|
30
|
+
- Downsample a long run before handing it over. The x step is 100 divided by one less than the number of points, spread across whatever width the cell has, so four hundred readings in a 200px cell land half a pixel apart and the path fills in as a band.
|
|
31
|
+
- Read a flat line through the middle as “unchanged”, not as “at its floor”. A run whose min equals its max has a scale with no width, so no position on it is truer than another and every point sits at the centre — the same answer Heatmap and BulletChart give a zero span, and the one that keeps “unchanged” and “pinned at its worst” apart in a column of them.
|
|
32
|
+
|
|
33
|
+
### Don’t
|
|
34
|
+
|
|
35
|
+
- Do not assume something chart-shaped always renders. Non-finite entries are filtered out first, and anything left under two points returns a line of text instead of an SVG, so the new account’s row is a sentence where every other row in the column is a chart.
|
|
36
|
+
|
|
15
37
|
## Accessibility
|
|
16
38
|
|
|
17
39
|
- label is required and is the whole accessible name: a sparkline has no axes and no legend, so nothing else describes it.
|