@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/lib/overlay-container.tsx"],"sourcesContent":["'use client'\n\nimport { createContext, useContext } from 'react'\nimport type { ReactNode } from 'react'\n\nconst OverlayContainerContext = createContext<HTMLElement | null>(null)\n\nexport interface OverlayContainerProps {\n /** The element overlays should render into. `null` restores the default. */\n container: HTMLElement | null\n children: ReactNode\n}\n\n/**\n * Redirects every overlay in the subtree — popover, select, menu, tooltip — into
|
|
1
|
+
{"version":3,"sources":["../../src/lib/overlay-container.tsx"],"sourcesContent":["'use client'\n\nimport { createContext, useContext } from 'react'\nimport type { ReactNode } from 'react'\n\nconst OverlayContainerContext = createContext<HTMLElement | null>(null)\n\nexport interface OverlayContainerProps {\n /** The element overlays should render into. `null` restores the default. */\n container: HTMLElement | null\n children: ReactNode\n}\n\n/**\n * Redirects every overlay in the subtree — popover, select, menu, tooltip,\n * dialog, sheet — into a given element instead of `document.body`.\n *\n * Two problems, one cause. An overlay portalled to the body is positioned\n * against the VIEWPORT, so inside a bounded frame (a documentation example, a\n * device preview, a canvas) it flips and shifts against edges the reader cannot\n * see, and lands outside the box it belongs to. It also leaves the subtree, so\n * `dir=\"rtl\"` and `data-density` set on that frame stop reaching it.\n *\n * Naming the container fixes both: the panel renders inside the frame,\n * inherits what the frame declares, and collides with the frame's edges.\n *\n * The container must be positioned (`relative` is enough) for the panel to be\n * placed against it rather than against the nearest positioned ancestor. The\n * modal surfaces need it for a second reason: they place themselves with\n * `position: fixed`, which resolves against the VIEWPORT whatever element they\n * are portalled into, so a named container switches them to `absolute` — and\n * an unpositioned container would then hand them the wrong box.\n *\n * @example\n * const [frame, setFrame] = useState<HTMLElement | null>(null)\n * <div ref={setFrame} className=\"relative\" data-density=\"compact\">\n * <OverlayContainer container={frame}>{children}</OverlayContainer>\n * </div>\n */\nexport function OverlayContainer({ container, children }: OverlayContainerProps) {\n return <OverlayContainerContext value={container}>{children}</OverlayContainerContext>\n}\n\n/**\n * The element overlays in this subtree should render into, or `null` for the\n * document body.\n *\n * Every portal in the library reads this. That sentence was false for a\n * release: `Dialog` and `Sheet` rendered the Radix portal with no container and\n * never called this hook, and their props derive from `Content`, which has no\n * `container` — so a caller could not pass one either, and every modal example\n * on the documentation site escaped the preview card it was drawn in.\n */\nexport function useOverlayContainer(): HTMLElement | null {\n return useContext(OverlayContainerContext)\n}\n"],"mappings":";AAwCS;AAtCT,SAAS,eAAe,kBAAkB;AAG1C,MAAM,0BAA0B,cAAkC,IAAI;AAkC/D,SAAS,iBAAiB,EAAE,WAAW,SAAS,GAA0B;AAC/E,SAAO,oBAAC,2BAAwB,OAAO,WAAY,UAAS;AAC9D;AAYO,SAAS,sBAA0C;AACxD,SAAO,WAAW,uBAAuB;AAC3C;","names":[]}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Taking an `<svg>` off the page as a file.
|
|
3
|
+
*
|
|
4
|
+
* Shared by two entries that both draw in SVG and both need to hand a reader a
|
|
5
|
+
* picture of it: `@misoto22/design/charts` and `@misoto22/design/diagrams`.
|
|
6
|
+
* Everything here is engine-agnostic — nothing knows what a series or a node
|
|
7
|
+
* is — so the parts that DO know (which `<svg>` inside a wrapper is the plot,
|
|
8
|
+
* what the file should be called, what sits behind it) stay with the caller.
|
|
9
|
+
*
|
|
10
|
+
* Nothing touches the DOM at module scope. Every browser API — `document`,
|
|
11
|
+
* `canvas`, `URL.createObjectURL` — is reached for inside a function body, so
|
|
12
|
+
* this module imports cleanly into a server component and only fails when a
|
|
13
|
+
* consumer actually asks for a file on a server, which is a call that cannot
|
|
14
|
+
* succeed anywhere.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Copies the resolved paint of every node in `live` onto the matching node in
|
|
18
|
+
* `clone`.
|
|
19
|
+
*
|
|
20
|
+
* ## The problem this function exists to solve
|
|
21
|
+
*
|
|
22
|
+
* Serialising an `<svg>` and handing it to an `<img>` puts it in a document of
|
|
23
|
+
* its own. That document has none of the page's stylesheets, so every
|
|
24
|
+
* `var(--ink)`, `var(--rule-2)` and `var(--diagram-node)` in the markup
|
|
25
|
+
* resolves to nothing — and a paint that resolves to nothing is not a fallback
|
|
26
|
+
* colour, it is an invisible mark. Serialise naively and you get an empty
|
|
27
|
+
* rectangle.
|
|
28
|
+
*
|
|
29
|
+
* ## The solution
|
|
30
|
+
*
|
|
31
|
+
* Walk the live tree and the clone in step, and on every node write
|
|
32
|
+
* `getComputedStyle`'s answer into an inline `style`. Computed values have
|
|
33
|
+
* already had `var()` substituted by the engine, so `fill: var(--ink)` arrives
|
|
34
|
+
* as `fill: rgb(16, 16, 16)` — and, because the walk reads the LIVE element, it
|
|
35
|
+
* reads it under whichever theme is currently applied. Light and dark come out
|
|
36
|
+
* right for free, with no theme argument anywhere in this file.
|
|
37
|
+
*
|
|
38
|
+
* `<stop>` and `<marker>` children are walked too, which is the half that is
|
|
39
|
+
* easy to miss: a gradient's stops and an arrowhead's fill carry custom
|
|
40
|
+
* properties of their own, and a `<defs>` that lost its paint takes every line
|
|
41
|
+
* ending with it.
|
|
42
|
+
*/
|
|
43
|
+
declare function inlinePaint(live: Element, clone: Element): void;
|
|
44
|
+
/**
|
|
45
|
+
* A custom property, resolved against the live element.
|
|
46
|
+
*
|
|
47
|
+
* `var()` inside a custom property is substituted at computed-value time, so
|
|
48
|
+
* `--diagram-surface: var(--paper)` reads back as a colour. The guard is for
|
|
49
|
+
* the case where it did not — an unregistered name, or a value the engine left
|
|
50
|
+
* as a token stream — because writing `var(--paper)` into a serialised SVG
|
|
51
|
+
* paints nothing at all.
|
|
52
|
+
*/
|
|
53
|
+
declare function readToken(element: Element, name: string, fallback: string): string;
|
|
54
|
+
interface SerializeOptions {
|
|
55
|
+
/** Space around the artwork, in user units. Defaults to 16. */
|
|
56
|
+
padding?: number;
|
|
57
|
+
/** Painted behind the artwork. Omit for a transparent ground. */
|
|
58
|
+
background?: string;
|
|
59
|
+
/** A band above the artwork carrying this text. */
|
|
60
|
+
title?: string;
|
|
61
|
+
/** Paint for the title. Defaults to `#101010`. */
|
|
62
|
+
titleColor?: string;
|
|
63
|
+
/** Family for the title. Defaults to `sans-serif`. */
|
|
64
|
+
titleFont?: string;
|
|
65
|
+
/**
|
|
66
|
+
* Forces the output box, letterboxing the artwork inside it.
|
|
67
|
+
*
|
|
68
|
+
* This is what a share card is: a fixed 1200×630 frame that the diagram is
|
|
69
|
+
* fitted into, rather than a frame the diagram sizes. Omit it and the output
|
|
70
|
+
* is the artwork plus its padding.
|
|
71
|
+
*/
|
|
72
|
+
frame?: {
|
|
73
|
+
width: number;
|
|
74
|
+
height: number;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* One standalone `<svg>` document: the element's own artwork, repainted with
|
|
79
|
+
* resolved colours, on an optional plate, under an optional title.
|
|
80
|
+
*
|
|
81
|
+
* Returns markup rather than a blob because the SVG export wants the string
|
|
82
|
+
* and every raster export wants it as a data source — one serialisation, four
|
|
83
|
+
* file formats.
|
|
84
|
+
*
|
|
85
|
+
* ## What this cannot capture, honestly
|
|
86
|
+
*
|
|
87
|
+
* - **Anything drawn in HTML.** A toolbar, a tooltip, an inspector panel are
|
|
88
|
+
* DOM, not SVG. The file is the artwork.
|
|
89
|
+
* - **Web fonts.** The isolated document cannot fetch the page's `@font-face`
|
|
90
|
+
* sources, so text is rasterised in whatever the resolved family stack finds
|
|
91
|
+
* locally. Type metrics will differ from the screen.
|
|
92
|
+
* - **Cross-origin images.** An `<image>` from another origin taints the canvas
|
|
93
|
+
* and `toBlob` throws; there is no way around it from script.
|
|
94
|
+
*/
|
|
95
|
+
declare function serializeSvg(svg: SVGSVGElement, options?: SerializeOptions): string;
|
|
96
|
+
/** The raster formats a browser canvas can encode. */
|
|
97
|
+
type RasterFormat = 'png' | 'jpeg' | 'webp';
|
|
98
|
+
interface RasterOptions {
|
|
99
|
+
/** Multiplier on the on-screen size. 2 is a retina-sharp export. */
|
|
100
|
+
scale?: number;
|
|
101
|
+
/** Encoder quality for `jpeg` and `webp`, 0–1. Ignored by `png`. */
|
|
102
|
+
quality?: number;
|
|
103
|
+
/**
|
|
104
|
+
* Painted behind the image, for a format with no alpha channel.
|
|
105
|
+
*
|
|
106
|
+
* JPEG has no transparency, so a diagram serialised without a plate lands on
|
|
107
|
+
* black. Passing the page's own surface here is what makes the file look
|
|
108
|
+
* like the screen rather than like a negative.
|
|
109
|
+
*/
|
|
110
|
+
background?: string;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* SVG markup, rasterised through a canvas.
|
|
114
|
+
*
|
|
115
|
+
* This is the browser's own SVG rasteriser re-drawing the markup, not a
|
|
116
|
+
* screenshot: antialiasing, `backdrop-filter` and any effect a page stylesheet
|
|
117
|
+
* applied from outside the `<svg>` are not in it.
|
|
118
|
+
*/
|
|
119
|
+
declare function rasterize(markup: string, format: RasterFormat, options?: RasterOptions): Promise<Blob>;
|
|
120
|
+
/**
|
|
121
|
+
* Hands a blob to the browser as a download.
|
|
122
|
+
*
|
|
123
|
+
* Throws rather than no-oping without a `document`: a download is something a
|
|
124
|
+
* person just asked for, and a silent return would look to them like a click
|
|
125
|
+
* that did nothing.
|
|
126
|
+
*/
|
|
127
|
+
declare function downloadBlob(blob: Blob, filename: string): void;
|
|
128
|
+
/**
|
|
129
|
+
* A title as a filename.
|
|
130
|
+
*
|
|
131
|
+
* Lowercase, ASCII-safe and hyphenated, because a downloaded file crosses into
|
|
132
|
+
* shells, zip archives and Windows paths where a title's spaces and slashes are
|
|
133
|
+
* someone else's problem. A title with no ASCII in it at all — a Chinese one,
|
|
134
|
+
* say — slugs to nothing, so the caller's fallback is what names the file.
|
|
135
|
+
*/
|
|
136
|
+
declare function exportFilename(title: string, extension: string, fallback?: string): string;
|
|
137
|
+
|
|
138
|
+
export { type RasterFormat, type RasterOptions, type SerializeOptions, downloadBlob, exportFilename, inlinePaint, rasterize, readToken, serializeSvg };
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
const SVG_NS = "http://www.w3.org/2000/svg";
|
|
2
|
+
const PAINTED_PROPERTIES = [
|
|
3
|
+
"display",
|
|
4
|
+
"visibility",
|
|
5
|
+
"opacity",
|
|
6
|
+
"color",
|
|
7
|
+
"fill",
|
|
8
|
+
"fill-opacity",
|
|
9
|
+
"fill-rule",
|
|
10
|
+
"stroke",
|
|
11
|
+
"stroke-opacity",
|
|
12
|
+
"stroke-width",
|
|
13
|
+
"stroke-linecap",
|
|
14
|
+
"stroke-linejoin",
|
|
15
|
+
"stroke-dasharray",
|
|
16
|
+
"stroke-dashoffset",
|
|
17
|
+
"stop-color",
|
|
18
|
+
"stop-opacity",
|
|
19
|
+
"flood-color",
|
|
20
|
+
"flood-opacity",
|
|
21
|
+
"marker-start",
|
|
22
|
+
"marker-mid",
|
|
23
|
+
"marker-end",
|
|
24
|
+
"mask",
|
|
25
|
+
"filter",
|
|
26
|
+
"clip-path",
|
|
27
|
+
"clip-rule",
|
|
28
|
+
"paint-order",
|
|
29
|
+
"mix-blend-mode",
|
|
30
|
+
"shape-rendering",
|
|
31
|
+
"text-anchor",
|
|
32
|
+
"dominant-baseline",
|
|
33
|
+
"font-family",
|
|
34
|
+
"font-size",
|
|
35
|
+
"font-style",
|
|
36
|
+
"font-weight",
|
|
37
|
+
"letter-spacing",
|
|
38
|
+
"text-transform"
|
|
39
|
+
];
|
|
40
|
+
function inlinePaint(live, clone) {
|
|
41
|
+
const computed = getComputedStyle(live);
|
|
42
|
+
let css = "";
|
|
43
|
+
for (const property of PAINTED_PROPERTIES) {
|
|
44
|
+
const value = computed.getPropertyValue(property);
|
|
45
|
+
if (value) css += `${property}:${value};`;
|
|
46
|
+
}
|
|
47
|
+
if (css) clone.setAttribute("style", css);
|
|
48
|
+
const children = live.children;
|
|
49
|
+
const clones = clone.children;
|
|
50
|
+
for (let index = 0; index < children.length; index += 1) {
|
|
51
|
+
const liveChild = children[index];
|
|
52
|
+
const cloneChild = clones[index];
|
|
53
|
+
if (liveChild && cloneChild) inlinePaint(liveChild, cloneChild);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function readToken(element, name, fallback) {
|
|
57
|
+
const value = getComputedStyle(element).getPropertyValue(name).trim();
|
|
58
|
+
return value && !value.includes("var(") ? value : fallback;
|
|
59
|
+
}
|
|
60
|
+
function serializeSvg(svg, options = {}) {
|
|
61
|
+
const { padding = 16, background, title, titleColor = "#101010", titleFont = "sans-serif" } = options;
|
|
62
|
+
const box = svg.getBoundingClientRect();
|
|
63
|
+
const width = Math.ceil(box.width) || Number(svg.getAttribute("width")) || 0;
|
|
64
|
+
const height = Math.ceil(box.height) || Number(svg.getAttribute("height")) || 0;
|
|
65
|
+
if (width === 0 || height === 0) {
|
|
66
|
+
throw new Error("serializeSvg: the artwork has no measured size yet \u2014 export it after it renders");
|
|
67
|
+
}
|
|
68
|
+
const clone = svg.cloneNode(true);
|
|
69
|
+
inlinePaint(svg, clone);
|
|
70
|
+
clone.setAttribute("width", String(width));
|
|
71
|
+
clone.setAttribute("height", String(height));
|
|
72
|
+
const titleBand = title ? 34 : 0;
|
|
73
|
+
const contentWidth = width + padding * 2;
|
|
74
|
+
const contentHeight = height + padding * 2 + titleBand;
|
|
75
|
+
const totalWidth = options.frame?.width ?? contentWidth;
|
|
76
|
+
const totalHeight = options.frame?.height ?? contentHeight;
|
|
77
|
+
const scale = options.frame ? Math.min(totalWidth / contentWidth, totalHeight / contentHeight, 1) : 1;
|
|
78
|
+
const offsetX = (totalWidth - contentWidth * scale) / 2;
|
|
79
|
+
const offsetY = (totalHeight - contentHeight * scale) / 2;
|
|
80
|
+
const page = document.createElementNS(SVG_NS, "svg");
|
|
81
|
+
page.setAttribute("xmlns", SVG_NS);
|
|
82
|
+
page.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
|
|
83
|
+
page.setAttribute("width", String(totalWidth));
|
|
84
|
+
page.setAttribute("height", String(totalHeight));
|
|
85
|
+
page.setAttribute("viewBox", `0 0 ${totalWidth} ${totalHeight}`);
|
|
86
|
+
if (background) {
|
|
87
|
+
const plate = document.createElementNS(SVG_NS, "rect");
|
|
88
|
+
plate.setAttribute("width", String(totalWidth));
|
|
89
|
+
plate.setAttribute("height", String(totalHeight));
|
|
90
|
+
plate.setAttribute("fill", background);
|
|
91
|
+
page.append(plate);
|
|
92
|
+
}
|
|
93
|
+
const stage = document.createElementNS(SVG_NS, "g");
|
|
94
|
+
stage.setAttribute("transform", `translate(${offsetX}, ${offsetY}) scale(${scale})`);
|
|
95
|
+
page.append(stage);
|
|
96
|
+
if (title) {
|
|
97
|
+
const caption = document.createElementNS(SVG_NS, "text");
|
|
98
|
+
caption.setAttribute("x", String(padding));
|
|
99
|
+
caption.setAttribute("y", String(padding + 15));
|
|
100
|
+
caption.setAttribute("fill", titleColor);
|
|
101
|
+
caption.setAttribute("font-size", "15");
|
|
102
|
+
caption.setAttribute("font-weight", "500");
|
|
103
|
+
caption.setAttribute("font-family", titleFont);
|
|
104
|
+
caption.textContent = title;
|
|
105
|
+
stage.append(caption);
|
|
106
|
+
}
|
|
107
|
+
const group = document.createElementNS(SVG_NS, "g");
|
|
108
|
+
group.setAttribute("transform", `translate(${padding}, ${padding + titleBand})`);
|
|
109
|
+
group.append(clone);
|
|
110
|
+
stage.append(group);
|
|
111
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
112
|
+
${new XMLSerializer().serializeToString(page)}`;
|
|
113
|
+
}
|
|
114
|
+
const MIME = {
|
|
115
|
+
png: "image/png",
|
|
116
|
+
jpeg: "image/jpeg",
|
|
117
|
+
webp: "image/webp"
|
|
118
|
+
};
|
|
119
|
+
async function rasterize(markup, format, options = {}) {
|
|
120
|
+
const { scale = 2, quality = 0.92, background } = options;
|
|
121
|
+
const url = URL.createObjectURL(new Blob([markup], { type: "image/svg+xml;charset=utf-8" }));
|
|
122
|
+
try {
|
|
123
|
+
const image = await loadImage(url);
|
|
124
|
+
const canvas = document.createElement("canvas");
|
|
125
|
+
canvas.width = Math.max(1, Math.ceil(image.width * scale));
|
|
126
|
+
canvas.height = Math.max(1, Math.ceil(image.height * scale));
|
|
127
|
+
const context = canvas.getContext("2d");
|
|
128
|
+
if (!context) throw new Error("rasterize: this browser gave back no 2D canvas context");
|
|
129
|
+
if (background) {
|
|
130
|
+
context.fillStyle = background;
|
|
131
|
+
context.fillRect(0, 0, canvas.width, canvas.height);
|
|
132
|
+
}
|
|
133
|
+
context.drawImage(image, 0, 0, canvas.width, canvas.height);
|
|
134
|
+
return await canvasToBlob(canvas, MIME[format], quality);
|
|
135
|
+
} finally {
|
|
136
|
+
URL.revokeObjectURL(url);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function loadImage(url) {
|
|
140
|
+
return new Promise((resolve, reject) => {
|
|
141
|
+
const image = new Image();
|
|
142
|
+
image.addEventListener("load", () => resolve(image));
|
|
143
|
+
image.addEventListener(
|
|
144
|
+
"error",
|
|
145
|
+
() => reject(new Error("rasterize: the browser refused to decode the serialised artwork"))
|
|
146
|
+
);
|
|
147
|
+
image.src = url;
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
function canvasToBlob(canvas, mime, quality) {
|
|
151
|
+
return new Promise((resolve, reject) => {
|
|
152
|
+
try {
|
|
153
|
+
canvas.toBlob(
|
|
154
|
+
(blob) => {
|
|
155
|
+
if (blob) resolve(blob);
|
|
156
|
+
else reject(new Error(`rasterize: the canvas produced no ${mime} data`));
|
|
157
|
+
},
|
|
158
|
+
mime,
|
|
159
|
+
quality
|
|
160
|
+
);
|
|
161
|
+
} catch (cause) {
|
|
162
|
+
reject(
|
|
163
|
+
new Error(
|
|
164
|
+
"rasterize: the canvas is tainted, which means the artwork contains a cross-origin image",
|
|
165
|
+
{ cause }
|
|
166
|
+
)
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
function downloadBlob(blob, filename) {
|
|
172
|
+
if (typeof document === "undefined") {
|
|
173
|
+
throw new Error("downloadBlob: needs a browser document \u2014 call it from an event handler");
|
|
174
|
+
}
|
|
175
|
+
const url = URL.createObjectURL(blob);
|
|
176
|
+
const anchor = document.createElement("a");
|
|
177
|
+
anchor.href = url;
|
|
178
|
+
anchor.download = filename;
|
|
179
|
+
anchor.rel = "noopener";
|
|
180
|
+
anchor.style.display = "none";
|
|
181
|
+
document.body.append(anchor);
|
|
182
|
+
anchor.click();
|
|
183
|
+
anchor.remove();
|
|
184
|
+
setTimeout(() => URL.revokeObjectURL(url), 0);
|
|
185
|
+
}
|
|
186
|
+
function exportFilename(title, extension, fallback = "figure") {
|
|
187
|
+
const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
188
|
+
return `${slug || fallback}.${extension}`;
|
|
189
|
+
}
|
|
190
|
+
export {
|
|
191
|
+
downloadBlob,
|
|
192
|
+
exportFilename,
|
|
193
|
+
inlinePaint,
|
|
194
|
+
rasterize,
|
|
195
|
+
readToken,
|
|
196
|
+
serializeSvg
|
|
197
|
+
};
|
|
198
|
+
//# sourceMappingURL=svg-export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/svg-export.ts"],"sourcesContent":["/**\n * Taking an `<svg>` off the page as a file.\n *\n * Shared by two entries that both draw in SVG and both need to hand a reader a\n * picture of it: `@misoto22/design/charts` and `@misoto22/design/diagrams`.\n * Everything here is engine-agnostic — nothing knows what a series or a node\n * is — so the parts that DO know (which `<svg>` inside a wrapper is the plot,\n * what the file should be called, what sits behind it) stay with the caller.\n *\n * Nothing touches the DOM at module scope. Every browser API — `document`,\n * `canvas`, `URL.createObjectURL` — is reached for inside a function body, so\n * this module imports cleanly into a server component and only fails when a\n * consumer actually asks for a file on a server, which is a call that cannot\n * succeed anywhere.\n */\n\nconst SVG_NS = 'http://www.w3.org/2000/svg'\n\n/**\n * The properties copied from the live DOM onto the serialised clone.\n *\n * Paint, geometry-adjacent paint, and type. Layout is deliberately absent: an\n * SVG's geometry is in its attributes, which the clone already carries, and\n * copying computed `width`/`height`/`transform` onto every node would fight\n * them.\n */\nconst PAINTED_PROPERTIES = [\n 'display',\n 'visibility',\n 'opacity',\n 'color',\n 'fill',\n 'fill-opacity',\n 'fill-rule',\n 'stroke',\n 'stroke-opacity',\n 'stroke-width',\n 'stroke-linecap',\n 'stroke-linejoin',\n 'stroke-dasharray',\n 'stroke-dashoffset',\n 'stop-color',\n 'stop-opacity',\n 'flood-color',\n 'flood-opacity',\n 'marker-start',\n 'marker-mid',\n 'marker-end',\n 'mask',\n 'filter',\n 'clip-path',\n 'clip-rule',\n 'paint-order',\n 'mix-blend-mode',\n 'shape-rendering',\n 'text-anchor',\n 'dominant-baseline',\n 'font-family',\n 'font-size',\n 'font-style',\n 'font-weight',\n 'letter-spacing',\n 'text-transform',\n] as const\n\n/**\n * Copies the resolved paint of every node in `live` onto the matching node in\n * `clone`.\n *\n * ## The problem this function exists to solve\n *\n * Serialising an `<svg>` and handing it to an `<img>` puts it in a document of\n * its own. That document has none of the page's stylesheets, so every\n * `var(--ink)`, `var(--rule-2)` and `var(--diagram-node)` in the markup\n * resolves to nothing — and a paint that resolves to nothing is not a fallback\n * colour, it is an invisible mark. Serialise naively and you get an empty\n * rectangle.\n *\n * ## The solution\n *\n * Walk the live tree and the clone in step, and on every node write\n * `getComputedStyle`'s answer into an inline `style`. Computed values have\n * already had `var()` substituted by the engine, so `fill: var(--ink)` arrives\n * as `fill: rgb(16, 16, 16)` — and, because the walk reads the LIVE element, it\n * reads it under whichever theme is currently applied. Light and dark come out\n * right for free, with no theme argument anywhere in this file.\n *\n * `<stop>` and `<marker>` children are walked too, which is the half that is\n * easy to miss: a gradient's stops and an arrowhead's fill carry custom\n * properties of their own, and a `<defs>` that lost its paint takes every line\n * ending with it.\n */\nexport function inlinePaint(live: Element, clone: Element): void {\n const computed = getComputedStyle(live)\n let css = ''\n for (const property of PAINTED_PROPERTIES) {\n const value = computed.getPropertyValue(property)\n if (value) css += `${property}:${value};`\n }\n if (css) clone.setAttribute('style', css)\n\n // The clone is a faithful deep copy, so child lists line up by index.\n const children = live.children\n const clones = clone.children\n for (let index = 0; index < children.length; index += 1) {\n const liveChild = children[index]\n const cloneChild = clones[index]\n if (liveChild && cloneChild) inlinePaint(liveChild, cloneChild)\n }\n}\n\n/**\n * A custom property, resolved against the live element.\n *\n * `var()` inside a custom property is substituted at computed-value time, so\n * `--diagram-surface: var(--paper)` reads back as a colour. The guard is for\n * the case where it did not — an unregistered name, or a value the engine left\n * as a token stream — because writing `var(--paper)` into a serialised SVG\n * paints nothing at all.\n */\nexport function readToken(element: Element, name: string, fallback: string): string {\n const value = getComputedStyle(element).getPropertyValue(name).trim()\n return value && !value.includes('var(') ? value : fallback\n}\n\nexport interface SerializeOptions {\n /** Space around the artwork, in user units. Defaults to 16. */\n padding?: number\n /** Painted behind the artwork. Omit for a transparent ground. */\n background?: string\n /** A band above the artwork carrying this text. */\n title?: string\n /** Paint for the title. Defaults to `#101010`. */\n titleColor?: string\n /** Family for the title. Defaults to `sans-serif`. */\n titleFont?: string\n /**\n * Forces the output box, letterboxing the artwork inside it.\n *\n * This is what a share card is: a fixed 1200×630 frame that the diagram is\n * fitted into, rather than a frame the diagram sizes. Omit it and the output\n * is the artwork plus its padding.\n */\n frame?: { width: number; height: number }\n}\n\n/**\n * One standalone `<svg>` document: the element's own artwork, repainted with\n * resolved colours, on an optional plate, under an optional title.\n *\n * Returns markup rather than a blob because the SVG export wants the string\n * and every raster export wants it as a data source — one serialisation, four\n * file formats.\n *\n * ## What this cannot capture, honestly\n *\n * - **Anything drawn in HTML.** A toolbar, a tooltip, an inspector panel are\n * DOM, not SVG. The file is the artwork.\n * - **Web fonts.** The isolated document cannot fetch the page's `@font-face`\n * sources, so text is rasterised in whatever the resolved family stack finds\n * locally. Type metrics will differ from the screen.\n * - **Cross-origin images.** An `<image>` from another origin taints the canvas\n * and `toBlob` throws; there is no way around it from script.\n */\nexport function serializeSvg(svg: SVGSVGElement, options: SerializeOptions = {}): string {\n const { padding = 16, background, title, titleColor = '#101010', titleFont = 'sans-serif' } = options\n\n const box = svg.getBoundingClientRect()\n const width = Math.ceil(box.width) || Number(svg.getAttribute('width')) || 0\n const height = Math.ceil(box.height) || Number(svg.getAttribute('height')) || 0\n if (width === 0 || height === 0) {\n // Artwork that has not been measured yet has no size to export. Silently\n // producing a 0×0 file would look to a reader like a broken download\n // rather than a call made one frame too early.\n throw new Error('serializeSvg: the artwork has no measured size yet — export it after it renders')\n }\n\n const clone = svg.cloneNode(true) as SVGSVGElement\n inlinePaint(svg, clone)\n clone.setAttribute('width', String(width))\n clone.setAttribute('height', String(height))\n\n const titleBand = title ? 34 : 0\n const contentWidth = width + padding * 2\n const contentHeight = height + padding * 2 + titleBand\n\n // A frame letterboxes rather than stretches: a share card that squashed a\n // wide diagram to 1200×630 would be a picture of a different diagram.\n const totalWidth = options.frame?.width ?? contentWidth\n const totalHeight = options.frame?.height ?? contentHeight\n const scale = options.frame\n ? Math.min(totalWidth / contentWidth, totalHeight / contentHeight, 1)\n : 1\n const offsetX = (totalWidth - contentWidth * scale) / 2\n const offsetY = (totalHeight - contentHeight * scale) / 2\n\n const page = document.createElementNS(SVG_NS, 'svg')\n page.setAttribute('xmlns', SVG_NS)\n page.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink')\n page.setAttribute('width', String(totalWidth))\n page.setAttribute('height', String(totalHeight))\n page.setAttribute('viewBox', `0 0 ${totalWidth} ${totalHeight}`)\n\n if (background) {\n const plate = document.createElementNS(SVG_NS, 'rect')\n plate.setAttribute('width', String(totalWidth))\n plate.setAttribute('height', String(totalHeight))\n plate.setAttribute('fill', background)\n page.append(plate)\n }\n\n const stage = document.createElementNS(SVG_NS, 'g')\n stage.setAttribute('transform', `translate(${offsetX}, ${offsetY}) scale(${scale})`)\n page.append(stage)\n\n if (title) {\n const caption = document.createElementNS(SVG_NS, 'text')\n caption.setAttribute('x', String(padding))\n caption.setAttribute('y', String(padding + 15))\n caption.setAttribute('fill', titleColor)\n caption.setAttribute('font-size', '15')\n caption.setAttribute('font-weight', '500')\n caption.setAttribute('font-family', titleFont)\n caption.textContent = title\n stage.append(caption)\n }\n\n const group = document.createElementNS(SVG_NS, 'g')\n group.setAttribute('transform', `translate(${padding}, ${padding + titleBand})`)\n group.append(clone)\n stage.append(group)\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n${new XMLSerializer().serializeToString(page)}`\n}\n\n/** The raster formats a browser canvas can encode. */\nexport type RasterFormat = 'png' | 'jpeg' | 'webp'\n\nconst MIME: Record<RasterFormat, string> = {\n png: 'image/png',\n jpeg: 'image/jpeg',\n webp: 'image/webp',\n}\n\nexport interface RasterOptions {\n /** Multiplier on the on-screen size. 2 is a retina-sharp export. */\n scale?: number\n /** Encoder quality for `jpeg` and `webp`, 0–1. Ignored by `png`. */\n quality?: number\n /**\n * Painted behind the image, for a format with no alpha channel.\n *\n * JPEG has no transparency, so a diagram serialised without a plate lands on\n * black. Passing the page's own surface here is what makes the file look\n * like the screen rather than like a negative.\n */\n background?: string\n}\n\n/**\n * SVG markup, rasterised through a canvas.\n *\n * This is the browser's own SVG rasteriser re-drawing the markup, not a\n * screenshot: antialiasing, `backdrop-filter` and any effect a page stylesheet\n * applied from outside the `<svg>` are not in it.\n */\nexport async function rasterize(\n markup: string,\n format: RasterFormat,\n options: RasterOptions = {},\n): Promise<Blob> {\n const { scale = 2, quality = 0.92, background } = options\n\n const url = URL.createObjectURL(new Blob([markup], { type: 'image/svg+xml;charset=utf-8' }))\n try {\n const image = await loadImage(url)\n const canvas = document.createElement('canvas')\n canvas.width = Math.max(1, Math.ceil(image.width * scale))\n canvas.height = Math.max(1, Math.ceil(image.height * scale))\n\n const context = canvas.getContext('2d')\n if (!context) throw new Error('rasterize: this browser gave back no 2D canvas context')\n\n if (background) {\n context.fillStyle = background\n context.fillRect(0, 0, canvas.width, canvas.height)\n }\n context.drawImage(image, 0, 0, canvas.width, canvas.height)\n\n return await canvasToBlob(canvas, MIME[format], quality)\n } finally {\n URL.revokeObjectURL(url)\n }\n}\n\nfunction loadImage(url: string): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const image = new Image()\n image.addEventListener('load', () => resolve(image))\n image.addEventListener('error', () =>\n reject(new Error('rasterize: the browser refused to decode the serialised artwork')),\n )\n image.src = url\n })\n}\n\nfunction canvasToBlob(canvas: HTMLCanvasElement, mime: string, quality: number): Promise<Blob> {\n return new Promise((resolve, reject) => {\n try {\n canvas.toBlob(\n (blob) => {\n if (blob) resolve(blob)\n else reject(new Error(`rasterize: the canvas produced no ${mime} data`))\n },\n mime,\n quality,\n )\n } catch (cause) {\n // A cross-origin image anywhere in the artwork taints the canvas and this\n // throws SecurityError. Nothing in script can untaint it, so the honest\n // move is to say which failure it was.\n reject(\n new Error(\n 'rasterize: the canvas is tainted, which means the artwork contains a cross-origin image',\n { cause },\n ),\n )\n }\n })\n}\n\n/**\n * Hands a blob to the browser as a download.\n *\n * Throws rather than no-oping without a `document`: a download is something a\n * person just asked for, and a silent return would look to them like a click\n * that did nothing.\n */\nexport function downloadBlob(blob: Blob, filename: string): void {\n if (typeof document === 'undefined') {\n throw new Error('downloadBlob: needs a browser document — call it from an event handler')\n }\n\n const url = URL.createObjectURL(blob)\n const anchor = document.createElement('a')\n anchor.href = url\n anchor.download = filename\n anchor.rel = 'noopener'\n anchor.style.display = 'none'\n document.body.append(anchor)\n anchor.click()\n anchor.remove()\n\n // Revoking in the same tick cancels the download in Safari; one turn of the\n // event loop is enough for the navigation to have started.\n setTimeout(() => URL.revokeObjectURL(url), 0)\n}\n\n/**\n * A title as a filename.\n *\n * Lowercase, ASCII-safe and hyphenated, because a downloaded file crosses into\n * shells, zip archives and Windows paths where a title's spaces and slashes are\n * someone else's problem. A title with no ASCII in it at all — a Chinese one,\n * say — slugs to nothing, so the caller's fallback is what names the file.\n */\nexport function exportFilename(title: string, extension: string, fallback = 'figure'): string {\n const slug = title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n return `${slug || fallback}.${extension}`\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Development warnings, written for the reader most likely to hit them.
|
|
3
|
+
*
|
|
4
|
+
* The skill in this package documents a handful of ways to misuse a component
|
|
5
|
+
* that fail SILENTLY — a `Field` whose child is a wrapper wires no label, an
|
|
6
|
+
* icon-only `Button` with no accessible name renders perfectly and is invisible
|
|
7
|
+
* to a screen reader. Documentation is the wrong place for those on its own: it
|
|
8
|
+
* only helps a reader who went looking, and the whole problem is that nothing
|
|
9
|
+
* told them to look.
|
|
10
|
+
*
|
|
11
|
+
* So the component says it, at the moment it happens. The shape follows what an
|
|
12
|
+
* agent needs to repair its own call without asking anyone: a stable `code` it
|
|
13
|
+
* can branch on, the `field` that caused it, an imperative one-line `fix`, and
|
|
14
|
+
* where to get the rest. A message that only says "invalid props" makes an
|
|
15
|
+
* agent guess, and it guesses by trying things.
|
|
16
|
+
*
|
|
17
|
+
* Three constraints this has to keep:
|
|
18
|
+
*
|
|
19
|
+
* - **Dev only.** Every call site is behind `process.env.NODE_ENV`, which the
|
|
20
|
+
* consumer's bundler replaces and then drops. Nothing here reaches a
|
|
21
|
+
* production bundle.
|
|
22
|
+
* - **Once per problem.** React renders twice in StrictMode and again on every
|
|
23
|
+
* state change; a warning printed each time is noise that trains people to
|
|
24
|
+
* ignore it.
|
|
25
|
+
* - **Never throws.** A warning that breaks the render is worse than the bug it
|
|
26
|
+
* describes, and this runs during render.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* True outside a production build, and false when nothing said either way.
|
|
30
|
+
*
|
|
31
|
+
* Every bundler replaces `process.env.NODE_ENV` with a literal, which folds
|
|
32
|
+
* this to `false` and lets the guarded calls below be dropped entirely. Off is
|
|
33
|
+
* the right default for the case where nothing replaced it: a warning that
|
|
34
|
+
* reaches a user's console is worse than one an author never sees.
|
|
35
|
+
*/
|
|
36
|
+
declare const DEV: boolean;
|
|
37
|
+
interface Warning {
|
|
38
|
+
/** Stable identifier. Never reused for a different cause. */
|
|
39
|
+
code: string;
|
|
40
|
+
/** What went wrong, in one declarative sentence. */
|
|
41
|
+
problem: string;
|
|
42
|
+
/** The prop or child that caused it. */
|
|
43
|
+
field: string;
|
|
44
|
+
/** Imperative, and self-sufficient — assume nobody opens the docs. */
|
|
45
|
+
fix: string;
|
|
46
|
+
/** The component to ask about. */
|
|
47
|
+
component: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Print one warning, once.
|
|
51
|
+
*
|
|
52
|
+
* Guarded at the call site too, so a production bundle drops the whole
|
|
53
|
+
* expression rather than the branch inside it.
|
|
54
|
+
*/
|
|
55
|
+
declare function warn({ code, problem, field, fix, component }: Warning): void;
|
|
56
|
+
/** Test seam: the dedupe is global state, and a suite needs it reset. */
|
|
57
|
+
declare function resetWarnings(): void;
|
|
58
|
+
/**
|
|
59
|
+
* Warn when a prop that is required for accessibility holds nothing usable.
|
|
60
|
+
*
|
|
61
|
+
* `Table.caption`, `Progress.label` and their siblings are required in the type
|
|
62
|
+
* precisely because forgetting them ships a control nobody can use without
|
|
63
|
+
* sight — and an empty string satisfies the type while satisfying nothing else.
|
|
64
|
+
* That is exactly the shape a model produces when it knows a prop is mandatory
|
|
65
|
+
* and has nothing to put in it.
|
|
66
|
+
*
|
|
67
|
+
* Not applied to `Avatar.alt`. An empty `alt` is the correct, deliberate markup
|
|
68
|
+
* for a decorative image, so warning on it would be a false positive on a
|
|
69
|
+
* pattern the platform endorses.
|
|
70
|
+
*/
|
|
71
|
+
declare function warnBlankName(component: string, field: string, value: unknown, announces: string): void;
|
|
72
|
+
|
|
73
|
+
export { DEV, resetWarnings, warn, warnBlankName };
|
package/dist/lib/warn.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const DEV = typeof process !== "undefined" && process?.env?.NODE_ENV !== "production";
|
|
2
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3
|
+
function warn({ code, problem, field, fix, component }) {
|
|
4
|
+
if (!DEV) return;
|
|
5
|
+
const key = `${code}:${field}`;
|
|
6
|
+
if (seen.has(key)) return;
|
|
7
|
+
seen.add(key);
|
|
8
|
+
console.warn(
|
|
9
|
+
[
|
|
10
|
+
`[@misoto22/design] ${code}`,
|
|
11
|
+
` ${problem}`,
|
|
12
|
+
` field: ${field}`,
|
|
13
|
+
` fix: ${fix}`,
|
|
14
|
+
` docs: npx misoto22-design docs ${component}`
|
|
15
|
+
].join("\n")
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
function resetWarnings() {
|
|
19
|
+
seen.clear();
|
|
20
|
+
}
|
|
21
|
+
function warnBlankName(component, field, value, announces) {
|
|
22
|
+
if (!DEV) return;
|
|
23
|
+
if (typeof value !== "string" || value.trim() !== "") return;
|
|
24
|
+
warn({
|
|
25
|
+
code: "REQUIRED_NAME_BLANK",
|
|
26
|
+
problem: `${component}.${field} is an empty string, so ${announces}. The type is satisfied; nothing else is.`,
|
|
27
|
+
field: `${component}.${field}`,
|
|
28
|
+
fix: `Give ${field} the words a person would need to understand this without seeing it.`,
|
|
29
|
+
component
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
export {
|
|
33
|
+
DEV,
|
|
34
|
+
resetWarnings,
|
|
35
|
+
warn,
|
|
36
|
+
warnBlankName
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=warn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/warn.ts"],"sourcesContent":["/**\n * Development warnings, written for the reader most likely to hit them.\n *\n * The skill in this package documents a handful of ways to misuse a component\n * that fail SILENTLY — a `Field` whose child is a wrapper wires no label, an\n * icon-only `Button` with no accessible name renders perfectly and is invisible\n * to a screen reader. Documentation is the wrong place for those on its own: it\n * only helps a reader who went looking, and the whole problem is that nothing\n * told them to look.\n *\n * So the component says it, at the moment it happens. The shape follows what an\n * agent needs to repair its own call without asking anyone: a stable `code` it\n * can branch on, the `field` that caused it, an imperative one-line `fix`, and\n * where to get the rest. A message that only says \"invalid props\" makes an\n * agent guess, and it guesses by trying things.\n *\n * Three constraints this has to keep:\n *\n * - **Dev only.** Every call site is behind `process.env.NODE_ENV`, which the\n * consumer's bundler replaces and then drops. Nothing here reaches a\n * production bundle.\n * - **Once per problem.** React renders twice in StrictMode and again on every\n * state change; a warning printed each time is noise that trains people to\n * ignore it.\n * - **Never throws.** A warning that breaks the render is worse than the bug it\n * describes, and this runs during render.\n */\n\n/**\n * `process.env.NODE_ENV`, without pulling Node's types into a browser library.\n *\n * Declared module-locally rather than in a `.d.ts`: an ambient `process` there\n * would travel into the emitted declarations and collide with a consumer's own\n * Node types. The `typeof` guard is what makes it safe in a bundle that never\n * defines it.\n */\ndeclare const process: { env?: { NODE_ENV?: string } } | undefined\n\n/**\n * True outside a production build, and false when nothing said either way.\n *\n * Every bundler replaces `process.env.NODE_ENV` with a literal, which folds\n * this to `false` and lets the guarded calls below be dropped entirely. Off is\n * the right default for the case where nothing replaced it: a warning that\n * reaches a user's console is worse than one an author never sees.\n */\nexport const DEV =\n typeof process !== 'undefined' && process?.env?.NODE_ENV !== 'production'\n\n/** Warnings already printed, keyed by code + detail, so a re-render is quiet. */\nconst seen = new Set<string>()\n\ninterface Warning {\n /** Stable identifier. Never reused for a different cause. */\n code: string\n /** What went wrong, in one declarative sentence. */\n problem: string\n /** The prop or child that caused it. */\n field: string\n /** Imperative, and self-sufficient — assume nobody opens the docs. */\n fix: string\n /** The component to ask about. */\n component: string\n}\n\n/**\n * Print one warning, once.\n *\n * Guarded at the call site too, so a production bundle drops the whole\n * expression rather than the branch inside it.\n */\nexport function warn({ code, problem, field, fix, component }: Warning): void {\n if (!DEV) return\n\n const key = `${code}:${field}`\n if (seen.has(key)) return\n seen.add(key)\n\n console.warn(\n [\n `[@misoto22/design] ${code}`,\n ` ${problem}`,\n ` field: ${field}`,\n ` fix: ${fix}`,\n ` docs: npx misoto22-design docs ${component}`,\n ].join('\\n'),\n )\n}\n\n/** Test seam: the dedupe is global state, and a suite needs it reset. */\nexport function resetWarnings(): void {\n seen.clear()\n}\n\n/**\n * Warn when a prop that is required for accessibility holds nothing usable.\n *\n * `Table.caption`, `Progress.label` and their siblings are required in the type\n * precisely because forgetting them ships a control nobody can use without\n * sight — and an empty string satisfies the type while satisfying nothing else.\n * That is exactly the shape a model produces when it knows a prop is mandatory\n * and has nothing to put in it.\n *\n * Not applied to `Avatar.alt`. An empty `alt` is the correct, deliberate markup\n * for a decorative image, so warning on it would be a false positive on a\n * pattern the platform endorses.\n */\nexport function warnBlankName(\n component: string,\n field: string,\n value: unknown,\n announces: string,\n): void {\n if (!DEV) return\n if (typeof value !== 'string' || value.trim() !== '') return\n\n warn({\n code: 'REQUIRED_NAME_BLANK',\n problem: `${component}.${field} is an empty string, so ${announces}. The type is satisfied; nothing else is.`,\n field: `${component}.${field}`,\n fix: `Give ${field} the words a person would need to understand this without seeing it.`,\n component,\n })\n}\n"],"mappings":"AA8CO,MAAM,MACX,OAAO,YAAY,eAAe,SAAS,KAAK,aAAa;AAG/D,MAAM,OAAO,oBAAI,IAAY;AAqBtB,SAAS,KAAK,EAAE,MAAM,SAAS,OAAO,KAAK,UAAU,GAAkB;AAC5E,MAAI,CAAC,IAAK;AAEV,QAAM,MAAM,GAAG,IAAI,IAAI,KAAK;AAC5B,MAAI,KAAK,IAAI,GAAG,EAAG;AACnB,OAAK,IAAI,GAAG;AAEZ,UAAQ;AAAA,IACN;AAAA,MACE,sBAAsB,IAAI;AAAA,MAC1B,KAAK,OAAO;AAAA,MACZ,YAAY,KAAK;AAAA,MACjB,YAAY,GAAG;AAAA,MACf,qCAAqC,SAAS;AAAA,IAChD,EAAE,KAAK,IAAI;AAAA,EACb;AACF;AAGO,SAAS,gBAAsB;AACpC,OAAK,MAAM;AACb;AAeO,SAAS,cACd,WACA,OACA,OACA,WACM;AACN,MAAI,CAAC,IAAK;AACV,MAAI,OAAO,UAAU,YAAY,MAAM,KAAK,MAAM,GAAI;AAEtD,OAAK;AAAA,IACH,MAAM;AAAA,IACN,SAAS,GAAG,SAAS,IAAI,KAAK,2BAA2B,SAAS;AAAA,IAClE,OAAO,GAAG,SAAS,IAAI,KAAK;AAAA,IAC5B,KAAK,QAAQ,KAAK;AAAA,IAClB;AAAA,EACF,CAAC;AACH;","names":[]}
|
package/dist/semantic.css
CHANGED
|
@@ -105,14 +105,21 @@
|
|
|
105
105
|
Law 2 — a box-shadow is never blurred. The system has no elevation ramp;
|
|
106
106
|
depth is a hard offset in ink, applied per component. These three resolve
|
|
107
107
|
to nothing on purpose, so a component ported from a shadowed system stays
|
|
108
|
-
flat instead of drawing a blur the White Reset does not have.
|
|
109
|
-
|
|
108
|
+
flat instead of drawing a blur the White Reset does not have. --lift below
|
|
109
|
+
is the sanctioned offset idiom for anything that must read as raised. */
|
|
110
110
|
--shadow-color: transparent;
|
|
111
111
|
--shadow-sm: none;
|
|
112
112
|
--shadow: none;
|
|
113
113
|
--shadow-lg: none;
|
|
114
|
-
/* The one depth cue the system does have: a hard 3px ink offset, no blur
|
|
115
|
-
|
|
114
|
+
/* The one depth cue the system does have: a hard 3px ink offset, no blur,
|
|
115
|
+
in the accent rather than a grey because --shadow-offset points at --clay.
|
|
116
|
+
|
|
117
|
+
PUBLISHED, NOT CONSUMED. No component in this package sets either one —
|
|
118
|
+
there is not a single shadow-(--lift) in src/. What the library actually
|
|
119
|
+
separates with is a hairline, a change of ground, and the reversal that
|
|
120
|
+
Card variant="plate" reaches for. These two exist so a consumer building a
|
|
121
|
+
raised plate of their own has the system's answer instead of inventing a
|
|
122
|
+
blur; do not read them as describing what the library does. */
|
|
116
123
|
--lift: 3px 3px 0 0 var(--shadow-offset);
|
|
117
124
|
--lift-sm: 2px 2px 0 0 var(--shadow-offset);
|
|
118
125
|
|
|
@@ -126,10 +133,48 @@
|
|
|
126
133
|
--overlay: var(--scrim);
|
|
127
134
|
--disabled-opacity: 0.5;
|
|
128
135
|
|
|
129
|
-
/* ─── Stacking ───
|
|
130
|
-
|
|
136
|
+
/* ─── Stacking ─── two component-facing names onto the seven ranks. ──────
|
|
137
|
+
The other five ranks are read by their own names; only these two had a
|
|
138
|
+
component-facing spelling that outlived the rank it pointed at.
|
|
139
|
+
--z-dropdown pointed at --z-drawer, 100, which put every anchored panel
|
|
140
|
+
under the modal at 210 that opened it. */
|
|
141
|
+
--z-dropdown: var(--z-anchored);
|
|
131
142
|
--z-overlay: var(--z-scrim);
|
|
132
143
|
|
|
144
|
+
/* ─── Diagrams ───────────────────────────────────────────────────────────
|
|
145
|
+
The figures in `@misoto22/design/diagrams`, which draw in SVG and
|
|
146
|
+
therefore cannot read a custom property from a presentation attribute —
|
|
147
|
+
every one of these reaches a mark through a style rule.
|
|
148
|
+
|
|
149
|
+
Named separately from the page's own rules rather than pointed straight at
|
|
150
|
+
--rule-2 because a figure is a PICTURE inside a document: its hairline has
|
|
151
|
+
to hold up against a 1200-wide raster export and a greyscale print, where
|
|
152
|
+
the page's own hairline is chosen to disappear. Keeping the two apart is
|
|
153
|
+
what lets a figure be tuned without touching a table.
|
|
154
|
+
|
|
155
|
+
Nothing here is a hue. The seven kinds of node are separated by drawn
|
|
156
|
+
sigils, and the only colour a figure spends is --success / --danger on a
|
|
157
|
+
terminal lifecycle state — the same two the rest of the system reserves
|
|
158
|
+
for state and refuses to spend on brand. */
|
|
159
|
+
--diagram-surface: var(--paper);
|
|
160
|
+
--diagram-node: var(--paper);
|
|
161
|
+
--diagram-node-2: var(--paper-2);
|
|
162
|
+
--diagram-band: var(--stone);
|
|
163
|
+
--diagram-chip: var(--paper-2);
|
|
164
|
+
--diagram-rule: var(--rule-2);
|
|
165
|
+
--diagram-rule-hard: var(--ink-3-aa);
|
|
166
|
+
--diagram-line: var(--ink-2);
|
|
167
|
+
--diagram-line-strong: var(--ink);
|
|
168
|
+
--diagram-line-soft: var(--ink-3-aa);
|
|
169
|
+
--diagram-sigil: var(--ink-3-aa);
|
|
170
|
+
--diagram-ink: var(--ink);
|
|
171
|
+
--diagram-ink-2: var(--ink-2);
|
|
172
|
+
--diagram-ink-3: var(--ink-3-aa);
|
|
173
|
+
/* The reversed plate, and its type. A figure gets ONE of these — the node the
|
|
174
|
+
diagram is about — for the same reason a page gets one Card variant="plate". */
|
|
175
|
+
--diagram-plate: var(--accent);
|
|
176
|
+
--diagram-plate-ink: var(--accent-foreground);
|
|
177
|
+
|
|
133
178
|
/* ─── Layout ───────────────────────────────────────────────────────────── */
|
|
134
179
|
--page-pad: var(--pad);
|
|
135
180
|
--w-page: var(--maxw);
|