@nanisoft/prism-ui 0.10.2 → 0.13.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 -21
- package/dist/.tsbuildinfo +1 -1
- package/dist/blocks/app-shell-01/app-shell.js +4 -4
- package/dist/blocks/app-shell-01/index.d.ts +2 -2
- package/dist/blocks/app-shell-01/index.js +1 -1
- package/dist/blocks/auth-form-01/auth-form.d.ts +11 -1
- package/dist/blocks/auth-form-01/auth-form.d.ts.map +1 -1
- package/dist/blocks/auth-form-01/auth-form.js +11 -8
- package/dist/blocks/auth-form-01/index.d.ts +2 -2
- package/dist/blocks/auth-form-01/index.js +1 -1
- package/dist/blocks/cta-01/cta.d.ts +26 -21
- package/dist/blocks/cta-01/cta.d.ts.map +1 -1
- package/dist/blocks/cta-01/cta.js +2 -2
- package/dist/blocks/cta-01/index.d.ts +2 -2
- package/dist/blocks/cta-01/index.js +1 -1
- package/dist/blocks/data-table-01/data-table.js +7 -7
- package/dist/blocks/data-table-01/index.d.ts +2 -2
- package/dist/blocks/data-table-01/index.js +1 -1
- package/dist/blocks/empty-state-01/empty-state.d.ts +143 -0
- package/dist/blocks/empty-state-01/empty-state.d.ts.map +1 -0
- package/dist/blocks/empty-state-01/empty-state.js +104 -0
- package/dist/blocks/empty-state-01/index.d.ts +3 -0
- package/dist/blocks/empty-state-01/index.d.ts.map +1 -0
- package/dist/blocks/empty-state-01/index.js +1 -0
- package/dist/blocks/feature-grid-01/feature-grid.d.ts +28 -1
- package/dist/blocks/feature-grid-01/feature-grid.d.ts.map +1 -1
- package/dist/blocks/feature-grid-01/feature-grid.js +34 -3
- package/dist/blocks/feature-grid-01/index.d.ts +2 -2
- package/dist/blocks/feature-grid-01/index.js +1 -1
- package/dist/blocks/hero-01/hero.d.ts +35 -15
- package/dist/blocks/hero-01/hero.d.ts.map +1 -1
- package/dist/blocks/hero-01/hero.js +14 -9
- package/dist/blocks/hero-01/index.d.ts +2 -1
- package/dist/blocks/hero-01/index.d.ts.map +1 -1
- package/dist/blocks/hero-01/index.js +1 -1
- package/dist/blocks/index.d.ts +20 -20
- package/dist/blocks/index.js +19 -19
- package/dist/blocks/instrument-panel-01/index.d.ts +2 -2
- package/dist/blocks/instrument-panel-01/index.js +1 -1
- package/dist/blocks/instrument-panel-01/instrument-panel.js +1 -1
- package/dist/blocks/logo-strip-01/index.d.ts +2 -2
- package/dist/blocks/logo-strip-01/index.js +1 -1
- package/dist/blocks/logo-strip-01/logo-strip.d.ts +1 -1
- package/dist/blocks/logo-strip-01/logo-strip.js +2 -2
- package/dist/blocks/note-grid-01/index.d.ts +2 -2
- package/dist/blocks/note-grid-01/index.js +1 -1
- package/dist/blocks/note-grid-01/note-grid.d.ts +1 -1
- package/dist/blocks/note-grid-01/note-grid.js +1 -1
- package/dist/blocks/page-header-01/index.d.ts +2 -2
- package/dist/blocks/page-header-01/index.js +1 -1
- package/dist/blocks/page-header-01/page-header.d.ts +1 -1
- package/dist/blocks/page-header-01/page-header.js +4 -4
- package/dist/blocks/pricing-01/index.d.ts +1 -1
- package/dist/blocks/pricing-01/index.js +1 -1
- package/dist/blocks/pricing-01/pricing.d.ts +8 -1
- package/dist/blocks/pricing-01/pricing.d.ts.map +1 -1
- package/dist/blocks/pricing-01/pricing.js +15 -5
- package/dist/blocks/process-flow-01/index.d.ts +3 -0
- package/dist/blocks/process-flow-01/index.d.ts.map +1 -0
- package/dist/blocks/process-flow-01/index.js +1 -0
- package/dist/blocks/process-flow-01/process-flow.d.ts +118 -0
- package/dist/blocks/process-flow-01/process-flow.d.ts.map +1 -0
- package/dist/blocks/process-flow-01/process-flow.js +71 -0
- package/dist/blocks/process-rail-01/index.d.ts +2 -2
- package/dist/blocks/process-rail-01/index.js +1 -1
- package/dist/blocks/process-rail-01/process-rail.d.ts +1 -1
- package/dist/blocks/process-rail-01/process-rail.js +2 -2
- package/dist/blocks/product-grid-01/index.d.ts +2 -2
- package/dist/blocks/product-grid-01/index.js +1 -1
- package/dist/blocks/product-grid-01/product-grid.d.ts +37 -5
- package/dist/blocks/product-grid-01/product-grid.d.ts.map +1 -1
- package/dist/blocks/product-grid-01/product-grid.js +20 -6
- package/dist/blocks/run-console-01/index.d.ts +3 -0
- package/dist/blocks/run-console-01/index.d.ts.map +1 -0
- package/dist/blocks/run-console-01/index.js +1 -0
- package/dist/blocks/run-console-01/run-console.d.ts +111 -0
- package/dist/blocks/run-console-01/run-console.d.ts.map +1 -0
- package/dist/blocks/run-console-01/run-console.js +48 -0
- package/dist/blocks/settings-panel-01/index.d.ts +2 -2
- package/dist/blocks/settings-panel-01/index.js +1 -1
- package/dist/blocks/settings-panel-01/settings-panel.d.ts +11 -1
- package/dist/blocks/settings-panel-01/settings-panel.d.ts.map +1 -1
- package/dist/blocks/settings-panel-01/settings-panel.js +15 -10
- package/dist/blocks/site-footer/index.d.ts +2 -2
- package/dist/blocks/site-footer/index.js +1 -1
- package/dist/blocks/site-footer/site-footer.d.ts +1 -1
- package/dist/blocks/site-footer/site-footer.js +2 -2
- package/dist/blocks/site-header/index.d.ts +2 -2
- package/dist/blocks/site-header/index.js +1 -1
- package/dist/blocks/site-header/site-header.d.ts +2 -2
- package/dist/blocks/site-header/site-header.js +3 -3
- package/dist/blocks/site-navbar/index.d.ts +3 -0
- package/dist/blocks/site-navbar/index.d.ts.map +1 -0
- package/dist/blocks/site-navbar/index.js +1 -0
- package/dist/blocks/site-navbar/mobile-nav.d.ts +48 -0
- package/dist/blocks/site-navbar/mobile-nav.d.ts.map +1 -0
- package/dist/blocks/site-navbar/mobile-nav.js +35 -0
- package/dist/blocks/site-navbar/mode-toggle.d.ts +39 -0
- package/dist/blocks/site-navbar/mode-toggle.d.ts.map +1 -0
- package/dist/blocks/site-navbar/mode-toggle.js +39 -0
- package/dist/blocks/site-navbar/navbar-controls.d.ts +79 -0
- package/dist/blocks/site-navbar/navbar-controls.d.ts.map +1 -0
- package/dist/blocks/site-navbar/navbar-controls.js +40 -0
- package/dist/blocks/site-navbar/search-entry.d.ts +29 -0
- package/dist/blocks/site-navbar/search-entry.d.ts.map +1 -0
- package/dist/blocks/site-navbar/search-entry.js +52 -0
- package/dist/blocks/site-navbar/site-navbar.d.ts +212 -0
- package/dist/blocks/site-navbar/site-navbar.d.ts.map +1 -0
- package/dist/blocks/site-navbar/site-navbar.js +61 -0
- package/dist/blocks/site-navbar/sites-menu.d.ts +40 -0
- package/dist/blocks/site-navbar/sites-menu.d.ts.map +1 -0
- package/dist/blocks/site-navbar/sites-menu.js +48 -0
- package/dist/blocks/site-navbar/theme-menu.d.ts +47 -0
- package/dist/blocks/site-navbar/theme-menu.d.ts.map +1 -0
- package/dist/blocks/site-navbar/theme-menu.js +55 -0
- package/dist/blocks/stack-grid-01/index.d.ts +2 -2
- package/dist/blocks/stack-grid-01/index.js +1 -1
- package/dist/blocks/stack-grid-01/stack-grid.d.ts +42 -11
- package/dist/blocks/stack-grid-01/stack-grid.d.ts.map +1 -1
- package/dist/blocks/stack-grid-01/stack-grid.js +15 -7
- package/dist/blocks/stats-01/index.d.ts +9 -1
- package/dist/blocks/stats-01/index.d.ts.map +1 -1
- package/dist/blocks/stats-01/index.js +8 -1
- package/dist/blocks/stats-01/stats.d.ts +1 -1
- package/dist/blocks/stats-01/stats.js +2 -2
- package/dist/blocks/status-ledger-01/index.d.ts +2 -2
- package/dist/blocks/status-ledger-01/index.js +1 -1
- package/dist/blocks/status-ledger-01/status-ledger.d.ts +1 -1
- package/dist/blocks/status-ledger-01/status-ledger.js +2 -2
- package/dist/catalog.d.ts +1 -1
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +473 -1
- package/dist/components/index.d.ts +104 -66
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +74 -40
- package/dist/components/ui/accordion.js +1 -1
- package/dist/components/ui/alert-dialog.d.ts +119 -0
- package/dist/components/ui/alert-dialog.d.ts.map +1 -0
- package/dist/components/ui/alert-dialog.js +82 -0
- package/dist/components/ui/alert.js +1 -1
- package/dist/components/ui/aspect-ratio.d.ts +60 -0
- package/dist/components/ui/aspect-ratio.d.ts.map +1 -0
- package/dist/components/ui/aspect-ratio.js +61 -0
- package/dist/components/ui/avatar.js +1 -1
- package/dist/components/ui/badge.js +1 -1
- package/dist/components/ui/breadcrumb.js +1 -1
- package/dist/components/ui/button-group.d.ts +68 -0
- package/dist/components/ui/button-group.d.ts.map +1 -0
- package/dist/components/ui/button-group.js +54 -0
- package/dist/components/ui/button.js +1 -1
- package/dist/components/ui/calendar.d.ts +158 -0
- package/dist/components/ui/calendar.d.ts.map +1 -0
- package/dist/components/ui/calendar.js +216 -0
- package/dist/components/ui/card.d.ts +18 -6
- package/dist/components/ui/card.d.ts.map +1 -1
- package/dist/components/ui/card.js +23 -8
- package/dist/components/ui/carousel.d.ts +118 -0
- package/dist/components/ui/carousel.d.ts.map +1 -0
- package/dist/components/ui/carousel.js +152 -0
- package/dist/components/ui/chart-frame.d.ts +216 -0
- package/dist/components/ui/chart-frame.d.ts.map +1 -0
- package/dist/components/ui/chart-frame.js +286 -0
- package/dist/components/ui/checkbox.js +1 -1
- package/dist/components/ui/collapsible.d.ts +97 -0
- package/dist/components/ui/collapsible.d.ts.map +1 -0
- package/dist/components/ui/collapsible.js +54 -0
- package/dist/components/ui/combobox.d.ts +141 -0
- package/dist/components/ui/combobox.d.ts.map +1 -0
- package/dist/components/ui/combobox.js +243 -0
- package/dist/components/ui/command-palette.d.ts +106 -0
- package/dist/components/ui/command-palette.d.ts.map +1 -0
- package/dist/components/ui/command-palette.js +176 -0
- package/dist/components/ui/command.d.ts +82 -0
- package/dist/components/ui/command.d.ts.map +1 -0
- package/dist/components/ui/command.js +37 -0
- package/dist/components/ui/context-menu.d.ts +151 -0
- package/dist/components/ui/context-menu.d.ts.map +1 -0
- package/dist/components/ui/context-menu.js +97 -0
- package/dist/components/ui/cta-link.js +1 -1
- package/dist/components/ui/date-picker.d.ts +111 -0
- package/dist/components/ui/date-picker.d.ts.map +1 -0
- package/dist/components/ui/date-picker.js +74 -0
- package/dist/components/ui/diagram.d.ts +84 -15
- package/dist/components/ui/diagram.d.ts.map +1 -1
- package/dist/components/ui/diagram.js +77 -7
- package/dist/components/ui/dialog.js +1 -1
- package/dist/components/ui/diff.d.ts +105 -0
- package/dist/components/ui/diff.d.ts.map +1 -0
- package/dist/components/ui/diff.js +113 -0
- package/dist/components/ui/dropdown-menu.d.ts +18 -0
- package/dist/components/ui/dropdown-menu.d.ts.map +1 -1
- package/dist/components/ui/dropdown-menu.js +1 -1
- package/dist/components/ui/fact-list.js +1 -1
- package/dist/components/ui/field.js +1 -1
- package/dist/components/ui/form.d.ts +151 -0
- package/dist/components/ui/form.d.ts.map +1 -0
- package/dist/components/ui/form.js +73 -0
- package/dist/components/ui/hover-card.d.ts +105 -0
- package/dist/components/ui/hover-card.d.ts.map +1 -0
- package/dist/components/ui/hover-card.js +49 -0
- package/dist/components/ui/input-group.d.ts +99 -0
- package/dist/components/ui/input-group.d.ts.map +1 -0
- package/dist/components/ui/input-group.js +83 -0
- package/dist/components/ui/input.js +1 -1
- package/dist/components/ui/item.d.ts +113 -0
- package/dist/components/ui/item.d.ts.map +1 -0
- package/dist/components/ui/item.js +61 -0
- package/dist/components/ui/kbd.js +1 -1
- package/dist/components/ui/label.d.ts +58 -0
- package/dist/components/ui/label.d.ts.map +1 -0
- package/dist/components/ui/label.js +29 -0
- package/dist/components/ui/live-region.d.ts +9 -0
- package/dist/components/ui/live-region.d.ts.map +1 -1
- package/dist/components/ui/live-region.js +10 -2
- package/dist/components/ui/mark.js +1 -1
- package/dist/components/ui/menubar.d.ts +197 -0
- package/dist/components/ui/menubar.d.ts.map +1 -0
- package/dist/components/ui/menubar.js +109 -0
- package/dist/components/ui/meter.d.ts +121 -0
- package/dist/components/ui/meter.d.ts.map +1 -0
- package/dist/components/ui/meter.js +82 -0
- package/dist/components/ui/native-select.d.ts +72 -0
- package/dist/components/ui/native-select.d.ts.map +1 -0
- package/dist/components/ui/native-select.js +55 -0
- package/dist/components/ui/navigation-menu.d.ts +186 -0
- package/dist/components/ui/navigation-menu.d.ts.map +1 -0
- package/dist/components/ui/navigation-menu.js +94 -0
- package/dist/components/ui/number-field.d.ts +111 -0
- package/dist/components/ui/number-field.d.ts.map +1 -0
- package/dist/components/ui/number-field.js +84 -0
- package/dist/components/ui/one-time-code.d.ts +127 -0
- package/dist/components/ui/one-time-code.d.ts.map +1 -0
- package/dist/components/ui/one-time-code.js +57 -0
- package/dist/components/ui/pagination.js +1 -1
- package/dist/components/ui/popover.js +1 -1
- package/dist/components/ui/product-mark.d.ts +1 -1
- package/dist/components/ui/product-mark.js +1 -1
- package/dist/components/ui/product-switcher.d.ts +1 -1
- package/dist/components/ui/product-switcher.js +2 -2
- package/dist/components/ui/progress.js +1 -1
- package/dist/components/ui/prose.js +1 -1
- package/dist/components/ui/pulse-graph.js +1 -1
- package/dist/components/ui/pulse-series.js +1 -1
- package/dist/components/ui/radio-group.js +1 -1
- package/dist/components/ui/resizable.d.ts +129 -0
- package/dist/components/ui/resizable.d.ts.map +1 -0
- package/dist/components/ui/resizable.js +205 -0
- package/dist/components/ui/scroll-area.d.ts +97 -0
- package/dist/components/ui/scroll-area.d.ts.map +1 -0
- package/dist/components/ui/scroll-area.js +68 -0
- package/dist/components/ui/search-dialog.d.ts +139 -0
- package/dist/components/ui/search-dialog.d.ts.map +1 -0
- package/dist/components/ui/search-dialog.js +178 -0
- package/dist/components/ui/section.d.ts +26 -0
- package/dist/components/ui/section.d.ts.map +1 -1
- package/dist/components/ui/section.js +32 -1
- package/dist/components/ui/select.js +1 -1
- package/dist/components/ui/separator.js +1 -1
- package/dist/components/ui/sheet.d.ts +103 -0
- package/dist/components/ui/sheet.d.ts.map +1 -0
- package/dist/components/ui/sheet.js +58 -0
- package/dist/components/ui/sidebar.d.ts +228 -0
- package/dist/components/ui/sidebar.d.ts.map +1 -0
- package/dist/components/ui/sidebar.js +172 -0
- package/dist/components/ui/signal-field.js +1 -1
- package/dist/components/ui/skeleton.js +1 -1
- package/dist/components/ui/slider.js +1 -1
- package/dist/components/ui/spinner.d.ts +79 -0
- package/dist/components/ui/spinner.d.ts.map +1 -0
- package/dist/components/ui/spinner.js +79 -0
- package/dist/components/ui/switch.js +1 -1
- package/dist/components/ui/table-sort.d.ts +97 -0
- package/dist/components/ui/table-sort.d.ts.map +1 -0
- package/dist/components/ui/table-sort.js +102 -0
- package/dist/components/ui/table.js +1 -1
- package/dist/components/ui/tabs.js +1 -1
- package/dist/components/ui/textarea.js +1 -1
- package/dist/components/ui/timeline.d.ts +106 -0
- package/dist/components/ui/timeline.d.ts.map +1 -0
- package/dist/components/ui/timeline.js +111 -0
- package/dist/components/ui/toast.d.ts +219 -0
- package/dist/components/ui/toast.d.ts.map +1 -0
- package/dist/components/ui/toast.js +270 -0
- package/dist/components/ui/toggle-group.d.ts +118 -0
- package/dist/components/ui/toggle-group.d.ts.map +1 -0
- package/dist/components/ui/toggle-group.js +194 -0
- package/dist/components/ui/toggle.d.ts +73 -0
- package/dist/components/ui/toggle.d.ts.map +1 -0
- package/dist/components/ui/toggle.js +44 -0
- package/dist/components/ui/tooltip.js +1 -1
- package/dist/components/ui/tree.js +1 -1
- package/dist/components/ui/typography.js +1 -1
- package/dist/fonts/Inter-OFL.txt +93 -93
- package/dist/index.d.ts +72 -70
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +61 -60
- package/dist/lib/rank.d.ts +69 -0
- package/dist/lib/rank.d.ts.map +1 -0
- package/dist/lib/rank.js +77 -0
- package/dist/live/index.d.ts +22 -0
- package/dist/live/index.d.ts.map +1 -0
- package/dist/live/index.js +20 -0
- package/dist/live/run-stream-01/index.d.ts +3 -0
- package/dist/live/run-stream-01/index.d.ts.map +1 -0
- package/dist/live/run-stream-01/index.js +1 -0
- package/dist/live/run-stream-01/run-stream.d.ts +125 -0
- package/dist/live/run-stream-01/run-stream.d.ts.map +1 -0
- package/dist/live/run-stream-01/run-stream.js +111 -0
- package/dist/pages/auth-page/index.d.ts +15 -2
- package/dist/pages/auth-page/index.d.ts.map +1 -1
- package/dist/pages/auth-page/index.js +8 -4
- package/dist/pages/blog-post-page/index.js +5 -5
- package/dist/pages/dashboard-page/index.d.ts +4 -4
- package/dist/pages/dashboard-page/index.js +4 -4
- package/dist/pages/docs-shell/docs-shell.d.ts +37 -4
- package/dist/pages/docs-shell/docs-shell.d.ts.map +1 -1
- package/dist/pages/docs-shell/docs-shell.js +107 -16
- package/dist/pages/docs-shell/index.d.ts +2 -2
- package/dist/pages/docs-shell/index.js +1 -1
- package/dist/pages/index.d.ts +14 -14
- package/dist/pages/index.js +7 -7
- package/dist/pages/marketing-page/index.d.ts +6 -6
- package/dist/pages/marketing-page/index.js +5 -5
- package/dist/pages/not-found-page/index.js +4 -4
- package/dist/pages/settings-page/index.d.ts +3 -3
- package/dist/pages/settings-page/index.js +4 -4
- package/dist/provider/index.d.ts +4 -4
- package/dist/provider/index.js +2 -2
- package/dist/provider/provider.d.ts +1 -1
- package/dist/provider/provider.js +1 -1
- package/dist/provider/theme-script.d.ts +1 -1
- package/dist/provider/theme-script.js +1 -1
- package/dist/styles.css +689 -0
- package/package.json +9 -1
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from '../../lib/utils.js';
|
|
3
|
+
/** The bar and the text tint for each kind, from the existing semantic roles. */
|
|
4
|
+
const KIND_BAR = {
|
|
5
|
+
// A context line has no bar at all rather than an empty one: a zero-width mark
|
|
6
|
+
// beside an unchanged line reads as "this changed a little", which is a claim
|
|
7
|
+
// about a line the diff is saying did not change.
|
|
8
|
+
context: 'bg-transparent',
|
|
9
|
+
added: 'bg-brand-ink',
|
|
10
|
+
removed: 'bg-destructive',
|
|
11
|
+
};
|
|
12
|
+
const KIND_TEXT = {
|
|
13
|
+
context: 'text-muted-foreground',
|
|
14
|
+
added: 'text-foreground',
|
|
15
|
+
removed: 'text-foreground',
|
|
16
|
+
};
|
|
17
|
+
/** How much of a line changed, as a fraction, clamped to the line it is on. */
|
|
18
|
+
function density(line) {
|
|
19
|
+
if (line.changed === undefined || line.content.length === 0)
|
|
20
|
+
return 0;
|
|
21
|
+
const covered = line.changed.reduce((total, [start, end]) => {
|
|
22
|
+
const from = Math.max(0, Math.min(start, line.content.length));
|
|
23
|
+
const to = Math.max(0, Math.min(end, line.content.length));
|
|
24
|
+
return total + Math.max(0, to - from);
|
|
25
|
+
}, 0);
|
|
26
|
+
// Clamped, because two ranges that overlap would otherwise report more than the
|
|
27
|
+
// whole line changed and a bar past the end of its own gutter says nothing.
|
|
28
|
+
return Math.min(covered / line.content.length, 1);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The line's text with its changed runs emphasised, and the rest left alone.
|
|
32
|
+
*
|
|
33
|
+
* The emphasis is weight, not colour. A diff that tinted its changed words green
|
|
34
|
+
* and red would be leaning on the two hues a reader is most likely to be unable to
|
|
35
|
+
* distinguish, and the tint would also fight the line's own state colour. A bolder
|
|
36
|
+
* weight inside a line that is already marked as added or removed says what
|
|
37
|
+
* changed without adding a second colour channel, and it survives greyscale,
|
|
38
|
+
* which is the condition any encoding here has to survive eventually.
|
|
39
|
+
*/
|
|
40
|
+
function emphasised(line) {
|
|
41
|
+
const ranges = (line.changed ?? [])
|
|
42
|
+
.map(([start, end]) => [Math.max(0, start), Math.min(end, line.content.length)])
|
|
43
|
+
.filter(([start, end]) => end > start)
|
|
44
|
+
.sort((a, b) => a[0] - b[0]);
|
|
45
|
+
if (ranges.length === 0)
|
|
46
|
+
return line.content;
|
|
47
|
+
const parts = [];
|
|
48
|
+
let at = 0;
|
|
49
|
+
ranges.forEach(([start, end], index) => {
|
|
50
|
+
if (start > at)
|
|
51
|
+
parts.push(line.content.slice(at, start));
|
|
52
|
+
parts.push(_jsx("strong", { className: "font-semibold", children: line.content.slice(start, end) }, `${start}-${end}-${index}`));
|
|
53
|
+
at = end;
|
|
54
|
+
});
|
|
55
|
+
if (at < line.content.length)
|
|
56
|
+
parts.push(line.content.slice(at));
|
|
57
|
+
return parts;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* A change, as lines with the numbers they had and the numbers they have.
|
|
61
|
+
*
|
|
62
|
+
* **The bar is change density, not a side marker.** A diff conventionally marks
|
|
63
|
+
* each line with a coloured wash and a rail, which tells a reader that a line
|
|
64
|
+
* changed and nothing about how much. Rewriting one identifier in a long line
|
|
65
|
+
* leaves the same mark as replacing the whole line, so the reader's eye, which is
|
|
66
|
+
* fast at finding saturated bands, is drawn to the least interesting change in the
|
|
67
|
+
* file. Here the bar's width is the fraction of the line that actually changed, so
|
|
68
|
+
* the eye goes to the line that was rewritten rather than the line that was
|
|
69
|
+
* touched, and the marks that used to be a wash become a measurement.
|
|
70
|
+
*
|
|
71
|
+
* **The line numbers carry the side, not the colour.** An added line has a new
|
|
72
|
+
* number and no old one; a removed line the reverse. That asymmetry is structural,
|
|
73
|
+
* it is how every diff reader a developer has ever used distinguishes the two, and
|
|
74
|
+
* it does not depend on distinguishing red from green. The colour is redundant on
|
|
75
|
+
* top of it, which is the right way round: the shape carries the meaning and the
|
|
76
|
+
* colour reinforces it.
|
|
77
|
+
*
|
|
78
|
+
* **It is a table, because a diff is two columns of numbers beside a column of
|
|
79
|
+
* text.** Row and column navigation, the count of lines, and the association
|
|
80
|
+
* between a line and its number all come from the semantics rather than from a
|
|
81
|
+
* grid of divs, and a reader moving by row hears the file the way they read it.
|
|
82
|
+
*
|
|
83
|
+
* **The changed words are emphasised by weight.** See the note on the helper: a
|
|
84
|
+
* diff that tinted them would spend the two hues a reader is most likely to be
|
|
85
|
+
* unable to tell apart, and weight survives greyscale.
|
|
86
|
+
*/
|
|
87
|
+
function Diff({ lines, label, labels, file, summary, className, empty, ...props }) {
|
|
88
|
+
if (lines.length === 0) {
|
|
89
|
+
// A diff with nothing in it is a state a caller reaches, and an empty grid
|
|
90
|
+
// with no words in it is a gap rather than a state.
|
|
91
|
+
return (_jsx("div", { "data-slot": "diff-empty", className: cn('text-muted-foreground text-sm', className), children: empty ?? null }));
|
|
92
|
+
}
|
|
93
|
+
const added = lines.filter((line) => (line.kind ?? 'context') === 'added').length;
|
|
94
|
+
const removed = lines.filter((line) => line.kind === 'removed').length;
|
|
95
|
+
return (_jsxs("div", { "data-slot": "diff", className: cn('border-border flex flex-col overflow-hidden rounded-md border', className), ...props, children: [_jsxs("div", { "data-slot": "diff-header", className: "border-border bg-muted/40 flex items-baseline justify-between gap-3 border-b px-3 py-2", children: [_jsx("span", { "data-slot": "diff-file", className: "text-foreground min-w-0 truncate text-sm font-medium", children: file ?? null }), summary === undefined ? (_jsx("span", { "data-slot": "diff-summary", className: "text-muted-foreground shrink-0 text-xs tabular-nums", "data-added": added, "data-removed": removed })) : (_jsx("span", { "data-slot": "diff-summary", className: "text-muted-foreground shrink-0 text-xs tabular-nums", children: summary }))] }), _jsx("table", { "data-slot": "diff-table", "aria-label": label, className: "w-full table-fixed border-collapse", children: _jsx("tbody", { children: lines.map((line, index) => {
|
|
96
|
+
const kind = line.kind ?? 'context';
|
|
97
|
+
const share = density(line);
|
|
98
|
+
return (_jsxs("tr", { "data-kind": kind, children: [_jsx("td", { "data-slot": "diff-old-number", className: "text-muted-foreground w-10 border-r border-transparent px-2 text-right align-top text-xs tabular-nums select-none", children: line.oldNumber ?? null }), _jsx("td", { "data-slot": "diff-new-number", className: "text-muted-foreground w-10 border-r border-transparent px-2 text-right align-top text-xs tabular-nums select-none", children: line.newNumber ?? null }), _jsx("td", { "data-slot": "diff-gutter", className: "w-1.5 border-r border-transparent p-0 align-stretch", children: kind === 'context' ? null : (_jsx("span", { "data-slot": "diff-bar", "aria-hidden": "true", className: cn('block h-full min-h-5 w-full', KIND_BAR[kind]),
|
|
99
|
+
/*
|
|
100
|
+
* The floor applies only when the density is unknown, which is
|
|
101
|
+
* a changed line the caller gave no ranges for. It does not
|
|
102
|
+
* apply to a measured density, because a floor on a real
|
|
103
|
+
* measurement overstates it: a one-character change in a long
|
|
104
|
+
* line is half a percent, and drawing it at twelve percent
|
|
105
|
+
* would have the bar claim something the data does not say,
|
|
106
|
+
* which is the one thing a measurement is not allowed to do.
|
|
107
|
+
* The floor exists to keep a line with no reported ranges
|
|
108
|
+
* findable, and that is the only case it serves.
|
|
109
|
+
*/
|
|
110
|
+
style: { width: `${(share > 0 ? share : 0.12) * 100}%` } })) }), _jsx("td", { "data-slot": "diff-content", "aria-label": labels[kind], className: cn('px-3 py-0.5 text-left font-mono text-xs leading-relaxed', KIND_TEXT[kind]), children: emphasised(line) })] }, `${kind}-${line.oldNumber ?? 'x'}-${line.newNumber ?? 'x'}-${index}`));
|
|
111
|
+
}) }) })] }));
|
|
112
|
+
}
|
|
113
|
+
export { Diff };
|
|
@@ -43,6 +43,24 @@ export interface DropdownMenuContentProps extends ComponentProps<'div'> {
|
|
|
43
43
|
* crosses the package seam (ticket 07 section 6).
|
|
44
44
|
*/
|
|
45
45
|
export interface DropdownMenuItemProps extends ComponentProps<'div'> {
|
|
46
|
+
/**
|
|
47
|
+
* The element the item is rendered as.
|
|
48
|
+
*
|
|
49
|
+
* Declared here rather than re-exported from Base UI so no upstream type crosses
|
|
50
|
+
* the package seam (ticket 07 section 6), and narrowed to the element form of
|
|
51
|
+
* the two Base UI accepts. The narrowing is stated because it is a narrowing:
|
|
52
|
+
* Base UI also takes a function of the props and the component's state, and that
|
|
53
|
+
* form is not forwarded, because typing it means naming Base UI's own prop and
|
|
54
|
+
* event types in a declaration a consumer reads. The element form is the one a
|
|
55
|
+
* menu of links needs, since the attributes that make a row a destination are
|
|
56
|
+
* the attributes of the anchor itself.
|
|
57
|
+
*
|
|
58
|
+
* It is here because a menu item is not always a command: an item that navigates
|
|
59
|
+
* has to BE the link, because a link nested inside a focusable item is two tab
|
|
60
|
+
* stops for one row, and a reader who middle-clicks a row that only looks like a
|
|
61
|
+
* link gets nothing.
|
|
62
|
+
*/
|
|
63
|
+
render?: React.ReactElement;
|
|
46
64
|
/** Whether the item aligns with the labels above it. @defaultValue false */
|
|
47
65
|
inset?: boolean;
|
|
48
66
|
/** Whether the item reads as a destructive action. @defaultValue default */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown-menu.d.ts","sourceRoot":"","sources":["../../../src/components/ui/dropdown-menu.tsx"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dropdown-menu.d.ts","sourceRoot":"","sources":["../../../src/components/ui/dropdown-menu.tsx"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { Menu as MenuPrimitive } from '@base-ui/react/menu';
|
|
4
4
|
import { CheckIcon, ChevronRightIcon, CircleIcon } from 'lucide-react';
|
|
5
|
-
import { cn } from '../../lib/utils';
|
|
5
|
+
import { cn } from '../../lib/utils.js';
|
|
6
6
|
const POPUP = 'bg-popover text-popover-foreground z-50 max-h-(--available-height) min-w-36 overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md outline-none transition-[opacity,transform] duration-fast ease-out data-[starting-style]:scale-95 data-[starting-style]:opacity-0 data-[ending-style]:scale-95 data-[ending-style]:opacity-0';
|
|
7
7
|
const ITEM = 'focus:bg-accent focus:text-accent-foreground data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*="size-"])]:size-4';
|
|
8
8
|
/**
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
/** The props the Form accepts. */
|
|
3
|
+
export interface FormProps extends Omit<ComponentProps<'form'>, 'onSubmit'> {
|
|
4
|
+
/**
|
|
5
|
+
* The errors the server returned, keyed by field name.
|
|
6
|
+
*
|
|
7
|
+
* This is the whole point of the binding. A submission fails and comes back with
|
|
8
|
+
* a record of what was wrong with it, and a form that cannot take that record has
|
|
9
|
+
* to either drop it or turn it into a banner above the form that the reader has to
|
|
10
|
+
* match to a field themselves. Passed here, each `FormField` named after the key
|
|
11
|
+
* renders it under the control that caused it, and the control is marked invalid.
|
|
12
|
+
* Pass an empty record to clear them: the errors are cleared as data, not by
|
|
13
|
+
* reloading the page. A key with no error is an absent key rather than a key
|
|
14
|
+
* holding nothing, because a record that says "this field is wrong" and does not
|
|
15
|
+
* say how is not one this can draw.
|
|
16
|
+
*/
|
|
17
|
+
errors?: Record<string, string | string[]>;
|
|
18
|
+
/**
|
|
19
|
+
* Called with the field values when the form submits.
|
|
20
|
+
*
|
|
21
|
+
* The native submit event is prevented, so this is where a server action goes.
|
|
22
|
+
* Nothing is submitted to the browser and no navigation happens unless the caller
|
|
23
|
+
* does it.
|
|
24
|
+
*/
|
|
25
|
+
onSubmit?: (values: Record<string, unknown>) => void;
|
|
26
|
+
/**
|
|
27
|
+
* Whether the browser's own validation bubbles are off. @defaultValue true
|
|
28
|
+
*
|
|
29
|
+
* On by default, because the binding reports validity on the field and a form
|
|
30
|
+
* that shows the browser's bubble and a styled message is two reports of one
|
|
31
|
+
* problem, in two places, in two voices.
|
|
32
|
+
*/
|
|
33
|
+
noValidate?: boolean;
|
|
34
|
+
}
|
|
35
|
+
/** The props the Form field accepts. */
|
|
36
|
+
export interface FormFieldProps extends ComponentProps<'div'> {
|
|
37
|
+
/**
|
|
38
|
+
* The name of the field, and the key its error arrives under.
|
|
39
|
+
*
|
|
40
|
+
* Required, and it is the join between the control's `name`, the key in the
|
|
41
|
+
* server's `errors` and the field the error is drawn under. A field that is not
|
|
42
|
+
* named cannot receive an error, so this is the one prop that makes the rest of
|
|
43
|
+
* the binding work.
|
|
44
|
+
*/
|
|
45
|
+
name: string;
|
|
46
|
+
/**
|
|
47
|
+
* The rule the field is checked against, returning the message to show.
|
|
48
|
+
*
|
|
49
|
+
* The message is the caller's, because it is a sentence about their product's
|
|
50
|
+
* rules. Returning nothing means the value is valid.
|
|
51
|
+
*/
|
|
52
|
+
validate?: (value: unknown) => string | string[] | null | void;
|
|
53
|
+
/** Whether the field is invalid, for a value a library of the caller's owns. */
|
|
54
|
+
invalid?: boolean;
|
|
55
|
+
/** Whether the field ignores interaction. */
|
|
56
|
+
disabled?: boolean;
|
|
57
|
+
}
|
|
58
|
+
/** The props the Form label accepts. */
|
|
59
|
+
export interface FormLabelProps extends ComponentProps<'label'> {
|
|
60
|
+
}
|
|
61
|
+
/** The props the Form description accepts. */
|
|
62
|
+
export interface FormDescriptionProps extends ComponentProps<'p'> {
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The props the Form control accepts.
|
|
66
|
+
*
|
|
67
|
+
* Declared here rather than as `ComponentProps<typeof FieldPrimitive.Control>`,
|
|
68
|
+
* for the same reason `Progress` declares its own props rather than re-exporting
|
|
69
|
+
* Base UI's (ticket 07 section 6): an upstream type in the signature reaches the
|
|
70
|
+
* emitted declaration, and the surface gate fails a declaration file that names
|
|
71
|
+
* an upstream module. A consumer would then need Base UI resolvable to typecheck a
|
|
72
|
+
* Prism import, which is the seam the rule exists to keep closed.
|
|
73
|
+
*
|
|
74
|
+
* It is `ComponentProps<'input'>` because that is the element the control renders
|
|
75
|
+
* by default, and naming the element is more honest than naming a `div` and being
|
|
76
|
+
* wrong about every attribute. A caller who swaps the element for a select or a
|
|
77
|
+
* textarea passes that element's own attributes and the runtime does the rest; the
|
|
78
|
+
* type here is the default case, not a limit on what may be rendered.
|
|
79
|
+
*/
|
|
80
|
+
export interface FormControlProps extends ComponentProps<'input'> {
|
|
81
|
+
}
|
|
82
|
+
/** The props the Form error accepts. */
|
|
83
|
+
export interface FormErrorProps extends ComponentProps<'div'> {
|
|
84
|
+
/**
|
|
85
|
+
* What the reader can do about the error, drawn after the message.
|
|
86
|
+
*
|
|
87
|
+
* The message and the way out are one unit. "That address is already registered"
|
|
88
|
+
* with nothing after it is a dead end, and the reader is left to guess whether
|
|
89
|
+
* they should sign in instead, change the address or ask somebody. So this
|
|
90
|
+
* Component renders both in the same live region: the recovery is announced with
|
|
91
|
+
* the problem rather than being something the reader has to find.
|
|
92
|
+
*/
|
|
93
|
+
action?: React.ReactNode;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* The form binding: a form, its fields, and the errors that came back from it.
|
|
97
|
+
*
|
|
98
|
+
* **`Field` is the layout; this is the wiring.** `Field` is presentational and says
|
|
99
|
+
* so: nothing in it generates an `id`, so the consumer owns the control's id and
|
|
100
|
+
* wires it to the label's `htmlFor` and to the description or error's `id` through
|
|
101
|
+
* `aria-describedby`. That is the right default for a layout, and it is a lot of
|
|
102
|
+
* hand-written ids in a form with eleven fields, none of which a reader can see
|
|
103
|
+
* and all of which a screen reader depends on. This module is the part that
|
|
104
|
+
* generates them: `FormField` owns the name, `FormControl` registers itself with
|
|
105
|
+
* the field, and `FormLabel` and `FormDescription` find the control and point at
|
|
106
|
+
* it. Nothing here changes how `Field` looks.
|
|
107
|
+
*
|
|
108
|
+
* **A server error arrives as data and lands under the control that caused it.**
|
|
109
|
+
* `errors` is a record keyed by field name and `FormField` is keyed by the same
|
|
110
|
+
* name, so the message a submission came back with is drawn under the control the
|
|
111
|
+
* reader has to fix, the control is marked invalid, and the message is added to the
|
|
112
|
+
* control's description so it is read out when the reader reaches the field. The
|
|
113
|
+
* errors clear when the record clears: a field that fixed itself still shows the
|
|
114
|
+
* server's complaint until the caller stops passing it, which is exactly as
|
|
115
|
+
* honest as it sounds.
|
|
116
|
+
*
|
|
117
|
+
* **The error and the way out are rendered together, in one live region.** The
|
|
118
|
+
* recovery is the half of an error that is usually missing. A `FormError` renders
|
|
119
|
+
* the message and then the caller's `action`, and the region is in the document
|
|
120
|
+
* before either of them is, because a live region inserted at the same moment as
|
|
121
|
+
* its content is not announced by every screen reader. The region is therefore
|
|
122
|
+
* present and empty while the field is valid, which is the cost of the reliable
|
|
123
|
+
* half.
|
|
124
|
+
*
|
|
125
|
+
* **Use a `FormControl` inside a `FormField`.** The control is the part that
|
|
126
|
+
* registers itself, which is what makes the label's `for` resolve and what puts the
|
|
127
|
+
* description and the error into the control's accessible description. A plain
|
|
128
|
+
* `Input` renders and submits perfectly well inside a `FormField` and is not
|
|
129
|
+
* registered, so its label points at an id that is on nothing and its error is
|
|
130
|
+
* never announced with it. That is the one rule this module asks for, and it is
|
|
131
|
+
* the rule `Field` deliberately leaves to the caller.
|
|
132
|
+
*/
|
|
133
|
+
declare function Form({ errors, onSubmit, noValidate, className, ...props }: FormProps): import("react").JSX.Element;
|
|
134
|
+
/** One field's name, its rule and the control that answers to it. */
|
|
135
|
+
declare function FormField({ name, validate, invalid, disabled, className, ...props }: FormFieldProps): import("react").JSX.Element;
|
|
136
|
+
/** The control's accessible name, associated with it rather than placed near it. */
|
|
137
|
+
declare function FormLabel({ className, ...props }: FormLabelProps): import("react").JSX.Element;
|
|
138
|
+
/** The control itself, registered with the field so the label and errors find it. */
|
|
139
|
+
declare function FormControl({ className, ...props }: FormControlProps): import("react").JSX.Element;
|
|
140
|
+
/** A short helper line under the control, announced with the control itself. */
|
|
141
|
+
declare function FormDescription({ className, ...props }: FormDescriptionProps): import("react").JSX.Element;
|
|
142
|
+
/**
|
|
143
|
+
* The field's error and what to do about it, in one announced region.
|
|
144
|
+
*
|
|
145
|
+
* The region is always in the document and the message is not, because a live
|
|
146
|
+
* region that arrives with its content is missed by some screen readers. It is
|
|
147
|
+
* empty while the field is valid.
|
|
148
|
+
*/
|
|
149
|
+
declare function FormError({ className, action, ...props }: FormErrorProps): import("react").JSX.Element;
|
|
150
|
+
export { Form, FormControl, FormDescription, FormError, FormField, FormLabel };
|
|
151
|
+
//# sourceMappingURL=form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../../src/components/ui/form.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAI3C,kCAAkC;AAClC,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IACzE;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAA;IAC1C;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;IACpD;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,wCAAwC;AACxC,MAAM,WAAW,cAAe,SAAQ,cAAc,CAAC,KAAK,CAAC;IAC3D;;;;;;;OAOG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,GAAG,IAAI,CAAA;IAC9D,gFAAgF;IAChF,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,wCAAwC;AACxC,MAAM,WAAW,cAAe,SAAQ,cAAc,CAAC,OAAO,CAAC;CAAG;AAElE,8CAA8C;AAC9C,MAAM,WAAW,oBAAqB,SAAQ,cAAc,CAAC,GAAG,CAAC;CAAG;AAEpE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,gBAAiB,SAAQ,cAAc,CAAC,OAAO,CAAC;CAAG;AAEpE,wCAAwC;AACxC,MAAM,WAAW,cAAe,SAAQ,cAAc,CAAC,KAAK,CAAC;IAC3D;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,iBAAS,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAiB,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,SAAS,+BAUpF;AAED,qEAAqE;AACrE,iBAAS,SAAS,CAAC,EACjB,IAAI,EACJ,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,SAAS,EACT,GAAG,KAAK,EACT,EAAE,cAAc,+BAYhB;AAED,oFAAoF;AACpF,iBAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,+BAQzD;AAED,qFAAqF;AACrF,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,gBAAgB,+BAc7D;AAED,gFAAgF;AAChF,iBAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,oBAAoB,+BAQrE;AAED;;;;;;GAMG;AACH,iBAAS,SAAS,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,+BAyBjE;AAED,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,eAAe,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,CAAA"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Field as FieldPrimitive } from '@base-ui/react/field';
|
|
4
|
+
import { Form as FormPrimitive } from '@base-ui/react/form';
|
|
5
|
+
import { cn } from '../../lib/utils.js';
|
|
6
|
+
/**
|
|
7
|
+
* The form binding: a form, its fields, and the errors that came back from it.
|
|
8
|
+
*
|
|
9
|
+
* **`Field` is the layout; this is the wiring.** `Field` is presentational and says
|
|
10
|
+
* so: nothing in it generates an `id`, so the consumer owns the control's id and
|
|
11
|
+
* wires it to the label's `htmlFor` and to the description or error's `id` through
|
|
12
|
+
* `aria-describedby`. That is the right default for a layout, and it is a lot of
|
|
13
|
+
* hand-written ids in a form with eleven fields, none of which a reader can see
|
|
14
|
+
* and all of which a screen reader depends on. This module is the part that
|
|
15
|
+
* generates them: `FormField` owns the name, `FormControl` registers itself with
|
|
16
|
+
* the field, and `FormLabel` and `FormDescription` find the control and point at
|
|
17
|
+
* it. Nothing here changes how `Field` looks.
|
|
18
|
+
*
|
|
19
|
+
* **A server error arrives as data and lands under the control that caused it.**
|
|
20
|
+
* `errors` is a record keyed by field name and `FormField` is keyed by the same
|
|
21
|
+
* name, so the message a submission came back with is drawn under the control the
|
|
22
|
+
* reader has to fix, the control is marked invalid, and the message is added to the
|
|
23
|
+
* control's description so it is read out when the reader reaches the field. The
|
|
24
|
+
* errors clear when the record clears: a field that fixed itself still shows the
|
|
25
|
+
* server's complaint until the caller stops passing it, which is exactly as
|
|
26
|
+
* honest as it sounds.
|
|
27
|
+
*
|
|
28
|
+
* **The error and the way out are rendered together, in one live region.** The
|
|
29
|
+
* recovery is the half of an error that is usually missing. A `FormError` renders
|
|
30
|
+
* the message and then the caller's `action`, and the region is in the document
|
|
31
|
+
* before either of them is, because a live region inserted at the same moment as
|
|
32
|
+
* its content is not announced by every screen reader. The region is therefore
|
|
33
|
+
* present and empty while the field is valid, which is the cost of the reliable
|
|
34
|
+
* half.
|
|
35
|
+
*
|
|
36
|
+
* **Use a `FormControl` inside a `FormField`.** The control is the part that
|
|
37
|
+
* registers itself, which is what makes the label's `for` resolve and what puts the
|
|
38
|
+
* description and the error into the control's accessible description. A plain
|
|
39
|
+
* `Input` renders and submits perfectly well inside a `FormField` and is not
|
|
40
|
+
* registered, so its label points at an id that is on nothing and its error is
|
|
41
|
+
* never announced with it. That is the one rule this module asks for, and it is
|
|
42
|
+
* the rule `Field` deliberately leaves to the caller.
|
|
43
|
+
*/
|
|
44
|
+
function Form({ errors, onSubmit, noValidate = true, className, ...props }) {
|
|
45
|
+
return (_jsx(FormPrimitive, { className: cn('flex w-full flex-col gap-6', className), noValidate: noValidate, ...(errors === undefined ? null : { errors }), onFormSubmit: (values) => onSubmit?.(values), ...props }));
|
|
46
|
+
}
|
|
47
|
+
/** One field's name, its rule and the control that answers to it. */
|
|
48
|
+
function FormField({ name, validate, invalid, disabled, className, ...props }) {
|
|
49
|
+
return (_jsx(FieldPrimitive.Root, { "data-slot": "form-field", name: name, className: cn('flex w-full flex-col gap-1.5', className), ...(validate === undefined ? null : { validate }), ...(invalid === undefined ? null : { invalid }), ...(disabled === undefined ? null : { disabled }), ...props }));
|
|
50
|
+
}
|
|
51
|
+
/** The control's accessible name, associated with it rather than placed near it. */
|
|
52
|
+
function FormLabel({ className, ...props }) {
|
|
53
|
+
return (_jsx(FieldPrimitive.Label, { "data-slot": "form-label", className: cn('text-foreground text-sm leading-none font-medium', className), ...props }));
|
|
54
|
+
}
|
|
55
|
+
/** The control itself, registered with the field so the label and errors find it. */
|
|
56
|
+
function FormControl({ className, ...props }) {
|
|
57
|
+
return (_jsx(FieldPrimitive.Control, { "data-slot": "form-control", className: cn('border-input bg-background text-foreground placeholder:text-muted-foreground flex h-9 w-full min-w-0 rounded-md border px-3 py-1 text-base shadow-xs transition-[color,box-shadow] duration-fast ease-out outline-none md:text-sm', 'focus-visible:border-ring focus-visible:ring-ring focus-visible:ring-[3px]', 'aria-invalid:border-destructive aria-invalid:ring-destructive/20', 'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50', className), ...props }));
|
|
58
|
+
}
|
|
59
|
+
/** A short helper line under the control, announced with the control itself. */
|
|
60
|
+
function FormDescription({ className, ...props }) {
|
|
61
|
+
return (_jsx(FieldPrimitive.Description, { "data-slot": "form-description", className: cn('text-muted-foreground text-sm', className), ...props }));
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The field's error and what to do about it, in one announced region.
|
|
65
|
+
*
|
|
66
|
+
* The region is always in the document and the message is not, because a live
|
|
67
|
+
* region that arrives with its content is missed by some screen readers. It is
|
|
68
|
+
* empty while the field is valid.
|
|
69
|
+
*/
|
|
70
|
+
function FormError({ className, action, ...props }) {
|
|
71
|
+
return (_jsxs("div", { "data-slot": "form-error", role: "alert", className: cn('flex flex-col items-start gap-1', className), ...props, children: [_jsx(FieldPrimitive.Error, { "data-slot": "form-error-message", className: "text-destructive text-sm font-medium" }), action === undefined ? null : (_jsx(FieldPrimitive.Validity, { children: (state) => (state.validity.valid === false ? action : null) }))] }));
|
|
72
|
+
}
|
|
73
|
+
export { Form, FormControl, FormDescription, FormError, FormField, FormLabel };
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The props the HoverCard 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 HoverCardProps {
|
|
9
|
+
/** The controlled open state. */
|
|
10
|
+
open?: boolean;
|
|
11
|
+
/** The initially open state, for an uncontrolled hover card. */
|
|
12
|
+
defaultOpen?: boolean;
|
|
13
|
+
/** Called when the open state changes. */
|
|
14
|
+
onOpenChange?: (open: boolean) => void;
|
|
15
|
+
/** The trigger and the preview. */
|
|
16
|
+
children?: React.ReactNode;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The props HoverCardTrigger forwards to Base UI.
|
|
20
|
+
*
|
|
21
|
+
* Declared here rather than re-exported from Base UI so no upstream type
|
|
22
|
+
* crosses the package seam (ticket 07 section 6).
|
|
23
|
+
*/
|
|
24
|
+
export interface HoverCardTriggerProps extends ComponentProps<'a'> {
|
|
25
|
+
/**
|
|
26
|
+
* How long the pointer must rest on the trigger before the card opens, in
|
|
27
|
+
* milliseconds.
|
|
28
|
+
*
|
|
29
|
+
* A prop and not a fixed number, because the delay is a decision about what
|
|
30
|
+
* counts as intent and a caller whose readers move differently, or whose
|
|
31
|
+
* pointer hardware reports a rest as a hover, has a different answer. What the
|
|
32
|
+
* Component refuses to do is decide that intent is instant, which is the
|
|
33
|
+
* failure a card with no delay always ships: the pointer crossing a line of
|
|
34
|
+
* text opens a surface, and a page of links becomes a page of flashes.
|
|
35
|
+
*
|
|
36
|
+
* @defaultValue 600
|
|
37
|
+
*/
|
|
38
|
+
delay?: number;
|
|
39
|
+
/**
|
|
40
|
+
* How long the card stays open after the pointer leaves it, in milliseconds.
|
|
41
|
+
*
|
|
42
|
+
* This is the half that is easy to leave at zero and that punishes the reader
|
|
43
|
+
* who was about to get what they wanted. Moving from the trigger to the card
|
|
44
|
+
* crosses a gap, and a card that closes on the first pixel outside the trigger
|
|
45
|
+
* closes in the gap, so the reader who did everything right gets nothing. A
|
|
46
|
+
* generous close delay is what makes a rest on the trigger mean something.
|
|
47
|
+
*
|
|
48
|
+
* @defaultValue 300
|
|
49
|
+
*/
|
|
50
|
+
closeDelay?: number;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The props HoverCardContent forwards to Base UI.
|
|
54
|
+
*
|
|
55
|
+
* Declared here rather than re-exported from Base UI so no upstream type
|
|
56
|
+
* crosses the package seam (ticket 07 section 6).
|
|
57
|
+
*/
|
|
58
|
+
export interface HoverCardContentProps extends ComponentProps<'div'> {
|
|
59
|
+
/** Which side of the trigger the card is placed on. @defaultValue bottom */
|
|
60
|
+
side?: 'top' | 'right' | 'bottom' | 'left';
|
|
61
|
+
/** How the card aligns against the trigger. @defaultValue center */
|
|
62
|
+
align?: 'start' | 'center' | 'end';
|
|
63
|
+
/** The distance in pixels between the trigger and the card. @defaultValue 8 */
|
|
64
|
+
sideOffset?: number;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* A preview of a destination, shown when the reader rests on a link.
|
|
68
|
+
*
|
|
69
|
+
* **The delay is the Component's decision, and the close delay is the half that
|
|
70
|
+
* matters.** A card with no open delay opens as the pointer crosses a line of
|
|
71
|
+
* text, so a page of links becomes a page of flashes and a reader learns that
|
|
72
|
+
* resting is punished. A card with no close delay is worse and quieter: the
|
|
73
|
+
* reader rests, waits, sees the card start to appear, moves toward it, and it
|
|
74
|
+
* vanishes in the gap between the trigger and the card, so the one reader who
|
|
75
|
+
* did everything right is the one who gets nothing. Both are delays here, and
|
|
76
|
+
* both are props, because how long a reader's pointer rests is a fact about the
|
|
77
|
+
* reader and not about the design system.
|
|
78
|
+
*
|
|
79
|
+
* **The preview is never the only copy of what it shows.** The trigger is a real
|
|
80
|
+
* anchor, so everything in the card is reachable at the destination without the
|
|
81
|
+
* card ever appearing, and a touch reader, who has no hover at all, is not
|
|
82
|
+
* missing anything. That is the honest way to express "the reader wants this"
|
|
83
|
+
* without punishing a reader on a slow device: the card is an accelerant for a
|
|
84
|
+
* reader with a pointer, and removing it costs the reader nothing. If a fact
|
|
85
|
+
* lives only in the card, it does not exist for half the people who can see it.
|
|
86
|
+
*
|
|
87
|
+
* The card is not a dialog. It takes no focus, traps nothing, and is not
|
|
88
|
+
* announced, because a screen reader is already moving through the link text and
|
|
89
|
+
* a surface that interrupted that to read a summary of it would be a worse
|
|
90
|
+
* version of the same information. For the same reason, put nothing in the card
|
|
91
|
+
* that is not also on the destination.
|
|
92
|
+
*/
|
|
93
|
+
declare function HoverCard({ ...props }: HoverCardProps): import("react").JSX.Element;
|
|
94
|
+
/**
|
|
95
|
+
* The link the card previews. It is an anchor, and it navigates on its own.
|
|
96
|
+
*
|
|
97
|
+
* The href is what makes the card safe to add: the destination is reachable
|
|
98
|
+
* whether or not the card ever opens, so the delay can be as long as intent
|
|
99
|
+
* requires without costing a reader anything they cannot already get.
|
|
100
|
+
*/
|
|
101
|
+
declare function HoverCardTrigger({ className, delay, closeDelay, ...props }: HoverCardTriggerProps): import("react").JSX.Element;
|
|
102
|
+
/** The floating preview surface. */
|
|
103
|
+
declare function HoverCardContent({ className, side, align, sideOffset, ...props }: HoverCardContentProps): import("react").JSX.Element;
|
|
104
|
+
export { HoverCard, HoverCardTrigger, HoverCardContent };
|
|
105
|
+
//# sourceMappingURL=hover-card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hover-card.d.ts","sourceRoot":"","sources":["../../../src/components/ui/hover-card.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAI3C;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,iCAAiC;IACjC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,gEAAgE;IAChE,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,0CAA0C;IAC1C,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,mCAAmC;IACnC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B;AAED;;;;;GAKG;AACH,MAAM,WAAW,qBAAsB,SAAQ,cAAc,CAAC,GAAG,CAAC;IAChE;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,qBAAsB,SAAQ,cAAc,CAAC,KAAK,CAAC;IAClE,4EAA4E;IAC5E,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;IAC1C,oEAAoE;IACpE,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAA;IAClC,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,iBAAS,SAAS,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,+BAE9C;AAED;;;;;;GAMG;AACH,iBAAS,gBAAgB,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,KAAK,EAAE,EAAE,qBAAqB,+BAe1F;AAED,oCAAoC;AACpC,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,IAAe,EACf,KAAgB,EAChB,UAAc,EACd,GAAG,KAAK,EACT,EAAE,qBAAqB,+BAwBvB;AAED,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,CAAA"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { PreviewCard as PreviewCardPrimitive } from '@base-ui/react/preview-card';
|
|
4
|
+
import { cn } from '../../lib/utils.js';
|
|
5
|
+
/**
|
|
6
|
+
* A preview of a destination, shown when the reader rests on a link.
|
|
7
|
+
*
|
|
8
|
+
* **The delay is the Component's decision, and the close delay is the half that
|
|
9
|
+
* matters.** A card with no open delay opens as the pointer crosses a line of
|
|
10
|
+
* text, so a page of links becomes a page of flashes and a reader learns that
|
|
11
|
+
* resting is punished. A card with no close delay is worse and quieter: the
|
|
12
|
+
* reader rests, waits, sees the card start to appear, moves toward it, and it
|
|
13
|
+
* vanishes in the gap between the trigger and the card, so the one reader who
|
|
14
|
+
* did everything right is the one who gets nothing. Both are delays here, and
|
|
15
|
+
* both are props, because how long a reader's pointer rests is a fact about the
|
|
16
|
+
* reader and not about the design system.
|
|
17
|
+
*
|
|
18
|
+
* **The preview is never the only copy of what it shows.** The trigger is a real
|
|
19
|
+
* anchor, so everything in the card is reachable at the destination without the
|
|
20
|
+
* card ever appearing, and a touch reader, who has no hover at all, is not
|
|
21
|
+
* missing anything. That is the honest way to express "the reader wants this"
|
|
22
|
+
* without punishing a reader on a slow device: the card is an accelerant for a
|
|
23
|
+
* reader with a pointer, and removing it costs the reader nothing. If a fact
|
|
24
|
+
* lives only in the card, it does not exist for half the people who can see it.
|
|
25
|
+
*
|
|
26
|
+
* The card is not a dialog. It takes no focus, traps nothing, and is not
|
|
27
|
+
* announced, because a screen reader is already moving through the link text and
|
|
28
|
+
* a surface that interrupted that to read a summary of it would be a worse
|
|
29
|
+
* version of the same information. For the same reason, put nothing in the card
|
|
30
|
+
* that is not also on the destination.
|
|
31
|
+
*/
|
|
32
|
+
function HoverCard({ ...props }) {
|
|
33
|
+
return _jsx(PreviewCardPrimitive.Root, { ...props });
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The link the card previews. It is an anchor, and it navigates on its own.
|
|
37
|
+
*
|
|
38
|
+
* The href is what makes the card safe to add: the destination is reachable
|
|
39
|
+
* whether or not the card ever opens, so the delay can be as long as intent
|
|
40
|
+
* requires without costing a reader anything they cannot already get.
|
|
41
|
+
*/
|
|
42
|
+
function HoverCardTrigger({ className, delay, closeDelay, ...props }) {
|
|
43
|
+
return (_jsx(PreviewCardPrimitive.Trigger, { "data-slot": "hover-card-trigger", ...(delay === undefined ? null : { delay }), ...(closeDelay === undefined ? null : { closeDelay }), className: cn('hover:decoration-foreground rounded-sm text-foreground underline decoration-muted-foreground underline-offset-2 outline-none', 'transition-colors duration-fast ease-out', 'focus-visible:ring-ring focus-visible:ring-[3px]', className), ...props }));
|
|
44
|
+
}
|
|
45
|
+
/** The floating preview surface. */
|
|
46
|
+
function HoverCardContent({ className, side = 'bottom', align = 'center', sideOffset = 8, ...props }) {
|
|
47
|
+
return (_jsx(PreviewCardPrimitive.Portal, { children: _jsx(PreviewCardPrimitive.Positioner, { side: side, align: align, sideOffset: sideOffset, className: "z-50", children: _jsx(PreviewCardPrimitive.Popup, { "data-slot": "hover-card-content", className: cn('bg-popover text-popover-foreground w-72 origin-(--transform-origin) rounded-md border p-4 shadow-md outline-none', 'transition-[opacity,transform] duration-fast ease-out', 'focus-visible:ring-ring focus-visible:ring-[3px]', 'data-[starting-style]:scale-95 data-[starting-style]:opacity-0', 'data-[ending-style]:scale-95 data-[ending-style]:opacity-0', className), ...props }) }) }));
|
|
48
|
+
}
|
|
49
|
+
export { HoverCard, HoverCardTrigger, HoverCardContent };
|