@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/Card/Card.tsx"],"sourcesContent":["import type { HTMLAttributes } from 'react'\nimport { cn } from '../../lib/cn'\n\nexport interface CardProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * `outline` is a hairline box on the page ground — the default, and correct\n * for a card sitting among other cards. `plate` fills with the one reversed\n * surface and is for a card that IS the point of its band; use at most one\n * per screen. `flat` drops the border entirely, for a card whose grid already\n * draws the rules between cells.\n */\n variant?: 'outline' | 'plate' | 'flat'\n}\n\nconst VARIANT = {\n outline: 'border border-(--rule) bg-(--paper)',\n plate:\n 'border border-(--feature-surface) bg-(--feature-surface) text-(--on-feature) [--card-title:var(--on-feature)]',\n flat: 'border border-transparent bg-transparent',\n} as const\n\n/**\n * A bounded surface.\n *\n * No shadow, by law: depth in this system is a hairline and a change of ground,\n * never a blur. A card that needs to read as raised is a `plate`, which\n * separates by reversal instead.\n *\n * Compose with the named sub-parts, or drop children straight in when the card\n * has no header or footer to speak of.\n *\n * @example\n * <Card>\n * <CardHeader><CardTitle>Recent deploys</CardTitle><Badge>12</Badge></CardHeader>\n * <CardBody>…</CardBody>\n * <CardFooter>Updated just now</CardFooter>\n * </Card>\n */\nexport function Card({ variant = 'outline', className, children, ...rest }: CardProps) {\n return (\n <div className={cn('rounded-(--radius-lg)', VARIANT[variant], className)} {...rest}>\n {children}\n </div>\n )\n}\n\n/** Header row — title on the left, an action or marker on the right. */\nexport function CardHeader({ className, children, ...rest }: HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n className={cn(\n 'flex items-center justify-between gap-4 border-b border-(--rule) px-5 py-4',\n className,\n )}\n {...rest}\n >\n {children}\n </div>\n )\n}\n\n/**\n * The card's title, in the editorial serif.\n *\n * An `<h3>` by default, which is right inside a section with its own `<h2>` and\n * wrong nearly everywhere else — pass `as` rather than leaving a page with a\n * heading order that jumps.\n */\nexport function CardTitle({\n as: Comp = 'h3',\n className,\n children,\n ...rest\n}: HTMLAttributes<HTMLHeadingElement> & { as?: 'h2' | 'h3' | 'h4' }) {\n return (\n <Comp\n // Reads the card's own title colour rather than --ink directly. A plate\n // is a reversed surface, and a hardcoded ink title on it came out at\n // 1.25:1 — invisible, and invisible only on the one variant whose whole\n // job is to be different.\n className={cn(\n 'm-0 font-heading text-[length:var(--fs-item)] font-normal text-[var(--card-title,var(--ink))]',\n className,\n )}\n {...rest}\n >\n {children}\n </Comp>\n )\n}\n\n/** The content well. */\nexport function CardBody({ className, children, ...rest }: HTMLAttributes<HTMLDivElement>) {\n return (\n <div className={cn('p-5 text-sm leading-relaxed text-(--ink-2)', className)} {...rest}>\n {children}\n </div>\n )\n}\n\n/** A quiet strip for metadata or secondary actions. */\nexport function CardFooter({ className, children, ...rest }: HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n className={cn('border-t border-(--rule) px-5 py-4 mono-meta text-(--ink-3-aa)', className)}\n {...rest}\n >\n {children}\n </div>\n )\n}\n\nexport default Card\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Card/Card.tsx"],"sourcesContent":["import type { HTMLAttributes } from 'react'\nimport { cn } from '../../lib/cn'\n\nexport interface CardProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * `outline` is a hairline box on the page ground — the default, and correct\n * for a card sitting among other cards. `plate` fills with the one reversed\n * surface and is for a card that IS the point of its band; use at most one\n * per screen. `flat` drops the border entirely, for a card whose grid already\n * draws the rules between cells.\n */\n variant?: 'outline' | 'plate' | 'flat'\n}\n\nconst VARIANT = {\n outline: 'border border-(--rule) bg-(--paper)',\n plate:\n 'border border-(--feature-surface) bg-(--feature-surface) text-(--on-feature) [--card-title:var(--on-feature)]',\n flat: 'border border-transparent bg-transparent',\n} as const\n\n/**\n * A bounded surface.\n *\n * No shadow, by law: depth in this system is a hairline and a change of ground,\n * never a blur. A card that needs to read as raised is a `plate`, which\n * separates by reversal instead.\n *\n * It clips to its own corner. A card that rounds and does not clip lays a\n * full-bleed image's square corners over its round ones at all four corners,\n * and the same goes for a filled first child — a defect that is invisible until\n * the first card with an image at the top of it. Pass `overflow-visible` for\n * the rarer card that deliberately overhangs.\n *\n * Compose with the named sub-parts, or drop children straight in when the card\n * has no header or footer to speak of.\n *\n * @example\n * <Card>\n * <CardHeader><CardTitle>Recent deploys</CardTitle><Badge>12</Badge></CardHeader>\n * <CardBody>…</CardBody>\n * <CardFooter>Updated just now</CardFooter>\n * </Card>\n */\nexport function Card({ variant = 'outline', className, children, ...rest }: CardProps) {\n return (\n <div className={cn('overflow-hidden rounded-(--radius-lg)', VARIANT[variant], className)} {...rest}>\n {children}\n </div>\n )\n}\n\n/** Header row — title on the left, an action or marker on the right. */\nexport function CardHeader({ className, children, ...rest }: HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n className={cn(\n 'flex items-center justify-between gap-4 border-b border-(--rule) px-5 py-4',\n className,\n )}\n {...rest}\n >\n {children}\n </div>\n )\n}\n\n/**\n * The card's title, in the editorial serif.\n *\n * An `<h3>` by default, which is right inside a section with its own `<h2>` and\n * wrong nearly everywhere else — pass `as` rather than leaving a page with a\n * heading order that jumps.\n */\nexport function CardTitle({\n as: Comp = 'h3',\n className,\n children,\n ...rest\n}: HTMLAttributes<HTMLHeadingElement> & { as?: 'h2' | 'h3' | 'h4' }) {\n return (\n <Comp\n // Reads the card's own title colour rather than --ink directly. A plate\n // is a reversed surface, and a hardcoded ink title on it came out at\n // 1.25:1 — invisible, and invisible only on the one variant whose whole\n // job is to be different.\n className={cn(\n 'm-0 font-heading text-[length:var(--fs-item)] font-normal text-[var(--card-title,var(--ink))]',\n className,\n )}\n {...rest}\n >\n {children}\n </Comp>\n )\n}\n\n/** The content well. */\nexport function CardBody({ className, children, ...rest }: HTMLAttributes<HTMLDivElement>) {\n return (\n <div className={cn('p-5 text-sm leading-relaxed text-(--ink-2)', className)} {...rest}>\n {children}\n </div>\n )\n}\n\n/** A quiet strip for metadata or secondary actions. */\nexport function CardFooter({ className, children, ...rest }: HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n className={cn('border-t border-(--rule) px-5 py-4 mono-meta text-(--ink-3-aa)', className)}\n {...rest}\n >\n {children}\n </div>\n )\n}\n\nexport default Card\n"],"mappings":"AA8CI;AA7CJ,SAAS,UAAU;AAanB,MAAM,UAAU;AAAA,EACd,SAAS;AAAA,EACT,OACE;AAAA,EACF,MAAM;AACR;AAyBO,SAAS,KAAK,EAAE,UAAU,WAAW,WAAW,UAAU,GAAG,KAAK,GAAc;AACrF,SACE,oBAAC,SAAI,WAAW,GAAG,yCAAyC,QAAQ,OAAO,GAAG,SAAS,GAAI,GAAG,MAC3F,UACH;AAEJ;AAGO,SAAS,WAAW,EAAE,WAAW,UAAU,GAAG,KAAK,GAAmC;AAC3F,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ;AASO,SAAS,UAAU;AAAA,EACxB,IAAI,OAAO;AAAA,EACX;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAqE;AACnE,SACE;AAAA,IAAC;AAAA;AAAA,MAKC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ;AAGO,SAAS,SAAS,EAAE,WAAW,UAAU,GAAG,KAAK,GAAmC;AACzF,SACE,oBAAC,SAAI,WAAW,GAAG,8CAA8C,SAAS,GAAI,GAAG,MAC9E,UACH;AAEJ;AAGO,SAAS,WAAW,EAAE,WAAW,UAAU,GAAG,KAAK,GAAmC;AAC3F,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,GAAG,kEAAkE,SAAS;AAAA,MACxF,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ;AAEA,IAAO,eAAQ;","names":[]}
|
|
@@ -8,7 +8,10 @@ type CheckboxProps = ComponentProps<typeof CheckboxPrimitive.Root>;
|
|
|
8
8
|
*
|
|
9
9
|
* Supports the indeterminate state (`checked="indeterminate"`), which is what a
|
|
10
10
|
* "select all" header needs when only some rows are selected — a plain
|
|
11
|
-
* unchecked box there tells the reader the opposite of the truth.
|
|
11
|
+
* unchecked box there tells the reader the opposite of the truth. Controlled or
|
|
12
|
+
* not: the glyph follows the state the box is actually in, so an uncontrolled
|
|
13
|
+
* `defaultChecked="indeterminate"` draws the dash rather than the tick that says
|
|
14
|
+
* the opposite.
|
|
12
15
|
*
|
|
13
16
|
* Pair with `Field`, or wrap it in a `<label>` at the call site so the words
|
|
14
17
|
* beside it are part of the click target.
|
|
@@ -18,6 +21,6 @@ type CheckboxProps = ComponentProps<typeof CheckboxPrimitive.Root>;
|
|
|
18
21
|
* <Checkbox defaultChecked /> Subscribe to updates
|
|
19
22
|
* </label>
|
|
20
23
|
*/
|
|
21
|
-
declare function Checkbox({ className, ...props }: CheckboxProps): react.JSX.Element;
|
|
24
|
+
declare function Checkbox({ className, onCheckedChange, ...props }: CheckboxProps): react.JSX.Element;
|
|
22
25
|
|
|
23
26
|
export { Checkbox, type CheckboxProps, Checkbox as default };
|
|
@@ -2,17 +2,27 @@
|
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
|
4
4
|
import { Check, Minus } from "lucide-react";
|
|
5
|
+
import { useState } from "react";
|
|
5
6
|
import { cn } from "../../lib/cn.js";
|
|
6
|
-
function Checkbox({ className, ...props }) {
|
|
7
|
+
function Checkbox({ className, onCheckedChange, ...props }) {
|
|
8
|
+
const [uncontrolled, setUncontrolled] = useState(
|
|
9
|
+
props.defaultChecked ?? false
|
|
10
|
+
);
|
|
11
|
+
const state = props.checked ?? uncontrolled;
|
|
12
|
+
const handleChange = (next) => {
|
|
13
|
+
if (props.checked === void 0) setUncontrolled(next);
|
|
14
|
+
onCheckedChange?.(next);
|
|
15
|
+
};
|
|
7
16
|
return /* @__PURE__ */ jsx(
|
|
8
17
|
CheckboxPrimitive.Root,
|
|
9
18
|
{
|
|
19
|
+
onCheckedChange: handleChange,
|
|
10
20
|
className: cn(
|
|
11
21
|
"inline-flex size-[18px] shrink-0 items-center justify-center rounded-(--radius-xs) border border-(--rule-2) bg-(--paper) text-(--accent-foreground) transition-colors duration-(--duration-fast) data-[state=checked]:border-(--accent) data-[state=checked]:bg-(--accent) data-[state=indeterminate]:border-(--accent) data-[state=indeterminate]:bg-(--accent) disabled:opacity-(--disabled-opacity) disabled:pointer-events-none",
|
|
12
22
|
className
|
|
13
23
|
),
|
|
14
24
|
...props,
|
|
15
|
-
children: /* @__PURE__ */ jsx(CheckboxPrimitive.Indicator, { className: "flex items-center justify-center text-current", children:
|
|
25
|
+
children: /* @__PURE__ */ jsx(CheckboxPrimitive.Indicator, { className: "flex items-center justify-center text-current", children: state === "indeterminate" ? /* @__PURE__ */ jsx(Minus, { className: "size-3", strokeWidth: 3, "aria-hidden": true }) : /* @__PURE__ */ jsx(Check, { className: "size-3", strokeWidth: 3, "aria-hidden": true }) })
|
|
16
26
|
}
|
|
17
27
|
);
|
|
18
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/Checkbox/Checkbox.tsx"],"sourcesContent":["'use client'\n\nimport * as CheckboxPrimitive from '@radix-ui/react-checkbox'\nimport { Check, Minus } from 'lucide-react'\nimport type
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Checkbox/Checkbox.tsx"],"sourcesContent":["'use client'\n\nimport * as CheckboxPrimitive from '@radix-ui/react-checkbox'\nimport { Check, Minus } from 'lucide-react'\nimport { useState, type ComponentProps } from 'react'\nimport { cn } from '../../lib/cn'\n\nexport type CheckboxProps = ComponentProps<typeof CheckboxPrimitive.Root>\n\n/**\n * A choice that takes effect when the form is submitted.\n *\n * Supports the indeterminate state (`checked=\"indeterminate\"`), which is what a\n * \"select all\" header needs when only some rows are selected — a plain\n * unchecked box there tells the reader the opposite of the truth. Controlled or\n * not: the glyph follows the state the box is actually in, so an uncontrolled\n * `defaultChecked=\"indeterminate\"` draws the dash rather than the tick that says\n * the opposite.\n *\n * Pair with `Field`, or wrap it in a `<label>` at the call site so the words\n * beside it are part of the click target.\n *\n * @example\n * <label className=\"flex items-center gap-2.5 text-sm\">\n * <Checkbox defaultChecked /> Subscribe to updates\n * </label>\n */\nexport function Checkbox({ className, onCheckedChange, ...props }: CheckboxProps) {\n // Tracked here rather than read off `props.checked`, which is set only by a\n // CONTROLLED box: an uncontrolled `defaultChecked=\"indeterminate\"` drew the\n // tick — the \"all of them\" picture on a partly selected list, which is the one\n // thing this state exists to avoid saying.\n const [uncontrolled, setUncontrolled] = useState<CheckboxProps['checked']>(\n props.defaultChecked ?? false,\n )\n const state = props.checked ?? uncontrolled\n\n const handleChange = (next: NonNullable<CheckboxProps['checked']>) => {\n if (props.checked === undefined) setUncontrolled(next)\n onCheckedChange?.(next)\n }\n\n return (\n <CheckboxPrimitive.Root\n onCheckedChange={handleChange}\n className={cn(\n 'inline-flex size-[18px] shrink-0 items-center justify-center rounded-(--radius-xs) border border-(--rule-2) bg-(--paper) text-(--accent-foreground) transition-colors duration-(--duration-fast) data-[state=checked]:border-(--accent) data-[state=checked]:bg-(--accent) data-[state=indeterminate]:border-(--accent) data-[state=indeterminate]:bg-(--accent) disabled:opacity-(--disabled-opacity) disabled:pointer-events-none',\n className,\n )}\n {...props}\n >\n <CheckboxPrimitive.Indicator className=\"flex items-center justify-center text-current\">\n {state === 'indeterminate' ? (\n <Minus className=\"size-3\" strokeWidth={3} aria-hidden />\n ) : (\n <Check className=\"size-3\" strokeWidth={3} aria-hidden />\n )}\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n )\n}\n\nexport default Checkbox\n"],"mappings":";AAqDU;AAnDV,YAAY,uBAAuB;AACnC,SAAS,OAAO,aAAa;AAC7B,SAAS,gBAAqC;AAC9C,SAAS,UAAU;AAsBZ,SAAS,SAAS,EAAE,WAAW,iBAAiB,GAAG,MAAM,GAAkB;AAKhF,QAAM,CAAC,cAAc,eAAe,IAAI;AAAA,IACtC,MAAM,kBAAkB;AAAA,EAC1B;AACA,QAAM,QAAQ,MAAM,WAAW;AAE/B,QAAM,eAAe,CAAC,SAAgD;AACpE,QAAI,MAAM,YAAY,OAAW,iBAAgB,IAAI;AACrD,sBAAkB,IAAI;AAAA,EACxB;AAEA,SACE;AAAA,IAAC,kBAAkB;AAAA,IAAlB;AAAA,MACC,iBAAiB;AAAA,MACjB,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEJ,8BAAC,kBAAkB,WAAlB,EAA4B,WAAU,iDACpC,oBAAU,kBACT,oBAAC,SAAM,WAAU,UAAS,aAAa,GAAG,eAAW,MAAC,IAEtD,oBAAC,SAAM,WAAU,UAAS,aAAa,GAAG,eAAW,MAAC,GAE1D;AAAA;AAAA,EACF;AAEJ;AAEA,IAAO,mBAAQ;","names":[]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface CodeProps extends HTMLAttributes<HTMLElement> {
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* A function name, a flag, a filename — inside a sentence.
|
|
9
|
+
*
|
|
10
|
+
* Renders a `<code>`, which is the element that means this. A `<span>` in a
|
|
11
|
+
* mono face looks identical and tells a screen reader nothing, and "pass
|
|
12
|
+
* dash dash force" is not what the sentence said.
|
|
13
|
+
*
|
|
14
|
+
* Sized in `em` rather than in pixels, so the chip tracks whatever type it sits
|
|
15
|
+
* beside — the same rule `Kbd` follows, and for the same reason: fixed at one
|
|
16
|
+
* value, the identical token came out three different sizes on one page
|
|
17
|
+
* depending on whether it landed in body copy, a caption or a table cell.
|
|
18
|
+
*
|
|
19
|
+
* The block form is `CodeBlock`. This one is inline by construction: it draws
|
|
20
|
+
* no plate, keeps no whitespace, and a multi-line string handed to it collapses
|
|
21
|
+
* into one run.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* Pass <Code>--force</Code> to overwrite the existing file.
|
|
25
|
+
* @example
|
|
26
|
+
* The helper lives in <Code>src/lib/cn.ts</Code>.
|
|
27
|
+
*/
|
|
28
|
+
declare function Code({ children, className, ...rest }: CodeProps): react.JSX.Element;
|
|
29
|
+
|
|
30
|
+
export { Code, type CodeProps, Code as default };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../../lib/cn.js";
|
|
3
|
+
function Code({ children, className, ...rest }) {
|
|
4
|
+
return /* @__PURE__ */ jsx(
|
|
5
|
+
"code",
|
|
6
|
+
{
|
|
7
|
+
className: cn(
|
|
8
|
+
"rounded-(--radius-sm) bg-(--stone) px-[0.4em] py-[0.15em] font-mono text-[0.85em] text-(--ink)",
|
|
9
|
+
className
|
|
10
|
+
),
|
|
11
|
+
...rest,
|
|
12
|
+
children
|
|
13
|
+
}
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
var Code_default = Code;
|
|
17
|
+
export {
|
|
18
|
+
Code,
|
|
19
|
+
Code_default as default
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=Code.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Code/Code.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\n\nexport interface CodeProps extends HTMLAttributes<HTMLElement> {\n children: ReactNode\n}\n\n/**\n * A function name, a flag, a filename — inside a sentence.\n *\n * Renders a `<code>`, which is the element that means this. A `<span>` in a\n * mono face looks identical and tells a screen reader nothing, and \"pass\n * dash dash force\" is not what the sentence said.\n *\n * Sized in `em` rather than in pixels, so the chip tracks whatever type it sits\n * beside — the same rule `Kbd` follows, and for the same reason: fixed at one\n * value, the identical token came out three different sizes on one page\n * depending on whether it landed in body copy, a caption or a table cell.\n *\n * The block form is `CodeBlock`. This one is inline by construction: it draws\n * no plate, keeps no whitespace, and a multi-line string handed to it collapses\n * into one run.\n *\n * @example\n * Pass <Code>--force</Code> to overwrite the existing file.\n * @example\n * The helper lives in <Code>src/lib/cn.ts</Code>.\n */\nexport function Code({ children, className, ...rest }: CodeProps) {\n return (\n <code\n className={cn(\n 'rounded-(--radius-sm) bg-(--stone) px-[0.4em] py-[0.15em] font-mono text-[0.85em] text-(--ink)',\n className,\n )}\n {...rest}\n >\n {children}\n </code>\n )\n}\n\nexport default Code\n"],"mappings":"AA8BI;AA7BJ,SAAS,UAAU;AA2BZ,SAAS,KAAK,EAAE,UAAU,WAAW,GAAG,KAAK,GAAc;AAChE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ;AAEA,IAAO,eAAQ;","names":[]}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
|
|
3
|
+
interface CommonProps {
|
|
4
|
+
/**
|
|
5
|
+
* The snippet, verbatim.
|
|
6
|
+
*
|
|
7
|
+
* Required even when `html` is supplied, and that is the point: this is what
|
|
8
|
+
* the copy button puts on the clipboard. A block that copies its own rendered
|
|
9
|
+
* markup hands the reader a wall of `<span>`s, and one that copies
|
|
10
|
+
* `textContent` scraped back out of the DOM is a single non-breaking space
|
|
11
|
+
* away from pasting something that does not run.
|
|
12
|
+
*/
|
|
13
|
+
code: string;
|
|
14
|
+
/** A filename or a caption, printed at the start of the strip. */
|
|
15
|
+
title?: string;
|
|
16
|
+
/**
|
|
17
|
+
* The language, printed at the end of the strip.
|
|
18
|
+
*
|
|
19
|
+
* Optional, and the omission is visible rather than silent: a block with no
|
|
20
|
+
* language gets no label instead of claiming a wrong one. A code block that
|
|
21
|
+
* does not say what it is written in makes the reader infer it from the
|
|
22
|
+
* syntax, which is the one thing they came to the block to learn.
|
|
23
|
+
*/
|
|
24
|
+
lang?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Caps the block's height and scrolls past it.
|
|
27
|
+
*
|
|
28
|
+
* A number is pixels; a string is any CSS length (`'24rem'`, `'50vh'`). The
|
|
29
|
+
* body scrolls in both axes and is focusable, so what is past the fold stays
|
|
30
|
+
* reachable with a keyboard rather than merely present in the DOM.
|
|
31
|
+
*/
|
|
32
|
+
maxHeight?: number | string;
|
|
33
|
+
/** Drops the copy button, for a block nobody is meant to run. */
|
|
34
|
+
copyable?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Names the scrollable body for a screen reader. Defaults to `title`, and to
|
|
37
|
+
* "Code" when there is not one.
|
|
38
|
+
*/
|
|
39
|
+
label?: string;
|
|
40
|
+
className?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The two forms, and why they are two.
|
|
44
|
+
*
|
|
45
|
+
* `html` is pre-highlighted markup for the SAME snippet. The package does not
|
|
46
|
+
* highlight, and will not: a highlighter is a few hundred kilobytes of grammar
|
|
47
|
+
* and a build-time job. The documentation site runs Shiki inside its generator
|
|
48
|
+
* and hands the result here, which is the shape that half exists for. Without
|
|
49
|
+
* `html` the block renders `code` as text, which is what a template, a README
|
|
50
|
+
* or an agent's answer has and all it needs.
|
|
51
|
+
*
|
|
52
|
+
* `lineNumbers` and `highlightLines` belong to the plain form only, and that is
|
|
53
|
+
* enforced in the TYPE rather than left to a note. They are a per-LINE
|
|
54
|
+
* structure, and `html` is one opaque string this component is not going to
|
|
55
|
+
* start parsing. Typed apart, passing both is a compile error at the call site;
|
|
56
|
+
* typed together it is a prop that renders nothing and says nothing.
|
|
57
|
+
*
|
|
58
|
+
* The plain form is written first because the emitted prop table reads the
|
|
59
|
+
* first arm of a union: this way `lineNumbers` documents as `boolean` rather
|
|
60
|
+
* than as the `never` the other arm gives it.
|
|
61
|
+
*/
|
|
62
|
+
type WithPlainSource = CommonProps & {
|
|
63
|
+
/**
|
|
64
|
+
* Absent on this form; `string` on the other.
|
|
65
|
+
*
|
|
66
|
+
* Pass pre-highlighted markup — Shiki's output, run at build time over this
|
|
67
|
+
* same `code` — and the block renders that instead of the plain text. Doing
|
|
68
|
+
* so takes `lineNumbers` and `highlightLines` away with it.
|
|
69
|
+
*/
|
|
70
|
+
html?: undefined;
|
|
71
|
+
/** Numbers every line, counting from one. */
|
|
72
|
+
lineNumbers?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Lines to band, counting from one. A number past the end of the snippet is
|
|
75
|
+
* ignored rather than throwing — the usual cause is a snippet that got
|
|
76
|
+
* shorter while the annotation did not.
|
|
77
|
+
*/
|
|
78
|
+
highlightLines?: number[];
|
|
79
|
+
};
|
|
80
|
+
type WithHighlightedHtml = CommonProps & {
|
|
81
|
+
html: string;
|
|
82
|
+
/** Not available alongside `html`, which the component does not parse. */
|
|
83
|
+
lineNumbers?: never;
|
|
84
|
+
/** Not available alongside `html`, which the component does not parse. */
|
|
85
|
+
highlightLines?: never;
|
|
86
|
+
};
|
|
87
|
+
type CodeBlockProps = WithPlainSource | WithHighlightedHtml;
|
|
88
|
+
/**
|
|
89
|
+
* A multi-line snippet, on a plate, with a way to take it away.
|
|
90
|
+
*
|
|
91
|
+
* The strip along the top carries the title, the language and the copy button,
|
|
92
|
+
* and it is there whenever there is anything to put in it. It is deliberately
|
|
93
|
+
* not a hover affordance: a control that appears on hover does not exist on a
|
|
94
|
+
* touch screen, which is where a reader is most likely to want the snippet and
|
|
95
|
+
* least able to select it by hand.
|
|
96
|
+
*
|
|
97
|
+
* Line numbers live INSIDE their own line's row rather than in a parallel gutter
|
|
98
|
+
* column. Two columns sharing a line-height align right up until one of them
|
|
99
|
+
* wraps, ships a different font, or scrolls on its own; a number that is a child
|
|
100
|
+
* of the line it numbers cannot come apart from it. The cost is that a number
|
|
101
|
+
* scrolls away with its line: it is inside the scrolling box, not in a gutter
|
|
102
|
+
* beside it. A gutter that stayed put would be a second column to keep in sync,
|
|
103
|
+
* which is the failure this avoids.
|
|
104
|
+
*
|
|
105
|
+
* The body is a focusable, named `role="group"`, and both halves of that are
|
|
106
|
+
* load-bearing. Focusable, because a scrollable box whose contents are not
|
|
107
|
+
* themselves focusable is unreachable by keyboard — there is nothing to Tab to
|
|
108
|
+
* and therefore no way to press an arrow key at it, so the right-hand half of a
|
|
109
|
+
* long line does not exist for anyone not using a mouse. Named, because a tab
|
|
110
|
+
* stop that announces nothing lands the reader in an anonymous box and leaves
|
|
111
|
+
* them to work out what they have arrived in.
|
|
112
|
+
*
|
|
113
|
+
* `group` rather than `region`, and that is the deliberate half. A region is a
|
|
114
|
+
* LANDMARK — one of the handful of major sections a reader navigates a whole
|
|
115
|
+
* page by — and a snippet is not one of those. Three fenced blocks in one
|
|
116
|
+
* article would put three landmarks called "Code" into that map, which is
|
|
117
|
+
* exactly the noise the `landmark-unique` rule exists to catch, and it would
|
|
118
|
+
* push the page's real landmarks down a list nobody can now skim. `group`
|
|
119
|
+
* carries the same accessible name to the same reader on the way in, and
|
|
120
|
+
* carries it nowhere else.
|
|
121
|
+
*
|
|
122
|
+
* For a function name inside a sentence, reach for `Code`.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* <CodeBlock code="pnpm add @misoto22/design" lang="bash" />
|
|
126
|
+
* @example
|
|
127
|
+
* <CodeBlock
|
|
128
|
+
* title="cn.ts"
|
|
129
|
+
* lang="ts"
|
|
130
|
+
* lineNumbers
|
|
131
|
+
* highlightLines={[2]}
|
|
132
|
+
* maxHeight="24rem"
|
|
133
|
+
* code={source}
|
|
134
|
+
* />
|
|
135
|
+
* @example
|
|
136
|
+
* // Highlighted at build time by the site's own Shiki pass.
|
|
137
|
+
* <CodeBlock code={source} html={highlighted} lang="tsx" />
|
|
138
|
+
*/
|
|
139
|
+
declare function CodeBlock({ code, html, title, lang, maxHeight, copyable, label, className, lineNumbers, highlightLines, }: CodeBlockProps): react.JSX.Element;
|
|
140
|
+
|
|
141
|
+
export { CodeBlock, type CodeBlockProps, CodeBlock as default };
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Check, Copy } from "lucide-react";
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
import { cn } from "../../lib/cn.js";
|
|
6
|
+
import { Button } from "../Button/Button.js";
|
|
7
|
+
const LANGUAGE_LABEL = {
|
|
8
|
+
bash: "Shell",
|
|
9
|
+
css: "CSS",
|
|
10
|
+
html: "HTML",
|
|
11
|
+
js: "JavaScript",
|
|
12
|
+
json: "JSON",
|
|
13
|
+
jsx: "JSX",
|
|
14
|
+
md: "Markdown",
|
|
15
|
+
sh: "Shell",
|
|
16
|
+
ts: "TypeScript",
|
|
17
|
+
tsx: "TSX"
|
|
18
|
+
};
|
|
19
|
+
const HIGHLIGHTED = "[&_pre]:m-0 [&_pre]:min-w-max [&_pre]:bg-transparent [&_pre]:p-0 [&_pre]:font-mono [&_pre]:text-[13px] [&_pre]:leading-[1.7] [&_code]:bg-transparent";
|
|
20
|
+
function CodeBlock({
|
|
21
|
+
code,
|
|
22
|
+
html,
|
|
23
|
+
title,
|
|
24
|
+
lang,
|
|
25
|
+
maxHeight,
|
|
26
|
+
copyable = true,
|
|
27
|
+
label,
|
|
28
|
+
className,
|
|
29
|
+
lineNumbers = false,
|
|
30
|
+
highlightLines
|
|
31
|
+
}) {
|
|
32
|
+
const [copied, setCopied] = useState(false);
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
if (!copied) return;
|
|
35
|
+
const timer = setTimeout(() => setCopied(false), 1600);
|
|
36
|
+
return () => clearTimeout(timer);
|
|
37
|
+
}, [copied]);
|
|
38
|
+
const copy = async () => {
|
|
39
|
+
try {
|
|
40
|
+
await navigator.clipboard.writeText(code);
|
|
41
|
+
setCopied(true);
|
|
42
|
+
} catch {
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const languageLabel = lang ? LANGUAGE_LABEL[lang] ?? lang.toUpperCase() : void 0;
|
|
46
|
+
const banded = new Set(highlightLines ?? []);
|
|
47
|
+
return /* @__PURE__ */ jsxs(
|
|
48
|
+
"div",
|
|
49
|
+
{
|
|
50
|
+
className: cn(
|
|
51
|
+
// `min-w-0` is what lets the body below actually scroll: a grid or flex
|
|
52
|
+
// item defaults to `min-width: auto`, so without it the block grows to
|
|
53
|
+
// the min-content width of its longest line — an unbroken install
|
|
54
|
+
// command — and pushes the whole page sideways on a phone.
|
|
55
|
+
"flex min-w-0 flex-col overflow-hidden rounded-(--radius-lg) border border-(--rule) bg-(--paper-2)",
|
|
56
|
+
className
|
|
57
|
+
),
|
|
58
|
+
children: [
|
|
59
|
+
title || languageLabel || copyable ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 border-b border-(--rule) py-1.5 ps-4 pe-1.5", children: [
|
|
60
|
+
title ? /* @__PURE__ */ jsx("span", { className: "mono-meta truncate text-(--ink-2)", children: title }) : null,
|
|
61
|
+
languageLabel ? /* @__PURE__ */ jsx("span", { className: "mono-meta shrink-0 text-(--ink-3-aa)", children: languageLabel }) : null,
|
|
62
|
+
copyable ? /* @__PURE__ */ jsx(
|
|
63
|
+
Button,
|
|
64
|
+
{
|
|
65
|
+
iconOnly: true,
|
|
66
|
+
size: "sm",
|
|
67
|
+
variant: "ghost",
|
|
68
|
+
onClick: copy,
|
|
69
|
+
"aria-label": copied ? "Copied" : "Copy the snippet",
|
|
70
|
+
className: "ms-auto shrink-0 pointer-coarse:min-h-11 pointer-coarse:min-w-11",
|
|
71
|
+
children: copied ? /* @__PURE__ */ jsx(Check, { size: 14, strokeWidth: 1.5, "aria-hidden": true }) : /* @__PURE__ */ jsx(Copy, { size: 14, strokeWidth: 1.5, "aria-hidden": true })
|
|
72
|
+
}
|
|
73
|
+
) : null
|
|
74
|
+
] }) : null,
|
|
75
|
+
/* @__PURE__ */ jsx(
|
|
76
|
+
"div",
|
|
77
|
+
{
|
|
78
|
+
tabIndex: 0,
|
|
79
|
+
role: "group",
|
|
80
|
+
"aria-label": label ?? title ?? "Code",
|
|
81
|
+
style: maxHeight === void 0 ? void 0 : { maxHeight },
|
|
82
|
+
className: "overflow-auto px-4 py-3.5 scroll-slim",
|
|
83
|
+
children: html === void 0 ? /* @__PURE__ */ jsx("pre", { className: "m-0 min-w-max bg-transparent p-0 font-mono text-[13px] leading-[1.7]", children: /* @__PURE__ */ jsx("code", { className: "block", children: code.split("\n").map((line, index) => /* @__PURE__ */ jsxs(
|
|
84
|
+
"span",
|
|
85
|
+
{
|
|
86
|
+
"data-line": index + 1,
|
|
87
|
+
"data-highlighted": banded.has(index + 1) ? "" : void 0,
|
|
88
|
+
className: cn(
|
|
89
|
+
"block min-h-[1.7em] border-s-2 border-transparent ps-2",
|
|
90
|
+
banded.has(index + 1) && "border-(--accent) bg-(--stone)"
|
|
91
|
+
),
|
|
92
|
+
children: [
|
|
93
|
+
lineNumbers ? /* @__PURE__ */ jsx(
|
|
94
|
+
"span",
|
|
95
|
+
{
|
|
96
|
+
"aria-hidden": true,
|
|
97
|
+
className: "inline-block w-8 shrink-0 select-none pe-3 text-end tabular-nums text-(--ink-3-aa)",
|
|
98
|
+
children: index + 1
|
|
99
|
+
}
|
|
100
|
+
) : null,
|
|
101
|
+
line
|
|
102
|
+
]
|
|
103
|
+
},
|
|
104
|
+
index
|
|
105
|
+
)) }) }) : (
|
|
106
|
+
// Trusted markup only: the output of the caller's own highlighter, run
|
|
107
|
+
// over the caller's own `code`. It is not a place to put anything a
|
|
108
|
+
// reader wrote — hand that to `code` and let the block render it as
|
|
109
|
+
// text, which it cannot mis-execute.
|
|
110
|
+
/* @__PURE__ */ jsx("div", { className: HIGHLIGHTED, dangerouslySetInnerHTML: { __html: html } })
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
var CodeBlock_default = CodeBlock;
|
|
119
|
+
export {
|
|
120
|
+
CodeBlock,
|
|
121
|
+
CodeBlock_default as default
|
|
122
|
+
};
|
|
123
|
+
//# sourceMappingURL=CodeBlock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/CodeBlock/CodeBlock.tsx"],"sourcesContent":["'use client'\n\nimport { Check, Copy } from 'lucide-react'\nimport { useEffect, useState } from 'react'\nimport { cn } from '../../lib/cn'\nimport { Button } from '../Button/Button'\n\n/**\n * What a language id is CALLED, for the handful where the id is not a label.\n *\n * Shiki's ids are identifiers, not words: `tsx` and `bash` read fine in upper\n * case, `md` and `ts` do not, and nobody reads `sh` as \"shell\". Anything absent\n * falls through to the id upper-cased, which is right far more often than it is\n * wrong — and a wrong label here is a label, not a crash.\n */\nconst LANGUAGE_LABEL: Record<string, string> = {\n bash: 'Shell',\n css: 'CSS',\n html: 'HTML',\n js: 'JavaScript',\n json: 'JSON',\n jsx: 'JSX',\n md: 'Markdown',\n sh: 'Shell',\n ts: 'TypeScript',\n tsx: 'TSX',\n}\n\ninterface CommonProps {\n /**\n * The snippet, verbatim.\n *\n * Required even when `html` is supplied, and that is the point: this is what\n * the copy button puts on the clipboard. A block that copies its own rendered\n * markup hands the reader a wall of `<span>`s, and one that copies\n * `textContent` scraped back out of the DOM is a single non-breaking space\n * away from pasting something that does not run.\n */\n code: string\n /** A filename or a caption, printed at the start of the strip. */\n title?: string\n /**\n * The language, printed at the end of the strip.\n *\n * Optional, and the omission is visible rather than silent: a block with no\n * language gets no label instead of claiming a wrong one. A code block that\n * does not say what it is written in makes the reader infer it from the\n * syntax, which is the one thing they came to the block to learn.\n */\n lang?: string\n /**\n * Caps the block's height and scrolls past it.\n *\n * A number is pixels; a string is any CSS length (`'24rem'`, `'50vh'`). The\n * body scrolls in both axes and is focusable, so what is past the fold stays\n * reachable with a keyboard rather than merely present in the DOM.\n */\n maxHeight?: number | string\n /** Drops the copy button, for a block nobody is meant to run. */\n copyable?: boolean\n /**\n * Names the scrollable body for a screen reader. Defaults to `title`, and to\n * \"Code\" when there is not one.\n */\n label?: string\n className?: string\n}\n\n/**\n * The two forms, and why they are two.\n *\n * `html` is pre-highlighted markup for the SAME snippet. The package does not\n * highlight, and will not: a highlighter is a few hundred kilobytes of grammar\n * and a build-time job. The documentation site runs Shiki inside its generator\n * and hands the result here, which is the shape that half exists for. Without\n * `html` the block renders `code` as text, which is what a template, a README\n * or an agent's answer has and all it needs.\n *\n * `lineNumbers` and `highlightLines` belong to the plain form only, and that is\n * enforced in the TYPE rather than left to a note. They are a per-LINE\n * structure, and `html` is one opaque string this component is not going to\n * start parsing. Typed apart, passing both is a compile error at the call site;\n * typed together it is a prop that renders nothing and says nothing.\n *\n * The plain form is written first because the emitted prop table reads the\n * first arm of a union: this way `lineNumbers` documents as `boolean` rather\n * than as the `never` the other arm gives it.\n */\ntype WithPlainSource = CommonProps & {\n /**\n * Absent on this form; `string` on the other.\n *\n * Pass pre-highlighted markup — Shiki's output, run at build time over this\n * same `code` — and the block renders that instead of the plain text. Doing\n * so takes `lineNumbers` and `highlightLines` away with it.\n */\n html?: undefined\n /** Numbers every line, counting from one. */\n lineNumbers?: boolean\n /**\n * Lines to band, counting from one. A number past the end of the snippet is\n * ignored rather than throwing — the usual cause is a snippet that got\n * shorter while the annotation did not.\n */\n highlightLines?: number[]\n}\n\ntype WithHighlightedHtml = CommonProps & {\n html: string\n /** Not available alongside `html`, which the component does not parse. */\n lineNumbers?: never\n /** Not available alongside `html`, which the component does not parse. */\n highlightLines?: never\n}\n\nexport type CodeBlockProps = WithPlainSource | WithHighlightedHtml\n\n/**\n * The caller's `<pre>`, normalised to ours.\n *\n * Shiki emits a `<pre>` of its own with a background and padding baked in, so\n * the highlighted path would otherwise draw a second plate a shade off the one\n * it is sitting on, at a size that does not match the plain path.\n */\nconst HIGHLIGHTED =\n '[&_pre]:m-0 [&_pre]:min-w-max [&_pre]:bg-transparent [&_pre]:p-0 [&_pre]:font-mono [&_pre]:text-[13px] [&_pre]:leading-[1.7] [&_code]:bg-transparent'\n\n/**\n * A multi-line snippet, on a plate, with a way to take it away.\n *\n * The strip along the top carries the title, the language and the copy button,\n * and it is there whenever there is anything to put in it. It is deliberately\n * not a hover affordance: a control that appears on hover does not exist on a\n * touch screen, which is where a reader is most likely to want the snippet and\n * least able to select it by hand.\n *\n * Line numbers live INSIDE their own line's row rather than in a parallel gutter\n * column. Two columns sharing a line-height align right up until one of them\n * wraps, ships a different font, or scrolls on its own; a number that is a child\n * of the line it numbers cannot come apart from it. The cost is that a number\n * scrolls away with its line: it is inside the scrolling box, not in a gutter\n * beside it. A gutter that stayed put would be a second column to keep in sync,\n * which is the failure this avoids.\n *\n * The body is a focusable, named `role=\"group\"`, and both halves of that are\n * load-bearing. Focusable, because a scrollable box whose contents are not\n * themselves focusable is unreachable by keyboard — there is nothing to Tab to\n * and therefore no way to press an arrow key at it, so the right-hand half of a\n * long line does not exist for anyone not using a mouse. Named, because a tab\n * stop that announces nothing lands the reader in an anonymous box and leaves\n * them to work out what they have arrived in.\n *\n * `group` rather than `region`, and that is the deliberate half. A region is a\n * LANDMARK — one of the handful of major sections a reader navigates a whole\n * page by — and a snippet is not one of those. Three fenced blocks in one\n * article would put three landmarks called \"Code\" into that map, which is\n * exactly the noise the `landmark-unique` rule exists to catch, and it would\n * push the page's real landmarks down a list nobody can now skim. `group`\n * carries the same accessible name to the same reader on the way in, and\n * carries it nowhere else.\n *\n * For a function name inside a sentence, reach for `Code`.\n *\n * @example\n * <CodeBlock code=\"pnpm add @misoto22/design\" lang=\"bash\" />\n * @example\n * <CodeBlock\n * title=\"cn.ts\"\n * lang=\"ts\"\n * lineNumbers\n * highlightLines={[2]}\n * maxHeight=\"24rem\"\n * code={source}\n * />\n * @example\n * // Highlighted at build time by the site's own Shiki pass.\n * <CodeBlock code={source} html={highlighted} lang=\"tsx\" />\n */\nexport function CodeBlock({\n code,\n html,\n title,\n lang,\n maxHeight,\n copyable = true,\n label,\n className,\n lineNumbers = false,\n highlightLines,\n}: CodeBlockProps) {\n const [copied, setCopied] = useState(false)\n\n useEffect(() => {\n if (!copied) return\n const timer = setTimeout(() => setCopied(false), 1600)\n return () => clearTimeout(timer)\n }, [copied])\n\n const copy = async () => {\n try {\n await navigator.clipboard.writeText(code)\n setCopied(true)\n } catch {\n // Clipboard access is denied in an insecure context and inside some\n // embeds. The snippet is still selectable, so there is nothing to\n // recover — and an unhandled rejection here would take the page with it.\n }\n }\n\n const languageLabel = lang ? (LANGUAGE_LABEL[lang] ?? lang.toUpperCase()) : undefined\n const banded = new Set(highlightLines ?? [])\n\n return (\n <div\n className={cn(\n // `min-w-0` is what lets the body below actually scroll: a grid or flex\n // item defaults to `min-width: auto`, so without it the block grows to\n // the min-content width of its longest line — an unbroken install\n // command — and pushes the whole page sideways on a phone.\n 'flex min-w-0 flex-col overflow-hidden rounded-(--radius-lg) border border-(--rule) bg-(--paper-2)',\n className,\n )}\n >\n {title || languageLabel || copyable ? (\n <div className=\"flex items-center gap-3 border-b border-(--rule) py-1.5 ps-4 pe-1.5\">\n {title ? <span className=\"mono-meta truncate text-(--ink-2)\">{title}</span> : null}\n {languageLabel ? (\n <span className=\"mono-meta shrink-0 text-(--ink-3-aa)\">{languageLabel}</span>\n ) : null}\n {copyable ? (\n <Button\n iconOnly\n size=\"sm\"\n variant=\"ghost\"\n onClick={copy}\n aria-label={copied ? 'Copied' : 'Copy the snippet'}\n // `sm` is 36px, under the 44px a finger needs. The bump is gated\n // on a coarse pointer so a mouse-driven page keeps the compact\n // strip (WCAG 2.5.5).\n className=\"ms-auto shrink-0 pointer-coarse:min-h-11 pointer-coarse:min-w-11\"\n >\n {copied ? (\n <Check size={14} strokeWidth={1.5} aria-hidden />\n ) : (\n <Copy size={14} strokeWidth={1.5} aria-hidden />\n )}\n </Button>\n ) : null}\n </div>\n ) : null}\n\n <div\n tabIndex={0}\n // A named group, not a landmark: see the note above the component.\n role=\"group\"\n aria-label={label ?? title ?? 'Code'}\n style={maxHeight === undefined ? undefined : { maxHeight }}\n className=\"overflow-auto px-4 py-3.5 scroll-slim\"\n >\n {html === undefined ? (\n <pre className=\"m-0 min-w-max bg-transparent p-0 font-mono text-[13px] leading-[1.7]\">\n <code className=\"block\">\n {code.split('\\n').map((line, index) => (\n <span\n key={index}\n data-line={index + 1}\n data-highlighted={banded.has(index + 1) ? '' : undefined}\n // The transparent border is carried by EVERY row, banded or\n // not. On the banded ones alone it would shift them two pixels\n // along the inline axis — which is the exact misalignment a\n // highlight is there to help the reader see past.\n //\n // `min-h` is what keeps a blank line a line: an empty block\n // has no line box and would otherwise collapse to nothing,\n // taking every number below it out of step with its code.\n className={cn(\n 'block min-h-[1.7em] border-s-2 border-transparent ps-2',\n banded.has(index + 1) && 'border-(--accent) bg-(--stone)',\n )}\n >\n {lineNumbers ? (\n <span\n aria-hidden\n className=\"inline-block w-8 shrink-0 select-none pe-3 text-end tabular-nums text-(--ink-3-aa)\"\n >\n {index + 1}\n </span>\n ) : null}\n {line}\n </span>\n ))}\n </code>\n </pre>\n ) : (\n // Trusted markup only: the output of the caller's own highlighter, run\n // over the caller's own `code`. It is not a place to put anything a\n // reader wrote — hand that to `code` and let the block render it as\n // text, which it cannot mis-execute.\n <div className={HIGHLIGHTED} dangerouslySetInnerHTML={{ __html: html }} />\n )}\n </div>\n </div>\n )\n}\n\nexport default CodeBlock\n"],"mappings":";AAgOQ,SACW,KADX;AA9NR,SAAS,OAAO,YAAY;AAC5B,SAAS,WAAW,gBAAgB;AACpC,SAAS,UAAU;AACnB,SAAS,cAAc;AAUvB,MAAM,iBAAyC;AAAA,EAC7C,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,KAAK;AAAA,EACL,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,KAAK;AACP;AAkGA,MAAM,cACJ;AAqDK,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AACF,GAAmB;AACjB,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAE1C,YAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,UAAM,QAAQ,WAAW,MAAM,UAAU,KAAK,GAAG,IAAI;AACrD,WAAO,MAAM,aAAa,KAAK;AAAA,EACjC,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,OAAO,YAAY;AACvB,QAAI;AACF,YAAM,UAAU,UAAU,UAAU,IAAI;AACxC,gBAAU,IAAI;AAAA,IAChB,QAAQ;AAAA,IAIR;AAAA,EACF;AAEA,QAAM,gBAAgB,OAAQ,eAAe,IAAI,KAAK,KAAK,YAAY,IAAK;AAC5E,QAAM,SAAS,IAAI,IAAI,kBAAkB,CAAC,CAAC;AAE3C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA,QAKT;AAAA,QACA;AAAA,MACF;AAAA,MAEC;AAAA,iBAAS,iBAAiB,WACzB,qBAAC,SAAI,WAAU,uEACZ;AAAA,kBAAQ,oBAAC,UAAK,WAAU,qCAAqC,iBAAM,IAAU;AAAA,UAC7E,gBACC,oBAAC,UAAK,WAAU,wCAAwC,yBAAc,IACpE;AAAA,UACH,WACC;AAAA,YAAC;AAAA;AAAA,cACC,UAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAQ;AAAA,cACR,SAAS;AAAA,cACT,cAAY,SAAS,WAAW;AAAA,cAIhC,WAAU;AAAA,cAET,mBACC,oBAAC,SAAM,MAAM,IAAI,aAAa,KAAK,eAAW,MAAC,IAE/C,oBAAC,QAAK,MAAM,IAAI,aAAa,KAAK,eAAW,MAAC;AAAA;AAAA,UAElD,IACE;AAAA,WACN,IACE;AAAA,QAEJ;AAAA,UAAC;AAAA;AAAA,YACC,UAAU;AAAA,YAEV,MAAK;AAAA,YACL,cAAY,SAAS,SAAS;AAAA,YAC9B,OAAO,cAAc,SAAY,SAAY,EAAE,UAAU;AAAA,YACzD,WAAU;AAAA,YAET,mBAAS,SACR,oBAAC,SAAI,WAAU,wEACb,8BAAC,UAAK,WAAU,SACb,eAAK,MAAM,IAAI,EAAE,IAAI,CAAC,MAAM,UAC3B;AAAA,cAAC;AAAA;AAAA,gBAEC,aAAW,QAAQ;AAAA,gBACnB,oBAAkB,OAAO,IAAI,QAAQ,CAAC,IAAI,KAAK;AAAA,gBAS/C,WAAW;AAAA,kBACT;AAAA,kBACA,OAAO,IAAI,QAAQ,CAAC,KAAK;AAAA,gBAC3B;AAAA,gBAEC;AAAA,gCACC;AAAA,oBAAC;AAAA;AAAA,sBACC,eAAW;AAAA,sBACX,WAAU;AAAA,sBAET,kBAAQ;AAAA;AAAA,kBACX,IACE;AAAA,kBACH;AAAA;AAAA;AAAA,cAxBI;AAAA,YAyBP,CACD,GACH,GACF;AAAA;AAAA;AAAA;AAAA;AAAA,cAMA,oBAAC,SAAI,WAAW,aAAa,yBAAyB,EAAE,QAAQ,KAAK,GAAG;AAAA;AAAA;AAAA,QAE5E;AAAA;AAAA;AAAA,EACF;AAEJ;AAEA,IAAO,oBAAQ;","names":[]}
|
|
@@ -12,8 +12,9 @@ function CollapsibleContent({
|
|
|
12
12
|
return /* @__PURE__ */ jsx(
|
|
13
13
|
CollapsiblePrimitive.Content,
|
|
14
14
|
{
|
|
15
|
+
"data-m22-animated": true,
|
|
15
16
|
className: cn(
|
|
16
|
-
"overflow-hidden data-[state=closed]:animate-[m22-collapsible-up_var(--duration-base)_var(--ease)] data-[state=open]:animate-[m22-collapsible-down_var(--duration-base)_var(--ease)]
|
|
17
|
+
"overflow-hidden data-[state=closed]:animate-[m22-collapsible-up_var(--duration-base)_var(--ease)] data-[state=open]:animate-[m22-collapsible-down_var(--duration-base)_var(--ease)]",
|
|
17
18
|
className
|
|
18
19
|
),
|
|
19
20
|
...props
|
|
@@ -39,7 +40,14 @@ function CollapsibleSection({
|
|
|
39
40
|
}
|
|
40
41
|
)
|
|
41
42
|
] }),
|
|
42
|
-
/* @__PURE__ */ jsx(
|
|
43
|
+
/* @__PURE__ */ jsx(
|
|
44
|
+
CollapsiblePrimitive.Content,
|
|
45
|
+
{
|
|
46
|
+
"data-m22-animated": true,
|
|
47
|
+
className: "overflow-hidden text-sm leading-relaxed text-(--ink-2) data-[state=closed]:animate-[m22-collapsible-up_var(--duration-base)_var(--ease)] data-[state=open]:animate-[m22-collapsible-down_var(--duration-base)_var(--ease)]",
|
|
48
|
+
children: /* @__PURE__ */ jsx("div", { className: "pb-3", children })
|
|
49
|
+
}
|
|
50
|
+
)
|
|
43
51
|
] });
|
|
44
52
|
}
|
|
45
53
|
var Collapsible_default = Collapsible;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/Collapsible/Collapsible.tsx"],"sourcesContent":["'use client'\n\nimport * as CollapsiblePrimitive from '@radix-ui/react-collapsible'\nimport { ChevronDown } from 'lucide-react'\nimport type { ComponentProps, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\n\n/** Radix Collapsible root, as a typed passthrough. */\nexport const Collapsible = CollapsiblePrimitive.Root\n\n/**\n * The trigger and the panel, unstyled, for a disclosure that needs its own\n * layout — a sidebar group whose header carries a count and a chevron on\n * opposite sides, say. `CollapsibleSection` is the composed version and is what\n * most call sites want; these two exist so the ones that do not have to reach\n * for Radix directly and re-derive the keyboard and `aria-expanded` wiring.\n *\n * The panel animates on `--radix-collapsible-content-height`, which Radix\n * measures — so it opens to its real height rather than to a guessed\n * `max-height`, which is what makes a long group and a short one take the same\n * time instead of the long one appearing to stall.\n */\nexport const CollapsibleTrigger = CollapsiblePrimitive.Trigger\n\nexport function CollapsibleContent({\n className,\n ...props\n}: ComponentProps<typeof CollapsiblePrimitive.Content>) {\n return (\n <CollapsiblePrimitive.Content\n className={cn(\n 'overflow-hidden data-[state=closed]:animate-[m22-collapsible-up_var(--duration-base)_var(--ease)] data-[state=open]:animate-[m22-collapsible-down_var(--duration-base)_var(--ease)]
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Collapsible/Collapsible.tsx"],"sourcesContent":["'use client'\n\nimport * as CollapsiblePrimitive from '@radix-ui/react-collapsible'\nimport { ChevronDown } from 'lucide-react'\nimport type { ComponentProps, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\n\n/** Radix Collapsible root, as a typed passthrough. */\nexport const Collapsible = CollapsiblePrimitive.Root\n\n/**\n * The trigger and the panel, unstyled, for a disclosure that needs its own\n * layout — a sidebar group whose header carries a count and a chevron on\n * opposite sides, say. `CollapsibleSection` is the composed version and is what\n * most call sites want; these two exist so the ones that do not have to reach\n * for Radix directly and re-derive the keyboard and `aria-expanded` wiring.\n *\n * The panel animates on `--radix-collapsible-content-height`, which Radix\n * measures — so it opens to its real height rather than to a guessed\n * `max-height`, which is what makes a long group and a short one take the same\n * time instead of the long one appearing to stall.\n */\nexport const CollapsibleTrigger = CollapsiblePrimitive.Trigger\n\nexport function CollapsibleContent({\n className,\n ...props\n}: ComponentProps<typeof CollapsiblePrimitive.Content>) {\n return (\n <CollapsiblePrimitive.Content\n data-m22-animated\n className={cn(\n 'overflow-hidden data-[state=closed]:animate-[m22-collapsible-up_var(--duration-base)_var(--ease)] data-[state=open]:animate-[m22-collapsible-down_var(--duration-base)_var(--ease)]',\n className,\n )}\n {...props}\n />\n )\n}\n\nexport interface CollapsibleSectionProps\n extends Omit<ComponentProps<typeof CollapsiblePrimitive.Root>, 'children' | 'title'> {\n /** What the trigger says. */\n title: ReactNode\n children: ReactNode\n}\n\n/**\n * One thing that opens, on its own.\n *\n * The difference from `Accordion` is arithmetic: an accordion is a SET, and a\n * set can coordinate — opening one closes another. A collapsible is one\n * disclosure with nothing to coordinate with. Reaching for an accordion of one\n * gets you a component managing a value you never read.\n *\n * The marker here is a chevron rather than the accordion's plus, and\n * deliberately: this reveals more of the same thing, where an accordion row\n * opens a distinct answer.\n *\n * @example\n * <CollapsibleSection title=\"Advanced settings\">\n * <Field label=\"Retries\"><Input type=\"number\" /></Field>\n * </CollapsibleSection>\n */\nexport function CollapsibleSection({\n title,\n children,\n className,\n ...props\n}: CollapsibleSectionProps) {\n return (\n <CollapsiblePrimitive.Root className={cn('w-full', className)} {...props}>\n <CollapsiblePrimitive.Trigger className=\"group flex w-full items-center justify-between gap-4 py-3 text-start text-sm text-(--ink) transition-colors duration-(--duration-fast) hover:text-(--ink-2)\">\n {title}\n <ChevronDown\n size={16}\n strokeWidth={1.5}\n aria-hidden\n className=\"shrink-0 text-(--ink-3-aa) transition-transform duration-(--duration-base) ease-(--ease-out-expo) group-data-[state=open]:rotate-180\"\n />\n </CollapsiblePrimitive.Trigger>\n <CollapsiblePrimitive.Content\n data-m22-animated\n className=\"overflow-hidden text-sm leading-relaxed text-(--ink-2) data-[state=closed]:animate-[m22-collapsible-up_var(--duration-base)_var(--ease)] data-[state=open]:animate-[m22-collapsible-down_var(--duration-base)_var(--ease)]\"\n >\n <div className=\"pb-3\">{children}</div>\n </CollapsiblePrimitive.Content>\n </CollapsiblePrimitive.Root>\n )\n}\n\nexport default Collapsible\n"],"mappings":";AA6BI,cA2CE,YA3CF;AA3BJ,YAAY,0BAA0B;AACtC,SAAS,mBAAmB;AAE5B,SAAS,UAAU;AAGZ,MAAM,cAAc,qBAAqB;AAczC,MAAM,qBAAqB,qBAAqB;AAEhD,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA,GAAG;AACL,GAAwD;AACtD,SACE;AAAA,IAAC,qBAAqB;AAAA,IAArB;AAAA,MACC,qBAAiB;AAAA,MACjB,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AA0BO,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAA4B;AAC1B,SACE,qBAAC,qBAAqB,MAArB,EAA0B,WAAW,GAAG,UAAU,SAAS,GAAI,GAAG,OACjE;AAAA,yBAAC,qBAAqB,SAArB,EAA6B,WAAU,+JACrC;AAAA;AAAA,MACD;AAAA,QAAC;AAAA;AAAA,UACC,MAAM;AAAA,UACN,aAAa;AAAA,UACb,eAAW;AAAA,UACX,WAAU;AAAA;AAAA,MACZ;AAAA,OACF;AAAA,IACA;AAAA,MAAC,qBAAqB;AAAA,MAArB;AAAA,QACC,qBAAiB;AAAA,QACjB,WAAU;AAAA,QAEV,8BAAC,SAAI,WAAU,QAAQ,UAAS;AAAA;AAAA,IAClC;AAAA,KACF;AAEJ;AAEA,IAAO,sBAAQ;","names":[]}
|
|
@@ -9,7 +9,13 @@ interface ComboboxOption {
|
|
|
9
9
|
}
|
|
10
10
|
interface CommonProps {
|
|
11
11
|
options: ComboboxOption[];
|
|
12
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Names the control. Required — the trigger's text is a value, not a label.
|
|
14
|
+
*
|
|
15
|
+
* Announced together with the summary rather than instead of it, so a reader
|
|
16
|
+
* hears "Tags, 3 selected". Inside a `Field` with a label, that label names
|
|
17
|
+
* the trigger and this one is not repeated.
|
|
18
|
+
*/
|
|
13
19
|
label: string;
|
|
14
20
|
/** Shown on the trigger when nothing is chosen. */
|
|
15
21
|
placeholder?: string;
|
|
@@ -19,6 +25,14 @@ interface CommonProps {
|
|
|
19
25
|
emptyMessage?: string;
|
|
20
26
|
disabled?: boolean;
|
|
21
27
|
className?: string;
|
|
28
|
+
/** The TRIGGER's id — the element a label points at. A `Field` sets it. */
|
|
29
|
+
id?: string;
|
|
30
|
+
/** Ids of the copy describing the control. A `Field` sets it from hint, error and description. */
|
|
31
|
+
'aria-describedby'?: string;
|
|
32
|
+
/** Paints the resting border with `--danger` and is announced. A `Field` sets it from `error`. */
|
|
33
|
+
'aria-invalid'?: boolean | 'true' | 'false';
|
|
34
|
+
/** Announced on the trigger. A `Field` sets it from `required`. */
|
|
35
|
+
'aria-required'?: boolean;
|
|
22
36
|
}
|
|
23
37
|
interface SingleProps extends CommonProps {
|
|
24
38
|
multiple?: false;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { Check, ChevronsUpDown, X } from "lucide-react";
|
|
4
|
-
import { useState } from "react";
|
|
4
|
+
import { useId, useState } from "react";
|
|
5
5
|
import { cn } from "../../lib/cn.js";
|
|
6
|
+
import { CONTROL_BORDER, isInvalid } from "../../lib/control.js";
|
|
7
|
+
import { useFieldControl } from "../Field/field-control.js";
|
|
8
|
+
import { warnBlankName } from "../../lib/warn.js";
|
|
6
9
|
import {
|
|
7
10
|
Command,
|
|
8
11
|
CommandEmpty,
|
|
@@ -21,9 +24,20 @@ function Combobox(props) {
|
|
|
21
24
|
searchPlaceholder = "Search\u2026",
|
|
22
25
|
emptyMessage = "Nothing matches.",
|
|
23
26
|
disabled = false,
|
|
24
|
-
className
|
|
27
|
+
className,
|
|
28
|
+
id,
|
|
29
|
+
"aria-describedby": describedBy,
|
|
30
|
+
"aria-invalid": ariaInvalid,
|
|
31
|
+
"aria-required": ariaRequired
|
|
25
32
|
} = props;
|
|
26
33
|
const multiple = props.multiple === true;
|
|
34
|
+
warnBlankName("Combobox", "label", label, "the trigger is announced with no name");
|
|
35
|
+
const field = useFieldControl();
|
|
36
|
+
const generated = useId();
|
|
37
|
+
const triggerId = id ?? generated;
|
|
38
|
+
const summaryId = `${triggerId}-value`;
|
|
39
|
+
const nameId = field?.labelId ?? `${triggerId}-name`;
|
|
40
|
+
const bad = isInvalid(void 0, ariaInvalid);
|
|
27
41
|
const [open, setOpen] = useState(false);
|
|
28
42
|
const [uncontrolled, setUncontrolled] = useState(() => {
|
|
29
43
|
if (props.multiple === true) return props.defaultValue ?? [];
|
|
@@ -51,16 +65,22 @@ function Combobox(props) {
|
|
|
51
65
|
PopoverTrigger,
|
|
52
66
|
{
|
|
53
67
|
role: "combobox",
|
|
68
|
+
id: triggerId,
|
|
54
69
|
"aria-expanded": open,
|
|
55
|
-
"aria-
|
|
70
|
+
"aria-labelledby": `${nameId} ${summaryId}`,
|
|
71
|
+
"aria-describedby": describedBy,
|
|
72
|
+
"aria-required": ariaRequired,
|
|
73
|
+
"aria-invalid": bad || void 0,
|
|
56
74
|
disabled,
|
|
57
75
|
className: cn(
|
|
58
|
-
"group flex w-full items-center justify-between gap-2 rounded-(--radius) border
|
|
76
|
+
"group flex w-full items-center justify-between gap-2 rounded-(--radius) border bg-(--paper) px-(--field-px) py-(--field-py) text-start text-sm transition-colors duration-(--duration-fast) hover:border-(--rule-hard) disabled:opacity-(--disabled-opacity) disabled:pointer-events-none",
|
|
77
|
+
bad ? CONTROL_BORDER.invalid : CONTROL_BORDER.resting,
|
|
59
78
|
chosen.length > 0 ? "text-(--ink)" : "text-(--ink-3-aa)",
|
|
60
79
|
className
|
|
61
80
|
),
|
|
62
81
|
children: [
|
|
63
|
-
/* @__PURE__ */ jsx("span", { className: "
|
|
82
|
+
field?.labelId == null && /* @__PURE__ */ jsx("span", { id: nameId, className: "sr-only", children: label }),
|
|
83
|
+
/* @__PURE__ */ jsx("span", { id: summaryId, className: "truncate", children: summary }),
|
|
64
84
|
/* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-1", children: [
|
|
65
85
|
multiple && chosen.length > 0 && // A `<span role="button">` rather than a nested `<button>`, which
|
|
66
86
|
// is invalid inside the trigger and which browsers reparent — the
|