@nanisoft/prism-ui 0.5.0 → 0.6.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/LICENSE +21 -0
- package/README.md +81 -0
- package/THIRD-PARTY-NOTICES.md +48 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/blocks/app-shell-01/app-shell.d.ts +38 -0
- package/dist/blocks/app-shell-01/app-shell.d.ts.map +1 -0
- package/dist/blocks/app-shell-01/app-shell.js +27 -0
- package/dist/blocks/app-shell-01/index.d.ts +3 -0
- package/dist/blocks/app-shell-01/index.d.ts.map +1 -0
- package/dist/blocks/app-shell-01/index.js +1 -0
- package/dist/blocks/auth-form-01/auth-form.d.ts +52 -0
- package/dist/blocks/auth-form-01/auth-form.d.ts.map +1 -0
- package/dist/blocks/auth-form-01/auth-form.js +23 -0
- package/dist/blocks/auth-form-01/index.d.ts +3 -0
- package/dist/blocks/auth-form-01/index.d.ts.map +1 -0
- package/dist/blocks/auth-form-01/index.js +1 -0
- package/dist/blocks/cta-01/cta.d.ts +83 -0
- package/dist/blocks/cta-01/cta.d.ts.map +1 -0
- package/dist/blocks/cta-01/cta.js +29 -0
- package/dist/blocks/cta-01/index.d.ts +3 -0
- package/dist/blocks/cta-01/index.d.ts.map +1 -0
- package/dist/blocks/cta-01/index.js +1 -0
- package/dist/blocks/data-table-01/data-table.d.ts +102 -0
- package/dist/blocks/data-table-01/data-table.d.ts.map +1 -0
- package/dist/blocks/data-table-01/data-table.js +116 -0
- package/dist/blocks/data-table-01/index.d.ts +3 -0
- package/dist/blocks/data-table-01/index.d.ts.map +1 -0
- package/dist/blocks/data-table-01/index.js +1 -0
- package/dist/blocks/feature-grid-01/feature-grid.d.ts +78 -0
- package/dist/blocks/feature-grid-01/feature-grid.d.ts.map +1 -0
- package/dist/blocks/feature-grid-01/feature-grid.js +24 -0
- package/dist/blocks/feature-grid-01/index.d.ts +3 -0
- package/dist/blocks/feature-grid-01/index.d.ts.map +1 -0
- package/dist/blocks/feature-grid-01/index.js +1 -0
- package/dist/blocks/hero-01/hero.d.ts +59 -0
- package/dist/blocks/hero-01/hero.d.ts.map +1 -0
- package/dist/blocks/hero-01/hero.js +24 -0
- package/dist/blocks/hero-01/index.d.ts +2 -0
- package/dist/blocks/hero-01/index.d.ts.map +1 -0
- package/dist/blocks/hero-01/index.js +1 -0
- package/dist/blocks/index.d.ts +28 -0
- package/dist/blocks/index.d.ts.map +1 -0
- package/dist/blocks/index.js +26 -0
- package/dist/blocks/instrument-panel-01/index.d.ts +3 -0
- package/dist/blocks/instrument-panel-01/index.d.ts.map +1 -0
- package/dist/blocks/instrument-panel-01/index.js +1 -0
- package/dist/blocks/instrument-panel-01/instrument-panel.d.ts +114 -0
- package/dist/blocks/instrument-panel-01/instrument-panel.d.ts.map +1 -0
- package/dist/blocks/instrument-panel-01/instrument-panel.js +64 -0
- package/dist/blocks/logo-strip-01/index.d.ts +3 -0
- package/dist/blocks/logo-strip-01/index.d.ts.map +1 -0
- package/dist/blocks/logo-strip-01/index.js +1 -0
- package/dist/blocks/logo-strip-01/logo-strip.d.ts +84 -0
- package/dist/blocks/logo-strip-01/logo-strip.d.ts.map +1 -0
- package/dist/blocks/logo-strip-01/logo-strip.js +40 -0
- package/dist/blocks/note-grid-01/index.d.ts +3 -0
- package/dist/blocks/note-grid-01/index.d.ts.map +1 -0
- package/dist/blocks/note-grid-01/index.js +1 -0
- package/dist/blocks/note-grid-01/note-grid.d.ts +79 -0
- package/dist/blocks/note-grid-01/note-grid.d.ts.map +1 -0
- package/dist/blocks/note-grid-01/note-grid.js +37 -0
- package/dist/blocks/page-header-01/index.d.ts +3 -0
- package/dist/blocks/page-header-01/index.d.ts.map +1 -0
- package/dist/blocks/page-header-01/index.js +1 -0
- package/dist/blocks/page-header-01/page-header.d.ts +48 -0
- package/dist/blocks/page-header-01/page-header.d.ts.map +1 -0
- package/dist/blocks/page-header-01/page-header.js +27 -0
- package/dist/blocks/pricing-01/index.d.ts +2 -0
- package/dist/blocks/pricing-01/index.d.ts.map +1 -0
- package/dist/blocks/pricing-01/index.js +1 -0
- package/dist/blocks/pricing-01/pricing.d.ts +35 -0
- package/dist/blocks/pricing-01/pricing.d.ts.map +1 -0
- package/dist/blocks/pricing-01/pricing.js +20 -0
- package/dist/blocks/process-rail-01/index.d.ts +3 -0
- package/dist/blocks/process-rail-01/index.d.ts.map +1 -0
- package/dist/blocks/process-rail-01/index.js +1 -0
- package/dist/blocks/process-rail-01/process-rail.d.ts +99 -0
- package/dist/blocks/process-rail-01/process-rail.d.ts.map +1 -0
- package/dist/blocks/process-rail-01/process-rail.js +58 -0
- package/dist/blocks/product-grid-01/index.d.ts +3 -0
- package/dist/blocks/product-grid-01/index.d.ts.map +1 -0
- package/dist/blocks/product-grid-01/index.js +1 -0
- package/dist/blocks/product-grid-01/product-grid.d.ts +114 -0
- package/dist/blocks/product-grid-01/product-grid.d.ts.map +1 -0
- package/dist/blocks/product-grid-01/product-grid.js +51 -0
- package/dist/blocks/settings-panel-01/index.d.ts +3 -0
- package/dist/blocks/settings-panel-01/index.d.ts.map +1 -0
- package/dist/blocks/settings-panel-01/index.js +1 -0
- package/dist/blocks/settings-panel-01/settings-panel.d.ts +71 -0
- package/dist/blocks/settings-panel-01/settings-panel.d.ts.map +1 -0
- package/dist/blocks/settings-panel-01/settings-panel.js +38 -0
- package/dist/blocks/site-footer/index.d.ts +3 -0
- package/dist/blocks/site-footer/index.d.ts.map +1 -0
- package/dist/blocks/site-footer/index.js +1 -0
- package/dist/blocks/site-footer/site-footer.d.ts +135 -0
- package/dist/blocks/site-footer/site-footer.d.ts.map +1 -0
- package/dist/blocks/site-footer/site-footer.js +41 -0
- package/dist/blocks/site-header/index.d.ts +3 -0
- package/dist/blocks/site-header/index.d.ts.map +1 -0
- package/dist/blocks/site-header/index.js +1 -0
- package/dist/blocks/site-header/site-header.d.ts +142 -0
- package/dist/blocks/site-header/site-header.d.ts.map +1 -0
- package/dist/blocks/site-header/site-header.js +46 -0
- package/dist/blocks/stack-grid-01/index.d.ts +3 -0
- package/dist/blocks/stack-grid-01/index.d.ts.map +1 -0
- package/dist/blocks/stack-grid-01/index.js +1 -0
- package/dist/blocks/stack-grid-01/stack-grid.d.ts +118 -0
- package/dist/blocks/stack-grid-01/stack-grid.d.ts.map +1 -0
- package/dist/blocks/stack-grid-01/stack-grid.js +49 -0
- package/dist/blocks/stats-01/index.d.ts +2 -0
- package/dist/blocks/stats-01/index.d.ts.map +1 -0
- package/dist/blocks/stats-01/index.js +1 -0
- package/dist/blocks/stats-01/stats.d.ts +28 -0
- package/dist/blocks/stats-01/stats.d.ts.map +1 -0
- package/dist/blocks/stats-01/stats.js +27 -0
- package/dist/blocks/status-ledger-01/index.d.ts +3 -0
- package/dist/blocks/status-ledger-01/index.d.ts.map +1 -0
- package/dist/blocks/status-ledger-01/index.js +1 -0
- package/dist/blocks/status-ledger-01/status-ledger.d.ts +131 -0
- package/dist/blocks/status-ledger-01/status-ledger.d.ts.map +1 -0
- package/dist/blocks/status-ledger-01/status-ledger.js +80 -0
- package/dist/catalog.d.ts +28 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +672 -0
- package/dist/components/index.d.ts +64 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +43 -0
- package/dist/components/ui/accordion.d.ts +65 -0
- package/dist/components/ui/accordion.d.ts.map +1 -0
- package/dist/components/ui/accordion.js +30 -0
- package/dist/components/ui/alert.d.ts +19 -0
- package/dist/components/ui/alert.d.ts.map +1 -0
- package/dist/components/ui/alert.js +31 -0
- package/dist/components/ui/avatar.d.ts +47 -0
- package/dist/components/ui/avatar.d.ts.map +1 -0
- package/dist/components/ui/avatar.js +30 -0
- package/dist/components/ui/badge.d.ts +14 -0
- package/dist/components/ui/badge.d.ts.map +1 -0
- package/dist/components/ui/badge.js +26 -0
- package/dist/components/ui/breadcrumb.d.ts +35 -0
- package/dist/components/ui/breadcrumb.d.ts.map +1 -0
- package/dist/components/ui/breadcrumb.js +48 -0
- package/dist/components/ui/button.d.ts +16 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/button.js +63 -0
- package/dist/components/ui/card.d.ts +41 -0
- package/dist/components/ui/card.d.ts.map +1 -0
- package/dist/components/ui/card.js +53 -0
- package/dist/components/ui/checkbox.d.ts +43 -0
- package/dist/components/ui/checkbox.d.ts.map +1 -0
- package/dist/components/ui/checkbox.js +18 -0
- package/dist/components/ui/cta-link.d.ts +45 -0
- package/dist/components/ui/cta-link.d.ts.map +1 -0
- package/dist/components/ui/cta-link.js +81 -0
- package/dist/components/ui/diagram.d.ts +154 -0
- package/dist/components/ui/diagram.d.ts.map +1 -0
- package/dist/components/ui/diagram.js +150 -0
- package/dist/components/ui/dialog.d.ts +81 -0
- package/dist/components/ui/dialog.d.ts.map +1 -0
- package/dist/components/ui/dialog.js +60 -0
- package/dist/components/ui/dropdown-menu.d.ts +189 -0
- package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
- package/dist/components/ui/dropdown-menu.js +67 -0
- package/dist/components/ui/fact-list.d.ts +90 -0
- package/dist/components/ui/fact-list.d.ts.map +1 -0
- package/dist/components/ui/fact-list.js +38 -0
- package/dist/components/ui/field.d.ts +36 -0
- package/dist/components/ui/field.d.ts.map +1 -0
- package/dist/components/ui/field.js +46 -0
- package/dist/components/ui/input.d.ts +12 -0
- package/dist/components/ui/input.d.ts.map +1 -0
- package/dist/components/ui/input.js +14 -0
- package/dist/components/ui/kbd.d.ts +10 -0
- package/dist/components/ui/kbd.d.ts.map +1 -0
- package/dist/components/ui/kbd.js +12 -0
- package/dist/components/ui/pagination.d.ts +40 -0
- package/dist/components/ui/pagination.d.ts.map +1 -0
- package/dist/components/ui/pagination.js +49 -0
- package/dist/components/ui/popover.d.ts +56 -0
- package/dist/components/ui/popover.d.ts.map +1 -0
- package/dist/components/ui/popover.js +25 -0
- package/dist/components/ui/product-mark.d.ts +115 -0
- package/dist/components/ui/product-mark.d.ts.map +1 -0
- package/dist/components/ui/product-mark.js +82 -0
- package/dist/components/ui/product-switcher.d.ts +108 -0
- package/dist/components/ui/product-switcher.d.ts.map +1 -0
- package/dist/components/ui/product-switcher.js +47 -0
- package/dist/components/ui/progress.d.ts +38 -0
- package/dist/components/ui/progress.d.ts.map +1 -0
- package/dist/components/ui/progress.js +17 -0
- package/dist/components/ui/prose.d.ts +88 -0
- package/dist/components/ui/prose.d.ts.map +1 -0
- package/dist/components/ui/prose.js +53 -0
- package/dist/components/ui/radio-group.d.ts +66 -0
- package/dist/components/ui/radio-group.d.ts.map +1 -0
- package/dist/components/ui/radio-group.js +30 -0
- package/dist/components/ui/section.d.ts +60 -0
- package/dist/components/ui/section.d.ts.map +1 -0
- package/dist/components/ui/section.js +21 -0
- package/dist/components/ui/select.d.ts +124 -0
- package/dist/components/ui/select.d.ts.map +1 -0
- package/dist/components/ui/select.js +47 -0
- package/dist/components/ui/separator.d.ts +16 -0
- package/dist/components/ui/separator.d.ts.map +1 -0
- package/dist/components/ui/separator.js +15 -0
- package/dist/components/ui/skeleton.d.ts +12 -0
- package/dist/components/ui/skeleton.d.ts.map +1 -0
- package/dist/components/ui/skeleton.js +14 -0
- package/dist/components/ui/slider.d.ts +43 -0
- package/dist/components/ui/slider.d.ts.map +1 -0
- package/dist/components/ui/slider.js +23 -0
- package/dist/components/ui/switch.d.ts +42 -0
- package/dist/components/ui/switch.d.ts.map +1 -0
- package/dist/components/ui/switch.js +16 -0
- package/dist/components/ui/table.d.ts +27 -0
- package/dist/components/ui/table.d.ts.map +1 -0
- package/dist/components/ui/table.js +43 -0
- package/dist/components/ui/tabs.d.ts +66 -0
- package/dist/components/ui/tabs.d.ts.map +1 -0
- package/dist/components/ui/tabs.js +29 -0
- package/dist/components/ui/textarea.d.ts +11 -0
- package/dist/components/ui/textarea.d.ts.map +1 -0
- package/dist/components/ui/textarea.js +13 -0
- package/dist/components/ui/tooltip.d.ts +63 -0
- package/dist/components/ui/tooltip.d.ts.map +1 -0
- package/dist/components/ui/tooltip.js +25 -0
- package/dist/components/ui/typography.d.ts +32 -0
- package/dist/components/ui/typography.d.ts.map +1 -0
- package/dist/components/ui/typography.js +51 -0
- package/dist/index.d.ts +79 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +68 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +5 -0
- package/dist/pages/auth-page/index.d.ts +36 -0
- package/dist/pages/auth-page/index.d.ts.map +1 -0
- package/dist/pages/auth-page/index.js +23 -0
- package/dist/pages/blog-post-page/index.d.ts +174 -0
- package/dist/pages/blog-post-page/index.d.ts.map +1 -0
- package/dist/pages/blog-post-page/index.js +49 -0
- package/dist/pages/dashboard-page/index.d.ts +36 -0
- package/dist/pages/dashboard-page/index.d.ts.map +1 -0
- package/dist/pages/dashboard-page/index.js +24 -0
- package/dist/pages/index.d.ts +21 -0
- package/dist/pages/index.d.ts.map +1 -0
- package/dist/pages/index.js +14 -0
- package/dist/pages/marketing-page/index.d.ts +43 -0
- package/dist/pages/marketing-page/index.d.ts.map +1 -0
- package/dist/pages/marketing-page/index.js +25 -0
- package/dist/pages/not-found-page/index.d.ts +112 -0
- package/dist/pages/not-found-page/index.d.ts.map +1 -0
- package/dist/pages/not-found-page/index.js +46 -0
- package/dist/pages/settings-page/index.d.ts +47 -0
- package/dist/pages/settings-page/index.d.ts.map +1 -0
- package/dist/pages/settings-page/index.js +24 -0
- package/dist/provider/index.d.ts +12 -0
- package/dist/provider/index.d.ts.map +1 -0
- package/dist/provider/index.js +9 -0
- package/dist/provider/provider.d.ts +42 -0
- package/dist/provider/provider.d.ts.map +1 -0
- package/dist/provider/provider.js +178 -0
- package/dist/provider/theme-script.d.ts +55 -0
- package/dist/provider/theme-script.d.ts.map +1 -0
- package/dist/provider/theme-script.js +79 -0
- package/dist/styles.css +2894 -0
- package/dist/theming/index.d.ts +173 -0
- package/dist/theming/index.d.ts.map +1 -0
- package/dist/theming/index.js +186 -0
- package/package.json +89 -18
- package/components.json +0 -21
- package/public/r/badge.json +0 -26
- package/public/r/button.json +0 -26
- package/public/r/card.json +0 -25
- package/public/r/cta-01.json +0 -44
- package/public/r/feature-grid-01.json +0 -44
- package/public/r/hero-01.json +0 -44
- package/public/r/pricing-01.json +0 -46
- package/public/r/registry.json +0 -294
- package/public/r/section.json +0 -25
- package/public/r/stats-01.json +0 -44
- package/registry.json +0 -294
- package/src/components/ds/blocks/cta-01/block.json +0 -8
- package/src/components/ds/blocks/cta-01/cta.tsx +0 -62
- package/src/components/ds/blocks/cta-01/index.tsx +0 -1
- package/src/components/ds/blocks/feature-grid-01/block.json +0 -8
- package/src/components/ds/blocks/feature-grid-01/feature-grid.tsx +0 -69
- package/src/components/ds/blocks/feature-grid-01/index.tsx +0 -1
- package/src/components/ds/blocks/hero-01/block.json +0 -8
- package/src/components/ds/blocks/hero-01/hero.tsx +0 -85
- package/src/components/ds/blocks/hero-01/index.tsx +0 -1
- package/src/components/ds/blocks/pricing-01/block.json +0 -8
- package/src/components/ds/blocks/pricing-01/index.tsx +0 -1
- package/src/components/ds/blocks/pricing-01/pricing.tsx +0 -122
- package/src/components/ds/blocks/section.meta.json +0 -6
- package/src/components/ds/blocks/section.tsx +0 -86
- package/src/components/ds/blocks/stats-01/block.json +0 -8
- package/src/components/ds/blocks/stats-01/index.tsx +0 -1
- package/src/components/ds/blocks/stats-01/stats.tsx +0 -92
- package/src/components/ui/badge.tsx +0 -37
- package/src/components/ui/button.tsx +0 -77
- package/src/components/ui/card.tsx +0 -65
- package/src/lib/utils.ts +0 -6
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../../src/components/ui/card.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAI3C;;;;;;GAMG;AACH,iBAAS,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,CAAC,KAAK,CAAC,+BAW3D;AAED;;;;;;GAMG;AACH,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,CAAC,KAAK,CAAC,+BAWjE;AAED;;;;;;;;GAQG;AACH,iBAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,CAAC,KAAK,CAAC,+BAQhE;AAED;;;GAGG;AACH,iBAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,CAAC,KAAK,CAAC,+BAQtE;AAED,wEAAwE;AACxE,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,CAAC,KAAK,CAAC,+BAElE;AAED;;;GAGG;AACH,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,CAAC,KAAK,CAAC,+BAQjE;AAED,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,CAAA"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from '../../lib/utils';
|
|
3
|
+
/**
|
|
4
|
+
* A bordered surface for a small group of related content.
|
|
5
|
+
*
|
|
6
|
+
* Compose it from `CardHeader`, `CardTitle`, `CardDescription`, `CardContent`
|
|
7
|
+
* and `CardFooter`. Those parts ship from this module rather than as separate
|
|
8
|
+
* subpaths.
|
|
9
|
+
*/
|
|
10
|
+
function Card({ className, ...props }) {
|
|
11
|
+
return (_jsx("div", { "data-slot": "card", className: cn('bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm', className), ...props }));
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The head of a card: the row above the card's content.
|
|
15
|
+
*
|
|
16
|
+
* A part rather than an Item, and it stays inside this module: `CardHeader` is not
|
|
17
|
+
* a second catalogue entry, and DESIGN.md's authoring contract says compound parts
|
|
18
|
+
* ship from their parent module and do not form a second vocabulary.
|
|
19
|
+
*/
|
|
20
|
+
function CardHeader({ className, ...props }) {
|
|
21
|
+
return (_jsx("div", { "data-slot": "card-header", className: cn('@container/card-header grid auto-rows-min items-start gap-1.5 px-6', className), ...props }));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The card's title: the one line that names the group of related content.
|
|
25
|
+
*
|
|
26
|
+
* Renders a `div` rather than a heading, because a card's title is not always the
|
|
27
|
+
* heading of the region it sits in: four cards in a grid are four titles under one
|
|
28
|
+
* section heading, and four `h3`s under one `h2` is right while four `h2`s is
|
|
29
|
+
* four sections. Pass Prism's `Heading` inside it when the card is the only thing
|
|
30
|
+
* in its region and the outline should say so.
|
|
31
|
+
*/
|
|
32
|
+
function CardTitle({ className, ...props }) {
|
|
33
|
+
return (_jsx("div", { "data-slot": "card-title", className: cn('font-semibold leading-none', className), ...props }));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The supporting line under a card's title: one sentence about what the card
|
|
37
|
+
* holds.
|
|
38
|
+
*/
|
|
39
|
+
function CardDescription({ className, ...props }) {
|
|
40
|
+
return (_jsx("div", { "data-slot": "card-description", className: cn('text-muted-foreground text-sm', className), ...props }));
|
|
41
|
+
}
|
|
42
|
+
/** The card's body: the content the title and description introduce. */
|
|
43
|
+
function CardContent({ className, ...props }) {
|
|
44
|
+
return _jsx("div", { "data-slot": "card-content", className: cn('px-6', className), ...props });
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The foot of a card: the actions that belong to the card rather than to the
|
|
48
|
+
* page.
|
|
49
|
+
*/
|
|
50
|
+
function CardFooter({ className, ...props }) {
|
|
51
|
+
return (_jsx("div", { "data-slot": "card-footer", className: cn('flex items-center px-6', className), ...props }));
|
|
52
|
+
}
|
|
53
|
+
export { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The props the Checkbox forwards to its Base UI root.
|
|
4
|
+
*
|
|
5
|
+
* Declared here rather than re-exported from Base UI so no upstream type
|
|
6
|
+
* crosses the package seam (ticket 07 section 6).
|
|
7
|
+
*/
|
|
8
|
+
export interface CheckboxProps extends Omit<ComponentProps<'span'>, 'onChange'> {
|
|
9
|
+
/** The control's accessible name when no visible label is used. */
|
|
10
|
+
'aria-label'?: string;
|
|
11
|
+
/** The controlled ticked state. */
|
|
12
|
+
checked?: boolean;
|
|
13
|
+
/** The initially ticked state, for an uncontrolled checkbox. */
|
|
14
|
+
defaultChecked?: boolean;
|
|
15
|
+
/** Whether the checkbox shows a mixed state: neither ticked nor unticked. */
|
|
16
|
+
indeterminate?: boolean;
|
|
17
|
+
/** Whether the control ignores user interaction. */
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
/** Whether the value must be ticked before the form submits. */
|
|
20
|
+
readOnly?: boolean;
|
|
21
|
+
/** Whether the value must be ticked before the form submits. */
|
|
22
|
+
required?: boolean;
|
|
23
|
+
/** The form field name submitted with the form. */
|
|
24
|
+
name?: string;
|
|
25
|
+
/** The value submitted when the checkbox is ticked. */
|
|
26
|
+
value?: string;
|
|
27
|
+
/** Identifies the form that owns the hidden input. */
|
|
28
|
+
form?: string;
|
|
29
|
+
/** Called when the ticked state changes. */
|
|
30
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A ticked or unticked choice, with an optional mixed state.
|
|
34
|
+
*
|
|
35
|
+
* The Checkbox renders as a span with a hidden native input beside it, so it
|
|
36
|
+
* submits and validates like a checkbox while accepting Prism's styling. Space
|
|
37
|
+
* toggles the focused control, and the indeterminate state is announced as
|
|
38
|
+
* `mixed` to assistive technology. Pair it with a `FieldLabel` in a `Field`,
|
|
39
|
+
* and mark it invalid with `aria-invalid` when the value is rejected.
|
|
40
|
+
*/
|
|
41
|
+
declare function Checkbox({ className, indeterminate, ...props }: CheckboxProps): import("react").JSX.Element;
|
|
42
|
+
export { Checkbox };
|
|
43
|
+
//# sourceMappingURL=checkbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkbox.d.ts","sourceRoot":"","sources":["../../../src/components/ui/checkbox.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAI3C;;;;;GAKG;AACH,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IAC7E,mEAAmE;IACnE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,mCAAmC;IACnC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gEAAgE;IAChE,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,mDAAmD;IACnD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,4CAA4C;IAC5C,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;CAC7C;AAED;;;;;;;;GAQG;AACH,iBAAS,QAAQ,CAAC,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,KAAK,EAAE,EAAE,aAAa,+BA4BtE;AAED,OAAO,EAAE,QAAQ,EAAE,CAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { Checkbox as CheckboxPrimitive } from '@base-ui/react/checkbox';
|
|
4
|
+
import { CheckIcon, MinusIcon } from 'lucide-react';
|
|
5
|
+
import { cn } from '../../lib/utils';
|
|
6
|
+
/**
|
|
7
|
+
* A ticked or unticked choice, with an optional mixed state.
|
|
8
|
+
*
|
|
9
|
+
* The Checkbox renders as a span with a hidden native input beside it, so it
|
|
10
|
+
* submits and validates like a checkbox while accepting Prism's styling. Space
|
|
11
|
+
* toggles the focused control, and the indeterminate state is announced as
|
|
12
|
+
* `mixed` to assistive technology. Pair it with a `FieldLabel` in a `Field`,
|
|
13
|
+
* and mark it invalid with `aria-invalid` when the value is rejected.
|
|
14
|
+
*/
|
|
15
|
+
function Checkbox({ className, indeterminate, ...props }) {
|
|
16
|
+
return (_jsx(CheckboxPrimitive.Root, { "data-slot": "checkbox", indeterminate: indeterminate, className: cn('border-input bg-background text-primary-foreground shadow-xs peer size-4 shrink-0 rounded-sm border outline-none', 'transition-[color,box-shadow,background-color] duration-fast ease-out', 'data-[checked]:border-primary data-[checked]:bg-primary data-[indeterminate]:border-primary data-[indeterminate]:bg-primary', 'focus-visible:border-ring focus-visible:ring-ring focus-visible:ring-[3px]', 'aria-invalid:border-destructive aria-invalid:ring-destructive/20', 'disabled:cursor-not-allowed disabled:opacity-50', className), ...props, children: _jsx(CheckboxPrimitive.Indicator, { "data-slot": "checkbox-indicator", className: "flex items-center justify-center text-current", children: indeterminate ? (_jsx(MinusIcon, { className: "size-3.5" })) : (_jsx(CheckIcon, { className: "size-3.5" })) }) }));
|
|
17
|
+
}
|
|
18
|
+
export { Checkbox };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type VariantProps } from 'class-variance-authority';
|
|
2
|
+
import type { ComponentProps } from 'react';
|
|
3
|
+
declare const ctaLinkVariants: (props?: ({
|
|
4
|
+
variant?: "default" | "outline" | "secondary" | "ghost" | null | undefined;
|
|
5
|
+
size?: "default" | "sm" | "lg" | null | undefined;
|
|
6
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
|
+
export type CtaLinkProps = Omit<ComponentProps<'a'>, 'href' | 'target'> & VariantProps<typeof ctaLinkVariants> & {
|
|
8
|
+
/**
|
|
9
|
+
* The destination. Required, because an anchor without one is not a link: a
|
|
10
|
+
* screen reader announces no destination, the middle-click and open-in-new-tab
|
|
11
|
+
* affordances go quiet, and the control is a button that cannot act.
|
|
12
|
+
*/
|
|
13
|
+
href: string;
|
|
14
|
+
/**
|
|
15
|
+
* Opens the destination in a new browsing context. This is the only way to
|
|
16
|
+
* ask for one: `target` is not accepted, so the safe relationship below
|
|
17
|
+
* cannot be opted out of by accident.
|
|
18
|
+
*
|
|
19
|
+
* Prism does not decide what counts as external. A destination on another
|
|
20
|
+
* origin is not automatically a new tab, and a destination on this origin is
|
|
21
|
+
* not automatically the same tab, so the caller declares it.
|
|
22
|
+
*/
|
|
23
|
+
newTab?: boolean;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* The call to action that goes somewhere.
|
|
27
|
+
*
|
|
28
|
+
* Renders a native `<a>`, so assistive technology announces a link and the
|
|
29
|
+
* browser's own link affordances all work: a status bar showing the destination,
|
|
30
|
+
* a context menu to copy it, middle-click to open a new tab. `Button` cannot
|
|
31
|
+
* offer any of that, and a call to action that is a button is announced as a
|
|
32
|
+
* command that does nothing.
|
|
33
|
+
*
|
|
34
|
+
* It is a Component in its own right rather than a mode of `Button`, which is the
|
|
35
|
+
* answer `BreadcrumbLink` and `PaginationLink` already give twice in this
|
|
36
|
+
* package. The two carry the same visual weight as the button they replace, so
|
|
37
|
+
* the only difference on screen is that this one has a destination.
|
|
38
|
+
*
|
|
39
|
+
* When `newTab` is set, `rel` defaults to `noopener noreferrer`, so the opened
|
|
40
|
+
* document cannot reach back through `window.opener` or read the referrer. A
|
|
41
|
+
* consumer that needs a different relationship passes `rel` and it wins.
|
|
42
|
+
*/
|
|
43
|
+
declare function CtaLink({ className, variant, size, href, newTab, rel, ...props }: CtaLinkProps): import("react").JSX.Element;
|
|
44
|
+
export { CtaLink };
|
|
45
|
+
//# sourceMappingURL=cta-link.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cta-link.d.ts","sourceRoot":"","sources":["../../../src/components/ui/cta-link.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AA0B3C,QAAA,MAAM,eAAe;;;8EAsCpB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC,GACrE,YAAY,CAAC,OAAO,eAAe,CAAC,GAAG;IACrC;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAA;AAEH;;;;;;;;;;;;;;;;;GAiBG;AACH,iBAAS,OAAO,CAAC,EACf,SAAS,EACT,OAAO,EACP,IAAI,EACJ,IAAI,EACJ,MAAc,EACd,GAAG,EACH,GAAG,KAAK,EACT,EAAE,YAAY,+BAWd;AAED,OAAO,EAAE,OAAO,EAAE,CAAA"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cva } from 'class-variance-authority';
|
|
3
|
+
import { cn } from '../../lib/utils';
|
|
4
|
+
/*
|
|
5
|
+
* Why this is a second Component rather than an `as` or `href` prop on `Button`.
|
|
6
|
+
* The design system has already answered this twice, in the two places a trail
|
|
7
|
+
* of links and a list of page links each needed both a non-link slot and a link
|
|
8
|
+
* slot: `BreadcrumbItem` renders an `<li>` and `BreadcrumbLink` renders an
|
|
9
|
+
* `<a>` (`src/components/ui/breadcrumb.tsx`), and `PaginationItem` renders an
|
|
10
|
+
* `<li>` and `PaginationLink` renders an `<a>`
|
|
11
|
+
* (`src/components/ui/pagination.tsx`). Both wrote a second export rather than
|
|
12
|
+
* widening one element into a prop, and both are the shape this Component takes.
|
|
13
|
+
* A polymorphic `as` would make the rendered element a runtime value that only
|
|
14
|
+
* the reader of the call site knows, which is exactly the disagreement between a
|
|
15
|
+
* type and a screen this ticket closes. It also costs nothing: both halves of
|
|
16
|
+
* that pair are server components, so the swap adds no client JavaScript.
|
|
17
|
+
*
|
|
18
|
+
* The recipe is written here rather than imported from `button.tsx`, because
|
|
19
|
+
* `buttonVariants` is module-internal and DESIGN.md keeps a raw variant map off
|
|
20
|
+
* the export surface: "There is no variant recipe on the surface." The base
|
|
21
|
+
* string and every shared variant below are therefore kept deliberately
|
|
22
|
+
* identical to `buttonVariants`, so swapping `Button` for `CtaLink` changes the
|
|
23
|
+
* element and the destination and nothing else on screen. If one recipe moves,
|
|
24
|
+
* the other moves with it.
|
|
25
|
+
*/
|
|
26
|
+
const ctaLinkVariants = cva(
|
|
27
|
+
// The focus ring is `ring-ring` at full strength, for the reason
|
|
28
|
+
// `button.tsx` states at length: half alpha composites to between 1.14:1 and
|
|
29
|
+
// 2.74:1 against every surface in all six themes and clears 3:1 in none of
|
|
30
|
+
// them, which fails WCAG 1.4.11 on the one indicator a keyboard user has.
|
|
31
|
+
//
|
|
32
|
+
// Two utilities are dropped from the button base, and each is dropped for a
|
|
33
|
+
// reason rather than by omission. `aria-invalid:*` is a form-control state and
|
|
34
|
+
// an anchor has no invalid state. `disabled:*` is likewise a button state: an
|
|
35
|
+
// anchor with a destination always navigates, and a control that should not
|
|
36
|
+
// navigate is not a call to action.
|
|
37
|
+
"inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium outline-none transition-[color,box-shadow,background-color] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring focus-visible:ring-[3px]", {
|
|
38
|
+
variants: {
|
|
39
|
+
variant: {
|
|
40
|
+
default: 'bg-primary text-primary-foreground shadow-xs hover:bg-primary/90',
|
|
41
|
+
outline: 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground',
|
|
42
|
+
secondary: 'bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80',
|
|
43
|
+
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
|
44
|
+
},
|
|
45
|
+
// The desktop metrics and the coarse-pointer 44px step are `Button`'s, for
|
|
46
|
+
// the reason `button.tsx` states: the target grows with the input method
|
|
47
|
+
// and not with the viewport, so a phone-sized metric never ships to a
|
|
48
|
+
// mouse. An `icon` size is absent because a call to action carries a label.
|
|
49
|
+
size: {
|
|
50
|
+
default: 'h-9 px-4 py-2 has-[>svg]:px-3 pointer-coarse:h-11 pointer-coarse:min-w-11 pointer-coarse:px-5 pointer-coarse:has-[>svg]:px-4',
|
|
51
|
+
sm: 'h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5 pointer-coarse:h-11 pointer-coarse:min-w-11',
|
|
52
|
+
lg: 'h-10 rounded-md px-6 has-[>svg]:px-4 pointer-coarse:h-11',
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
defaultVariants: {
|
|
56
|
+
variant: 'default',
|
|
57
|
+
size: 'default',
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
/**
|
|
61
|
+
* The call to action that goes somewhere.
|
|
62
|
+
*
|
|
63
|
+
* Renders a native `<a>`, so assistive technology announces a link and the
|
|
64
|
+
* browser's own link affordances all work: a status bar showing the destination,
|
|
65
|
+
* a context menu to copy it, middle-click to open a new tab. `Button` cannot
|
|
66
|
+
* offer any of that, and a call to action that is a button is announced as a
|
|
67
|
+
* command that does nothing.
|
|
68
|
+
*
|
|
69
|
+
* It is a Component in its own right rather than a mode of `Button`, which is the
|
|
70
|
+
* answer `BreadcrumbLink` and `PaginationLink` already give twice in this
|
|
71
|
+
* package. The two carry the same visual weight as the button they replace, so
|
|
72
|
+
* the only difference on screen is that this one has a destination.
|
|
73
|
+
*
|
|
74
|
+
* When `newTab` is set, `rel` defaults to `noopener noreferrer`, so the opened
|
|
75
|
+
* document cannot reach back through `window.opener` or read the referrer. A
|
|
76
|
+
* consumer that needs a different relationship passes `rel` and it wins.
|
|
77
|
+
*/
|
|
78
|
+
function CtaLink({ className, variant, size, href, newTab = false, rel, ...props }) {
|
|
79
|
+
return (_jsx("a", { "data-slot": "cta-link", href: href, rel: rel ?? (newTab ? 'noopener noreferrer' : undefined), target: newTab ? '_blank' : undefined, className: cn(ctaLinkVariants({ variant, size, className })), ...props }));
|
|
80
|
+
}
|
|
81
|
+
export { CtaLink };
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One named thing in a Diagram, at a position the caller chooses.
|
|
3
|
+
*
|
|
4
|
+
* `x` and `y` are in the caller's own coordinate space and are normalised into
|
|
5
|
+
* the Diagram's canvas, so fractions, pixels or any other monotonic scale all
|
|
6
|
+
* draw the same shape. Two nodes given the same position collapse onto one
|
|
7
|
+
* another, so a caller that means a column spreads it rather than repeating a
|
|
8
|
+
* number.
|
|
9
|
+
*
|
|
10
|
+
* `emphasis` marks the one node the drawing is about, and it is the only
|
|
11
|
+
* difference a node may carry: the emphasised node takes the brand ink, which
|
|
12
|
+
* DESIGN.md's Brand Ink Rule names as the colour for something that must read
|
|
13
|
+
* as the brand rather than as body text. Two emphasised nodes are a caller's
|
|
14
|
+
* mistake, not a second emphasis level.
|
|
15
|
+
*/
|
|
16
|
+
export type DiagramNode = {
|
|
17
|
+
/**
|
|
18
|
+
* A key unique within the diagram. Relations name a node by this, and it is
|
|
19
|
+
* carried on the markup as `data-node` so a test can address one node rather
|
|
20
|
+
* than the first one.
|
|
21
|
+
*/
|
|
22
|
+
id: string;
|
|
23
|
+
/**
|
|
24
|
+
* The name printed under the node. It is a label on a picture, so a screen
|
|
25
|
+
* reader does not read it: see `DiagramProps` for what carries the meaning.
|
|
26
|
+
*/
|
|
27
|
+
name: string;
|
|
28
|
+
/** The node's position along the horizontal axis, in the caller's space. */
|
|
29
|
+
x: number;
|
|
30
|
+
/** The node's position along the vertical axis, in the caller's space. */
|
|
31
|
+
y: number;
|
|
32
|
+
/** Marks the node the diagram is about. See the Brand Ink Rule. */
|
|
33
|
+
emphasis?: boolean;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* One relation between two nodes, with the word that says what it is.
|
|
37
|
+
*
|
|
38
|
+
* A relation is drawn as a straight line between the two node marks, so the
|
|
39
|
+
* geometry a caller lays out is the geometry a reader sees. The label is placed
|
|
40
|
+
* beside the line rather than on it, because a label drawn over a line has to
|
|
41
|
+
* be knocked out with a halo, and a halo has to be filled with the colour of
|
|
42
|
+
* the surface the diagram happens to sit on, which the component is not told.
|
|
43
|
+
*
|
|
44
|
+
* `indirect` draws the line dashed. That is the standing convention for "this
|
|
45
|
+
* holds, but not by this route", and it is chosen over fading the line because
|
|
46
|
+
* a dashed line keeps its contrast while a faded one does not.
|
|
47
|
+
*/
|
|
48
|
+
export type DiagramRelation = {
|
|
49
|
+
/** The `id` of the node the relation leaves. */
|
|
50
|
+
from: string;
|
|
51
|
+
/** The `id` of the node the relation arrives at. */
|
|
52
|
+
to: string;
|
|
53
|
+
/** The word printed beside the line. */
|
|
54
|
+
label: string;
|
|
55
|
+
/** Draws the line dashed, for a relation that holds but not by this route. */
|
|
56
|
+
indirect?: boolean;
|
|
57
|
+
};
|
|
58
|
+
/** What both arms of `DiagramProps` carry. */
|
|
59
|
+
type DiagramFigure = {
|
|
60
|
+
/** The things drawn. At least one, or the Diagram renders an empty canvas. */
|
|
61
|
+
nodes: DiagramNode[];
|
|
62
|
+
/** The relations drawn between them. A relation naming a node that is not in `nodes` is dropped. */
|
|
63
|
+
relations: DiagramRelation[];
|
|
64
|
+
/**
|
|
65
|
+
* Layout only, exactly as on every Component: grid placement and width.
|
|
66
|
+
* Changing a Prism-owned visual property from here is prohibited, and this
|
|
67
|
+
* Component spreads no other prop, so there is no second way to do it.
|
|
68
|
+
*/
|
|
69
|
+
className?: string;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* The props a Diagram takes.
|
|
73
|
+
*
|
|
74
|
+
* The name is required unless the drawing is decorative, and it is forbidden
|
|
75
|
+
* when it is. That is a union rather than `label?: string` because only a union
|
|
76
|
+
* lets the type system see the exception: an optional label on one type can
|
|
77
|
+
* only be optional everywhere or required everywhere, and both halves of that
|
|
78
|
+
* are wrong. `Separator` takes the same shape as `decorative`.
|
|
79
|
+
*/
|
|
80
|
+
export type DiagramProps = DiagramFigure & ({
|
|
81
|
+
/**
|
|
82
|
+
* Hides the drawing from assistive technology and drops the name. Use it
|
|
83
|
+
* when the surrounding sentence already says what the diagram shows, and
|
|
84
|
+
* nothing inside the hidden tree is named either: there is no `<title>`
|
|
85
|
+
* here, so there is no name stranded inside an `aria-hidden` subtree.
|
|
86
|
+
*/
|
|
87
|
+
decorative: true;
|
|
88
|
+
label?: never;
|
|
89
|
+
} | {
|
|
90
|
+
/** The name of the drawing, and the only thing a screen reader reads from it. */
|
|
91
|
+
label: string;
|
|
92
|
+
decorative?: false;
|
|
93
|
+
});
|
|
94
|
+
/**
|
|
95
|
+
* A diagram of named things and the relations between them.
|
|
96
|
+
*
|
|
97
|
+
* Data in, vector markup out. Every stroke and every fill is a semantic token
|
|
98
|
+
* named as a utility, never a value read from anywhere, so a scoped `data-pack`
|
|
99
|
+
* boundary above the drawing restyles it through the cascade exactly as it
|
|
100
|
+
* restyles a heading. That is the whole reason this is a Component and the
|
|
101
|
+
* reason a canvas was not: a canvas paints pixels it has already resolved, and
|
|
102
|
+
* a resolved value does not move when the pack beneath it does.
|
|
103
|
+
*
|
|
104
|
+
* It is a server Component. It ships no client code, takes no hook, has no mode
|
|
105
|
+
* of its own and reads no context, so a consumer renders it from a server file
|
|
106
|
+
* with no provider mounted. `check-client-budget.mjs` keeps it off the client
|
|
107
|
+
* roster, and a `'use client'` line added here would put it back on that roster.
|
|
108
|
+
*
|
|
109
|
+
* **Accessibility.** A diagram carries meaning, so by default it is one image
|
|
110
|
+
* with a name: `role="img"` and the `label` the caller passes. Everything inside
|
|
111
|
+
* a `role="img"` is presentational, so the node names and relation words are
|
|
112
|
+
* drawn for sighted readers and the surrounding sentence is what a screen reader
|
|
113
|
+
* gets. Pass `decorative` when the sentence already says what the drawing
|
|
114
|
+
* shows, and the whole tree leaves the accessibility tree with nothing named
|
|
115
|
+
* inside it.
|
|
116
|
+
*
|
|
117
|
+
* **Shape.** Nodes are circles and relations are paths. Both are shapes with no
|
|
118
|
+
* radius concept, so no corner radius here is a function of `--radius` and a
|
|
119
|
+
* pack boundary above the drawing moves nothing about its shape. A `<rect>` was
|
|
120
|
+
* rejected for the opposite reason: its corner attribute is a CSS property and
|
|
121
|
+
* does follow a boundary, and no utility pins it.
|
|
122
|
+
*
|
|
123
|
+
* **The node mark's base edges must draw.** Two things go wrong when a shape is
|
|
124
|
+
* left to its defaults, and this file answers both explicitly on every mark.
|
|
125
|
+
*
|
|
126
|
+
* 1. A shape with no `fill` and no `fill: none` paints opaque black, which
|
|
127
|
+
* hides every label behind it. A relation path therefore names `fill-none`
|
|
128
|
+
* and a node circle names a fill, and neither relies on an initial value.
|
|
129
|
+
* 2. A stroke only exists if something draws it. `stroke-width`'s initial
|
|
130
|
+
* value is 1 rather than 0, so the width is not what fails here; what fails
|
|
131
|
+
* is a mark whose stroke colour is `currentColor` on a surface whose text
|
|
132
|
+
* colour is that same surface, which is an invisible edge, or a width
|
|
133
|
+
* utility dropped in an edit. So every mark names an explicit width, an
|
|
134
|
+
* explicit stroke from a token, and never `current` or `currentColor`.
|
|
135
|
+
*
|
|
136
|
+
* A Component whose nodes render as invisible rectangles is worse than no
|
|
137
|
+
* Component, so this is stated here and covered by `test/diagram.test.tsx`.
|
|
138
|
+
*
|
|
139
|
+
* It spreads no other prop. `Separator` and `Kbd` spread a native element's
|
|
140
|
+
* props because there is no other route to them; a Diagram whose entire claim
|
|
141
|
+
* is that every ink is a token would be undermined by a spread that hands a
|
|
142
|
+
* caller `stroke`, so the surface is `nodes`, `relations`, `label`,
|
|
143
|
+
* `decorative` and `className` and nothing else.
|
|
144
|
+
*
|
|
145
|
+
* Positions are the caller's: the Component fits and draws, and it does not lay
|
|
146
|
+
* out a graph, so it cannot know that two labels will not collide. A relation
|
|
147
|
+
* naming a node that is not in `nodes` is dropped, and the count of dropped
|
|
148
|
+
* relations is on the element as `data-unresolved-relations` rather than
|
|
149
|
+
* swallowed, because a line that silently did not draw is the failure this
|
|
150
|
+
* Component exists to make impossible.
|
|
151
|
+
*/
|
|
152
|
+
declare function Diagram({ nodes, relations, label, decorative, className, }: DiagramProps): import("react").JSX.Element;
|
|
153
|
+
export { Diagram };
|
|
154
|
+
//# sourceMappingURL=diagram.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagram.d.ts","sourceRoot":"","sources":["../../../src/components/ui/diagram.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB;;;;OAIG;IACH,EAAE,EAAE,MAAM,CAAA;IACV;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ,4EAA4E;IAC5E,CAAC,EAAE,MAAM,CAAA;IACT,0EAA0E;IAC1E,CAAC,EAAE,MAAM,CAAA;IACT,mEAAmE;IACnE,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAA;IACZ,oDAAoD;IACpD,EAAE,EAAE,MAAM,CAAA;IACV,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAA;IACb,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,8CAA8C;AAC9C,KAAK,aAAa,GAAG;IACnB,8EAA8E;IAC9E,KAAK,EAAE,WAAW,EAAE,CAAA;IACpB,oGAAoG;IACpG,SAAS,EAAE,eAAe,EAAE,CAAA;IAC5B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG,aAAa,GACtC,CACI;IACE;;;;;OAKG;IACH,UAAU,EAAE,IAAI,CAAA;IAChB,KAAK,CAAC,EAAE,KAAK,CAAA;CACd,GACD;IACE,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,KAAK,CAAA;CACnB,CACJ,CAAA;AAoFH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,iBAAS,OAAO,CAAC,EACf,KAAK,EACL,SAAS,EACT,KAAK,EACL,UAAkB,EAClB,SAAS,GACV,EAAE,YAAY,+BAsFd;AAED,OAAO,EAAE,OAAO,EAAE,CAAA"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from '../../lib/utils';
|
|
3
|
+
/**
|
|
4
|
+
* The canvas the Diagram draws into, in its own user units.
|
|
5
|
+
*
|
|
6
|
+
* A fixed canvas rather than a viewBox derived from the caller's numbers, for
|
|
7
|
+
* one reason: type inside a scaled SVG is sized in the SVG's own user units, so
|
|
8
|
+
* a viewBox derived from a caller's coordinates would make the label size a
|
|
9
|
+
* function of how large a number the caller happened to use, and the same
|
|
10
|
+
* drawing would come out with 3px labels in one call and 40px labels in another.
|
|
11
|
+
* Fitting the caller's points into a fixed canvas makes the label a constant
|
|
12
|
+
* and makes the drawing a function of the shape rather than of the scale.
|
|
13
|
+
*/
|
|
14
|
+
const CANVAS_WIDTH = 640;
|
|
15
|
+
const CANVAS_HEIGHT = 400;
|
|
16
|
+
/**
|
|
17
|
+
* The band left empty around the fitted points, in user units.
|
|
18
|
+
*
|
|
19
|
+
* It reserves room for what is drawn beside a node rather than for the node: a
|
|
20
|
+
* node mark is 5 units in radius and its name is set about 20 units below it,
|
|
21
|
+
* and a name is wider than the mark. The band is the honest cost of a server
|
|
22
|
+
* component not being able to measure text, and it is why a name that runs long
|
|
23
|
+
* still lands inside the canvas rather than off its edge.
|
|
24
|
+
*/
|
|
25
|
+
const PADDING = 56;
|
|
26
|
+
/** The node mark's radius. A circle, so there is no corner radius for the pack to move. */
|
|
27
|
+
const NODE_RADIUS = 5;
|
|
28
|
+
/**
|
|
29
|
+
* Type sizes, in user units rather than in `rem`.
|
|
30
|
+
*
|
|
31
|
+
* The authored type scale is in `rem` and cannot be used inside a viewBox, where
|
|
32
|
+
* a font size is a coordinate and not a length on the page. These are geometry,
|
|
33
|
+
* the one thing Tailwind stays authoritative for, and they are the only numbers
|
|
34
|
+
* in this file that are not a token.
|
|
35
|
+
*/
|
|
36
|
+
const NODE_NAME_SIZE = 13;
|
|
37
|
+
const NODE_NAME_OFFSET = 20;
|
|
38
|
+
const RELATION_NAME_SIZE = 11;
|
|
39
|
+
/**
|
|
40
|
+
* How far a relation's label sits off its line, in user units. Perpendicular to
|
|
41
|
+
* the line, so the label never sits on the stroke it belongs to.
|
|
42
|
+
*/
|
|
43
|
+
const RELATION_NAME_LIFT = 7;
|
|
44
|
+
/**
|
|
45
|
+
* The caller's points, fitted into the canvas with their aspect ratio kept and
|
|
46
|
+
* the leftover shared out evenly.
|
|
47
|
+
*
|
|
48
|
+
* A caller whose points span one axis only, or who passes a single node, gets
|
|
49
|
+
* the other axis centred rather than a division by zero: the scale is taken
|
|
50
|
+
* over the axes that have an extent, and a diagram with no extent at all keeps
|
|
51
|
+
* the caller's own numbers.
|
|
52
|
+
*/
|
|
53
|
+
function fit(nodes) {
|
|
54
|
+
if (nodes.length === 0)
|
|
55
|
+
return () => ({ x: CANVAS_WIDTH / 2, y: CANVAS_HEIGHT / 2 });
|
|
56
|
+
const xs = nodes.map((node) => node.x);
|
|
57
|
+
const ys = nodes.map((node) => node.y);
|
|
58
|
+
const minX = Math.min(...xs);
|
|
59
|
+
const minY = Math.min(...ys);
|
|
60
|
+
const spanX = Math.max(...xs) - minX;
|
|
61
|
+
const spanY = Math.max(...ys) - minY;
|
|
62
|
+
const roomX = CANVAS_WIDTH - PADDING * 2;
|
|
63
|
+
const roomY = CANVAS_HEIGHT - PADDING * 2;
|
|
64
|
+
const scale = Math.min(spanX === 0 ? Number.POSITIVE_INFINITY : roomX / spanX, spanY === 0 ? Number.POSITIVE_INFINITY : roomY / spanY);
|
|
65
|
+
const unit = Number.isFinite(scale) && scale > 0 ? scale : 1;
|
|
66
|
+
const offsetX = PADDING + (roomX - spanX * unit) / 2 - minX * unit;
|
|
67
|
+
const offsetY = PADDING + (roomY - spanY * unit) / 2 - minY * unit;
|
|
68
|
+
return (node) => ({ x: node.x * unit + offsetX, y: node.y * unit + offsetY });
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* A diagram of named things and the relations between them.
|
|
72
|
+
*
|
|
73
|
+
* Data in, vector markup out. Every stroke and every fill is a semantic token
|
|
74
|
+
* named as a utility, never a value read from anywhere, so a scoped `data-pack`
|
|
75
|
+
* boundary above the drawing restyles it through the cascade exactly as it
|
|
76
|
+
* restyles a heading. That is the whole reason this is a Component and the
|
|
77
|
+
* reason a canvas was not: a canvas paints pixels it has already resolved, and
|
|
78
|
+
* a resolved value does not move when the pack beneath it does.
|
|
79
|
+
*
|
|
80
|
+
* It is a server Component. It ships no client code, takes no hook, has no mode
|
|
81
|
+
* of its own and reads no context, so a consumer renders it from a server file
|
|
82
|
+
* with no provider mounted. `check-client-budget.mjs` keeps it off the client
|
|
83
|
+
* roster, and a `'use client'` line added here would put it back on that roster.
|
|
84
|
+
*
|
|
85
|
+
* **Accessibility.** A diagram carries meaning, so by default it is one image
|
|
86
|
+
* with a name: `role="img"` and the `label` the caller passes. Everything inside
|
|
87
|
+
* a `role="img"` is presentational, so the node names and relation words are
|
|
88
|
+
* drawn for sighted readers and the surrounding sentence is what a screen reader
|
|
89
|
+
* gets. Pass `decorative` when the sentence already says what the drawing
|
|
90
|
+
* shows, and the whole tree leaves the accessibility tree with nothing named
|
|
91
|
+
* inside it.
|
|
92
|
+
*
|
|
93
|
+
* **Shape.** Nodes are circles and relations are paths. Both are shapes with no
|
|
94
|
+
* radius concept, so no corner radius here is a function of `--radius` and a
|
|
95
|
+
* pack boundary above the drawing moves nothing about its shape. A `<rect>` was
|
|
96
|
+
* rejected for the opposite reason: its corner attribute is a CSS property and
|
|
97
|
+
* does follow a boundary, and no utility pins it.
|
|
98
|
+
*
|
|
99
|
+
* **The node mark's base edges must draw.** Two things go wrong when a shape is
|
|
100
|
+
* left to its defaults, and this file answers both explicitly on every mark.
|
|
101
|
+
*
|
|
102
|
+
* 1. A shape with no `fill` and no `fill: none` paints opaque black, which
|
|
103
|
+
* hides every label behind it. A relation path therefore names `fill-none`
|
|
104
|
+
* and a node circle names a fill, and neither relies on an initial value.
|
|
105
|
+
* 2. A stroke only exists if something draws it. `stroke-width`'s initial
|
|
106
|
+
* value is 1 rather than 0, so the width is not what fails here; what fails
|
|
107
|
+
* is a mark whose stroke colour is `currentColor` on a surface whose text
|
|
108
|
+
* colour is that same surface, which is an invisible edge, or a width
|
|
109
|
+
* utility dropped in an edit. So every mark names an explicit width, an
|
|
110
|
+
* explicit stroke from a token, and never `current` or `currentColor`.
|
|
111
|
+
*
|
|
112
|
+
* A Component whose nodes render as invisible rectangles is worse than no
|
|
113
|
+
* Component, so this is stated here and covered by `test/diagram.test.tsx`.
|
|
114
|
+
*
|
|
115
|
+
* It spreads no other prop. `Separator` and `Kbd` spread a native element's
|
|
116
|
+
* props because there is no other route to them; a Diagram whose entire claim
|
|
117
|
+
* is that every ink is a token would be undermined by a spread that hands a
|
|
118
|
+
* caller `stroke`, so the surface is `nodes`, `relations`, `label`,
|
|
119
|
+
* `decorative` and `className` and nothing else.
|
|
120
|
+
*
|
|
121
|
+
* Positions are the caller's: the Component fits and draws, and it does not lay
|
|
122
|
+
* out a graph, so it cannot know that two labels will not collide. A relation
|
|
123
|
+
* naming a node that is not in `nodes` is dropped, and the count of dropped
|
|
124
|
+
* relations is on the element as `data-unresolved-relations` rather than
|
|
125
|
+
* swallowed, because a line that silently did not draw is the failure this
|
|
126
|
+
* Component exists to make impossible.
|
|
127
|
+
*/
|
|
128
|
+
function Diagram({ nodes, relations, label, decorative = false, className, }) {
|
|
129
|
+
const place = fit(nodes);
|
|
130
|
+
const byId = new Map(nodes.map((node) => [node.id, node]));
|
|
131
|
+
const drawn = relations.flatMap((relation) => {
|
|
132
|
+
const from = byId.get(relation.from);
|
|
133
|
+
const to = byId.get(relation.to);
|
|
134
|
+
return from && to ? [{ relation, from: place(from), to: place(to) }] : [];
|
|
135
|
+
});
|
|
136
|
+
return (_jsxs("svg", { "data-slot": "diagram", "data-unresolved-relations": relations.length - drawn.length, viewBox: `0 0 ${CANVAS_WIDTH} ${CANVAS_HEIGHT}`, xmlns: "http://www.w3.org/2000/svg", role: decorative ? undefined : 'img', "aria-label": decorative ? undefined : label, "aria-hidden": decorative || undefined, className: cn('h-auto w-full', className), children: [drawn.map(({ relation, from, to }) => {
|
|
137
|
+
// A label placed beside its line rather than on it. The offset is the
|
|
138
|
+
// line's normal, so a vertical relation's label sits beside it and a
|
|
139
|
+
// horizontal one's sits above it, and neither ever sits on the stroke.
|
|
140
|
+
const dx = to.x - from.x;
|
|
141
|
+
const dy = to.y - from.y;
|
|
142
|
+
const length = Math.hypot(dx, dy);
|
|
143
|
+
const lift = length === 0 ? 0 : RELATION_NAME_LIFT / length;
|
|
144
|
+
return (_jsxs("g", { "data-slot": "diagram-relation", "data-relation": `${relation.from}-${relation.to}`, children: [_jsx("path", { d: `M ${from.x} ${from.y} L ${to.x} ${to.y}`, strokeWidth: 1, strokeDasharray: relation.indirect ? '4 4' : undefined, className: "stroke-muted-foreground fill-none" }), _jsx("text", { x: (from.x + to.x) / 2 - dy * lift, y: (from.y + to.y) / 2 + dx * lift, fontSize: RELATION_NAME_SIZE, textAnchor: "middle", className: "fill-muted-foreground font-mono", children: relation.label })] }, `${relation.from}-${relation.to}`));
|
|
145
|
+
}), nodes.map((node) => {
|
|
146
|
+
const at = place(node);
|
|
147
|
+
return (_jsxs("g", { "data-slot": "diagram-node", "data-node": node.id, "data-emphasis": node.emphasis || undefined, children: [_jsx("circle", { cx: at.x, cy: at.y, r: NODE_RADIUS, strokeWidth: node.emphasis ? 2 : 1, className: cn(node.emphasis ? 'fill-accent stroke-brand-ink' : 'fill-card stroke-border') }), _jsx("text", { x: at.x, y: at.y + NODE_NAME_OFFSET, fontSize: NODE_NAME_SIZE, textAnchor: "middle", className: "fill-foreground font-mono", children: node.name })] }, node.id));
|
|
148
|
+
})] }));
|
|
149
|
+
}
|
|
150
|
+
export { Diagram };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The props the Dialog root forwards to Base UI.
|
|
4
|
+
*
|
|
5
|
+
* Declared here rather than re-exported from Base UI so no upstream type
|
|
6
|
+
* crosses the package seam (ticket 07 section 6).
|
|
7
|
+
*/
|
|
8
|
+
export interface DialogProps {
|
|
9
|
+
/** The controlled open state. */
|
|
10
|
+
open?: boolean;
|
|
11
|
+
/** The initially open state, for an uncontrolled dialog. */
|
|
12
|
+
defaultOpen?: boolean;
|
|
13
|
+
/** Called when the open state changes. */
|
|
14
|
+
onOpenChange?: (open: boolean) => void;
|
|
15
|
+
/** Whether the dialog is modal. @defaultValue true */
|
|
16
|
+
modal?: boolean | 'trap-focus';
|
|
17
|
+
/** The trigger and content. */
|
|
18
|
+
children?: React.ReactNode;
|
|
19
|
+
}
|
|
20
|
+
/** The props DialogTrigger forwards to Base UI. */
|
|
21
|
+
export interface DialogTriggerProps extends ComponentProps<'button'> {
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The props DialogContent forwards to Base UI.
|
|
25
|
+
*
|
|
26
|
+
* Declared here rather than re-exported from Base UI so no upstream type
|
|
27
|
+
* crosses the package seam (ticket 07 section 6).
|
|
28
|
+
*/
|
|
29
|
+
export interface DialogContentProps extends ComponentProps<'div'> {
|
|
30
|
+
/**
|
|
31
|
+
* Where the dialog is anchored.
|
|
32
|
+
*
|
|
33
|
+
* `center` is a modal card; `top`, `bottom`, `left` and `right` anchor the
|
|
34
|
+
* panel to an edge as a sheet, which is the old drawer re-expressed.
|
|
35
|
+
* @defaultValue center
|
|
36
|
+
*/
|
|
37
|
+
side?: 'center' | 'top' | 'bottom' | 'left' | 'right';
|
|
38
|
+
/** Whether the built-in close control is rendered. @defaultValue true */
|
|
39
|
+
showCloseButton?: boolean;
|
|
40
|
+
}
|
|
41
|
+
/** The props DialogHeader forwards to a plain container. */
|
|
42
|
+
export interface DialogHeaderProps extends ComponentProps<'div'> {
|
|
43
|
+
}
|
|
44
|
+
/** The props DialogFooter forwards to a plain container. */
|
|
45
|
+
export interface DialogFooterProps extends ComponentProps<'div'> {
|
|
46
|
+
}
|
|
47
|
+
/** The props DialogTitle forwards to Base UI. */
|
|
48
|
+
export interface DialogTitleProps extends ComponentProps<'h2'> {
|
|
49
|
+
}
|
|
50
|
+
/** The props DialogDescription forwards to Base UI. */
|
|
51
|
+
export interface DialogDescriptionProps extends ComponentProps<'p'> {
|
|
52
|
+
}
|
|
53
|
+
/** The props DialogClose forwards to Base UI. */
|
|
54
|
+
export interface DialogCloseProps extends ComponentProps<'button'> {
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* A modal surface that interrupts the page.
|
|
58
|
+
*
|
|
59
|
+
* The dialog traps focus while it is open, locks page scroll, closes on
|
|
60
|
+
* Escape and on an outside press, and returns focus to its trigger when it
|
|
61
|
+
* closes. Always give it a `DialogTitle`, which names the dialog for every
|
|
62
|
+
* reader. Use a Dialog for a decision or a short task; for content that is
|
|
63
|
+
* not a task, use a Popover or navigate to a page.
|
|
64
|
+
*/
|
|
65
|
+
declare function Dialog({ ...props }: DialogProps): import("react").JSX.Element;
|
|
66
|
+
/** The element that opens the dialog. */
|
|
67
|
+
declare function DialogTrigger({ className, ...props }: DialogTriggerProps): import("react").JSX.Element;
|
|
68
|
+
/** The dialog panel, its backdrop and its portal. */
|
|
69
|
+
declare function DialogContent({ className, side, showCloseButton, children, ...props }: DialogContentProps): import("react").JSX.Element;
|
|
70
|
+
/** The dialog's heading area, above the body. */
|
|
71
|
+
declare function DialogHeader({ className, ...props }: DialogHeaderProps): import("react").JSX.Element;
|
|
72
|
+
/** The dialog's action area, below the body. */
|
|
73
|
+
declare function DialogFooter({ className, ...props }: DialogFooterProps): import("react").JSX.Element;
|
|
74
|
+
/** The dialog's heading. It names the dialog for assistive technology. */
|
|
75
|
+
declare function DialogTitle({ className, ...props }: DialogTitleProps): import("react").JSX.Element;
|
|
76
|
+
/** A supporting line under the title. */
|
|
77
|
+
declare function DialogDescription({ className, ...props }: DialogDescriptionProps): import("react").JSX.Element;
|
|
78
|
+
/** A control that closes the dialog from inside its content. */
|
|
79
|
+
declare function DialogClose({ className, ...props }: DialogCloseProps): import("react").JSX.Element;
|
|
80
|
+
export { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription, DialogClose, };
|
|
81
|
+
//# sourceMappingURL=dialog.d.ts.map
|