@misoto22/folio 0.0.0 → 0.16.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 +88 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +21 -0
- package/README.md +208 -2
- package/bin/folio-design.mjs +277 -0
- package/bin/migrate-legacy.mjs +81 -0
- package/dist/agent/Accordion.md +65 -0
- package/dist/agent/Actions.md +49 -0
- package/dist/agent/Alert.md +65 -0
- package/dist/agent/AppShell.md +69 -0
- package/dist/agent/ArchitectureFigure.md +72 -0
- package/dist/agent/AreaChart.md +94 -0
- package/dist/agent/Article.md +65 -0
- package/dist/agent/AspectRatio.md +58 -0
- package/dist/agent/Avatar.md +53 -0
- package/dist/agent/Badge.md +62 -0
- package/dist/agent/BarChart.md +93 -0
- package/dist/agent/BarList.md +67 -0
- package/dist/agent/BigNumber.md +70 -0
- package/dist/agent/BoxPlot.md +82 -0
- package/dist/agent/Breadcrumb.md +55 -0
- package/dist/agent/BulletChart.md +71 -0
- package/dist/agent/Button.md +81 -0
- package/dist/agent/Calendar.md +77 -0
- package/dist/agent/CalendarHeatmap.md +75 -0
- package/dist/agent/Card.md +72 -0
- package/dist/agent/Checkbox.md +57 -0
- package/dist/agent/Code.md +51 -0
- package/dist/agent/CodeBlock.md +77 -0
- package/dist/agent/Collapsible.md +68 -0
- package/dist/agent/Collection.md +169 -0
- package/dist/agent/ColorPicker.md +76 -0
- package/dist/agent/Combobox.md +77 -0
- package/dist/agent/Command.md +122 -0
- package/dist/agent/ComposedChart.md +82 -0
- package/dist/agent/Contact.md +90 -0
- package/dist/agent/Content.md +70 -0
- package/dist/agent/ContextMenu.md +93 -0
- package/dist/agent/Conversation.md +247 -0
- package/dist/agent/DataflowFigure.md +49 -0
- package/dist/agent/DatePicker.md +104 -0
- package/dist/agent/DescriptionList.md +69 -0
- package/dist/agent/Diagram.md +71 -0
- package/dist/agent/DiagramCanvas.md +71 -0
- package/dist/agent/DiagramExportMenu.md +65 -0
- package/dist/agent/DiagramInspector.md +73 -0
- package/dist/agent/DiagramLegend.md +56 -0
- package/dist/agent/DiagramMinimap.md +69 -0
- package/dist/agent/DiagramToolbar.md +70 -0
- package/dist/agent/Dialog.md +76 -0
- package/dist/agent/DropdownMenu.md +110 -0
- package/dist/agent/EmptyState.md +63 -0
- package/dist/agent/ErrorState.md +67 -0
- package/dist/agent/Evidence.md +165 -0
- package/dist/agent/Facet.md +107 -0
- package/dist/agent/Field.md +79 -0
- package/dist/agent/FigureBand.md +49 -0
- package/dist/agent/FloatingIconButton.md +61 -0
- package/dist/agent/FunnelChart.md +75 -0
- package/dist/agent/Heading.md +65 -0
- package/dist/agent/Heatmap.md +78 -0
- package/dist/agent/Histogram.md +88 -0
- package/dist/agent/Input.md +52 -0
- package/dist/agent/Kbd.md +48 -0
- package/dist/agent/LifecycleFigure.md +50 -0
- package/dist/agent/LineChart.md +85 -0
- package/dist/agent/LinkArrow.md +49 -0
- package/dist/agent/Markdown.md +69 -0
- package/dist/agent/Media.md +261 -0
- package/dist/agent/Metric.md +70 -0
- package/dist/agent/Metrics.md +114 -0
- package/dist/agent/Music.md +86 -0
- package/dist/agent/NativeSelect.md +62 -0
- package/dist/agent/NavItem.md +56 -0
- package/dist/agent/NumberField.md +73 -0
- package/dist/agent/PageHeader.md +69 -0
- package/dist/agent/Pagination.md +70 -0
- package/dist/agent/PieChart.md +80 -0
- package/dist/agent/Popover.md +80 -0
- package/dist/agent/Portfolio.md +93 -0
- package/dist/agent/PortfolioIndex.md +34 -0
- package/dist/agent/Progress.md +58 -0
- package/dist/agent/RadarChart.md +79 -0
- package/dist/agent/RadialChart.md +81 -0
- package/dist/agent/RadioGroup.md +66 -0
- package/dist/agent/Reading.md +233 -0
- package/dist/agent/Recovery.md +72 -0
- package/dist/agent/SankeyChart.md +85 -0
- package/dist/agent/ScatterChart.md +80 -0
- package/dist/agent/ScrollArea.md +62 -0
- package/dist/agent/SearchPalette.md +51 -0
- package/dist/agent/SearchableMenu.md +69 -0
- package/dist/agent/Select.md +102 -0
- package/dist/agent/Separator.md +60 -0
- package/dist/agent/SequenceFigure.md +51 -0
- package/dist/agent/Sheet.md +82 -0
- package/dist/agent/Sidebar.md +194 -0
- package/dist/agent/SiteNavigation.md +62 -0
- package/dist/agent/SiteShell.md +67 -0
- package/dist/agent/Skeleton.md +96 -0
- package/dist/agent/Slider.md +67 -0
- package/dist/agent/Sparkline.md +68 -0
- package/dist/agent/Spinner.md +62 -0
- package/dist/agent/StatusDot.md +56 -0
- package/dist/agent/StatusPill.md +55 -0
- package/dist/agent/Steps.md +68 -0
- package/dist/agent/Switch.md +50 -0
- package/dist/agent/Table.md +111 -0
- package/dist/agent/Tabs.md +71 -0
- package/dist/agent/Tag.md +67 -0
- package/dist/agent/Text.md +66 -0
- package/dist/agent/Textarea.md +46 -0
- package/dist/agent/Timeline.md +114 -0
- package/dist/agent/Timestamp.md +65 -0
- package/dist/agent/Toast.md +51 -0
- package/dist/agent/ToggleGroup.md +67 -0
- package/dist/agent/Toolbar.md +72 -0
- package/dist/agent/Tooltip.md +74 -0
- package/dist/agent/TreemapChart.md +76 -0
- package/dist/agent/WaterfallChart.md +86 -0
- package/dist/agent/WorkflowFigure.md +51 -0
- package/dist/agent/catalog.json +8006 -0
- package/dist/agent/index.md +182 -0
- package/dist/article.css +407 -0
- package/dist/charts/AreaChart/AreaChart.d.ts +198 -0
- package/dist/charts/AreaChart/AreaChart.js +479 -0
- package/dist/charts/AreaChart/AreaChart.js.map +1 -0
- package/dist/charts/BarChart/BarChart.d.ts +190 -0
- package/dist/charts/BarChart/BarChart.js +599 -0
- package/dist/charts/BarChart/BarChart.js.map +1 -0
- package/dist/charts/BarList/BarList.d.ts +65 -0
- package/dist/charts/BarList/BarList.js +79 -0
- package/dist/charts/BarList/BarList.js.map +1 -0
- package/dist/charts/BigNumber/BigNumber.d.ts +72 -0
- package/dist/charts/BigNumber/BigNumber.js +51 -0
- package/dist/charts/BigNumber/BigNumber.js.map +1 -0
- package/dist/charts/BoxPlot/BoxPlot.d.ts +177 -0
- package/dist/charts/BoxPlot/BoxPlot.js +497 -0
- package/dist/charts/BoxPlot/BoxPlot.js.map +1 -0
- package/dist/charts/BulletChart/BulletChart.d.ts +100 -0
- package/dist/charts/BulletChart/BulletChart.js +197 -0
- package/dist/charts/BulletChart/BulletChart.js.map +1 -0
- package/dist/charts/CalendarHeatmap/CalendarHeatmap.d.ts +106 -0
- package/dist/charts/CalendarHeatmap/CalendarHeatmap.js +103 -0
- package/dist/charts/CalendarHeatmap/CalendarHeatmap.js.map +1 -0
- package/dist/charts/ComposedChart/ComposedChart.d.ts +178 -0
- package/dist/charts/ComposedChart/ComposedChart.js +667 -0
- package/dist/charts/ComposedChart/ComposedChart.js.map +1 -0
- package/dist/charts/Facet/Facet.d.ts +240 -0
- package/dist/charts/Facet/Facet.js +133 -0
- package/dist/charts/Facet/Facet.js.map +1 -0
- package/dist/charts/Facet/panels.d.ts +187 -0
- package/dist/charts/Facet/panels.js +203 -0
- package/dist/charts/Facet/panels.js.map +1 -0
- package/dist/charts/FunnelChart/FunnelChart.d.ts +106 -0
- package/dist/charts/FunnelChart/FunnelChart.js +137 -0
- package/dist/charts/FunnelChart/FunnelChart.js.map +1 -0
- package/dist/charts/Heatmap/Heatmap.d.ts +101 -0
- package/dist/charts/Heatmap/Heatmap.js +125 -0
- package/dist/charts/Heatmap/Heatmap.js.map +1 -0
- package/dist/charts/Histogram/Histogram.d.ts +188 -0
- package/dist/charts/Histogram/Histogram.js +382 -0
- package/dist/charts/Histogram/Histogram.js.map +1 -0
- package/dist/charts/LineChart/LineChart.d.ts +174 -0
- package/dist/charts/LineChart/LineChart.js +485 -0
- package/dist/charts/LineChart/LineChart.js.map +1 -0
- package/dist/charts/PieChart/PieChart.d.ts +140 -0
- package/dist/charts/PieChart/PieChart.js +317 -0
- package/dist/charts/PieChart/PieChart.js.map +1 -0
- package/dist/charts/RadarChart/RadarChart.d.ts +135 -0
- package/dist/charts/RadarChart/RadarChart.js +303 -0
- package/dist/charts/RadarChart/RadarChart.js.map +1 -0
- package/dist/charts/RadialChart/RadialChart.d.ts +142 -0
- package/dist/charts/RadialChart/RadialChart.js +279 -0
- package/dist/charts/RadialChart/RadialChart.js.map +1 -0
- package/dist/charts/SankeyChart/SankeyChart.d.ts +149 -0
- package/dist/charts/SankeyChart/SankeyChart.js +509 -0
- package/dist/charts/SankeyChart/SankeyChart.js.map +1 -0
- package/dist/charts/ScatterChart/ScatterChart.d.ts +149 -0
- package/dist/charts/ScatterChart/ScatterChart.js +275 -0
- package/dist/charts/ScatterChart/ScatterChart.js.map +1 -0
- package/dist/charts/Sparkline/Sparkline.d.ts +53 -0
- package/dist/charts/Sparkline/Sparkline.js +95 -0
- package/dist/charts/Sparkline/Sparkline.js.map +1 -0
- package/dist/charts/TreemapChart/TreemapChart.d.ts +98 -0
- package/dist/charts/TreemapChart/TreemapChart.js +127 -0
- package/dist/charts/TreemapChart/TreemapChart.js.map +1 -0
- package/dist/charts/WaterfallChart/WaterfallChart.d.ts +164 -0
- package/dist/charts/WaterfallChart/WaterfallChart.js +321 -0
- package/dist/charts/WaterfallChart/WaterfallChart.js.map +1 -0
- package/dist/charts/index.d.ts +43 -0
- package/dist/charts/index.js +130 -0
- package/dist/charts/index.js.map +1 -0
- package/dist/charts/lib/annotations.d.ts +103 -0
- package/dist/charts/lib/annotations.js +99 -0
- package/dist/charts/lib/annotations.js.map +1 -0
- package/dist/charts/lib/axis.d.ts +18 -0
- package/dist/charts/lib/axis.js +21 -0
- package/dist/charts/lib/axis.js.map +1 -0
- package/dist/charts/lib/background.d.ts +33 -0
- package/dist/charts/lib/background.js +173 -0
- package/dist/charts/lib/background.js.map +1 -0
- package/dist/charts/lib/brush.d.ts +94 -0
- package/dist/charts/lib/brush.js +535 -0
- package/dist/charts/lib/brush.js.map +1 -0
- package/dist/charts/lib/chart.d.ts +94 -0
- package/dist/charts/lib/chart.js +149 -0
- package/dist/charts/lib/chart.js.map +1 -0
- package/dist/charts/lib/dot.d.ts +29 -0
- package/dist/charts/lib/dot.js +78 -0
- package/dist/charts/lib/dot.js.map +1 -0
- package/dist/charts/lib/empty.d.ts +31 -0
- package/dist/charts/lib/empty.js +24 -0
- package/dist/charts/lib/empty.js.map +1 -0
- package/dist/charts/lib/export.d.ts +94 -0
- package/dist/charts/lib/export.js +62 -0
- package/dist/charts/lib/export.js.map +1 -0
- package/dist/charts/lib/figure.d.ts +81 -0
- package/dist/charts/lib/figure.js +62 -0
- package/dist/charts/lib/figure.js.map +1 -0
- package/dist/charts/lib/format.d.ts +46 -0
- package/dist/charts/lib/format.js +56 -0
- package/dist/charts/lib/format.js.map +1 -0
- package/dist/charts/lib/legend.d.ts +45 -0
- package/dist/charts/lib/legend.js +117 -0
- package/dist/charts/lib/legend.js.map +1 -0
- package/dist/charts/lib/loading.d.ts +48 -0
- package/dist/charts/lib/loading.js +105 -0
- package/dist/charts/lib/loading.js.map +1 -0
- package/dist/charts/lib/paint.d.ts +154 -0
- package/dist/charts/lib/paint.js +551 -0
- package/dist/charts/lib/paint.js.map +1 -0
- 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/sonify-control.d.ts +163 -0
- package/dist/charts/lib/sonify-control.js +172 -0
- package/dist/charts/lib/sonify-control.js.map +1 -0
- package/dist/charts/lib/sonify.d.ts +248 -0
- package/dist/charts/lib/sonify.js +262 -0
- package/dist/charts/lib/sonify.js.map +1 -0
- package/dist/charts/lib/toolbar.d.ts +144 -0
- package/dist/charts/lib/toolbar.js +156 -0
- package/dist/charts/lib/toolbar.js.map +1 -0
- package/dist/charts/lib/tooltip.d.ts +59 -0
- package/dist/charts/lib/tooltip.js +135 -0
- package/dist/charts/lib/tooltip.js.map +1 -0
- package/dist/charts/lib/values.d.ts +56 -0
- package/dist/charts/lib/values.js +71 -0
- package/dist/charts/lib/values.js.map +1 -0
- package/dist/charts/lib/zoom.d.ts +139 -0
- package/dist/charts/lib/zoom.js +314 -0
- package/dist/charts/lib/zoom.js.map +1 -0
- package/dist/components/Accordion/Accordion.d.ts +34 -0
- package/dist/components/Accordion/Accordion.js +43 -0
- package/dist/components/Accordion/Accordion.js.map +1 -0
- package/dist/components/Alert/Alert.d.ts +32 -0
- package/dist/components/Alert/Alert.js +49 -0
- package/dist/components/Alert/Alert.js.map +1 -0
- package/dist/components/AppShell/AppShell.d.ts +58 -0
- package/dist/components/AppShell/AppShell.js +126 -0
- package/dist/components/AppShell/AppShell.js.map +1 -0
- package/dist/components/Article/Article.d.ts +58 -0
- package/dist/components/Article/Article.js +34 -0
- package/dist/components/Article/Article.js.map +1 -0
- 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 +38 -0
- package/dist/components/Avatar/Avatar.js +44 -0
- package/dist/components/Avatar/Avatar.js.map +1 -0
- package/dist/components/Badge/Badge.d.ts +30 -0
- package/dist/components/Badge/Badge.js +29 -0
- package/dist/components/Badge/Badge.js.map +1 -0
- package/dist/components/Breadcrumb/Breadcrumb.d.ts +37 -0
- package/dist/components/Breadcrumb/Breadcrumb.js +46 -0
- package/dist/components/Breadcrumb/Breadcrumb.js.map +1 -0
- package/dist/components/Button/Button.d.ts +70 -0
- package/dist/components/Button/Button.js +95 -0
- package/dist/components/Button/Button.js.map +1 -0
- package/dist/components/Calendar/Calendar.d.ts +54 -0
- package/dist/components/Calendar/Calendar.js +369 -0
- package/dist/components/Calendar/Calendar.js.map +1 -0
- package/dist/components/Card/Card.d.ts +55 -0
- package/dist/components/Card/Card.js +64 -0
- package/dist/components/Card/Card.js.map +1 -0
- package/dist/components/Checkbox/Checkbox.d.ts +26 -0
- package/dist/components/Checkbox/Checkbox.js +34 -0
- package/dist/components/Checkbox/Checkbox.js.map +1 -0
- 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 +145 -0
- package/dist/components/CodeBlock/CodeBlock.js +114 -0
- package/dist/components/CodeBlock/CodeBlock.js.map +1 -0
- package/dist/components/Collapsible/Collapsible.d.ts +45 -0
- package/dist/components/Collapsible/Collapsible.js +60 -0
- package/dist/components/Collapsible/Collapsible.js.map +1 -0
- package/dist/components/ColorPicker/ColorPicker.d.ts +67 -0
- package/dist/components/ColorPicker/ColorPicker.js +334 -0
- package/dist/components/ColorPicker/ColorPicker.js.map +1 -0
- package/dist/components/Combobox/Combobox.d.ts +77 -0
- package/dist/components/Combobox/Combobox.js +170 -0
- package/dist/components/Combobox/Combobox.js.map +1 -0
- package/dist/components/Command/Command.d.ts +125 -0
- package/dist/components/Command/Command.js +204 -0
- package/dist/components/Command/Command.js.map +1 -0
- package/dist/components/ContextMenu/ContextMenu.d.ts +63 -0
- package/dist/components/ContextMenu/ContextMenu.js +109 -0
- package/dist/components/ContextMenu/ContextMenu.js.map +1 -0
- package/dist/components/DatePicker/DatePicker.d.ts +130 -0
- package/dist/components/DatePicker/DatePicker.js +257 -0
- package/dist/components/DatePicker/DatePicker.js.map +1 -0
- 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 +86 -0
- package/dist/components/Diagram/Diagram.js +211 -0
- package/dist/components/Diagram/Diagram.js.map +1 -0
- package/dist/components/Dialog/Dialog.d.ts +63 -0
- package/dist/components/Dialog/Dialog.js +90 -0
- package/dist/components/Dialog/Dialog.js.map +1 -0
- package/dist/components/DropdownMenu/DropdownMenu.d.ts +87 -0
- package/dist/components/DropdownMenu/DropdownMenu.js +120 -0
- package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -0
- package/dist/components/EmptyState/EmptyState.d.ts +55 -0
- package/dist/components/EmptyState/EmptyState.js +32 -0
- package/dist/components/EmptyState/EmptyState.js.map +1 -0
- package/dist/components/ErrorState/ErrorState.d.ts +55 -0
- package/dist/components/ErrorState/ErrorState.js +41 -0
- package/dist/components/ErrorState/ErrorState.js.map +1 -0
- package/dist/components/Field/Field.d.ts +111 -0
- package/dist/components/Field/Field.js +95 -0
- package/dist/components/Field/Field.js.map +1 -0
- 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/FigureBand/FigureBand.d.ts +31 -0
- package/dist/components/FigureBand/FigureBand.js +51 -0
- package/dist/components/FigureBand/FigureBand.js.map +1 -0
- package/dist/components/FloatingIconButton/FloatingIconButton.d.ts +29 -0
- package/dist/components/FloatingIconButton/FloatingIconButton.js +34 -0
- package/dist/components/FloatingIconButton/FloatingIconButton.js.map +1 -0
- 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/Input/Input.d.ts +22 -0
- package/dist/components/Input/Input.js +21 -0
- package/dist/components/Input/Input.js.map +1 -0
- package/dist/components/Kbd/Kbd.d.ts +27 -0
- package/dist/components/Kbd/Kbd.js +21 -0
- package/dist/components/Kbd/Kbd.js.map +1 -0
- package/dist/components/LinkArrow/LinkArrow.d.ts +24 -0
- package/dist/components/LinkArrow/LinkArrow.js +24 -0
- package/dist/components/LinkArrow/LinkArrow.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/Metric/Metric.d.ts +61 -0
- package/dist/components/Metric/Metric.js +51 -0
- package/dist/components/Metric/Metric.js.map +1 -0
- package/dist/components/NativeSelect/NativeSelect.d.ts +33 -0
- package/dist/components/NativeSelect/NativeSelect.js +44 -0
- package/dist/components/NativeSelect/NativeSelect.js.map +1 -0
- package/dist/components/NavItem/NavItem.d.ts +39 -0
- package/dist/components/NavItem/NavItem.js +31 -0
- package/dist/components/NavItem/NavItem.js.map +1 -0
- package/dist/components/NumberField/NumberField.d.ts +69 -0
- package/dist/components/NumberField/NumberField.js +162 -0
- package/dist/components/NumberField/NumberField.js.map +1 -0
- package/dist/components/PageHeader/PageHeader.d.ts +92 -0
- package/dist/components/PageHeader/PageHeader.js +37 -0
- package/dist/components/PageHeader/PageHeader.js.map +1 -0
- package/dist/components/Pagination/Pagination.d.ts +67 -0
- package/dist/components/Pagination/Pagination.js +112 -0
- package/dist/components/Pagination/Pagination.js.map +1 -0
- package/dist/components/Popover/Popover.d.ts +39 -0
- package/dist/components/Popover/Popover.js +57 -0
- package/dist/components/Popover/Popover.js.map +1 -0
- package/dist/components/Progress/Progress.d.ts +43 -0
- package/dist/components/Progress/Progress.js +57 -0
- package/dist/components/Progress/Progress.js.map +1 -0
- package/dist/components/RadioGroup/RadioGroup.d.ts +49 -0
- package/dist/components/RadioGroup/RadioGroup.js +53 -0
- package/dist/components/RadioGroup/RadioGroup.js.map +1 -0
- package/dist/components/ScrollArea/ScrollArea.d.ts +46 -0
- package/dist/components/ScrollArea/ScrollArea.js +54 -0
- package/dist/components/ScrollArea/ScrollArea.js.map +1 -0
- package/dist/components/SearchableMenu/SearchableMenu.d.ts +68 -0
- package/dist/components/SearchableMenu/SearchableMenu.js +101 -0
- package/dist/components/SearchableMenu/SearchableMenu.js.map +1 -0
- package/dist/components/Select/Select.d.ts +87 -0
- package/dist/components/Select/Select.js +130 -0
- package/dist/components/Select/Select.js.map +1 -0
- package/dist/components/Separator/Separator.d.ts +48 -0
- package/dist/components/Separator/Separator.js +43 -0
- package/dist/components/Separator/Separator.js.map +1 -0
- package/dist/components/Sheet/Sheet.d.ts +43 -0
- package/dist/components/Sheet/Sheet.js +79 -0
- package/dist/components/Sheet/Sheet.js.map +1 -0
- package/dist/components/Sidebar/Sidebar.d.ts +357 -0
- package/dist/components/Sidebar/Sidebar.js +447 -0
- package/dist/components/Sidebar/Sidebar.js.map +1 -0
- package/dist/components/Skeleton/Skeleton.d.ts +70 -0
- package/dist/components/Skeleton/Skeleton.js +44 -0
- package/dist/components/Skeleton/Skeleton.js.map +1 -0
- package/dist/components/Slider/Slider.d.ts +74 -0
- package/dist/components/Slider/Slider.js +143 -0
- package/dist/components/Slider/Slider.js.map +1 -0
- package/dist/components/Spinner/Spinner.d.ts +58 -0
- package/dist/components/Spinner/Spinner.js +49 -0
- package/dist/components/Spinner/Spinner.js.map +1 -0
- package/dist/components/StatusDot/StatusDot.d.ts +29 -0
- package/dist/components/StatusDot/StatusDot.js +44 -0
- package/dist/components/StatusDot/StatusDot.js.map +1 -0
- package/dist/components/StatusPill/StatusPill.d.ts +30 -0
- package/dist/components/StatusPill/StatusPill.js +37 -0
- package/dist/components/StatusPill/StatusPill.js.map +1 -0
- package/dist/components/Steps/Steps.d.ts +65 -0
- package/dist/components/Steps/Steps.js +25 -0
- package/dist/components/Steps/Steps.js.map +1 -0
- package/dist/components/Switch/Switch.d.ts +23 -0
- package/dist/components/Switch/Switch.js +23 -0
- package/dist/components/Switch/Switch.js.map +1 -0
- package/dist/components/Table/Table.d.ts +116 -0
- package/dist/components/Table/Table.js +137 -0
- package/dist/components/Table/Table.js.map +1 -0
- package/dist/components/Tabs/Tabs.d.ts +37 -0
- package/dist/components/Tabs/Tabs.js +205 -0
- package/dist/components/Tabs/Tabs.js.map +1 -0
- package/dist/components/Tag/Tag.d.ts +87 -0
- package/dist/components/Tag/Tag.js +62 -0
- package/dist/components/Tag/Tag.js.map +1 -0
- 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/Textarea/Textarea.d.ts +20 -0
- package/dist/components/Textarea/Textarea.js +32 -0
- package/dist/components/Textarea/Textarea.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 +32 -0
- package/dist/components/Toast/Toast.js +64 -0
- package/dist/components/Toast/Toast.js.map +1 -0
- package/dist/components/ToggleGroup/ToggleGroup.d.ts +46 -0
- package/dist/components/ToggleGroup/ToggleGroup.js +88 -0
- package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -0
- 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/components/Tooltip/Tooltip.d.ts +43 -0
- package/dist/components/Tooltip/Tooltip.js +40 -0
- package/dist/components/Tooltip/Tooltip.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 +106 -0
- package/dist/diagrams/lib/route.js +201 -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 +94 -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/fonts/hanken-grotesk-300.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-400.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-500.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-600.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-700.woff2 +0 -0
- package/dist/fonts/ibm-plex-mono-400.woff2 +0 -0
- package/dist/fonts/ibm-plex-mono-500.woff2 +0 -0
- package/dist/fonts/ibm-plex-mono-600.woff2 +0 -0
- package/dist/fonts/newsreader-300.woff2 +0 -0
- package/dist/fonts/newsreader-400.woff2 +0 -0
- package/dist/fonts/newsreader-500.woff2 +0 -0
- package/dist/fonts/newsreader-600.woff2 +0 -0
- package/dist/fonts.css +96 -0
- package/dist/index.d.ts +97 -0
- package/dist/index.js +80 -0
- package/dist/index.js.map +1 -0
- package/dist/keyframes.css +300 -0
- package/dist/lib/cn.d.ts +21 -0
- package/dist/lib/cn.js +9 -0
- package/dist/lib/cn.js.map +1 -0
- package/dist/lib/color.d.ts +80 -0
- package/dist/lib/color.js +189 -0
- package/dist/lib/color.js.map +1 -0
- package/dist/lib/control.d.ts +32 -0
- package/dist/lib/control.js +14 -0
- package/dist/lib/control.js.map +1 -0
- package/dist/lib/index.d.ts +4 -0
- package/dist/lib/index.js +11 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/numeric.d.ts +35 -0
- package/dist/lib/numeric.js +29 -0
- package/dist/lib/numeric.js.map +1 -0
- package/dist/lib/overlay-container.d.ts +48 -0
- package/dist/lib/overlay-container.js +15 -0
- package/dist/lib/overlay-container.js.map +1 -0
- package/dist/lib/slot-content.d.ts +8 -0
- package/dist/lib/slot-content.js +17 -0
- package/dist/lib/slot-content.js.map +1 -0
- package/dist/lib/step-rail.d.ts +45 -0
- package/dist/lib/step-rail.js +47 -0
- package/dist/lib/step-rail.js.map +1 -0
- 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/useClipboardCopy.d.ts +30 -0
- package/dist/lib/useClipboardCopy.js +37 -0
- package/dist/lib/useClipboardCopy.js.map +1 -0
- package/dist/lib/useSelectionIndicator.d.ts +29 -0
- package/dist/lib/useSelectionIndicator.js +49 -0
- package/dist/lib/useSelectionIndicator.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 +193 -0
- package/dist/styles.css +98 -0
- package/dist/themes.css +514 -0
- package/dist/tokens/brand.d.ts +47 -0
- package/dist/tokens/brand.js +38 -0
- package/dist/tokens/brand.js.map +1 -0
- package/dist/tokens.css +652 -0
- package/dist/tokens.d.ts +198 -0
- package/dist/tokens.js +1020 -0
- package/dist/tokens.json +1019 -0
- package/dist/website/Actions/Actions.d.ts +34 -0
- package/dist/website/Actions/Actions.js +29 -0
- package/dist/website/Actions/Actions.js.map +1 -0
- package/dist/website/Collection/Collection.d.ts +128 -0
- package/dist/website/Collection/Collection.js +162 -0
- package/dist/website/Collection/Collection.js.map +1 -0
- package/dist/website/Contact/Contact.d.ts +87 -0
- package/dist/website/Contact/Contact.js +94 -0
- package/dist/website/Contact/Contact.js.map +1 -0
- package/dist/website/Content/CodePanel.d.ts +27 -0
- package/dist/website/Content/CodePanel.js +30 -0
- package/dist/website/Content/CodePanel.js.map +1 -0
- package/dist/website/Content/Content.d.ts +29 -0
- package/dist/website/Content/Content.js +38 -0
- package/dist/website/Content/Content.js.map +1 -0
- package/dist/website/Conversation/Conversation.d.ts +193 -0
- package/dist/website/Conversation/Conversation.js +252 -0
- package/dist/website/Conversation/Conversation.js.map +1 -0
- package/dist/website/Evidence/Evidence.d.ts +116 -0
- package/dist/website/Evidence/Evidence.js +142 -0
- package/dist/website/Evidence/Evidence.js.map +1 -0
- package/dist/website/Media/Media.d.ts +173 -0
- package/dist/website/Media/Media.js +225 -0
- package/dist/website/Media/Media.js.map +1 -0
- package/dist/website/Media/MediaLightbox.d.ts +18 -0
- package/dist/website/Media/MediaLightbox.js +38 -0
- package/dist/website/Media/MediaLightbox.js.map +1 -0
- package/dist/website/Metrics/Metrics.d.ts +74 -0
- package/dist/website/Metrics/Metrics.js +96 -0
- package/dist/website/Metrics/Metrics.js.map +1 -0
- package/dist/website/Music/Music.d.ts +60 -0
- package/dist/website/Music/Music.js +80 -0
- package/dist/website/Music/Music.js.map +1 -0
- package/dist/website/Portfolio/FrameLayout.d.ts +9 -0
- package/dist/website/Portfolio/FrameLayout.js +42 -0
- package/dist/website/Portfolio/FrameLayout.js.map +1 -0
- package/dist/website/Portfolio/Portfolio.d.ts +49 -0
- package/dist/website/Portfolio/Portfolio.js +66 -0
- package/dist/website/Portfolio/Portfolio.js.map +1 -0
- package/dist/website/Portfolio/QuestionCard.d.ts +22 -0
- package/dist/website/Portfolio/QuestionCard.js +33 -0
- package/dist/website/Portfolio/QuestionCard.js.map +1 -0
- package/dist/website/PortfolioIndex/PortfolioIndex.d.ts +21 -0
- package/dist/website/PortfolioIndex/PortfolioIndex.js +31 -0
- package/dist/website/PortfolioIndex/PortfolioIndex.js.map +1 -0
- package/dist/website/Reading/Reading.d.ts +203 -0
- package/dist/website/Reading/Reading.js +357 -0
- package/dist/website/Reading/Reading.js.map +1 -0
- package/dist/website/Recovery/Recovery.d.ts +39 -0
- package/dist/website/Recovery/Recovery.js +96 -0
- package/dist/website/Recovery/Recovery.js.map +1 -0
- package/dist/website/SearchPalette/SearchPalette.d.ts +59 -0
- package/dist/website/SearchPalette/SearchPalette.js +120 -0
- package/dist/website/SearchPalette/SearchPalette.js.map +1 -0
- package/dist/website/SiteNavigation/SiteNavigation.d.ts +46 -0
- package/dist/website/SiteNavigation/SiteNavigation.js +101 -0
- package/dist/website/SiteNavigation/SiteNavigation.js.map +1 -0
- package/dist/website/SiteShell/SiteShell.d.ts +45 -0
- package/dist/website/SiteShell/SiteShell.js +46 -0
- package/dist/website/SiteShell/SiteShell.js.map +1 -0
- package/dist/website/Timeline/Timeline.d.ts +80 -0
- package/dist/website/Timeline/Timeline.js +99 -0
- package/dist/website/Timeline/Timeline.js.map +1 -0
- package/dist/website/index.d.ts +27 -0
- package/dist/website/index.js +21 -0
- package/dist/website/index.js.map +1 -0
- package/dist/website-actions.css +6 -0
- package/dist/website-base.css +46 -0
- package/dist/website-collection.css +89 -0
- package/dist/website-contact.css +29 -0
- package/dist/website-content.css +17 -0
- package/dist/website-controls.css +91 -0
- package/dist/website-conversation.css +115 -0
- package/dist/website-evidence.css +56 -0
- package/dist/website-media.css +227 -0
- package/dist/website-metrics.css +15 -0
- package/dist/website-music.css +27 -0
- package/dist/website-portfolio.css +94 -0
- package/dist/website-reading.css +159 -0
- package/dist/website-recovery.css +28 -0
- package/dist/website-search.css +26 -0
- package/dist/website-shell.css +89 -0
- package/dist/website-timeline.css +43 -0
- package/dist/website.css +25 -0
- package/llms.txt +35 -0
- package/package.json +163 -5
- package/skills/folio-design/SKILL.md +228 -0
- package/skills/folio-design/evals/claims.json +95 -0
- package/skills/folio-design/evals/evals.json +84 -0
- package/skills/folio-design/rules/a11y.md +167 -0
- package/skills/folio-design/rules/composition.md +108 -0
- package/skills/folio-design/rules/forms.md +135 -0
- package/skills/folio-design/rules/naming.md +155 -0
- package/skills/folio-design/rules/tokens.md +133 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Markdown/Markdown.tsx"],"sourcesContent":["import { Fragment, type ReactNode } from 'react'\nimport { Code } from '../Code/Code'\nimport { CodeBlock } from '../CodeBlock/CodeBlock'\nimport { Heading } from '../Heading/Heading'\nimport { LinkArrow } from '../LinkArrow/LinkArrow'\nimport { Separator } from '../Separator/Separator'\nimport { Text } from '../Text/Text'\nimport { isOutbound } from './inline'\nimport type { MarkdownHeadingLevel, MarkdownInline, MarkdownNode } from './nodes'\nimport { parseMarkdown } from './parse'\nimport { slugify } from './slug'\n\nexport type { MarkdownHeadingLevel, MarkdownInline, MarkdownNode } from './nodes'\nexport { parseMarkdown } from './parse'\nexport { slugify } from './slug'\n\n/** The plain text of an inline run — what a heading's id is derived from. */\nfunction textOf(nodes: MarkdownInline[]): string {\n return nodes\n .map((node) => {\n if (node.type === 'text' || node.type === 'code') return node.value\n if (node.type === 'image') return node.alt\n return textOf(node.children)\n })\n .join('')\n}\n\ninterface RenderContext {\n headingLevelStart: MarkdownHeadingLevel\n idPrefix?: string\n markExternalLinks: boolean\n /** How many headings have already claimed each slug, for the `-2` suffix. */\n taken: Map<string, number>\n}\n\nfunction headingId(text: string, context: RenderContext): string {\n const base = slugify(text) || 'section'\n const seen = (context.taken.get(base) ?? 0) + 1\n context.taken.set(base, seen)\n const id = seen === 1 ? base : `${base}-${seen}`\n return context.idPrefix ? `${context.idPrefix}-${id}` : id\n}\n\nfunction renderInline(node: MarkdownInline, key: number, context: RenderContext): ReactNode {\n switch (node.type) {\n case 'text':\n return node.value\n case 'code':\n return <Code key={key}>{node.value}</Code>\n case 'strong':\n return (\n <strong key={key} className=\"font-medium text-(--ink)\">\n {node.children.map((child, index) => renderInline(child, index, context))}\n </strong>\n )\n case 'emphasis':\n return (\n <em key={key} className=\"italic\">\n {node.children.map((child, index) => renderInline(child, index, context))}\n </em>\n )\n case 'image':\n return (\n <img\n key={key}\n src={node.src}\n alt={node.alt}\n loading=\"lazy\"\n className=\"h-auto max-w-full rounded-(--radius)\"\n />\n )\n case 'link': {\n // Refusing `javascript:` keeps the link from EXECUTING; `rel` keeps it\n // from spending the page's reputation and its reader's location. The\n // author of this href is the untrusted party the component exists for,\n // so an outbound link they wrote passes no ranking on (`nofollow`) and\n // hands the destination no `Referer` to read the current URL out of\n // (`noreferrer`). A relative href cannot leave, so it is left alone.\n const outbound = isOutbound(node.href)\n return (\n <a\n key={key}\n href={node.href}\n rel={outbound ? 'noreferrer nofollow' : undefined}\n className=\"text-(--ink) underline decoration-[var(--rule-2)] underline-offset-4 transition-[text-decoration-color] duration-(--duration-fast) hover:decoration-[var(--ink)]\"\n >\n {node.children.map((child, index) => renderInline(child, index, context))}\n {outbound && context.markExternalLinks ? <LinkArrow /> : null}\n </a>\n )\n }\n }\n}\n\n/**\n * A list item's blocks, unwrapped when there is only prose in it.\n *\n * A one-paragraph item renders its inline content directly, so a tight list\n * does not put a `<p>` inside every `<li>` — which is what Markdown means by a\n * tight list, and what keeps the item's line spacing the list's rather than the\n * paragraph's.\n */\nfunction renderItem(blocks: MarkdownNode[], key: number, context: RenderContext): ReactNode {\n const first = blocks[0]\n const only = blocks.length === 1 && first?.type === 'paragraph' ? first : undefined\n return (\n <li key={key} className=\"relative\">\n {only\n ? only.children.map((child, i) => renderInline(child, i, context))\n : blocks.map((block, i) => renderBlock(block, i, context))}\n </li>\n )\n}\n\nfunction renderBlock(node: MarkdownNode, key: number, context: RenderContext): ReactNode {\n switch (node.type) {\n case 'heading': {\n // Clamped, not wrapped: a level past six has nowhere to go, and an <h7>\n // is a <span> as far as every screen reader is concerned.\n const level = Math.min(6, node.level + context.headingLevelStart - 1) as MarkdownHeadingLevel\n return (\n <Heading key={key} level={level} id={headingId(textOf(node.children), context)}>\n {node.children.map((child, index) => renderInline(child, index, context))}\n </Heading>\n )\n }\n case 'paragraph':\n return (\n <Text key={key}>{node.children.map((child, index) => renderInline(child, index, context))}</Text>\n )\n case 'code':\n return <CodeBlock key={key} code={node.value} lang={node.lang} />\n case 'rule':\n // Not decorative: a thematic break is a change of subject the author\n // wrote, so it is announced rather than drawn and hidden.\n return <Separator key={key} weight=\"edge\" decorative={false} />\n case 'quote':\n return (\n <blockquote\n key={key}\n className=\"m-0 border-s-2 border-(--rule-hard) ps-[1.25em] font-serif text-[length:var(--fs-item)] leading-[1.55] text-(--ink) [&>*+*]:mt-[0.6em]\"\n >\n {node.children.map((child, i) => renderBlock(child, i, context))}\n </blockquote>\n )\n case 'list':\n return node.ordered ? (\n <ol\n key={key}\n className=\"m-0 list-decimal ps-[1.4em] text-(--ink-2) marker:text-(--ink-3-aa) [&>li+li]:mt-[0.4em]\"\n >\n {node.items.map((item, i) => renderItem(item, i, context))}\n </ol>\n ) : (\n // The marker is a hairline dash drawn on `::before`, not a disc: the\n // system's only filled circle is a status dot. `article.css` draws the\n // same dash on the same pseudo-element, so markdown dropped into an\n // Article coincides with the stylesheet rather than doubling it.\n <ul\n key={key}\n className=\"m-0 list-none ps-[1.15em] text-(--ink-2) [&>li+li]:mt-[0.4em] [&>li]:before:absolute [&>li]:before:start-[-1.15em] [&>li]:before:top-[0.85em] [&>li]:before:h-px [&>li]:before:w-[0.55em] [&>li]:before:bg-(--rule-2) [&>li]:before:content-['']\"\n >\n {node.items.map((item, i) => renderItem(item, i, context))}\n </ul>\n )\n }\n}\n\nexport interface MarkdownProps {\n /** The Markdown source. A string — not nodes, not HTML. */\n children: string\n /**\n * The level the document's top heading renders at.\n *\n * Markdown is written as a document, so its `#` is an `<h1>`. Dropped into a\n * page that already has one — inside an `<h2>` section, in a card, under a\n * dialog's title — that produces two first-level headings and an outline a\n * screen reader cannot navigate. Set this to the level BELOW the heading the\n * content sits under, and every level in the document shifts with it.\n */\n headingLevelStart?: MarkdownHeadingLevel\n /**\n * Namespaces the generated heading ids.\n *\n * Two documents on one page both containing \"Installation\" would otherwise\n * both claim `#installation`, and a fragment link would land on whichever the\n * browser found first.\n */\n idPrefix?: string\n /**\n * Adds the system's outbound arrow to links that leave for another site.\n *\n * Off by default, and opt-in rather than automatic for two reasons. The mark\n * is an addition to a sentence the component did not write, which is a\n * different kind of act from styling one. And `Markdown` has no idea what\n * origin it is being rendered on, so \"leaves for another site\" can only mean\n * \"carries an `http`/`https` scheme\" — an absolute link back to your own\n * domain gets the arrow too. A caller who knows the shape of their content\n * turns it on; one who does not should not have it turned on for them.\n *\n * The `rel` on an outbound link is NOT opt-in and cannot be turned off: it\n * is the security half of the same boundary as the scheme check.\n */\n markExternalLinks?: boolean\n /**\n * Bring your own parser.\n *\n * Anything that turns the source into `MarkdownNode`s: markdown-it, remark,\n * or a pipeline that already has an AST and only needs mapping. The node\n * shapes are exported alongside the component as `MarkdownNode`,\n * `MarkdownInline` and `MarkdownHeadingLevel`. The built-in parser covers the\n * subset this system styles; this is the seam for tables, footnotes, task\n * lists and everything else.\n */\n parse?: (source: string) => MarkdownNode[]\n}\n\n/**\n * A Markdown string, rendered as this system's components.\n *\n * The gap it fills is content nobody on this side wrote: a comment, a README, a\n * model's answer, a description out of a database. `Article` cannot take those\n * — it renders HTML through `dangerouslySetInnerHTML` and is documented as\n * trusted-input-only — and until now the alternative was a `<pre>` or a\n * sanitiser bolted onto a styling primitive.\n *\n * IT IS NOT AN `Article`, and the two do not merge. `Markdown` turns a string\n * into nodes; `Article` is the reading column those nodes can sit in. It\n * renders a FRAGMENT rather than a wrapper, which is what makes that nesting\n * work — `Article`'s rhythm is a direct-child combinator, so any element\n * between the two, `display: contents` included, would cost every paragraph\n * its spacing.\n *\n * ── It brings type and colour, and no vertical rhythm ──\n *\n * The nodes carry the system's faces and inks on their own, so one of these\n * looks right in isolation. It is not SPACED in isolation: every node renders\n * `m-0`, and a fragment has no box of its own to put a gap in. Nor does a\n * uniform `gap` on a container reproduce it, because prose spacing is not\n * uniform — `article.css` gives a heading 2.25em above and 0.75em below, which\n * is what sits a heading with the paragraph it introduces rather than midway\n * between two. For anything longer than a sentence — a comment, an answer, a\n * README — put it in `<Article as=\"div\">` and get the real rhythm for the cost\n * of one element.\n *\n * ── A fenced code block brings a client component with it ──\n *\n * The renderer is plain functions and has no state, but a fenced block renders\n * `CodeBlock`, which is `'use client'` and arrives with `useState`,\n * `useEffect` and two icons. That is correct — the copy button is the reason\n * the block exists — but \"server-rendered\" only holds for content with no code\n * in it, which is worth knowing before this goes into a route that has no\n * client bundle yet.\n *\n * ── Why there is no parser in `dependencies` ──\n *\n * Three options, and the decision is written here because it is the one a\n * reader will want to argue with.\n *\n * 1. BUNDLE A PARSER. markdown-it is the obvious pick, and the documentation\n * site already depends on it — but the site is an app and this is a\n * library, where the dependency list is part of the contract every consumer\n * signs. Measured with the same esbuild pass `check:size` uses, markdown-it\n * is 110.7 kB minified against the 38.9 kB this package had left under its\n * bundle budget. It is not close, and \"we will raise the budget\" is how a\n * design system becomes the largest thing on a page.\n * 2. TAKE PRE-PARSED HTML, the way `Article` does. Cheapest, and wrong for the\n * case this exists for: HTML from an untrusted author is the input this is\n * supposed to make safe, and it cannot carry `headingLevelStart` or stable\n * heading ids without the component parsing markup back apart to find them.\n * 3. PARSE THE SUBSET WE STYLE, and take a `parse` function for the rest.\n * Chosen. The block grammar is line-based and small (see `parse.ts`), it\n * emits React elements rather than markup — so there is no\n * `dangerouslySetInnerHTML` in this path at all, no sanitiser to configure\n * and no sanitiser to get wrong — and a consumer who needs tables,\n * footnotes or task lists passes `parse` and keeps every other promise the\n * component makes.\n *\n * Headings carry an `id` slugged from their own text and deduplicated within\n * the document, so a table of contents can link to them without the caller\n * post-processing the DOM to find out where they went.\n *\n * A link in the source is validated here, at the boundary: a scheme that is not\n * `http`, `https`, `mailto` or `tel` never becomes a link, and one that leaves\n * for another site carries `rel=\"noreferrer nofollow\"` — so an author the page\n * does not trust cannot spend its ranking or read its URL out of the `Referer`.\n *\n * @example\n * // A comment body or an answer: the reading column is what spaces it.\n * <Article as=\"div\">\n * <Markdown headingLevelStart={3} idPrefix=\"answer\">{answer}</Markdown>\n * </Article>\n * @example\n * // A whole document, in the column it was written for.\n * <Article><Markdown>{readme}</Markdown></Article>\n * @example\n * // Tables and footnotes, via the consumer's own pipeline.\n * <Markdown parse={(source) => toMarkdownNodes(md.parse(source, {}))}>{post}</Markdown>\n */\nexport function Markdown({\n children,\n headingLevelStart = 1,\n idPrefix,\n markExternalLinks = false,\n parse = parseMarkdown,\n}: MarkdownProps) {\n const context: RenderContext = { headingLevelStart, idPrefix, markExternalLinks, taken: new Map() }\n const nodes = typeof children === 'string' ? parse(children) : []\n\n return <Fragment>{nodes.map((node, index) => renderBlock(node, index, context))}</Fragment>\n}\n\nexport default Markdown\n"],"mappings":"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","names":["parseMarkdown","slugify"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { MarkdownInline } from './nodes.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The schemes a link is allowed to carry, and the reason this function exists
|
|
5
|
+
* at all.
|
|
6
|
+
*
|
|
7
|
+
* `Markdown` renders strings nobody on this side wrote — a comment, a README,
|
|
8
|
+
* a model's answer — so the href is untrusted input arriving at a system
|
|
9
|
+
* boundary and is validated there (HAR-SEC-002). A URL with no scheme is
|
|
10
|
+
* relative and cannot reach a scheme handler, so it passes; a URL WITH one has
|
|
11
|
+
* to be on this list, which is what turns `[click](javascript:…)` into plain
|
|
12
|
+
* text instead of a working control.
|
|
13
|
+
*
|
|
14
|
+
* @returns the href, or `undefined` when it must not be linked.
|
|
15
|
+
*/
|
|
16
|
+
declare function safeHref(raw: string): string | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Whether a validated href can leave this origin.
|
|
19
|
+
*
|
|
20
|
+
* `safeHref` decides what may be linked at all; this decides what a link is
|
|
21
|
+
* allowed to take with it. Only `http` and `https` reach another site — a
|
|
22
|
+
* relative href resolves against the page, and `mailto:` and `tel:` hand the
|
|
23
|
+
* URL to a handler rather than to a document that could read a `Referer`.
|
|
24
|
+
*/
|
|
25
|
+
declare function isOutbound(href: string): boolean;
|
|
26
|
+
/** One run of text, as inline nodes. */
|
|
27
|
+
declare function parseInline(text: string): MarkdownInline[];
|
|
28
|
+
|
|
29
|
+
export { isOutbound, parseInline, safeHref };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
function safeHref(raw) {
|
|
2
|
+
const href = raw.trim();
|
|
3
|
+
if (href === "") return void 0;
|
|
4
|
+
const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(href);
|
|
5
|
+
if (!scheme) return href;
|
|
6
|
+
return ["http", "https", "mailto", "tel"].includes((scheme[1] ?? "").toLowerCase()) ? href : void 0;
|
|
7
|
+
}
|
|
8
|
+
function isOutbound(href) {
|
|
9
|
+
return /^https?:/i.test(href);
|
|
10
|
+
}
|
|
11
|
+
const INLINE = new RegExp(
|
|
12
|
+
[
|
|
13
|
+
// `\x60` is a backtick. Written as an escape because these are raw strings
|
|
14
|
+
// in a template literal, where a real backtick needs escaping and the raw
|
|
15
|
+
// form then keeps the backslash — which is a different pattern than the one
|
|
16
|
+
// it looks like.
|
|
17
|
+
String.raw`(?<escape>\\[\\\x60*_{}[\]()#+\-.!>])`,
|
|
18
|
+
String.raw`(?<ticks>\x60+)(?<code>[\s\S]*?)\k<ticks>`,
|
|
19
|
+
String.raw`!\[(?<alt>[^\]]*)\]\((?<src>[^)\s]+)\)`,
|
|
20
|
+
String.raw`\[(?<text>[^\]]*)\]\((?<href>[^)\s]+)\)`,
|
|
21
|
+
String.raw`\*\*(?<strongStar>[\s\S]+?)\*\*`,
|
|
22
|
+
String.raw`(?<![A-Za-z0-9])__(?<strongUnderscore>[\s\S]+?)__(?![A-Za-z0-9])`,
|
|
23
|
+
String.raw`\*(?<emphasisStar>[^*\n][\s\S]*?)\*`,
|
|
24
|
+
String.raw`(?<![A-Za-z0-9])_(?<emphasisUnderscore>[^_\n][\s\S]*?)_(?![A-Za-z0-9])`
|
|
25
|
+
].join("|"),
|
|
26
|
+
"g"
|
|
27
|
+
);
|
|
28
|
+
function tokenOf(groups) {
|
|
29
|
+
if (groups.escape !== void 0) return { type: "text", value: groups.escape.slice(1) };
|
|
30
|
+
if (groups.code !== void 0) return { type: "code", value: groups.code.trim() };
|
|
31
|
+
if (groups.src !== void 0) {
|
|
32
|
+
const src = safeHref(groups.src);
|
|
33
|
+
return src ? { type: "image", src, alt: groups.alt ?? "" } : { type: "text", value: groups.alt ?? "" };
|
|
34
|
+
}
|
|
35
|
+
if (groups.href !== void 0) {
|
|
36
|
+
const href = safeHref(groups.href);
|
|
37
|
+
const children = parseInline(groups.text ?? "");
|
|
38
|
+
return href ? { type: "link", href, children } : { type: "text", value: groups.text ?? "" };
|
|
39
|
+
}
|
|
40
|
+
const strong = groups.strongStar ?? groups.strongUnderscore;
|
|
41
|
+
if (strong !== void 0) return { type: "strong", children: parseInline(strong) };
|
|
42
|
+
return {
|
|
43
|
+
type: "emphasis",
|
|
44
|
+
children: parseInline(groups.emphasisStar ?? groups.emphasisUnderscore ?? "")
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function merge(nodes) {
|
|
48
|
+
const out = [];
|
|
49
|
+
for (const node of nodes) {
|
|
50
|
+
const last = out[out.length - 1];
|
|
51
|
+
if (node.type === "text" && node.value === "") continue;
|
|
52
|
+
if (node.type === "text" && last?.type === "text") last.value += node.value;
|
|
53
|
+
else out.push(node);
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
function parseInline(text) {
|
|
58
|
+
const nodes = [];
|
|
59
|
+
let cursor = 0;
|
|
60
|
+
for (const match of text.matchAll(INLINE)) {
|
|
61
|
+
const at = match.index;
|
|
62
|
+
if (at > cursor) nodes.push({ type: "text", value: text.slice(cursor, at) });
|
|
63
|
+
nodes.push(tokenOf(match.groups ?? {}));
|
|
64
|
+
cursor = at + match[0].length;
|
|
65
|
+
}
|
|
66
|
+
if (cursor < text.length) nodes.push({ type: "text", value: text.slice(cursor) });
|
|
67
|
+
return merge(nodes);
|
|
68
|
+
}
|
|
69
|
+
export {
|
|
70
|
+
isOutbound,
|
|
71
|
+
parseInline,
|
|
72
|
+
safeHref
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=inline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Markdown/inline.ts"],"sourcesContent":["import type { MarkdownInline } from './nodes'\n\n/**\n * The schemes a link is allowed to carry, and the reason this function exists\n * at all.\n *\n * `Markdown` renders strings nobody on this side wrote — a comment, a README,\n * a model's answer — so the href is untrusted input arriving at a system\n * boundary and is validated there (HAR-SEC-002). A URL with no scheme is\n * relative and cannot reach a scheme handler, so it passes; a URL WITH one has\n * to be on this list, which is what turns `[click](javascript:…)` into plain\n * text instead of a working control.\n *\n * @returns the href, or `undefined` when it must not be linked.\n */\nexport function safeHref(raw: string): string | undefined {\n const href = raw.trim()\n if (href === '') return undefined\n const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(href)\n if (!scheme) return href\n return ['http', 'https', 'mailto', 'tel'].includes((scheme[1] ?? '').toLowerCase())\n ? href\n : undefined\n}\n\n/**\n * Whether a validated href can leave this origin.\n *\n * `safeHref` decides what may be linked at all; this decides what a link is\n * allowed to take with it. Only `http` and `https` reach another site — a\n * relative href resolves against the page, and `mailto:` and `tel:` hand the\n * URL to a handler rather than to a document that could read a `Referer`.\n */\nexport function isOutbound(href: string): boolean {\n return /^https?:/i.test(href)\n}\n\n/**\n * Every inline construct, in one ordered alternation.\n *\n * Order is the precedence: an escape beats everything, a code span beats the\n * emphasis markers inside it, an image beats the link it otherwise looks like,\n * and `**` beats `*`. One pass with `matchAll` rather than a nest of\n * `String.replace` calls, because replace-based Markdown is how a link's URL\n * ends up italicised by an underscore in a query string.\n *\n * The `_` forms carry word-boundary guards and the `*` forms do not, which is\n * the rule every implementation converges on: `snake_case_name` is an\n * identifier, and `a*b*c` is emphasis.\n */\nconst INLINE = new RegExp(\n [\n // `\\x60` is a backtick. Written as an escape because these are raw strings\n // in a template literal, where a real backtick needs escaping and the raw\n // form then keeps the backslash — which is a different pattern than the one\n // it looks like.\n String.raw`(?<escape>\\\\[\\\\\\x60*_{}[\\]()#+\\-.!>])`,\n String.raw`(?<ticks>\\x60+)(?<code>[\\s\\S]*?)\\k<ticks>`,\n String.raw`!\\[(?<alt>[^\\]]*)\\]\\((?<src>[^)\\s]+)\\)`,\n String.raw`\\[(?<text>[^\\]]*)\\]\\((?<href>[^)\\s]+)\\)`,\n String.raw`\\*\\*(?<strongStar>[\\s\\S]+?)\\*\\*`,\n String.raw`(?<![A-Za-z0-9])__(?<strongUnderscore>[\\s\\S]+?)__(?![A-Za-z0-9])`,\n String.raw`\\*(?<emphasisStar>[^*\\n][\\s\\S]*?)\\*`,\n String.raw`(?<![A-Za-z0-9])_(?<emphasisUnderscore>[^_\\n][\\s\\S]*?)_(?![A-Za-z0-9])`,\n ].join('|'),\n 'g',\n)\n\n/** One match, as the node it stands for. */\nfunction tokenOf(groups: Record<string, string | undefined>): MarkdownInline {\n if (groups.escape !== undefined) return { type: 'text', value: groups.escape.slice(1) }\n if (groups.code !== undefined) return { type: 'code', value: groups.code.trim() }\n\n if (groups.src !== undefined) {\n const src = safeHref(groups.src)\n // A blocked image degrades to its own alt text, which is the description\n // the author wrote for exactly this situation.\n return src ? { type: 'image', src, alt: groups.alt ?? '' } : { type: 'text', value: groups.alt ?? '' }\n }\n\n if (groups.href !== undefined) {\n const href = safeHref(groups.href)\n const children = parseInline(groups.text ?? '')\n return href ? { type: 'link', href, children } : { type: 'text', value: groups.text ?? '' }\n }\n\n const strong = groups.strongStar ?? groups.strongUnderscore\n if (strong !== undefined) return { type: 'strong', children: parseInline(strong) }\n\n return {\n type: 'emphasis',\n children: parseInline(groups.emphasisStar ?? groups.emphasisUnderscore ?? ''),\n }\n}\n\n/** Adjacent text runs are one run; an empty one is nothing at all. */\nfunction merge(nodes: MarkdownInline[]): MarkdownInline[] {\n const out: MarkdownInline[] = []\n for (const node of nodes) {\n const last = out[out.length - 1]\n if (node.type === 'text' && node.value === '') continue\n if (node.type === 'text' && last?.type === 'text') last.value += node.value\n else out.push(node)\n }\n return out\n}\n\n/** One run of text, as inline nodes. */\nexport function parseInline(text: string): MarkdownInline[] {\n const nodes: MarkdownInline[] = []\n let cursor = 0\n\n for (const match of text.matchAll(INLINE)) {\n const at = match.index\n if (at > cursor) nodes.push({ type: 'text', value: text.slice(cursor, at) })\n nodes.push(tokenOf(match.groups ?? {}))\n cursor = at + match[0].length\n }\n if (cursor < text.length) nodes.push({ type: 'text', value: text.slice(cursor) })\n\n return merge(nodes)\n}\n"],"mappings":"AAeO,SAAS,SAAS,KAAiC;AACxD,QAAM,OAAO,IAAI,KAAK;AACtB,MAAI,SAAS,GAAI,QAAO;AACxB,QAAM,SAAS,yBAAyB,KAAK,IAAI;AACjD,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,CAAC,QAAQ,SAAS,UAAU,KAAK,EAAE,UAAU,OAAO,CAAC,KAAK,IAAI,YAAY,CAAC,IAC9E,OACA;AACN;AAUO,SAAS,WAAW,MAAuB;AAChD,SAAO,YAAY,KAAK,IAAI;AAC9B;AAeA,MAAM,SAAS,IAAI;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA,IAKE,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,EACT,EAAE,KAAK,GAAG;AAAA,EACV;AACF;AAGA,SAAS,QAAQ,QAA4D;AAC3E,MAAI,OAAO,WAAW,OAAW,QAAO,EAAE,MAAM,QAAQ,OAAO,OAAO,OAAO,MAAM,CAAC,EAAE;AACtF,MAAI,OAAO,SAAS,OAAW,QAAO,EAAE,MAAM,QAAQ,OAAO,OAAO,KAAK,KAAK,EAAE;AAEhF,MAAI,OAAO,QAAQ,QAAW;AAC5B,UAAM,MAAM,SAAS,OAAO,GAAG;AAG/B,WAAO,MAAM,EAAE,MAAM,SAAS,KAAK,KAAK,OAAO,OAAO,GAAG,IAAI,EAAE,MAAM,QAAQ,OAAO,OAAO,OAAO,GAAG;AAAA,EACvG;AAEA,MAAI,OAAO,SAAS,QAAW;AAC7B,UAAM,OAAO,SAAS,OAAO,IAAI;AACjC,UAAM,WAAW,YAAY,OAAO,QAAQ,EAAE;AAC9C,WAAO,OAAO,EAAE,MAAM,QAAQ,MAAM,SAAS,IAAI,EAAE,MAAM,QAAQ,OAAO,OAAO,QAAQ,GAAG;AAAA,EAC5F;AAEA,QAAM,SAAS,OAAO,cAAc,OAAO;AAC3C,MAAI,WAAW,OAAW,QAAO,EAAE,MAAM,UAAU,UAAU,YAAY,MAAM,EAAE;AAEjF,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU,YAAY,OAAO,gBAAgB,OAAO,sBAAsB,EAAE;AAAA,EAC9E;AACF;AAGA,SAAS,MAAM,OAA2C;AACxD,QAAM,MAAwB,CAAC;AAC/B,aAAW,QAAQ,OAAO;AACxB,UAAM,OAAO,IAAI,IAAI,SAAS,CAAC;AAC/B,QAAI,KAAK,SAAS,UAAU,KAAK,UAAU,GAAI;AAC/C,QAAI,KAAK,SAAS,UAAU,MAAM,SAAS,OAAQ,MAAK,SAAS,KAAK;AAAA,QACjE,KAAI,KAAK,IAAI;AAAA,EACpB;AACA,SAAO;AACT;AAGO,SAAS,YAAY,MAAgC;AAC1D,QAAM,QAA0B,CAAC;AACjC,MAAI,SAAS;AAEb,aAAW,SAAS,KAAK,SAAS,MAAM,GAAG;AACzC,UAAM,KAAK,MAAM;AACjB,QAAI,KAAK,OAAQ,OAAM,KAAK,EAAE,MAAM,QAAQ,OAAO,KAAK,MAAM,QAAQ,EAAE,EAAE,CAAC;AAC3E,UAAM,KAAK,QAAQ,MAAM,UAAU,CAAC,CAAC,CAAC;AACtC,aAAS,KAAK,MAAM,CAAC,EAAE;AAAA,EACzB;AACA,MAAI,SAAS,KAAK,OAAQ,OAAM,KAAK,EAAE,MAAM,QAAQ,OAAO,KAAK,MAAM,MAAM,EAAE,CAAC;AAEhF,SAAO,MAAM,KAAK;AACpB;","names":[]}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The node shapes `Markdown` renders, and the contract a custom `parse`
|
|
3
|
+
* function has to meet.
|
|
4
|
+
*
|
|
5
|
+
* Deliberately small. It is not an attempt at mdast: it is the set of blocks
|
|
6
|
+
* this design system has an opinion about, which is the set `article.css`
|
|
7
|
+
* already styles. Anything outside it — footnotes, tables, task lists,
|
|
8
|
+
* definition lists, embedded HTML — is a `parse` away, and the point of naming
|
|
9
|
+
* the shapes here rather than accepting a foreign AST is that a consumer
|
|
10
|
+
* bringing markdown-it or remark maps into a surface the package can promise
|
|
11
|
+
* to keep rendering.
|
|
12
|
+
*/
|
|
13
|
+
type MarkdownHeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
|
14
|
+
/** A run of text, and the four things that can happen inside one. */
|
|
15
|
+
type MarkdownInline = {
|
|
16
|
+
type: 'text';
|
|
17
|
+
value: string;
|
|
18
|
+
} | {
|
|
19
|
+
type: 'code';
|
|
20
|
+
value: string;
|
|
21
|
+
} | {
|
|
22
|
+
type: 'strong';
|
|
23
|
+
children: MarkdownInline[];
|
|
24
|
+
} | {
|
|
25
|
+
type: 'emphasis';
|
|
26
|
+
children: MarkdownInline[];
|
|
27
|
+
} | {
|
|
28
|
+
type: 'link';
|
|
29
|
+
href: string;
|
|
30
|
+
children: MarkdownInline[];
|
|
31
|
+
} | {
|
|
32
|
+
type: 'image';
|
|
33
|
+
src: string;
|
|
34
|
+
alt: string;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* A block.
|
|
38
|
+
*
|
|
39
|
+
* `list` items and `quote` children are blocks in turn, which is what makes a
|
|
40
|
+
* nested list, or a fence inside a bullet, fall out of the same recursion
|
|
41
|
+
* rather than needing a case of its own.
|
|
42
|
+
*/
|
|
43
|
+
type MarkdownNode = {
|
|
44
|
+
type: 'heading';
|
|
45
|
+
level: MarkdownHeadingLevel;
|
|
46
|
+
children: MarkdownInline[];
|
|
47
|
+
} | {
|
|
48
|
+
type: 'paragraph';
|
|
49
|
+
children: MarkdownInline[];
|
|
50
|
+
} | {
|
|
51
|
+
type: 'code';
|
|
52
|
+
value: string;
|
|
53
|
+
lang?: string;
|
|
54
|
+
} | {
|
|
55
|
+
type: 'list';
|
|
56
|
+
ordered: boolean;
|
|
57
|
+
items: MarkdownNode[][];
|
|
58
|
+
} | {
|
|
59
|
+
type: 'quote';
|
|
60
|
+
children: MarkdownNode[];
|
|
61
|
+
} | {
|
|
62
|
+
type: 'rule';
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export type { MarkdownHeadingLevel, MarkdownInline, MarkdownNode };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=nodes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { MarkdownNode } from './nodes.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A Markdown string, as nodes.
|
|
5
|
+
*
|
|
6
|
+
* The supported subset, stated so nobody has to find its edges by experiment:
|
|
7
|
+
* ATX headings, paragraphs, fenced code with an info string, blockquotes,
|
|
8
|
+
* ordered and unordered lists including nesting, thematic breaks — and inline
|
|
9
|
+
* emphasis, strong, code spans, links, images and backslash escapes.
|
|
10
|
+
*
|
|
11
|
+
* What is NOT here, and is deliberate: tables, footnotes, task lists, setext
|
|
12
|
+
* headings, reference links, hard line breaks, and raw HTML. Raw HTML is the
|
|
13
|
+
* one that matters — it is left as text rather than rendered, so this path has
|
|
14
|
+
* no `dangerouslySetInnerHTML` anywhere in it and cannot be talked into one. A
|
|
15
|
+
* document that needs the rest brings its own parser through `Markdown`'s
|
|
16
|
+
* `parse` prop.
|
|
17
|
+
*
|
|
18
|
+
* Never throws. Malformed input is not an error condition here — it is Tuesday
|
|
19
|
+
* — so an unterminated fence, a stray bracket or an empty string each produce
|
|
20
|
+
* the nodes they can and no more.
|
|
21
|
+
*/
|
|
22
|
+
declare function parseMarkdown(source: string): MarkdownNode[];
|
|
23
|
+
|
|
24
|
+
export { parseMarkdown };
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { parseInline } from "./inline.js";
|
|
2
|
+
const FENCE = /^ {0,3}(`{3,}|~{3,})\s*([^\s`]*)\s*$/;
|
|
3
|
+
const HEADING = /^ {0,3}(#{1,6})\s+(.*?)\s*#*\s*$/;
|
|
4
|
+
const RULE = /^ {0,3}(?:-{3,}|\*{3,}|_{3,})\s*$/;
|
|
5
|
+
const QUOTE = /^ {0,3}>\s?(.*)$/;
|
|
6
|
+
const ITEM = /^(\s*)([-*+]|\d{1,9}[.)])\s+(.*)$/;
|
|
7
|
+
const lineAt = (lines, index) => lines[index] ?? "";
|
|
8
|
+
const opensBlock = (line) => HEADING.test(line) || RULE.test(line) || FENCE.test(line) || QUOTE.test(line) || ITEM.test(line);
|
|
9
|
+
const closesFence = (line, marker) => new RegExp(`^ {0,3}${marker.charAt(0)}{${marker.length},}\\s*$`).test(line);
|
|
10
|
+
function takeFence(lines, start, out) {
|
|
11
|
+
const fence = FENCE.exec(lineAt(lines, start));
|
|
12
|
+
if (!fence) return start + 1;
|
|
13
|
+
const [, marker = "", info = ""] = fence;
|
|
14
|
+
const body = [];
|
|
15
|
+
let i = start + 1;
|
|
16
|
+
while (i < lines.length && !closesFence(lineAt(lines, i), marker)) {
|
|
17
|
+
body.push(lineAt(lines, i));
|
|
18
|
+
i += 1;
|
|
19
|
+
}
|
|
20
|
+
out.push({ type: "code", value: body.join("\n"), lang: info || void 0 });
|
|
21
|
+
return i < lines.length ? i + 1 : i;
|
|
22
|
+
}
|
|
23
|
+
function takeQuote(lines, start, out) {
|
|
24
|
+
const body = [];
|
|
25
|
+
let i = start;
|
|
26
|
+
while (i < lines.length) {
|
|
27
|
+
const quoted = QUOTE.exec(lineAt(lines, i));
|
|
28
|
+
if (!quoted) break;
|
|
29
|
+
body.push(quoted[1] ?? "");
|
|
30
|
+
i += 1;
|
|
31
|
+
}
|
|
32
|
+
out.push({ type: "quote", children: parseBlocks(body) });
|
|
33
|
+
return i;
|
|
34
|
+
}
|
|
35
|
+
function takeList(lines, start, out) {
|
|
36
|
+
const first = ITEM.exec(lineAt(lines, start));
|
|
37
|
+
if (!first) return start + 1;
|
|
38
|
+
const baseIndent = (first[1] ?? "").length;
|
|
39
|
+
const ordered = /\d/.test(first[2] ?? "");
|
|
40
|
+
const items = [];
|
|
41
|
+
let current;
|
|
42
|
+
let indent = 0;
|
|
43
|
+
let i = start;
|
|
44
|
+
while (i < lines.length) {
|
|
45
|
+
const line = lineAt(lines, i);
|
|
46
|
+
const item = ITEM.exec(line);
|
|
47
|
+
const [, gap = "", bullet = "", rest = ""] = item ?? [];
|
|
48
|
+
if (item && gap.length <= baseIndent) {
|
|
49
|
+
if (ordered !== /\d/.test(bullet)) break;
|
|
50
|
+
if (current) items.push(parseBlocks(current));
|
|
51
|
+
indent = gap.length + bullet.length + 1;
|
|
52
|
+
current = [rest];
|
|
53
|
+
i += 1;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (current !== void 0 && (line.trim() === "" || line.startsWith(" ".repeat(indent)))) {
|
|
57
|
+
current.push(line.slice(indent));
|
|
58
|
+
i += 1;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
if (current) items.push(parseBlocks(current));
|
|
64
|
+
out.push({ type: "list", ordered, items });
|
|
65
|
+
return i;
|
|
66
|
+
}
|
|
67
|
+
function takeParagraph(lines, start, out) {
|
|
68
|
+
const body = [];
|
|
69
|
+
let i = start;
|
|
70
|
+
for (let line = lineAt(lines, i); i < lines.length; line = lineAt(lines, i)) {
|
|
71
|
+
if (line.trim() === "" || opensBlock(line)) break;
|
|
72
|
+
body.push(line.trim());
|
|
73
|
+
i += 1;
|
|
74
|
+
}
|
|
75
|
+
if (body.length === 0) return start + 1;
|
|
76
|
+
out.push({ type: "paragraph", children: parseInline(body.join(" ")) });
|
|
77
|
+
return i;
|
|
78
|
+
}
|
|
79
|
+
function parseBlocks(lines) {
|
|
80
|
+
const out = [];
|
|
81
|
+
let i = 0;
|
|
82
|
+
while (i < lines.length) {
|
|
83
|
+
const line = lineAt(lines, i);
|
|
84
|
+
const heading = HEADING.exec(line);
|
|
85
|
+
if (line.trim() === "") i += 1;
|
|
86
|
+
else if (FENCE.test(line)) i = takeFence(lines, i, out);
|
|
87
|
+
else if (heading) {
|
|
88
|
+
out.push({
|
|
89
|
+
type: "heading",
|
|
90
|
+
level: (heading[1] ?? "#").length,
|
|
91
|
+
children: parseInline(heading[2] ?? "")
|
|
92
|
+
});
|
|
93
|
+
i += 1;
|
|
94
|
+
} else if (RULE.test(line)) {
|
|
95
|
+
out.push({ type: "rule" });
|
|
96
|
+
i += 1;
|
|
97
|
+
} else if (QUOTE.test(line)) i = takeQuote(lines, i, out);
|
|
98
|
+
else if (ITEM.test(line)) i = takeList(lines, i, out);
|
|
99
|
+
else i = takeParagraph(lines, i, out);
|
|
100
|
+
}
|
|
101
|
+
return out;
|
|
102
|
+
}
|
|
103
|
+
function parseMarkdown(source) {
|
|
104
|
+
if (typeof source !== "string" || source.trim() === "") return [];
|
|
105
|
+
return parseBlocks(source.replace(/\r\n?/g, "\n").split("\n"));
|
|
106
|
+
}
|
|
107
|
+
export {
|
|
108
|
+
parseMarkdown
|
|
109
|
+
};
|
|
110
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Markdown/parse.ts"],"sourcesContent":["import { parseInline } from './inline'\nimport type { MarkdownHeadingLevel, MarkdownNode } from './nodes'\n\n/**\n * The block grammar, as the six line shapes it recognises.\n *\n * Line-based rather than character-based, which is what keeps this small enough\n * to live in a design system: Markdown's blocks are decided by how a line\n * STARTS, and the interesting half — emphasis, links, code spans — is the\n * inline pass, which runs once per block.\n */\nconst FENCE = /^ {0,3}(`{3,}|~{3,})\\s*([^\\s`]*)\\s*$/\nconst HEADING = /^ {0,3}(#{1,6})\\s+(.*?)\\s*#*\\s*$/\nconst RULE = /^ {0,3}(?:-{3,}|\\*{3,}|_{3,})\\s*$/\nconst QUOTE = /^ {0,3}>\\s?(.*)$/\nconst ITEM = /^(\\s*)([-*+]|\\d{1,9}[.)])\\s+(.*)$/\n\n/**\n * A line, or the empty string past the end.\n *\n * `noUncheckedIndexedAccess` is on, and every scanner below walks off the end\n * of the array by construction — reading one line ahead is how a list decides\n * whether a blank line ended it. An empty string matches none of the patterns,\n * which is exactly the answer wanted there.\n */\nconst lineAt = (lines: string[], index: number): string => lines[index] ?? ''\n\nconst opensBlock = (line: string): boolean =>\n HEADING.test(line) || RULE.test(line) || FENCE.test(line) || QUOTE.test(line) || ITEM.test(line)\n\n/** A fence closes on the same character, at the same length or longer. */\nconst closesFence = (line: string, marker: string): boolean =>\n new RegExp(`^ {0,3}${marker.charAt(0)}{${marker.length},}\\\\s*$`).test(line)\n\nfunction takeFence(lines: string[], start: number, out: MarkdownNode[]): number {\n const fence = FENCE.exec(lineAt(lines, start))\n if (!fence) return start + 1\n const [, marker = '', info = ''] = fence\n\n const body: string[] = []\n let i = start + 1\n while (i < lines.length && !closesFence(lineAt(lines, i), marker)) {\n body.push(lineAt(lines, i))\n i += 1\n }\n out.push({ type: 'code', value: body.join('\\n'), lang: info || undefined })\n\n // An unclosed fence runs to the end of the document rather than throwing.\n // That is what CommonMark specifies, and it is also the exact shape of a\n // model's answer that hit its token limit mid-snippet.\n return i < lines.length ? i + 1 : i\n}\n\nfunction takeQuote(lines: string[], start: number, out: MarkdownNode[]): number {\n const body: string[] = []\n let i = start\n while (i < lines.length) {\n const quoted = QUOTE.exec(lineAt(lines, i))\n if (!quoted) break\n body.push(quoted[1] ?? '')\n i += 1\n }\n // Recursive, so a list, a fence or a nested quote inside a blockquote is the\n // same code path rather than five more cases.\n out.push({ type: 'quote', children: parseBlocks(body) })\n return i\n}\n\nfunction takeList(lines: string[], start: number, out: MarkdownNode[]): number {\n const first = ITEM.exec(lineAt(lines, start))\n if (!first) return start + 1\n\n const baseIndent = (first[1] ?? '').length\n const ordered = /\\d/.test(first[2] ?? '')\n const items: MarkdownNode[][] = []\n let current: string[] | undefined\n let indent = 0\n let i = start\n\n while (i < lines.length) {\n const line = lineAt(lines, i)\n const item = ITEM.exec(line)\n const [, gap = '', bullet = '', rest = ''] = item ?? []\n\n if (item && gap.length <= baseIndent) {\n // A bullet directly under a number is a second list, not a stray item.\n if (ordered !== /\\d/.test(bullet)) break\n if (current) items.push(parseBlocks(current))\n indent = gap.length + bullet.length + 1\n current = [rest]\n i += 1\n continue\n }\n if (current !== undefined && (line.trim() === '' || line.startsWith(' '.repeat(indent)))) {\n current.push(line.slice(indent))\n i += 1\n continue\n }\n break\n }\n\n if (current) items.push(parseBlocks(current))\n out.push({ type: 'list', ordered, items })\n return i\n}\n\nfunction takeParagraph(lines: string[], start: number, out: MarkdownNode[]): number {\n const body: string[] = []\n let i = start\n for (let line = lineAt(lines, i); i < lines.length; line = lineAt(lines, i)) {\n if (line.trim() === '' || opensBlock(line)) break\n body.push(line.trim())\n i += 1\n }\n if (body.length === 0) return start + 1\n\n // Soft line breaks join with a space, which is what Markdown means by them:\n // a paragraph hard-wrapped at 80 columns is one paragraph.\n out.push({ type: 'paragraph', children: parseInline(body.join(' ')) })\n return i\n}\n\nfunction parseBlocks(lines: string[]): MarkdownNode[] {\n const out: MarkdownNode[] = []\n let i = 0\n while (i < lines.length) {\n const line = lineAt(lines, i)\n const heading = HEADING.exec(line)\n\n if (line.trim() === '') i += 1\n else if (FENCE.test(line)) i = takeFence(lines, i, out)\n else if (heading) {\n out.push({\n type: 'heading',\n level: (heading[1] ?? '#').length as MarkdownHeadingLevel,\n children: parseInline(heading[2] ?? ''),\n })\n i += 1\n } else if (RULE.test(line)) {\n out.push({ type: 'rule' })\n i += 1\n } else if (QUOTE.test(line)) i = takeQuote(lines, i, out)\n else if (ITEM.test(line)) i = takeList(lines, i, out)\n else i = takeParagraph(lines, i, out)\n }\n return out\n}\n\n/**\n * A Markdown string, as nodes.\n *\n * The supported subset, stated so nobody has to find its edges by experiment:\n * ATX headings, paragraphs, fenced code with an info string, blockquotes,\n * ordered and unordered lists including nesting, thematic breaks — and inline\n * emphasis, strong, code spans, links, images and backslash escapes.\n *\n * What is NOT here, and is deliberate: tables, footnotes, task lists, setext\n * headings, reference links, hard line breaks, and raw HTML. Raw HTML is the\n * one that matters — it is left as text rather than rendered, so this path has\n * no `dangerouslySetInnerHTML` anywhere in it and cannot be talked into one. A\n * document that needs the rest brings its own parser through `Markdown`'s\n * `parse` prop.\n *\n * Never throws. Malformed input is not an error condition here — it is Tuesday\n * — so an unterminated fence, a stray bracket or an empty string each produce\n * the nodes they can and no more.\n */\nexport function parseMarkdown(source: string): MarkdownNode[] {\n if (typeof source !== 'string' || source.trim() === '') return []\n return parseBlocks(source.replace(/\\r\\n?/g, '\\n').split('\\n'))\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A heading's text, as an anchor id.
|
|
3
|
+
*
|
|
4
|
+
* Exported because a table of contents has to arrive at the SAME id the
|
|
5
|
+
* rendered heading got, and the alternative is building the list by reading it
|
|
6
|
+
* back off the DOM — which a server render does not have.
|
|
7
|
+
*
|
|
8
|
+
* Letters and numbers survive in any script (`\p{L}`, not `a-z`), so a Chinese
|
|
9
|
+
* or Greek heading keeps its characters instead of slugging away to nothing and
|
|
10
|
+
* colliding with every other one on the page. `Markdown` deduplicates what does
|
|
11
|
+
* collide by appending `-2`, `-3`, and so on in document order.
|
|
12
|
+
*/
|
|
13
|
+
declare function slugify(text: string): string;
|
|
14
|
+
|
|
15
|
+
export { slugify };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Markdown/slug.ts"],"sourcesContent":["/**\n * A heading's text, as an anchor id.\n *\n * Exported because a table of contents has to arrive at the SAME id the\n * rendered heading got, and the alternative is building the list by reading it\n * back off the DOM — which a server render does not have.\n *\n * Letters and numbers survive in any script (`\\p{L}`, not `a-z`), so a Chinese\n * or Greek heading keeps its characters instead of slugging away to nothing and\n * colliding with every other one on the page. `Markdown` deduplicates what does\n * collide by appending `-2`, `-3`, and so on in document order.\n */\nexport function slugify(text: string): string {\n return text\n .trim()\n .toLowerCase()\n .replace(/[^\\p{L}\\p{N}]+/gu, '-')\n .replace(/^-+|-+$/g, '')\n}\n"],"mappings":"AAYO,SAAS,QAAQ,MAAsB;AAC5C,SAAO,KACJ,KAAK,EACL,YAAY,EACZ,QAAQ,oBAAoB,GAAG,EAC/B,QAAQ,YAAY,EAAE;AAC3B;","names":[]}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
3
|
+
import { StatusTone } from '../StatusDot/StatusDot.js';
|
|
4
|
+
|
|
5
|
+
interface MetricProps extends HTMLAttributes<HTMLElement> {
|
|
6
|
+
/** What the figure counts. */
|
|
7
|
+
label: ReactNode;
|
|
8
|
+
/** The figure, already formatted — this does not guess a unit or a locale. */
|
|
9
|
+
value: ReactNode;
|
|
10
|
+
/** One line of context. A figure without it is a number, not a reading. */
|
|
11
|
+
detail?: ReactNode;
|
|
12
|
+
/**
|
|
13
|
+
* How the reading stands. Drawn as a dot beside the label, and only ever a
|
|
14
|
+
* SECOND carrier: the dot is `aria-hidden`, so whatever the tone means has to
|
|
15
|
+
* be in `detail` as well or it reaches nobody who cannot see it.
|
|
16
|
+
*/
|
|
17
|
+
tone?: StatusTone;
|
|
18
|
+
/** A sparkline, a denominator, a caveat. Sits under the figure. */
|
|
19
|
+
aside?: ReactNode;
|
|
20
|
+
/**
|
|
21
|
+
* Render `children` as the tile instead of the `<article>`, keeping these
|
|
22
|
+
* styles — how a linkable tile gets a router's own `Link` without this
|
|
23
|
+
* package importing one.
|
|
24
|
+
*
|
|
25
|
+
* The slotted element must take no children of its own: the label, the figure
|
|
26
|
+
* and everything under them are injected INTO it, which is the point. A whole
|
|
27
|
+
* tile inside one link also means the link's accessible name is every word in
|
|
28
|
+
* it, read in order — "Rows, 63,851, newest yesterday" — so keep `detail`
|
|
29
|
+
* short enough to be heard as part of a link.
|
|
30
|
+
*/
|
|
31
|
+
asChild?: boolean;
|
|
32
|
+
/** The element the tile becomes under `asChild`. Ignored without it. */
|
|
33
|
+
children?: ReactNode;
|
|
34
|
+
className?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* One reading, on a plate: a label, a figure, and what qualifies it.
|
|
38
|
+
*
|
|
39
|
+
* Distinct from `BigNumber`, which is the same idea at headline scale for the
|
|
40
|
+
* ONE figure a view is about, and which needs the charts entry. This is the
|
|
41
|
+
* tile that appears four across on a console: smaller, monospaced rather than
|
|
42
|
+
* editorial, and carrying two things `BigNumber` has nowhere for — a status
|
|
43
|
+
* tone, and a free slot under the number that is not a delta. Those two are the
|
|
44
|
+
* whole reason it exists; a dashboard whose tiles have to be a `<div>` because
|
|
45
|
+
* the delta does not apply is a dashboard with two tile designs in it.
|
|
46
|
+
*
|
|
47
|
+
* The figure is monospace and tabular by construction, because four of these in
|
|
48
|
+
* a row are read down the column as much as along it, and proportional digits
|
|
49
|
+
* put the same magnitude at two different widths.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* <Metric label="Rows" value="63,851" detail="newest yesterday" tone="success" />
|
|
53
|
+
* @example
|
|
54
|
+
* // A tile that is also a link, with the router's own component.
|
|
55
|
+
* <Metric asChild label="Jobs" value="12" detail="3 waiting">
|
|
56
|
+
* <Link href="/jobs" />
|
|
57
|
+
* </Metric>
|
|
58
|
+
*/
|
|
59
|
+
declare function Metric({ label, value, detail, tone, aside, asChild, children, className, ...rest }: MetricProps): react.JSX.Element;
|
|
60
|
+
|
|
61
|
+
export { Metric, type MetricProps, Metric as default };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Slot, Slottable } from "@radix-ui/react-slot";
|
|
3
|
+
import { StatusDot } from "../StatusDot/StatusDot.js";
|
|
4
|
+
import { cn } from "../../lib/cn.js";
|
|
5
|
+
const CLASS = {
|
|
6
|
+
card: "flex flex-col gap-1 rounded-(--radius) border border-(--rule) p-3",
|
|
7
|
+
/* The link affordance, and only under `asChild`: a plate that lifts under the
|
|
8
|
+
pointer when nothing happens on a click is a plate that has promised
|
|
9
|
+
something. */
|
|
10
|
+
link: "no-underline transition-colors duration-(--duration-fast) hover:border-(--rule-2) hover:bg-(--stone)",
|
|
11
|
+
head: "flex items-start justify-between gap-2",
|
|
12
|
+
label: "eyebrow text-(--ink-3-aa)",
|
|
13
|
+
/* Mono and tabular: the figures line up between tiles and stay comparable
|
|
14
|
+
down a column, which is the whole reason four of these sit in a row. */
|
|
15
|
+
value: "font-mono text-[length:var(--fs-item)] leading-none tabular-nums text-(--ink)",
|
|
16
|
+
detail: "text-xs text-(--ink-2)"
|
|
17
|
+
};
|
|
18
|
+
function Metric({
|
|
19
|
+
label,
|
|
20
|
+
value,
|
|
21
|
+
detail,
|
|
22
|
+
tone,
|
|
23
|
+
aside,
|
|
24
|
+
asChild = false,
|
|
25
|
+
children,
|
|
26
|
+
className,
|
|
27
|
+
...rest
|
|
28
|
+
}) {
|
|
29
|
+
const body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
30
|
+
/* @__PURE__ */ jsxs("div", { className: CLASS.head, children: [
|
|
31
|
+
/* @__PURE__ */ jsx("span", { className: CLASS.label, children: label }),
|
|
32
|
+
tone !== void 0 && /* @__PURE__ */ jsx(StatusDot, { tone, pulse: false })
|
|
33
|
+
] }),
|
|
34
|
+
/* @__PURE__ */ jsx("p", { className: CLASS.value, children: value }),
|
|
35
|
+
detail !== void 0 && /* @__PURE__ */ jsx("p", { className: CLASS.detail, children: detail }),
|
|
36
|
+
aside
|
|
37
|
+
] });
|
|
38
|
+
if (asChild) {
|
|
39
|
+
return /* @__PURE__ */ jsxs(Slot, { className: cn(CLASS.card, CLASS.link, className), ...rest, children: [
|
|
40
|
+
/* @__PURE__ */ jsx(Slottable, { children }),
|
|
41
|
+
body
|
|
42
|
+
] });
|
|
43
|
+
}
|
|
44
|
+
return /* @__PURE__ */ jsx("article", { className: cn(CLASS.card, className), ...rest, children: body });
|
|
45
|
+
}
|
|
46
|
+
var Metric_default = Metric;
|
|
47
|
+
export {
|
|
48
|
+
Metric,
|
|
49
|
+
Metric_default as default
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=Metric.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Metric/Metric.tsx"],"sourcesContent":["import { Slot, Slottable } from '@radix-ui/react-slot'\nimport type { HTMLAttributes, ReactNode } from 'react'\nimport { StatusDot, type StatusTone } from '../StatusDot/StatusDot'\nimport { cn } from '../../lib/cn'\n\n/**\n * The parts, named. A caller adjusts the tile's placement with `className` and\n * never has to reach for one of these.\n */\nconst CLASS = {\n card: 'flex flex-col gap-1 rounded-(--radius) border border-(--rule) p-3',\n /* The link affordance, and only under `asChild`: a plate that lifts under the\n pointer when nothing happens on a click is a plate that has promised\n something. */\n link: 'no-underline transition-colors duration-(--duration-fast) hover:border-(--rule-2) hover:bg-(--stone)',\n head: 'flex items-start justify-between gap-2',\n label: 'eyebrow text-(--ink-3-aa)',\n /* Mono and tabular: the figures line up between tiles and stay comparable\n down a column, which is the whole reason four of these sit in a row. */\n value: 'font-mono text-[length:var(--fs-item)] leading-none tabular-nums text-(--ink)',\n detail: 'text-xs text-(--ink-2)',\n} as const\n\nexport interface MetricProps extends HTMLAttributes<HTMLElement> {\n /** What the figure counts. */\n label: ReactNode\n /** The figure, already formatted — this does not guess a unit or a locale. */\n value: ReactNode\n /** One line of context. A figure without it is a number, not a reading. */\n detail?: ReactNode\n /**\n * How the reading stands. Drawn as a dot beside the label, and only ever a\n * SECOND carrier: the dot is `aria-hidden`, so whatever the tone means has to\n * be in `detail` as well or it reaches nobody who cannot see it.\n */\n tone?: StatusTone\n /** A sparkline, a denominator, a caveat. Sits under the figure. */\n aside?: ReactNode\n /**\n * Render `children` as the tile instead of the `<article>`, keeping these\n * styles — how a linkable tile gets a router's own `Link` without this\n * package importing one.\n *\n * The slotted element must take no children of its own: the label, the figure\n * and everything under them are injected INTO it, which is the point. A whole\n * tile inside one link also means the link's accessible name is every word in\n * it, read in order — \"Rows, 63,851, newest yesterday\" — so keep `detail`\n * short enough to be heard as part of a link.\n */\n asChild?: boolean\n /** The element the tile becomes under `asChild`. Ignored without it. */\n children?: ReactNode\n className?: string\n}\n\n/**\n * One reading, on a plate: a label, a figure, and what qualifies it.\n *\n * Distinct from `BigNumber`, which is the same idea at headline scale for the\n * ONE figure a view is about, and which needs the charts entry. This is the\n * tile that appears four across on a console: smaller, monospaced rather than\n * editorial, and carrying two things `BigNumber` has nowhere for — a status\n * tone, and a free slot under the number that is not a delta. Those two are the\n * whole reason it exists; a dashboard whose tiles have to be a `<div>` because\n * the delta does not apply is a dashboard with two tile designs in it.\n *\n * The figure is monospace and tabular by construction, because four of these in\n * a row are read down the column as much as along it, and proportional digits\n * put the same magnitude at two different widths.\n *\n * @example\n * <Metric label=\"Rows\" value=\"63,851\" detail=\"newest yesterday\" tone=\"success\" />\n * @example\n * // A tile that is also a link, with the router's own component.\n * <Metric asChild label=\"Jobs\" value=\"12\" detail=\"3 waiting\">\n * <Link href=\"/jobs\" />\n * </Metric>\n */\nexport function Metric({\n label,\n value,\n detail,\n tone,\n aside,\n asChild = false,\n children,\n className,\n ...rest\n}: MetricProps) {\n const body = (\n <>\n <div className={CLASS.head}>\n <span className={CLASS.label}>{label}</span>\n {tone !== undefined && <StatusDot tone={tone} pulse={false} />}\n </div>\n <p className={CLASS.value}>{value}</p>\n {detail !== undefined && <p className={CLASS.detail}>{detail}</p>}\n {aside}\n </>\n )\n\n if (asChild) {\n // `Slottable` rather than a bare `Slot`: a bare one hands the child the\n // PROPS and leaves it holding its own content, and this component's content\n // is the whole tile. Marking the child slottable makes it the element and\n // the siblings its children, which is the only arrangement where a caller\n // writes `<Link href=\"…\" />` and gets a tile rather than an empty box.\n return (\n <Slot className={cn(CLASS.card, CLASS.link, className)} {...rest}>\n <Slottable>{children}</Slottable>\n {body}\n </Slot>\n )\n }\n\n return (\n <article className={cn(CLASS.card, className)} {...rest}>\n {body}\n </article>\n )\n}\n\nexport default Metric\n"],"mappings":"AA0FI,mBAEI,KADF,YADF;AA1FJ,SAAS,MAAM,iBAAiB;AAEhC,SAAS,iBAAkC;AAC3C,SAAS,UAAU;AAMnB,MAAM,QAAQ;AAAA,EACZ,MAAM;AAAA;AAAA;AAAA;AAAA,EAIN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA;AAAA;AAAA,EAGP,OAAO;AAAA,EACP,QAAQ;AACV;AAyDO,SAAS,OAAO;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAgB;AACd,QAAM,OACJ,iCACE;AAAA,yBAAC,SAAI,WAAW,MAAM,MACpB;AAAA,0BAAC,UAAK,WAAW,MAAM,OAAQ,iBAAM;AAAA,MACpC,SAAS,UAAa,oBAAC,aAAU,MAAY,OAAO,OAAO;AAAA,OAC9D;AAAA,IACA,oBAAC,OAAE,WAAW,MAAM,OAAQ,iBAAM;AAAA,IACjC,WAAW,UAAa,oBAAC,OAAE,WAAW,MAAM,QAAS,kBAAO;AAAA,IAC5D;AAAA,KACH;AAGF,MAAI,SAAS;AAMX,WACE,qBAAC,QAAK,WAAW,GAAG,MAAM,MAAM,MAAM,MAAM,SAAS,GAAI,GAAG,MAC1D;AAAA,0BAAC,aAAW,UAAS;AAAA,MACpB;AAAA,OACH;AAAA,EAEJ;AAEA,SACE,oBAAC,aAAQ,WAAW,GAAG,MAAM,MAAM,SAAS,GAAI,GAAG,MAChD,gBACH;AAEJ;AAEA,IAAO,iBAAQ;","names":[]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { SelectHTMLAttributes, Ref } from 'react';
|
|
3
|
+
|
|
4
|
+
interface NativeSelectProps extends SelectHTMLAttributes<HTMLSelectElement> {
|
|
5
|
+
/** Paints the resting border with `--danger` and reflects `aria-invalid`. */
|
|
6
|
+
invalid?: boolean;
|
|
7
|
+
ref?: Ref<HTMLSelectElement>;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* A native `<select>`, restyled.
|
|
11
|
+
*
|
|
12
|
+
* The escape hatch, not the default — `Select` is the styled one. Reach for
|
|
13
|
+
* this where the platform's own picker is genuinely better: a very long list on
|
|
14
|
+
* a phone, a form that must work without JavaScript, a page where the last
|
|
15
|
+
* kilobyte matters. The browser gives typeahead and the mobile wheel for free,
|
|
16
|
+
* and those are real.
|
|
17
|
+
*
|
|
18
|
+
* What it cannot do is look like the rest of the system once open. The option
|
|
19
|
+
* list is drawn by the operating system, so it carries none of these tokens —
|
|
20
|
+
* which is exactly why it stopped being the default.
|
|
21
|
+
*
|
|
22
|
+
* `className` sizes the WRAPPER, not the `<select>` inside it. This is the one
|
|
23
|
+
* control here that renders two elements, and the chevron is pinned to the
|
|
24
|
+
* wrapper's end edge: a width on the select alone narrowed the box and left the
|
|
25
|
+
* arrow floating at the far side of the row. The select fills whatever the
|
|
26
|
+
* wrapper is.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* <NativeSelect defaultValue="au"><option value="au">Australia</option></NativeSelect>
|
|
30
|
+
*/
|
|
31
|
+
declare function NativeSelect({ invalid, className, ref, children, 'aria-invalid': ariaInvalid, ...rest }: NativeSelectProps): react.JSX.Element;
|
|
32
|
+
|
|
33
|
+
export { NativeSelect, type NativeSelectProps, NativeSelect as default };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { RiArrowDownSLine } from "@remixicon/react";
|
|
3
|
+
import { cn } from "../../lib/cn.js";
|
|
4
|
+
import { CONTROL_BASE, CONTROL_BORDER, isInvalid } from "../../lib/control.js";
|
|
5
|
+
function NativeSelect({
|
|
6
|
+
invalid,
|
|
7
|
+
className,
|
|
8
|
+
ref,
|
|
9
|
+
children,
|
|
10
|
+
"aria-invalid": ariaInvalid,
|
|
11
|
+
...rest
|
|
12
|
+
}) {
|
|
13
|
+
const bad = isInvalid(invalid, ariaInvalid);
|
|
14
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
|
|
15
|
+
/* @__PURE__ */ jsx(
|
|
16
|
+
"select",
|
|
17
|
+
{
|
|
18
|
+
ref,
|
|
19
|
+
"aria-invalid": ariaInvalid ?? (invalid ? true : void 0),
|
|
20
|
+
className: cn(
|
|
21
|
+
CONTROL_BASE,
|
|
22
|
+
"cursor-pointer appearance-none pe-9",
|
|
23
|
+
bad ? CONTROL_BORDER.invalid : CONTROL_BORDER.resting
|
|
24
|
+
),
|
|
25
|
+
...rest,
|
|
26
|
+
children
|
|
27
|
+
}
|
|
28
|
+
),
|
|
29
|
+
/* @__PURE__ */ jsx(
|
|
30
|
+
RiArrowDownSLine,
|
|
31
|
+
{
|
|
32
|
+
size: 16,
|
|
33
|
+
className: "pointer-events-none absolute end-3 top-1/2 -translate-y-1/2 text-(--ink-3-aa)",
|
|
34
|
+
"aria-hidden": true
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
] });
|
|
38
|
+
}
|
|
39
|
+
var NativeSelect_default = NativeSelect;
|
|
40
|
+
export {
|
|
41
|
+
NativeSelect,
|
|
42
|
+
NativeSelect_default as default
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=NativeSelect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/NativeSelect/NativeSelect.tsx"],"sourcesContent":["import { RiArrowDownSLine } from '@remixicon/react'\nimport type { Ref, SelectHTMLAttributes } from 'react'\nimport { cn } from '../../lib/cn'\nimport { CONTROL_BASE, CONTROL_BORDER, isInvalid } from '../../lib/control'\n\nexport interface NativeSelectProps extends SelectHTMLAttributes<HTMLSelectElement> {\n /** Paints the resting border with `--danger` and reflects `aria-invalid`. */\n invalid?: boolean\n ref?: Ref<HTMLSelectElement>\n}\n\n/**\n * A native `<select>`, restyled.\n *\n * The escape hatch, not the default — `Select` is the styled one. Reach for\n * this where the platform's own picker is genuinely better: a very long list on\n * a phone, a form that must work without JavaScript, a page where the last\n * kilobyte matters. The browser gives typeahead and the mobile wheel for free,\n * and those are real.\n *\n * What it cannot do is look like the rest of the system once open. The option\n * list is drawn by the operating system, so it carries none of these tokens —\n * which is exactly why it stopped being the default.\n *\n * `className` sizes the WRAPPER, not the `<select>` inside it. This is the one\n * control here that renders two elements, and the chevron is pinned to the\n * wrapper's end edge: a width on the select alone narrowed the box and left the\n * arrow floating at the far side of the row. The select fills whatever the\n * wrapper is.\n *\n * @example\n * <NativeSelect defaultValue=\"au\"><option value=\"au\">Australia</option></NativeSelect>\n */\nexport function NativeSelect({\n invalid,\n className,\n ref,\n children,\n 'aria-invalid': ariaInvalid,\n ...rest\n}: NativeSelectProps) {\n const bad = isInvalid(invalid, ariaInvalid)\n return (\n <div className={cn('relative', className)}>\n <select\n ref={ref}\n aria-invalid={ariaInvalid ?? (invalid ? true : undefined)}\n className={cn(\n CONTROL_BASE,\n 'cursor-pointer appearance-none pe-9',\n bad ? CONTROL_BORDER.invalid : CONTROL_BORDER.resting,\n )}\n {...rest}\n >\n {children}\n </select>\n <RiArrowDownSLine\n size={16}\n className=\"pointer-events-none absolute end-3 top-1/2 -translate-y-1/2 text-(--ink-3-aa)\"\n aria-hidden\n />\n </div>\n )\n}\n\nexport default NativeSelect\n"],"mappings":"AA2CI,SACE,KADF;AA3CJ,SAAS,wBAAwB;AAEjC,SAAS,UAAU;AACnB,SAAS,cAAc,gBAAgB,iBAAiB;AA8BjD,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB,GAAG;AACL,GAAsB;AACpB,QAAM,MAAM,UAAU,SAAS,WAAW;AAC1C,SACE,qBAAC,SAAI,WAAW,GAAG,YAAY,SAAS,GACtC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,gBAAc,gBAAgB,UAAU,OAAO;AAAA,QAC/C,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA,MAAM,eAAe,UAAU,eAAe;AAAA,QAChD;AAAA,QACC,GAAG;AAAA,QAEH;AAAA;AAAA,IACH;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,WAAU;AAAA,QACV,eAAW;AAAA;AAAA,IACb;AAAA,KACF;AAEJ;AAEA,IAAO,uBAAQ;","names":[]}
|