@misoto22/design 0.6.1 → 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 +62 -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 +71 -0
- 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 +48 -0
- 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 +70 -0
- package/dist/agent/DiagramExportMenu.md +64 -0
- package/dist/agent/DiagramInspector.md +72 -0
- package/dist/agent/DiagramLegend.md +55 -0
- package/dist/agent/DiagramMinimap.md +68 -0
- package/dist/agent/DiagramToolbar.md +69 -0
- 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 +49 -0
- 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 +50 -0
- 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 +50 -0
- package/dist/agent/catalog.json +6086 -1009
- package/dist/agent/index.md +27 -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/index.d.ts +2 -1
- package/dist/charts/lib/export.d.ts +34 -43
- package/dist/charts/lib/export.js +16 -158
- package/dist/charts/lib/export.js.map +1 -1
- 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 +55 -0
- package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.js +175 -0
- package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.js.map +1 -0
- package/dist/diagrams/DataflowFigure/DataflowFigure.d.ts +28 -0
- package/dist/diagrams/DataflowFigure/DataflowFigure.js +148 -0
- package/dist/diagrams/DataflowFigure/DataflowFigure.js.map +1 -0
- package/dist/diagrams/DiagramCanvas/DiagramCanvas.d.ts +78 -0
- package/dist/diagrams/DiagramCanvas/DiagramCanvas.js +229 -0
- package/dist/diagrams/DiagramCanvas/DiagramCanvas.js.map +1 -0
- package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.d.ts +106 -0
- package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.js +123 -0
- package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.js.map +1 -0
- package/dist/diagrams/DiagramInspector/DiagramInspector.d.ts +70 -0
- package/dist/diagrams/DiagramInspector/DiagramInspector.js +94 -0
- package/dist/diagrams/DiagramInspector/DiagramInspector.js.map +1 -0
- package/dist/diagrams/DiagramLegend/DiagramLegend.d.ts +42 -0
- package/dist/diagrams/DiagramLegend/DiagramLegend.js +35 -0
- package/dist/diagrams/DiagramLegend/DiagramLegend.js.map +1 -0
- package/dist/diagrams/DiagramMinimap/DiagramMinimap.d.ts +77 -0
- package/dist/diagrams/DiagramMinimap/DiagramMinimap.js +106 -0
- package/dist/diagrams/DiagramMinimap/DiagramMinimap.js.map +1 -0
- package/dist/diagrams/DiagramToolbar/DiagramToolbar.d.ts +48 -0
- package/dist/diagrams/DiagramToolbar/DiagramToolbar.js +53 -0
- package/dist/diagrams/DiagramToolbar/DiagramToolbar.js.map +1 -0
- package/dist/diagrams/LifecycleFigure/LifecycleFigure.d.ts +31 -0
- package/dist/diagrams/LifecycleFigure/LifecycleFigure.js +234 -0
- package/dist/diagrams/LifecycleFigure/LifecycleFigure.js.map +1 -0
- package/dist/diagrams/SequenceFigure/SequenceFigure.d.ts +38 -0
- package/dist/diagrams/SequenceFigure/SequenceFigure.js +261 -0
- package/dist/diagrams/SequenceFigure/SequenceFigure.js.map +1 -0
- package/dist/diagrams/WorkflowFigure/WorkflowFigure.d.ts +36 -0
- package/dist/diagrams/WorkflowFigure/WorkflowFigure.js +259 -0
- package/dist/diagrams/WorkflowFigure/WorkflowFigure.js.map +1 -0
- package/dist/diagrams/index.d.ts +17 -0
- package/dist/diagrams/index.js +29 -0
- package/dist/diagrams/index.js.map +1 -0
- 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 +138 -0
- package/dist/diagrams/lib/frame.js +131 -0
- package/dist/diagrams/lib/frame.js.map +1 -0
- package/dist/diagrams/lib/geometry.d.ts +114 -0
- package/dist/diagrams/lib/geometry.js +113 -0
- package/dist/diagrams/lib/geometry.js.map +1 -0
- package/dist/diagrams/lib/legend.d.ts +32 -0
- package/dist/diagrams/lib/legend.js +84 -0
- package/dist/diagrams/lib/legend.js.map +1 -0
- package/dist/diagrams/lib/marks.d.ts +207 -0
- package/dist/diagrams/lib/marks.js +480 -0
- package/dist/diagrams/lib/marks.js.map +1 -0
- package/dist/diagrams/lib/route.d.ts +85 -0
- package/dist/diagrams/lib/route.js +178 -0
- package/dist/diagrams/lib/route.js.map +1 -0
- package/dist/diagrams/lib/wires.d.ts +59 -0
- package/dist/diagrams/lib/wires.js +90 -0
- package/dist/diagrams/lib/wires.js.map +1 -0
- package/dist/diagrams/spec.d.ts +405 -0
- package/dist/diagrams/spec.js +1 -0
- package/dist/diagrams/spec.js.map +1 -0
- 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/svg-export.d.ts +138 -0
- package/dist/lib/svg-export.js +198 -0
- package/dist/lib/svg-export.js.map +1 -0
- 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 +51 -6
- package/dist/styles.css +1 -1
- package/dist/tokens.css +20 -2
- package/dist/tokens.d.ts +17 -1
- package/dist/tokens.js +121 -36
- package/dist/tokens.json +121 -36
- package/llms.txt +35 -0
- package/package.json +9 -2
- package/skills/misoto22-design/SKILL.md +21 -7
- 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/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.
|
package/dist/agent/Spinner.md
CHANGED
|
@@ -4,7 +4,7 @@ The one “working” indicator — a ring, never a shimmer.
|
|
|
4
4
|
|
|
5
5
|
- Group: Feedback
|
|
6
6
|
- Import: `import { Spinner } from '@misoto22/design'`
|
|
7
|
-
- Version: 0.
|
|
7
|
+
- Version: 0.8.0
|
|
8
8
|
- Docs: https://ui.misoto22.com/components/spinner/
|
|
9
9
|
- Related: skeleton, progress
|
|
10
10
|
|
|
@@ -12,6 +12,27 @@ The one “working” indicator — a ring, never a shimmer.
|
|
|
12
12
|
|
|
13
13
|
A wait short enough that the shape of what is coming does not matter. Longer than that, use a Skeleton.
|
|
14
14
|
|
|
15
|
+
## Anatomy
|
|
16
|
+
|
|
17
|
+
- **Live region** (required) — The outer span, and the only part with a voice. It carries role="status" while there is a label; pass label={null} and it turns into an aria-hidden box with no role at all.
|
|
18
|
+
- **Ring** (required) — The inner span — 14px, 18px or 26px of border on a transparent box, and the only element size, tone and className reach.
|
|
19
|
+
- **Leading quarter** (required) — border-t, drawn in --ink at the default tone and in the inherited colour at current. It is the whole difference between a ring and a plain circle, which is why a still ring still reads as unfinished.
|
|
20
|
+
- **Screen-reader label** — An sr-only span holding label, present unless label is null. Announced once, when the spinner mounts, and never again.
|
|
21
|
+
|
|
22
|
+
## Best practices
|
|
23
|
+
|
|
24
|
+
### Do
|
|
25
|
+
|
|
26
|
+
- Pass tone="current" for a spinner on any filled ground: the default draws the leading quarter in --ink over a --rule-2 track, and inside a primary Button both of those are the ground it is sitting on.
|
|
27
|
+
- Announce the arrival somewhere else. The label is read once on mount and nothing is said on the way out, so a reader who heard “Loading projects” is never told the projects came.
|
|
28
|
+
- Reach for label={null} only inside a control that already names the operation — it hides the whole element from assistive tech rather than merely dropping the text, so a silenced spinner standing on its own is a wait nobody is told about.
|
|
29
|
+
|
|
30
|
+
### Don’t
|
|
31
|
+
|
|
32
|
+
- label defaults to the bare word “Loading”, so a Spinner written without the prop ships the exact announcement the prop exists to prevent — the default is a placeholder, not a value.
|
|
33
|
+
- className is merged onto the ring AFTER size and tone, so it beats both: <Spinner size="lg" className="size-4" /> is a 16px ring, and the prop whose whole job was naming the size is the one that lost.
|
|
34
|
+
- Nothing here sets aria-busy — Button does that for its own control — so a spinner laid over a panel leaves the panel announced as ready while its contents are stale and its buttons still take clicks.
|
|
35
|
+
|
|
15
36
|
## Accessibility
|
|
16
37
|
|
|
17
38
|
- label names the specific thing being waited on; three spinners all saying “Loading” tell a screen reader nothing.
|
|
@@ -20,12 +41,13 @@ A wait short enough that the shape of what is coming does not matter. Longer tha
|
|
|
20
41
|
|
|
21
42
|
## Spinner
|
|
22
43
|
|
|
23
|
-
The system's one "working" indicator. A ring, not a blurred glow and not a shimmer: the White Reset has no light source, so depth and softness are not available to it. The leading quarter is the only thing that distinguishes the ring from a plain circle, which is why the track stays a hairline — a spinner is a hint that time is passing, not a feature of the page. It spins under `motion-safe` only. A reader who has asked for less motion gets a static ring, which still reads as "not finished" because the leading quarter is darker than the track. For a wait long enough that the reader would otherwise wonder whether the page is broken, prefer `Skeleton` — a shape that describes what is coming beats a dot that describes nothing.
|
|
44
|
+
The system's one "working" indicator. A ring, not a blurred glow and not a shimmer: the White Reset has no light source, so depth and softness are not available to it. The leading quarter is the only thing that distinguishes the ring from a plain circle, which is why the track stays a hairline — a spinner is a hint that time is passing, not a feature of the page. It spins under `motion-safe` only. A reader who has asked for less motion gets a static ring, which still reads as "not finished" because the leading quarter is darker than the track. For a wait long enough that the reader would otherwise wonder whether the page is broken, prefer `Skeleton` — a shape that describes what is coming beats a dot that describes nothing. `className` reaches the RING, alongside `size` and `tone`, and overrides them: every utility a caller has for a spinner is about the ring, and merged onto the wrapper instead `className="size-8"` grew an invisible box around an unchanged 18px circle. Layout still works from there — the wrapper is `inline-flex` and takes the ring's margin box as its own.
|
|
24
45
|
|
|
25
46
|
### Props
|
|
26
47
|
|
|
27
48
|
- `size` — `'sm' | 'md' | 'lg'` default `'md'`. 14px / 18px / 26px. Match the size of the type it sits beside.
|
|
28
49
|
- `tone` — `'default' | 'current'` default `'default'`. `default` draws the ring against the page — a hairline track in the rule colour with the leading quarter in ink. `current` draws it in the inherited text colour, which is what a spinner inside a filled button needs: on an ink ground an ink ring is invisible.
|
|
50
|
+
- `className` — `string`. Merged onto the RING, after `size` and `tone`, so it overrides both.
|
|
29
51
|
- `label` — `string | null` default `'Loading'`. Announced to assistive tech. Pass the specific thing being waited on ("Loading projects"), not the generic word — a screen reader user hearing "Loading" three times cannot tell which three things. Pass `null` for a spinner that sits inside a control which already names the operation (a button whose own label changes to "Saving…"), so the two are not read out twice.
|
|
30
52
|
|
|
31
53
|
Also accepts: `HTMLAttributes<HTMLSpanElement>`.
|
package/dist/agent/StatusDot.md
CHANGED
|
@@ -4,10 +4,29 @@ The dot beside a status word.
|
|
|
4
4
|
|
|
5
5
|
- Group: Display
|
|
6
6
|
- Import: `import { StatusDot } from '@misoto22/design'`
|
|
7
|
-
- Version: 0.
|
|
7
|
+
- Version: 0.8.0
|
|
8
8
|
- Docs: https://ui.misoto22.com/components/status-dot/
|
|
9
9
|
- Related: status-pill
|
|
10
10
|
|
|
11
|
+
## Anatomy
|
|
12
|
+
|
|
13
|
+
- **Box** (required) — The aria-hidden <span> the whole thing lives in — 8px square at md, 7px at sm, inline-grid and shrink-0 so it stays circular in a flex row however long the label beside it runs.
|
|
14
|
+
- **Dot** (required) — An absolutely-positioned filled circle in --ok, --warn, --danger or --ink-3-aa. It is the only part of this component tone touches.
|
|
15
|
+
- **Halo** — A second ring of the same colour on the m22-halo keyframes, present only while pulse is true. A separate element rather than a box-shadow, because a shadow in this system is never blurred.
|
|
16
|
+
|
|
17
|
+
## Best practices
|
|
18
|
+
|
|
19
|
+
### Do
|
|
20
|
+
|
|
21
|
+
- Set pulse={false} for anything settled. It defaults to true, so a dot for a build that finished or a status that will not change today carries a halo announcing that something is happening right now.
|
|
22
|
+
- Reach for StatusPill the moment you find yourself writing the dot and its label together — that pairing assembled per call site is how one site ended up with three dot sizes and two pulse timings for the same state.
|
|
23
|
+
- Let it sit directly in the flex row beside its label: shrink-0 is what keeps it round, and a dot wrapped in a div that can shrink comes out an ellipse as soon as the label runs long.
|
|
24
|
+
|
|
25
|
+
### Don’t
|
|
26
|
+
|
|
27
|
+
- An aria-label on the dot buys nothing — aria-hidden is still set, and a hidden element has no name to give. A call site with no visible label is a state no screen reader ever reports.
|
|
28
|
+
- sm and md are 7px and 8px, one pixel apart. That is an optical adjustment for sitting beside smaller type, not a size scale, and nothing in a layout should be built on the difference.
|
|
29
|
+
|
|
11
30
|
## Accessibility
|
|
12
31
|
|
|
13
32
|
- aria-hidden without exception: it repeats a state the adjacent label already names.
|
package/dist/agent/StatusPill.md
CHANGED
|
@@ -4,13 +4,39 @@ A live state, named: a dot plus an uppercase mono label.
|
|
|
4
4
|
|
|
5
5
|
- Group: Display
|
|
6
6
|
- Import: `import { StatusPill } from '@misoto22/design'`
|
|
7
|
-
- Version: 0.
|
|
7
|
+
- Version: 0.8.0
|
|
8
8
|
- Docs: https://ui.misoto22.com/components/status-pill/
|
|
9
9
|
- Related: status-dot, badge
|
|
10
10
|
|
|
11
|
+
## Anatomy
|
|
12
|
+
|
|
13
|
+
- **Pill** (required) — The outlined <span>: --radius-pill, a --rule-2 hairline, --paper ground, and deliberately uneven padding — 10px before the dot, 12px after the label — so the pair sits optically centred rather than mathematically.
|
|
14
|
+
- **Dot** (required) — A StatusDot handed tone and pulse. It is aria-hidden, so it is not where the tone reaches a reader who cannot see it.
|
|
15
|
+
- **Label** (required) — children in the eyebrow idiom — 11px uppercase mono, tracking pulled back from 0.2em to 0.12em because a pill is a shorter run than a section kicker.
|
|
16
|
+
- **Severity** — A visually-hidden “Warning” or “Error” at the warning and danger tones, so those two reach a reader through something other than a colour on a hidden dot. success and neutral add nothing: they are the absence of alarm, which is what a reader already assumes.
|
|
17
|
+
|
|
18
|
+
## Best practices
|
|
19
|
+
|
|
20
|
+
### Do
|
|
21
|
+
|
|
22
|
+
- Put the state in the words anyway. The severity word reaches a screen reader and nothing else — the pill’s own text is --ink-2 at every tone, so on a monochrome screen “Degraded” in a warning pill and in a neutral one are still the same pill.
|
|
23
|
+
- Set pulse={false} once the state has settled — the default halo means “right now”, and an archived or shipped pill pulsing forever tells the reader something is live when nothing is.
|
|
24
|
+
- Take the whole pill rather than composing a dot and a span at the call site: that assembly is how the same “available for work” chip came out at three dot sizes and two pulse timings on one site.
|
|
25
|
+
|
|
26
|
+
### Don’t
|
|
27
|
+
|
|
28
|
+
- It is not a live region. The pill is a plain <span>, so a state flipping from Available to Degraded while the reader is on the page changes silently — if the change is the news, the call site owns the role="status" around it.
|
|
29
|
+
- One per view, not one per row. The label is an uppercase eyebrow at 0.12em tracking — the loudest small type the system has — and a column of them down a table is Badge’s job, which is why Badge carries the same status tones in plain 12px mono.
|
|
30
|
+
|
|
31
|
+
## Accessibility
|
|
32
|
+
|
|
33
|
+
- The warning and danger tones are doubled by a visually-hidden severity word, because the dot that carries the colour is aria-hidden and has no name to give.
|
|
34
|
+
- success and neutral are silent on purpose: announcing “OK” before every settled pill is noise charged to the two tones worth interrupting for.
|
|
35
|
+
- Not a live region. A state that flips while the reader is on the page changes silently unless the call site owns a role="status" around it.
|
|
36
|
+
|
|
11
37
|
## StatusPill
|
|
12
38
|
|
|
13
|
-
A live state, named: a dot plus an uppercase mono label in an outlined pill. One component rather than a dot and a pill assembled per call site, which is how the same "available for work" chip ended up with three different dot sizes and two different pulse timings on one site.
|
|
39
|
+
A live state, named: a dot plus an uppercase mono label in an outlined pill. One component rather than a dot and a pill assembled per call site, which is how the same "available for work" chip ended up with three different dot sizes and two different pulse timings on one site. A warning or danger tone is doubled by a visually-hidden severity word, so the tone survives the dot being hidden. It does not survive monochrome: the pill's own text is `--ink-2` at every tone, and the state itself still belongs in the words the call site writes.
|
|
14
40
|
|
|
15
41
|
### Props
|
|
16
42
|
|
package/dist/agent/Steps.md
CHANGED
|
@@ -4,7 +4,7 @@ A numbered sequence, as a rail — one thing after another, with a rule through
|
|
|
4
4
|
|
|
5
5
|
- Group: Display
|
|
6
6
|
- Import: `import { Steps } from '@misoto22/design'`
|
|
7
|
-
- Version: 0.
|
|
7
|
+
- Version: 0.8.0
|
|
8
8
|
- Docs: https://ui.misoto22.com/components/steps/
|
|
9
9
|
- Related: diagram, article
|
|
10
10
|
|
|
@@ -12,6 +12,29 @@ A numbered sequence, as a rail — one thing after another, with a rule through
|
|
|
12
12
|
|
|
13
13
|
A pipeline, a migration, a recipe: an order with no branches. The moment something forks or points at something else it is a Diagram, and drawing a fork as a list hides it.
|
|
14
14
|
|
|
15
|
+
## Anatomy
|
|
16
|
+
|
|
17
|
+
- **Rail** (required) — The <ol>, carrying --step-size — one number that three rules read: the marker’s own box, where the connector starts, and where it is centred.
|
|
18
|
+
- **Marker** (required) — A 2rem circle per step, aria-hidden: the position number, or a blank hairline node when marker is "rule". Filled with --accent for the current one.
|
|
19
|
+
- **Connector** — A hairline drawn on every item but the last, placed absolutely from the foot of that marker to the foot of its row — so it spans the gap rather than running behind the markers, and no tail hangs off the end of the sequence.
|
|
20
|
+
- **Title** (required) — step.title, at 15px in the interface face. The step’s name — a noun, not a description of what happens in it.
|
|
21
|
+
- **Note** — step.note, a mono line under the title: what the step is made of, what it costs, what it uses.
|
|
22
|
+
|
|
23
|
+
## Best practices
|
|
24
|
+
|
|
25
|
+
### Do
|
|
26
|
+
|
|
27
|
+
- Use marker="rule" for a sequence of states. “Queued, running, done” is an order rather than an instruction list, and a digit in front of each one tells the reader they are steps to perform.
|
|
28
|
+
- Mark at most one step current: it is the one thing the rail states rather than draws, and two filled markers put the process in two places at once.
|
|
29
|
+
- Pass label when no heading names the sequence — it is the list’s only name, so without it the rail is announced as five items belonging to nothing.
|
|
30
|
+
- Retune the rail through --step-size on the list rather than by restyling the marker: the marker box, the connector’s start and its centring all read that one number, and moving one of the three leaves the line beginning in mid-air.
|
|
31
|
+
|
|
32
|
+
### Don’t
|
|
33
|
+
|
|
34
|
+
- A fork drawn here is a fork the reader never sees. The connector runs from each step to the next one in the array and to nothing else, so two branches flatten into four consecutive steps and the choice between them leaves the figure entirely.
|
|
35
|
+
- steps={[]} renders null rather than an empty rail, so a list filtered down to nothing leaves a heading standing over a gap unless the call site checks the length itself.
|
|
36
|
+
- Nothing here is clickable and the props spread onto the <ol>, so an onClick meant for a step lands on the whole list. A sequence the reader is meant to move through is a Breadcrumb or a Tabs.
|
|
37
|
+
|
|
15
38
|
## Accessibility
|
|
16
39
|
|
|
17
40
|
- An <ol>, because the order IS the content — a stack of divs says nothing about sequence.
|
package/dist/agent/Switch.md
CHANGED
|
@@ -4,7 +4,7 @@ A setting that takes effect immediately.
|
|
|
4
4
|
|
|
5
5
|
- Group: Forms
|
|
6
6
|
- Import: `import { Switch } from '@misoto22/design'`
|
|
7
|
-
- Version: 0.
|
|
7
|
+
- Version: 0.8.0
|
|
8
8
|
- Docs: https://ui.misoto22.com/components/switch/
|
|
9
9
|
- Related: checkbox
|
|
10
10
|
|
|
@@ -12,6 +12,26 @@ A setting that takes effect immediately.
|
|
|
12
12
|
|
|
13
13
|
Inside a form with a Save button, a switch is a lie about when the change happened. Use a Checkbox.
|
|
14
14
|
|
|
15
|
+
## Anatomy
|
|
16
|
+
|
|
17
|
+
- **Track** (required) — A 36×20 <button role="switch"> on a pill radius, filled --stone when off and --accent when on. Filled rather than outlined, so it still reads as a control on a white page.
|
|
18
|
+
- **Thumb** (required) — A 14px paper circle with a hairline, not a white disc on a shadow — this system has no shadows. It stretches to 20px while pressed and rounds out as it lands; motion-reduce drops that entirely.
|
|
19
|
+
- **Label** — Not rendered here either. The Radix root IS a <button>, though, which a <label for> does bind to — so unlike Select or RadioGroup, a Field’s label above a Switch really does click through to it.
|
|
20
|
+
|
|
21
|
+
## Best practices
|
|
22
|
+
|
|
23
|
+
### Do
|
|
24
|
+
|
|
25
|
+
- Handle the failure at the control. The flip has already claimed the change happened, so an onCheckedChange whose request fails must put the thumb back and say why, or the page is showing a setting the server does not have.
|
|
26
|
+
- Name it for the state, not the action: the accessible name is read together with “on” or “off”, so “Email notifications, on” is a sentence and “Turn on email notifications, on” is two contradictory ones.
|
|
27
|
+
- Keep the flip instant to the eye even when the write is not — an optimistic thumb with a quiet undo beats a spinner on a control whose whole claim is that it already took effect.
|
|
28
|
+
|
|
29
|
+
### Don’t
|
|
30
|
+
|
|
31
|
+
- A switch has two states and no third. “Inherit from the workspace” cannot be a switch, because the only way to draw it is unchecked, which announces “off” — that is a RadioGroup or a Select.
|
|
32
|
+
- There is no readOnly: disabled is the only lock, and it takes the control out of the tab order, so a keyboard reader tabbing the form passes the setting without ever hearing its value.
|
|
33
|
+
- Do not add transition-all from a call site. It replaces transition-[transform,width] wholesale, which puts the track’s colour on the thumb’s longer duration and turns a flip into a fade.
|
|
34
|
+
|
|
15
35
|
## Keyboard
|
|
16
36
|
|
|
17
37
|
- Space / Enter — Toggles it, and the change applies immediately.
|
package/dist/agent/Table.md
CHANGED
|
@@ -4,7 +4,7 @@ A ruled data table — alignment, sorting and rules all per column.
|
|
|
4
4
|
|
|
5
5
|
- Group: Data
|
|
6
6
|
- Import: `import { Table } from '@misoto22/design'`
|
|
7
|
-
- Version: 0.
|
|
7
|
+
- Version: 0.8.0
|
|
8
8
|
- Docs: https://ui.misoto22.com/components/table/
|
|
9
9
|
- Related: card, figure-band
|
|
10
10
|
|
|
@@ -12,6 +12,28 @@ A ruled data table — alignment, sorting and rules all per column.
|
|
|
12
12
|
|
|
13
13
|
Alignment is per column and numbers belong at the end edge, so digits line up. Sorting is opt-in per column: a table where every header is a button invites sorting a column the data cannot be ordered by.
|
|
14
14
|
|
|
15
|
+
## Anatomy
|
|
16
|
+
|
|
17
|
+
- **Scroll region** (required) — The focusable <div role="region"> around the table, named by caption. It carries the border setting and the density attribute, and it is what scrolls sideways — so the table exceeds the measure and the page does not. It is also positioned, which is what keeps an sr-only label inside a cell from resolving against the document and dragging the page sideways with it.
|
|
18
|
+
- **Caption** (required) — A real <caption>, visually hidden unless showCaption prints it as an eyebrow above the table. The same string is the scroll region’s accessible name, so it is heard on the way in and again from the table.
|
|
19
|
+
- **Column label** (required) — TH — mono and uppercase so it never reads as data, aligned per column, and always emitting scope="col" unless a call site overrides it.
|
|
20
|
+
- **Sort control** — On a sortable header only: a <button> INSIDE the th, with ArrowUp, ArrowDown or a dimmed ChevronsUpDown beside the label, and aria-sort on the th set from sortDirection.
|
|
21
|
+
- **Cells** (required) — TD — top-aligned at --ink-2, sharing --table-pad-x with the header so the columns line up, and taking their row height from --table-pad-y, which density halves from 14px to 8px.
|
|
22
|
+
|
|
23
|
+
## Best practices
|
|
24
|
+
|
|
25
|
+
### Do
|
|
26
|
+
|
|
27
|
+
- Bound the height from outside for stickyHeader: className and every other prop land on the <table>, not on the scrolling div around it, so only a constraining parent — a flex column with a height — gives that div something to stick within. A max-height on a plain wrapper does not, and the header simply travels with the page.
|
|
28
|
+
- Pass scope="row" on a row’s first cell — TH writes scope="col" and your props are spread after it, so the override lands; without it every row header claims to head a column and a cell traced back reaches the wrong label.
|
|
29
|
+
- Reset the other columns to sortDirection="none" when the sort moves: each header carries its own aria-sort and nothing coordinates them, so a table can end up announcing two columns as sorted at once.
|
|
30
|
+
- Give TD the same align as its TH — alignment is per cell, not inherited down the column, and end-aligned numbers under a start-aligned label is a column whose digits stop lining up with their own heading.
|
|
31
|
+
|
|
32
|
+
### Don’t
|
|
33
|
+
|
|
34
|
+
- aria-sort tells a reader how the table is ordered once they reach the header; it announces nothing at the moment the button is pressed. A table that re-orders under a screen reader has to say so somewhere the reader already is, or every row silently changes and nothing is said.
|
|
35
|
+
- Do not expect it to reflow on a phone: nothing stacks, the region scrolls sideways behind a hairline scrollbar, and a column past the fold is reachable only by a reader who works out that it scrolls. Eight columns at 375px wants a different presentation, not a smaller font.
|
|
36
|
+
|
|
15
37
|
## Accessibility
|
|
16
38
|
|
|
17
39
|
- caption is required: an unnamed table on a page with three tables is unnavigable.
|
|
@@ -19,6 +41,7 @@ Alignment is per column and numbers belong at the end edge, so digits line up. S
|
|
|
19
41
|
- A sortable header is a button INSIDE the th, not a click handler on the cell — a cell with an onClick is not focusable and not announced, so the sort would exist only for a mouse.
|
|
20
42
|
- aria-sort is set from sortDirection, which is the only way a screen reader learns the table is ordered at all.
|
|
21
43
|
- No zebra striping at any border setting: in a monochrome system a striped row is a second surface competing with the page ground.
|
|
44
|
+
- The scroll region is a containing block, so a visually-hidden label in a cell stays inside the table rather than escaping it and widening the page.
|
|
22
45
|
|
|
23
46
|
## Keyboard
|
|
24
47
|
|
|
@@ -27,14 +50,14 @@ Alignment is per column and numbers belong at the end edge, so digits line up. S
|
|
|
27
50
|
|
|
28
51
|
## Table
|
|
29
52
|
|
|
30
|
-
A ruled data table. Wrapped in its own horizontally scrolling container, because a table is the one block that legitimately exceeds the measure — and a page that scrolls sideways as a whole is a layout bug, while a table that does is a table. That container is focusable, and it has to be. A scrollable region whose contents are not themselves focusable is unreachable by keyboard: there is no element to Tab to and therefore no way to press an arrow key at it, so the columns past the fold simply do not exist for anyone not using a mouse. No zebra striping at any border setting. In a monochrome system a striped row is a second surface competing with the page ground, and the hairline between rows is already enough to track a line across.
|
|
53
|
+
A ruled data table. Wrapped in its own horizontally scrolling container, because a table is the one block that legitimately exceeds the measure — and a page that scrolls sideways as a whole is a layout bug, while a table that does is a table. That container is focusable, and it has to be. A scrollable region whose contents are not themselves focusable is unreachable by keyboard: there is no element to Tab to and therefore no way to press an arrow key at it, so the columns past the fold simply do not exist for anyone not using a mouse. It is also POSITIONED, which is not decoration. `sr-only` is `position: absolute`, so a visually-hidden label in a cell resolves against the nearest positioned ancestor — and with none between it and the document, it escapes the scroll container and every `overflow-hidden` around it, and widens the page by however far the table happens to be scrolled. No zebra striping at any border setting. In a monochrome system a striped row is a second surface competing with the page ground, and the hairline between rows is already enough to track a line across.
|
|
31
54
|
|
|
32
55
|
### Props
|
|
33
56
|
|
|
34
57
|
- `caption` (required) — `string`. Describes the table for a screen reader, which cannot see the heading above it. Rendered as a visually-hidden `<caption>` — required, because an unnamed table in a page with three tables is unnavigable.
|
|
35
58
|
- `showCaption` — `boolean` default `false`. Prints the caption instead of hiding it.
|
|
36
59
|
- `stickyHeader` — `boolean` default `false`. Pins the header row while the body scrolls. Needs a bounded height on the container — otherwise the page scrolls, not the table, and nothing sticks.
|
|
37
|
-
- `borders` — `TableBorders` default `'rows'`. Which rules to draw. See .
|
|
60
|
+
- `borders` — `TableBorders` default `'rows'`. Which rules to draw. See TableBorders.
|
|
38
61
|
- `density` — `'comfortable' | 'compact'` default `'comfortable'`. Tightens the row padding, for a table that is mostly numbers.
|
|
39
62
|
|
|
40
63
|
Also accepts: `TableHTMLAttributes<HTMLTableElement>`.
|
package/dist/agent/Tabs.md
CHANGED
|
@@ -4,10 +4,32 @@ One strip, several panels.
|
|
|
4
4
|
|
|
5
5
|
- Group: Navigation
|
|
6
6
|
- Import: `import { Tabs } from '@misoto22/design'`
|
|
7
|
-
- Version: 0.
|
|
7
|
+
- Version: 0.8.0
|
|
8
8
|
- Docs: https://ui.misoto22.com/components/tabs/
|
|
9
9
|
- Related: accordion
|
|
10
10
|
|
|
11
|
+
## Anatomy
|
|
12
|
+
|
|
13
|
+
- **Root** (required) — Tabs — Radix’s root, re-exported. It draws nothing and owns everything: value or defaultValue, and activationMode. With neither value nor defaultValue no tab is selected and no panel is mounted.
|
|
14
|
+
- **Tab strip** (required) — TabsList — the role="tablist" row, sitting on one hairline rule and scrolling on its own axis with scroll-slim. It has no accessible name unless you give it one.
|
|
15
|
+
- **Tab** (required) — TabsTrigger, at the md control height with its label on one line. Every tab carries the 2px active marker, transparent until it is the selected one; the marker is pulled onto the strip’s own border with -mb-px so the two share a line rather than stacking into a 3px edge.
|
|
16
|
+
- **Panel** — TabsContent, paired to its tab by matching value. Mounted only while it is the selected one, and marked data-m22-animated so its entrance is dropped for a reader who asked for less motion.
|
|
17
|
+
|
|
18
|
+
## Best practices
|
|
19
|
+
|
|
20
|
+
### Do
|
|
21
|
+
|
|
22
|
+
- Give the root a defaultValue or a value: with neither, nothing matches, every panel stays unmounted, and the page renders a strip above an empty space with nothing to say what is missing.
|
|
23
|
+
- Match each trigger’s value to a panel’s value exactly — the pairing is string equality, and a typo is not an error but a tab that opens onto nothing.
|
|
24
|
+
- Pass activationMode="manual" when a panel fetches or renders something expensive: the default is automatic, so ← and → select as they move and arrowing across four tabs starts four loads before the reader has stopped.
|
|
25
|
+
- Give TabsList an aria-label on a page with more than one set: Radix names the tablist after nothing, and two unnamed tablists are two “tab list”s a reader cannot tell apart.
|
|
26
|
+
|
|
27
|
+
### Don’t
|
|
28
|
+
|
|
29
|
+
- An unselected panel is unmounted, not hidden — find-in-page cannot reach its text, a print takes only the panel that was open, and a half-filled form in another tab has lost what was typed into it by the time the reader comes back.
|
|
30
|
+
- The selected tab lives in React state, not in the URL: a reader who reloads or shares the page lands on the first panel, so anything worth linking to needs value lifted into a query parameter.
|
|
31
|
+
- Tabs are not a way to fit more in: the strip scrolls silently, and a sixth tab past the fold looks exactly like a page that only has five.
|
|
32
|
+
|
|
11
33
|
## Accessibility
|
|
12
34
|
|
|
13
35
|
- The strip scrolls rather than wrapping: a wrapped second row moves every tab below it and the reader loses the one they were about to click.
|
|
@@ -33,7 +55,7 @@ One tab. The active marker is a 2px ink rule pulled onto the strip's own border
|
|
|
33
55
|
|
|
34
56
|
## TabsContent
|
|
35
57
|
|
|
36
|
-
The panel paired to a
|
|
58
|
+
The panel paired to a TabsTrigger by matching `value`.
|
|
37
59
|
|
|
38
60
|
## Examples
|
|
39
61
|
|
package/dist/agent/Tag.md
CHANGED
|
@@ -1,35 +1,66 @@
|
|
|
1
1
|
# Tag
|
|
2
2
|
|
|
3
|
-
A subject label — a topic, a technology, a filter facet.
|
|
3
|
+
A subject label — a topic, a technology, a filter facet — that filters with onClick and is dismissed with onRemove.
|
|
4
4
|
|
|
5
5
|
- Group: Display
|
|
6
6
|
- Import: `import { Tag } from '@misoto22/design'`
|
|
7
|
-
- Version: 0.
|
|
7
|
+
- Version: 0.8.0
|
|
8
8
|
- Docs: https://ui.misoto22.com/components/tag/
|
|
9
|
-
- Related: badge
|
|
9
|
+
- Related: badge, status-pill
|
|
10
10
|
|
|
11
11
|
## When to reach for it
|
|
12
12
|
|
|
13
|
-
Several sit together and the reader scans them. One fact about one record is a Badge.
|
|
13
|
+
Several sit together and the reader scans them. One fact about one record is a Badge. A chip the reader can toggle or dismiss is this one with onClick or onRemove, not a fourth component.
|
|
14
|
+
|
|
15
|
+
## Anatomy
|
|
16
|
+
|
|
17
|
+
- **Chip** (required) — The <span>: the same --radius-sm corner, the same 10px by 4px padding and the same 12px mono as a Badge, with no border of its own.
|
|
18
|
+
- **Ground** (required) — --stone at rest, --accent once active, cross-fading over --duration-fast. The accent is the system’s one pointer at a choice, which is why it is what selection is drawn in.
|
|
19
|
+
- **Label** (required) — children, in --ink-3-aa — the AA floor rather than a light grey — and in --accent-foreground once active.
|
|
20
|
+
- **Remove button** — On onRemove only: a real <button type="button"> after the label, holding a 12px X and named by removeLabel. The drawn box is 16px, under the 24px WCAG 2.5.8 floor, so an inset pseudo-element takes the hit area out to 24 without changing the drawing or pushing the chips apart.
|
|
21
|
+
- **Filter control** — On onClick only: the chip itself becomes the <button>, carrying aria-pressed from active. Given onRemove as well, the label splits into its own button beside the X — two siblings, never one inside the other — and takes the leading padding with it so the target is the chip up to the X rather than just the words.
|
|
22
|
+
|
|
23
|
+
## Best practices
|
|
24
|
+
|
|
25
|
+
### Do
|
|
26
|
+
|
|
27
|
+
- Filter with onClick, not with a wrapper. The chip becomes the button itself, so the padding is part of the target and the focus ring is drawn around what the reader sees — and a removable chip does not end up with a button inside a button.
|
|
28
|
+
- Pass active on a chip that toggles, and leave it off one that does not. aria-pressed is read off that same value, so the accent fill and the state assistive tech hears cannot drift apart; omitted, nothing is announced, which is the right answer for a chip that navigates rather than toggles.
|
|
29
|
+
- Give a filter row an off state to come back to — active is the accent, and a row in which every tag is active spends the mark that means “this one” on all of them.
|
|
30
|
+
- Name the subject in removeLabel — "Remove Rust filter", not "Remove". It is required alongside onRemove because eight chips whose controls are all called Remove is eight controls a screen reader cannot tell apart.
|
|
31
|
+
|
|
32
|
+
### Don’t
|
|
33
|
+
|
|
34
|
+
- It carries no tone at all, so a tag cannot say success or danger. Colouring one in through className puts a hue into the system by hand and leaves the accent as the only thing that still reads as selected.
|
|
35
|
+
- One tag on its own is a Badge that lost its tone. The component is built to be scanned in a row, and a single chip beside a record is one fact about one record.
|
|
36
|
+
- Do not wrap it in a button of your own. Around a removable chip that is a button inside a button — invalid markup a parser splits into siblings, leaving a DOM neither the author nor the accessibility tree expects. onClick is what that wrapper was for.
|
|
14
37
|
|
|
15
38
|
## Accessibility
|
|
16
39
|
|
|
17
|
-
- Presentational
|
|
40
|
+
- Presentational until it is given a handler. onClick makes the chip a real button carrying aria-pressed from active, so the focus ring and the pressed state stay on the element that draws them.
|
|
41
|
+
- Both controls are real <button type="button">s and siblings, so Tab reaches each, Enter and Space fire each, and neither submits the form it happens to sit in.
|
|
42
|
+
- removeLabel is required with onRemove and is the button’s whole accessible name — the X itself is aria-hidden.
|
|
18
43
|
|
|
19
44
|
## Tag
|
|
20
45
|
|
|
21
|
-
A subject label — a topic, a technology, a filter facet
|
|
46
|
+
A subject label — a topic, a technology, a filter facet — that can filter with `onClick` and be dismissed with `onRemove`. Distinct from `Badge`, which carries a state or a count. A tag names what something is ABOUT, so several sit together in a row and the reader scans them; a badge is one fact about one record. This is where a `Token` component would have gone. It was not built: a token is a tag with a remove button, and the difference between the two is one prop, not one component. The system already ships three things that look alike — `Badge`, `Tag`, `StatusPill` — and a fourth whose whole distinction is an X on the end would be the one a call site picks by coin toss. Presentational until it is given a handler, and the component owns both interactive cases rather than leaving one to a wrapper at the call site. That is not a convenience: a wrapping `<button>` around a chip that already holds the remove `<button>` is a button inside a button, which no parser keeps and no accessibility tree reports the way it was written. Given both, the chip renders the label and the X as SIBLING buttons — the label takes the leading padding with it, so it is the whole of the chip up to the X rather than the words with dead padding around them.
|
|
22
47
|
|
|
23
48
|
### Props
|
|
24
49
|
|
|
25
50
|
- `children` (required) — `ReactNode`.
|
|
26
|
-
- `active` — `boolean
|
|
51
|
+
- `active` — `boolean`. Renders the pressed/selected look, and declares the chip a toggle. An interactive chip reads `aria-pressed` off this same value, so the accent fill and the state a screen reader hears cannot drift apart. Leave it off for a chip whose `onClick` navigates or opens something: a control that is neither pressed nor unpressed is better announced as neither than as "not pressed".
|
|
52
|
+
- `onClick` — `() => void`. Makes the chip ITSELF the filter control. This prop exists because the alternative did not survive contact with `onRemove`. The advice used to be to wrap the tag in a button at the call site, which is fine on its own and invalid the moment the chip is also removable: the remove control is a real `<button>`, so the wrapper puts a button inside a button — markup the parser splits into siblings, leaving a DOM neither the author nor the accessibility tree expects. With this the wrapper is never written. The chip carries the click, the focus ring and the pressed state on the element that draws them, and a removable filter chip renders its two controls side by side instead of one inside the other.
|
|
53
|
+
- `onRemove` — `() => void`. Called when the reader dismisses the chip.
|
|
54
|
+
- `removeLabel` — `string`. The remove button's accessible name. Name the subject, not the action.
|
|
27
55
|
|
|
28
|
-
Also accepts: `HTMLAttributes<
|
|
56
|
+
Also accepts: `Omit<HTMLAttributes<HTMLElement>, 'onClick'>`.
|
|
29
57
|
|
|
30
58
|
## Examples
|
|
31
59
|
|
|
32
60
|
```tsx
|
|
33
61
|
<Tag>TypeScript</Tag>
|
|
34
|
-
<
|
|
62
|
+
<Tag active={on} onClick={toggle}>Rust</Tag>
|
|
63
|
+
<Tag onRemove={() => drop('rust')} removeLabel="Remove Rust filter">Rust</Tag>
|
|
64
|
+
// Both: a filter the reader can toggle and also take out of the row.
|
|
65
|
+
<Tag active={on} onClick={toggle} onRemove={drop} removeLabel="Remove Rust filter">Rust</Tag>
|
|
35
66
|
```
|