@nocoo/basalt 2.2.0 → 3.0.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/README.md +2 -0
- package/ai/COMPATIBILITY.md +11 -1
- package/ai/DESIGN.md +342 -0
- package/ai/INTEGRATION.md +179 -128
- package/ai/RECIPES.md +51 -26
- package/ai/USAGE.md +4 -4
- package/ai/registry.json +2836 -270
- package/dist/charts/config.d.ts +11 -11
- package/dist/charts/config.js +4 -4
- package/dist/charts/config.js.map +1 -1
- package/dist/charts/date-navigation.js +10 -10
- package/dist/charts/date-navigation.js.map +1 -1
- package/dist/charts/donut.js +1 -1
- package/dist/charts/donut.js.map +1 -1
- package/dist/charts/frame.d.ts +1 -1
- package/dist/charts/frame.js +4 -4
- package/dist/charts/frame.js.map +1 -1
- package/dist/charts/gauge.js +5 -5
- package/dist/charts/gauge.js.map +1 -1
- package/dist/charts/heatmap-calendar.js +11 -11
- package/dist/charts/heatmap-calendar.js.map +1 -1
- package/dist/charts/heatmap-matrix.js +8 -8
- package/dist/charts/heatmap-matrix.js.map +1 -1
- package/dist/charts/item-list.js +1 -1
- package/dist/charts/item-list.js.map +1 -1
- package/dist/charts/legend.js +19 -19
- package/dist/charts/legend.js.map +1 -1
- package/dist/charts/palette.js +2 -2
- package/dist/charts/palette.js.map +1 -1
- package/dist/charts/slot-bar.js +2 -2
- package/dist/charts/slot-bar.js.map +1 -1
- package/dist/charts/sparkline.js +38 -23
- package/dist/charts/sparkline.js.map +1 -1
- package/dist/charts/stat-card.d.ts +2 -2
- package/dist/charts/stat-card.js +61 -58
- package/dist/charts/stat-card.js.map +1 -1
- package/dist/charts/timeline.js +18 -9
- package/dist/charts/timeline.js.map +1 -1
- package/dist/charts/tooltip.js +16 -16
- package/dist/charts/tooltip.js.map +1 -1
- package/dist/components/accordion.js +1 -1
- package/dist/components/accordion.js.map +1 -1
- package/dist/components/alert-dialog.js +4 -4
- package/dist/components/alert-dialog.js.map +1 -1
- package/dist/components/app-header.js +8 -8
- package/dist/components/app-header.js.map +1 -1
- package/dist/components/app-shell.js +1 -1
- package/dist/components/app-shell.js.map +1 -1
- package/dist/components/approval-card.d.ts +13 -0
- package/dist/components/approval-card.js +161 -0
- package/dist/components/approval-card.js.map +1 -0
- package/dist/components/avatar.d.ts +12 -0
- package/dist/components/avatar.js +39 -18
- package/dist/components/avatar.js.map +1 -1
- package/dist/components/badge.js +8 -8
- package/dist/components/badge.js.map +1 -1
- package/dist/components/banner.d.ts +2 -2
- package/dist/components/banner.js +9 -8
- package/dist/components/banner.js.map +1 -1
- package/dist/components/basalt-mark.js +1 -1
- package/dist/components/basalt-mark.js.map +1 -1
- package/dist/components/battery-meter.js +5 -5
- package/dist/components/battery-meter.js.map +1 -1
- package/dist/components/breadcrumbs.js +6 -6
- package/dist/components/breadcrumbs.js.map +1 -1
- package/dist/components/button.js +10 -10
- package/dist/components/button.js.map +1 -1
- package/dist/components/chat-bubble.js +4 -3
- package/dist/components/chat-bubble.js.map +1 -1
- package/dist/components/chat-composer.d.ts +21 -3
- package/dist/components/chat-composer.js +126 -60
- package/dist/components/chat-composer.js.map +1 -1
- package/dist/components/chat-header.js +6 -6
- package/dist/components/chat-header.js.map +1 -1
- package/dist/components/chat-inbox.js +34 -30
- package/dist/components/chat-inbox.js.map +1 -1
- package/dist/components/chat-markdown.d.ts +8 -0
- package/dist/components/chat-markdown.js +122 -0
- package/dist/components/chat-markdown.js.map +1 -0
- package/dist/components/chat-message.d.ts +26 -0
- package/dist/components/chat-message.js +145 -0
- package/dist/components/chat-message.js.map +1 -0
- package/dist/components/checkbox.js +11 -11
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/clipboard-text.js +3 -3
- package/dist/components/clipboard-text.js.map +1 -1
- package/dist/components/code.d.ts +22 -20
- package/dist/components/code.js +94 -32
- package/dist/components/code.js.map +1 -1
- package/dist/components/collapsible.js +8 -4
- package/dist/components/collapsible.js.map +1 -1
- package/dist/components/command-palette.js +73 -47
- package/dist/components/command-palette.js.map +1 -1
- package/dist/components/context-cards.d.ts +15 -0
- package/dist/components/context-cards.js +148 -0
- package/dist/components/context-cards.js.map +1 -0
- package/dist/components/context-menu.d.ts +1 -1
- package/dist/components/context-menu.js +18 -14
- package/dist/components/context-menu.js.map +1 -1
- package/dist/components/data-table.d.ts +8 -2
- package/dist/components/data-table.js +161 -106
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.js +13 -13
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/delete-resource.js +1 -1
- package/dist/components/delete-resource.js.map +1 -1
- package/dist/components/description-list.js +3 -3
- package/dist/components/description-list.js.map +1 -1
- package/dist/components/dialog.d.ts +2 -2
- package/dist/components/dialog.js +8 -8
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/diff-table.d.ts +15 -0
- package/dist/components/diff-table.js +146 -0
- package/dist/components/diff-table.js.map +1 -0
- package/dist/components/dock.js +2 -2
- package/dist/components/dock.js.map +1 -1
- package/dist/components/dropdown-menu.js +23 -18
- package/dist/components/dropdown-menu.js.map +1 -1
- package/dist/components/editable-nav-item.js +63 -58
- package/dist/components/editable-nav-item.js.map +1 -1
- package/dist/components/empty.js +6 -6
- package/dist/components/empty.js.map +1 -1
- package/dist/components/fab.js +1 -1
- package/dist/components/fab.js.map +1 -1
- package/dist/components/field.js +3 -3
- package/dist/components/field.js.map +1 -1
- package/dist/components/file-dropzone.js +7 -7
- package/dist/components/file-dropzone.js.map +1 -1
- package/dist/components/filter-bar.js +6 -6
- package/dist/components/filter-bar.js.map +1 -1
- package/dist/components/flow.js +4 -3
- package/dist/components/flow.js.map +1 -1
- package/dist/components/grid.d.ts +3 -1
- package/dist/components/grid.js +15 -8
- package/dist/components/grid.js.map +1 -1
- package/dist/components/hover-card.js +1 -1
- package/dist/components/hover-card.js.map +1 -1
- package/dist/components/icon-picker.d.ts +8 -2
- package/dist/components/icon-picker.js +75 -47
- package/dist/components/icon-picker.js.map +1 -1
- package/dist/components/inline-editable.js +6 -6
- package/dist/components/inline-editable.js.map +1 -1
- package/dist/components/input-area.js +3 -3
- package/dist/components/input-area.js.map +1 -1
- package/dist/components/input-group.js +5 -5
- package/dist/components/input-group.js.map +1 -1
- package/dist/components/input.js +4 -4
- package/dist/components/input.js.map +1 -1
- package/dist/components/label.js +3 -3
- package/dist/components/label.js.map +1 -1
- package/dist/components/layer-card.d.ts +9 -4
- package/dist/components/layer-card.js +72 -67
- package/dist/components/layer-card.js.map +1 -1
- package/dist/components/loader.d.ts +16 -10
- package/dist/components/loader.js +46 -53
- package/dist/components/loader.js.map +1 -1
- package/dist/components/loading-screen.js +3 -3
- package/dist/components/loading-screen.js.map +1 -1
- package/dist/components/menu-bar.js +32 -27
- package/dist/components/menu-bar.js.map +1 -1
- package/dist/components/meter.d.ts +5 -5
- package/dist/components/meter.js +25 -12
- package/dist/components/meter.js.map +1 -1
- package/dist/components/multi-select.js +66 -62
- package/dist/components/multi-select.js.map +1 -1
- package/dist/components/navigation-menu.d.ts +2 -2
- package/dist/components/navigation-menu.js +22 -8
- package/dist/components/navigation-menu.js.map +1 -1
- package/dist/components/overlay.js +2 -2
- package/dist/components/overlay.js.map +1 -1
- package/dist/components/page-header.d.ts +3 -1
- package/dist/components/page-header.js +12 -12
- package/dist/components/page-header.js.map +1 -1
- package/dist/components/pagination.js +3 -3
- package/dist/components/pagination.js.map +1 -1
- package/dist/components/popover.js +18 -23
- package/dist/components/popover.js.map +1 -1
- package/dist/components/prompt-bar.d.ts +16 -0
- package/dist/components/prompt-bar.js +49 -0
- package/dist/components/prompt-bar.js.map +1 -0
- package/dist/components/radio.js +9 -9
- package/dist/components/radio.js.map +1 -1
- package/dist/components/recommendation-card.d.ts +13 -0
- package/dist/components/recommendation-card.js +123 -0
- package/dist/components/recommendation-card.js.map +1 -0
- package/dist/components/resource-list.js +1 -1
- package/dist/components/resource-list.js.map +1 -1
- package/dist/components/responsive-master-detail.js +4 -4
- package/dist/components/responsive-master-detail.js.map +1 -1
- package/dist/components/scroll-area.js +3 -3
- package/dist/components/scroll-area.js.map +1 -1
- package/dist/components/section-rule.d.ts +5 -3
- package/dist/components/section-rule.js +12 -12
- package/dist/components/section-rule.js.map +1 -1
- package/dist/components/segment-control.js +3 -3
- package/dist/components/segment-control.js.map +1 -1
- package/dist/components/select.js +47 -32
- package/dist/components/select.js.map +1 -1
- package/dist/components/sensitive-input.js +17 -19
- package/dist/components/sensitive-input.js.map +1 -1
- package/dist/components/sheet.d.ts +4 -4
- package/dist/components/sheet.js +11 -10
- package/dist/components/sheet.js.map +1 -1
- package/dist/components/sidebar.js +146 -137
- package/dist/components/sidebar.js.map +1 -1
- package/dist/components/skeleton-line.d.ts +1 -1
- package/dist/components/skeleton-line.js +2 -2
- package/dist/components/skeleton-line.js.map +1 -1
- package/dist/components/slider.js +2 -2
- package/dist/components/slider.js.map +1 -1
- package/dist/components/stat-strip.js +5 -4
- package/dist/components/stat-strip.js.map +1 -1
- package/dist/components/switch.js +6 -6
- package/dist/components/switch.js.map +1 -1
- package/dist/components/table-of-contents.js +5 -5
- package/dist/components/table-of-contents.js.map +1 -1
- package/dist/components/table-pager.js +2 -2
- package/dist/components/table-pager.js.map +1 -1
- package/dist/components/table.js +4 -4
- package/dist/components/table.js.map +1 -1
- package/dist/components/tabs.js +7 -6
- package/dist/components/tabs.js.map +1 -1
- package/dist/components/tag-badge.d.ts +10 -10
- package/dist/components/tag-badge.js +11 -11
- package/dist/components/tag-badge.js.map +1 -1
- package/dist/components/tag-color-picker.d.ts +8 -1
- package/dist/components/tag-color-picker.js +33 -25
- package/dist/components/tag-color-picker.js.map +1 -1
- package/dist/components/text.js +5 -5
- package/dist/components/text.js.map +1 -1
- package/dist/components/theme-toggle.js +1 -1
- package/dist/components/theme-toggle.js.map +1 -1
- package/dist/components/thinking.d.ts +16 -0
- package/dist/components/thinking.js +85 -0
- package/dist/components/thinking.js.map +1 -0
- package/dist/components/toast.js +25 -20
- package/dist/components/toast.js.map +1 -1
- package/dist/components/toggle-group.js +6 -5
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/toggle.js +6 -6
- package/dist/components/toggle.js.map +1 -1
- package/dist/components/tool-chips.d.ts +12 -0
- package/dist/components/tool-chips.js +138 -0
- package/dist/components/tool-chips.js.map +1 -0
- package/dist/components/toolbar.js +3 -3
- package/dist/components/toolbar.js.map +1 -1
- package/dist/components/tooltip.js +1 -1
- package/dist/components/tooltip.js.map +1 -1
- package/dist/components/typeahead-field.js +59 -56
- package/dist/components/typeahead-field.js.map +1 -1
- package/dist/components/upload-queue.js +15 -14
- package/dist/components/upload-queue.js.map +1 -1
- package/dist/models/agent-feedback.d.ts +44 -0
- package/dist/models/agent-feedback.js +28 -0
- package/dist/models/agent-feedback.js.map +1 -0
- package/dist/models/avatar.d.ts +2 -0
- package/dist/models/avatar.js +15 -0
- package/dist/models/avatar.js.map +1 -0
- package/dist/models/code.d.ts +6 -0
- package/dist/models/code.js +24 -0
- package/dist/models/code.js.map +1 -0
- package/dist/models/context-cards.d.ts +13 -0
- package/dist/models/context-cards.js +17 -0
- package/dist/models/context-cards.js.map +1 -0
- package/dist/models/diff-table.d.ts +12 -0
- package/dist/models/diff-table.js +9 -0
- package/dist/models/diff-table.js.map +1 -0
- package/dist/models/recommendation.d.ts +26 -0
- package/dist/models/recommendation.js +23 -0
- package/dist/models/recommendation.js.map +1 -0
- package/dist/styles/base.css +14 -2
- package/dist/styles/standalone.css +1865 -929
- package/dist/styles/tailwind.css +179 -13
- package/dist/styles/tokens.css +679 -20
- package/dist/utils/cn.js +25 -4
- package/dist/utils/cn.js.map +1 -1
- package/dist/utils/control-surface.d.ts +1 -1
- package/dist/utils/control-surface.js +1 -1
- package/dist/utils/control-surface.js.map +1 -1
- package/dist/utils/navigation.d.ts +3 -0
- package/dist/utils/navigation.js +8 -0
- package/dist/utils/navigation.js.map +1 -0
- package/dist/utils/selection-indicator.d.ts +1 -1
- package/dist/utils/selection-indicator.js +49 -72
- package/dist/utils/selection-indicator.js.map +1 -1
- package/dist/utils/use-hover-highlight.d.ts +4 -0
- package/dist/utils/use-hover-highlight.js +80 -0
- package/dist/utils/use-hover-highlight.js.map +1 -0
- package/dist/viewmodels/use-approval-card.d.ts +20 -0
- package/dist/viewmodels/use-approval-card.js +83 -0
- package/dist/viewmodels/use-approval-card.js.map +1 -0
- package/dist/viewmodels/use-chat-composer.d.ts +16 -0
- package/dist/viewmodels/use-chat-composer.js +34 -0
- package/dist/viewmodels/use-chat-composer.js.map +1 -0
- package/dist/viewmodels/use-chat-message.d.ts +16 -0
- package/dist/viewmodels/use-chat-message.js +26 -0
- package/dist/viewmodels/use-chat-message.js.map +1 -0
- package/dist/viewmodels/use-code-block.d.ts +8 -0
- package/dist/viewmodels/use-code-block.js +38 -0
- package/dist/viewmodels/use-code-block.js.map +1 -0
- package/dist/viewmodels/use-context-cards.d.ts +17 -0
- package/dist/viewmodels/use-context-cards.js +18 -0
- package/dist/viewmodels/use-context-cards.js.map +1 -0
- package/dist/viewmodels/use-diff-table.d.ts +16 -0
- package/dist/viewmodels/use-diff-table.js +42 -0
- package/dist/viewmodels/use-diff-table.js.map +1 -0
- package/dist/viewmodels/use-loader.d.ts +4 -0
- package/dist/viewmodels/use-loader.js +22 -0
- package/dist/viewmodels/use-loader.js.map +1 -0
- package/dist/viewmodels/use-recommendation-card.d.ts +17 -0
- package/dist/viewmodels/use-recommendation-card.js +41 -0
- package/dist/viewmodels/use-recommendation-card.js.map +1 -0
- package/dist/viewmodels/use-thinking.d.ts +13 -0
- package/dist/viewmodels/use-thinking.js +18 -0
- package/dist/viewmodels/use-thinking.js.map +1 -0
- package/dist/viewmodels/use-tool-chips.d.ts +10 -0
- package/dist/viewmodels/use-tool-chips.js +20 -0
- package/dist/viewmodels/use-tool-chips.js.map +1 -0
- package/package.json +3 -1
package/README.md
CHANGED
package/ai/COMPATIBILITY.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Basalt Public API and Compatibility Policy
|
|
2
2
|
|
|
3
|
+
## 3.0 migration
|
|
4
|
+
|
|
5
|
+
Loader now renders an inline span with an eight-cell perimeter grid, an optional shimmering label, and an elapsed timer shown after 5000ms. Use `showLabel={false} showElapsed={false}` for icon-only slots. `size` controls grid dimensions, not the entire row. SVG-specific attributes no longer apply; span attributes do. `animate`, `shimmer`, `showElapsed`, and `elapsedDelayMs` control presentation. Reduced motion stops both animations. The timer measures real elapsed time from mount, including time before it becomes visible, and is hidden from live announcements.
|
|
6
|
+
|
|
7
|
+
Component geometry and DOM styling are intentional major-version changes. Recheck custom selectors and visual snapshots against the current components rather than relying on former utility classes. Action rows are 34px; banners are 46px with 12px vertical and 16px horizontal insets. Compact control spacing remains separate from the 12/16/24/32px card and layout scale. ContentIsland owns page insets and card slots own card padding; remove duplicated wrapper padding rather than overriding shared control tokens.
|
|
8
|
+
|
|
9
|
+
IconPicker trigger names include the current value (`Folder icon: Folder`, then `Folder icon: Book`). Exact-name automation must follow that value; Field labels, validation and descriptions remain attached to the trigger. Standalone application recipes scope native-element resets with `basalt-ui` and explicitly focus mobile drawer openers before opening them. The catalog's visitor-badge login is an intentional layout exception, not a general application-shell template.
|
|
10
|
+
|
|
11
|
+
The historical export baseline below stays frozen. This major release documents actual DOM, geometry and presentation changes; it does not imply removal of those entrypoints or require a React major upgrade.
|
|
12
|
+
|
|
3
13
|
This document defines the stability contracts, export architecture, and semantic versioning guarantees for `@nocoo/basalt`.
|
|
4
14
|
|
|
5
15
|
---
|
|
@@ -144,7 +154,7 @@ These notes cover the components, documentation, examples and palette changes in
|
|
|
144
154
|
|
|
145
155
|
Chart gray retains its prior light/dark values. Marks use solid candy colors without contrasting outlines or shadows; their fills are not darkened. Raw candy fills can fall below 3:1 on light surfaces; use descriptive labels and `summary` / `dataAlternative` alongside them. Custom control palettes remain independent.
|
|
146
156
|
|
|
147
|
-
Named Teal and Purple `Badge` variants
|
|
157
|
+
Named Teal and Purple `Badge` variants retain the Bondi and Grape identities with dedicated light/dark background tokens. Solid color badges (`success`, `red`, `orange`, `teal`, `blue`, `purple`) now use paired semantic foreground tokens, including dark text on brighter dark-theme fills. Do not force white text or substitute raw chart colors for those background/foreground pairs.
|
|
148
158
|
|
|
149
159
|
v2.1.0 includes the palette count and value changes above as an explicit exception to the usual minor-release compatibility policy. Consumers that index colors or persist palette choices must follow these migration notes. The unchanged export baseline alone does not prove runtime-value compatibility.
|
|
150
160
|
|
package/ai/DESIGN.md
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# Basalt Design Contract
|
|
2
|
+
|
|
3
|
+
This is the authoritative design contract for the library, catalog and copyable
|
|
4
|
+
examples. [INTEGRATION.md](INTEGRATION.md) describes composition and public APIs.
|
|
5
|
+
All dimensions below are reference CSS pixels at a 16px root font, not device
|
|
6
|
+
pixels or fixed-height limits. Respect browser font preferences and zoom.
|
|
7
|
+
|
|
8
|
+
## Visual direction
|
|
9
|
+
|
|
10
|
+
Simple, generous and worldly. Use precise alignment, confident type hierarchy,
|
|
11
|
+
matte material and readable proportions rather than scenic dashboard backgrounds,
|
|
12
|
+
decorative frames or empty hero heights. Reading pages and task interfaces have
|
|
13
|
+
different density; opening the page layout must not enlarge compact controls.
|
|
14
|
+
|
|
15
|
+
## Ownership and units
|
|
16
|
+
|
|
17
|
+
- Shared design values belong in `packages/basalt/src/styles/tokens.css` and are
|
|
18
|
+
exposed identically by the Tailwind and standalone entrypoints. Components
|
|
19
|
+
consume tokens; examples must not repair a component through private selectors.
|
|
20
|
+
- Use `rem` for lengths, unitless line-height for text, `em`/`lh` for text-relative
|
|
21
|
+
geometry, and percentages, fractions and intrinsic sizing for layout. Do not
|
|
22
|
+
set the root font-size to a pixel value.
|
|
23
|
+
- DOM measurements, SVG coordinates, data/chart dimensions, aspect ratios and
|
|
24
|
+
caller-owned viewport constraints are geometry, not spacing. Measured CSS pixel
|
|
25
|
+
coordinates are allowed for overlays; never round them to the spacing scale.
|
|
26
|
+
- Model/ViewModel code owns data, state and transitions. Geometry measurement is
|
|
27
|
+
View-only; ViewModels do not import React Views or DOM APIs.
|
|
28
|
+
|
|
29
|
+
## Spacing
|
|
30
|
+
|
|
31
|
+
| Step | Token | Value | Reference |
|
|
32
|
+
| --- | --- | --- | --- |
|
|
33
|
+
| Extra small | `--basalt-space-xs` | `.125rem` | 2px |
|
|
34
|
+
| Small | `--basalt-space-sm` | `.25rem` | 4px |
|
|
35
|
+
| Medium | `--basalt-space-md` | `.375rem` | 6px |
|
|
36
|
+
| Large / default | `--basalt-space-lg`, `--basalt-space-default` | `.5rem` | 8px |
|
|
37
|
+
|
|
38
|
+
These four steps belong to control content: labels, icons, fields, actions,
|
|
39
|
+
selectable rows, menus and banner content. They are not the maximum spacing for a page
|
|
40
|
+
or content surface. Card and layout boundaries use their own four-step roles:
|
|
41
|
+
|
|
42
|
+
| Step | Card token | Layout token | Value | Reference |
|
|
43
|
+
| --- | --- | --- | --- | --- |
|
|
44
|
+
| Small | `--basalt-space-card-sm` | `--basalt-space-layout-sm` | `.75rem` | 12px |
|
|
45
|
+
| Medium | `--basalt-space-card` | `--basalt-space-layout` | `1rem` | 16px |
|
|
46
|
+
| Large | `--basalt-space-card-lg` | `--basalt-space-layout-lg` | `1.5rem` | 24px |
|
|
47
|
+
| Extra large | `--basalt-space-card-xl` | `--basalt-space-layout-xl` | `2rem` | 32px |
|
|
48
|
+
|
|
49
|
+
Card padding defaults to medium. LayerCard header/footer insets are 16px horizontal
|
|
50
|
+
and 12px vertical; Body/Well use 16px. `padding="sm|md|lg|xl"` selects unstructured
|
|
51
|
+
card padding; structured cards keep their slot-owned insets. Compact composite
|
|
52
|
+
card panels use the same 16/12px panel aliases. Their internal buttons and rows
|
|
53
|
+
keep control spacing; do not stretch action rows to the card scale.
|
|
54
|
+
|
|
55
|
+
Layout grids default to medium (16px). ContentIsland owns 16px insets on mobile,
|
|
56
|
+
24px on tablets and 24px vertical / 32px horizontal from 1024px. The catalog shell
|
|
57
|
+
keeps 8px outside the island on mobile and 12px from 768px. Ordinary application
|
|
58
|
+
sections use 24px gaps, including catalog documentation. SectionRule
|
|
59
|
+
uses 12px content separation for compact labels and 16px for reading headings. `Grid gap="sm|md|lg|xl"`
|
|
60
|
+
and semantic utilities such as `gap-basalt-layout-xl` select these tiers.
|
|
61
|
+
There is no universal height for either category.
|
|
62
|
+
|
|
63
|
+
Dialog and AlertDialog panels use 16px outer insets on mobile and 24px from
|
|
64
|
+
640px. Their buttons and fields retain compact control spacing. Sheets and
|
|
65
|
+
small floating menus have separate inset contracts.
|
|
66
|
+
|
|
67
|
+
Metric cards use the shared `StatCard`, not a hand-built Header/Body split. A single
|
|
68
|
+
16px inset owns the title, value, comparison and supporting chart; 12px separates
|
|
69
|
+
the heading, metric and content groups, and 4px separates value/supporting text.
|
|
70
|
+
Keep the comparison next to the metric in reading order, before the chart. Icons
|
|
71
|
+
are small unboxed heading cues, not a second painted surface. Values use tabular
|
|
72
|
+
display numerals and wrap naturally. Compact trend plots use 4rem geometry, not
|
|
73
|
+
`flex-1` to fill the card; analytical charts with axes remain separate surfaces.
|
|
74
|
+
Show the time window and disclose a nonzero line-chart scale. Bar charts keep
|
|
75
|
+
their zero baseline. Metric cards have no internal divider or decorative border.
|
|
76
|
+
|
|
77
|
+
All nonzero padding, margin and gaps use the appropriate category scale or aliases.
|
|
78
|
+
Zero, auto margins and hairline seams are structural exceptions, not new density
|
|
79
|
+
levels. Negative margins may cancel an owned boundary, not invent a new gap.
|
|
80
|
+
Use `p-basalt-card`, `gap-basalt-layout`, `gap-basalt-space-sm`, etc. Default nav
|
|
81
|
+
insets and field gaps remain 8px. Selectable rows use 8px horizontal / 6px vertical
|
|
82
|
+
insets and an 8px icon gap. One component owns each boundary: nested sections must
|
|
83
|
+
not accidentally double outer padding. Indented detail content may derive its
|
|
84
|
+
alignment from the row inset + icon width + gap; this is not another density tier.
|
|
85
|
+
|
|
86
|
+
Existing numbered `--basalt-space-*` tokens are a geometry scale for icons,
|
|
87
|
+
media and shell widths. They are not an alternative margin/padding scale.
|
|
88
|
+
|
|
89
|
+
## Component categories and natural size
|
|
90
|
+
|
|
91
|
+
Choose a category before implementing a component. A composite's root and its
|
|
92
|
+
children can have different categories. Root module inventory:
|
|
93
|
+
|
|
94
|
+
| Category | Reference | Component modules |
|
|
95
|
+
| --- | --- | --- |
|
|
96
|
+
| Inline | 22px single line | `badge`, `tag-badge` |
|
|
97
|
+
| Action | 34px default | `button`, `input`, `select`, `toggle`, `toggle-group`, `segment-control`, `autocomplete`, `combobox`, `typeahead-field`, `sensitive-input`, `input-group`, `input-area`, `clipboard-text`, `inline-editable`, `multi-select`, `date-picker`, `icon-picker`, `tag-color-picker`, `theme-toggle`, `pagination`, `table-pager` |
|
|
98
|
+
| Banner | 38px single line | `banner`, `toast` |
|
|
99
|
+
| Card / content surface | Natural | `layer-card`, `approval-card`, `context-cards`, `recommendation-card`, `chat-bubble`, `code`, `empty`, `file-dropzone`, `resource-list`, `upload-queue` |
|
|
100
|
+
| Layout / composite | Natural | `accordion`, `collapsible`, `app-header`, `app-shell`, `sidebar`, `navigation-menu`, `editable-nav-item`, `breadcrumbs`, `page-header`, `section-rule`, `filter-bar`, `toolbar`, `grid`, `flow`, `field`, `description-list`, `table`, `data-table`, `diff-table`, `tabs`, `table-of-contents`, `responsive-master-detail`, `scroll-area`, `separator`, `stat-strip`, `chat-header`, `chat-inbox`, `chat-message`, `chat-markdown`, `chat-composer`, `prompt-bar`, `thinking`, `tool-chips`, `loading-screen` |
|
|
101
|
+
| Overlay composite | Natural; triggers/actions follow Action | `dialog`, `alert-dialog`, `confirm-dialog`, `delete-resource`, `sheet`, `dock`, `popover`, `hover-card`, `tooltip`, `dropdown-menu`, `context-menu`, `menu-bar`, `command-palette` |
|
|
102
|
+
| Graphic / text primitive | Content-specific | `avatar`, `basalt-mark`, `battery-meter`, `meter`, `loader`, `skeleton-line`, `text`, `label`, `link`, `checkbox`, `radio`, `switch`, `slider`, `fab` |
|
|
103
|
+
|
|
104
|
+
Graphic primitives preserve their intrinsic shape: a checkbox mark is not a
|
|
105
|
+
34px square and an avatar is not a text input. Their containing action rows use
|
|
106
|
+
the Action standard. Inline links retain surrounding typography. Floating and
|
|
107
|
+
mobile shell actions may use the shared 44px touch minimum for accessibility.
|
|
108
|
+
Charts use data geometry; their toolbars still follow Action and spacing rules.
|
|
109
|
+
|
|
110
|
+
The live catalog splits Components into Inline, Actions, Banners, Cards, Layouts,
|
|
111
|
+
Overlays and Primitives. Each begins with an Overview covering design reasoning,
|
|
112
|
+
geometry, interaction and best practices at `/ui/overview/<category>` (singular
|
|
113
|
+
category IDs). Nonvisual theme/link providers live with Layouts. Charts and Blocks
|
|
114
|
+
retain separate navigation groups and their own overviews; blocks still inherit
|
|
115
|
+
the root categories in the inventory above. Existing `/ui/<component>` URLs do
|
|
116
|
+
not change. Catalog navigation, filters and discovery share
|
|
117
|
+
`src/pages/ui/catalog-categories.ts`; guide content is application documentation,
|
|
118
|
+
not a separate set of component tokens or APIs.
|
|
119
|
+
|
|
120
|
+
The shared classes calculate natural size as follows:
|
|
121
|
+
|
|
122
|
+
- `basalt-inline`: 12px font, 16px line box + 2px padding each side + 1px border
|
|
123
|
+
each side = 22px. Text wraps/grows rather than being clipped.
|
|
124
|
+
- `basalt-action`: 14px font, 24px line box + 4px vertical padding each side +
|
|
125
|
+
1px border each side = 34px. Explicit `sm` (28px) and `lg` (40px) are shared
|
|
126
|
+
size variants, not ad-hoc height utilities. Icon-only actions use a minimum
|
|
127
|
+
derived from `1lh`, not a fixed height; icons are normally 14px.
|
|
128
|
+
- `basalt-banner`: 14px font, 22px line box + 12px vertical padding = 46px.
|
|
129
|
+
The outer boundary uses 16px horizontal / 12px vertical panel insets; internal
|
|
130
|
+
icons and actions retain compact control spacing.
|
|
131
|
+
Descriptions, wrapping and actions can make a banner taller.
|
|
132
|
+
- Action rows: 22px text line (`--basalt-line-row`) + 6px vertical padding each
|
|
133
|
+
side = 34px. Body prose/code retain the 20px line box. Compound inputs own one
|
|
134
|
+
outer border; inset children do not add another. Segmented tracks keep 12px text
|
|
135
|
+
on a 20px line box: 30px items + 2px track inset per side = 34px.
|
|
136
|
+
- Cards, dialogs and layout containers have no mandatory height. Textareas and
|
|
137
|
+
chat inputs grow with content (chat: up to five lines, then scroll).
|
|
138
|
+
|
|
139
|
+
Do not use `height`, `max-height`, truncation or overflow clipping to force text
|
|
140
|
+
controls to a target. Use a line box, shared padding and optional minimums.
|
|
141
|
+
Constrain scroll regions, not their individual text rows. Long labels, loading
|
|
142
|
+
indicators, validation text and 200% text zoom must remain usable.
|
|
143
|
+
|
|
144
|
+
Reading surfaces such as code panels contain horizontal overflow without trapping
|
|
145
|
+
vertical page scrolling. Use axis-specific overscroll: contain X, allow Y to chain.
|
|
146
|
+
Natural-height code leaves vertical scrolling to its ancestor; height-constrained
|
|
147
|
+
code scrolls internally and hands off at its top/bottom boundary. Keep native wheel
|
|
148
|
+
and touch behavior instead of intercepting events or converting vertical deltas
|
|
149
|
+
into horizontal movement. Modal scroll locks and editable text inputs have separate
|
|
150
|
+
interaction contracts; do not change their containment as a global workaround.
|
|
151
|
+
|
|
152
|
+
## Radius, typography and color
|
|
153
|
+
|
|
154
|
+
- Radius choices: `--basalt-radius-sm` (.25rem), `-md` (.5rem), `-lg` (.75rem)
|
|
155
|
+
and `-full` (pill/circle); `none` and `inherit` are structural choices. Widget,
|
|
156
|
+
card and island aliases reference those choices; no per-component radii.
|
|
157
|
+
- Typography uses `--basalt-text-*` and `--basalt-leading-*`. Ordinary text is
|
|
158
|
+
at least 11px reference, body/action 14px, code content 12px (`text-basalt-sm`),
|
|
159
|
+
code panel titles 13px (`text-basalt-code`). Display headings use
|
|
160
|
+
the shared larger scale. Do not shrink text to fit a fixed box.
|
|
161
|
+
- Surfaces preserve the matte L0/L1/L2/L3 hierarchy. Controls use the
|
|
162
|
+
surface-relative control fill. Hover uses `--basalt-hover`,
|
|
163
|
+
`--basalt-primary-hover` or `--basalt-destructive-hover`, not caller opacity.
|
|
164
|
+
- Semantic states, tags, data series and brand imagery may choose semantic
|
|
165
|
+
palettes; keep foreground/background pairs and verify both themes. Centralize
|
|
166
|
+
shared values rather than declaring hex colors in component classes. Site-only
|
|
167
|
+
scenery tokens live in `src/styles/site-tokens.css`, not in reusable controls.
|
|
168
|
+
|
|
169
|
+
## Selection and navigation hierarchy
|
|
170
|
+
|
|
171
|
+
- Neutral selection uses `--basalt-selected` and `--basalt-selected-foreground`.
|
|
172
|
+
Selected surfaces are brighter than their container (white in light mode, 22%
|
|
173
|
+
lightness in dark mode), never the darker decorative `accent` or `muted` fill.
|
|
174
|
+
Do not add decorative side bars, selection outlines, shadows or pseudo-element
|
|
175
|
+
frames. Navigation uses foreground contrast and medium weight alongside fill;
|
|
176
|
+
existing semantic checkmarks and tab underlines remain. Both primary and
|
|
177
|
+
secondary text retain at least 4.5:1 contrast.
|
|
178
|
+
- Hover is transient and follows the configured primary. `--basalt-hover` and
|
|
179
|
+
`--basalt-hover-end` are complete CSS colors, mixed against the theme popover
|
|
180
|
+
surface at 9.6%/4.8% in light mode and 16%/9.6% in dark mode. Moving menu and command
|
|
181
|
+
highlights use a subtle gradient between them, without decorative borders.
|
|
182
|
+
SegmentControl and ToggleGroup selected items use `--basalt-primary` and its
|
|
183
|
+
contrast-corrected foreground; they are accent controls, not neutral navigation.
|
|
184
|
+
Neutral row selection retains its independent selected tokens.
|
|
185
|
+
Selection remains painted on its own row when the shared hover layer moves
|
|
186
|
+
elsewhere. The layer animates transforms, not a second React state per item.
|
|
187
|
+
Multi-selection paints every selected row, not only the current hover target.
|
|
188
|
+
Typeahead and command active descendants are transient candidates, not committed
|
|
189
|
+
choices; retain their moving layer instead of painting an instant second fill.
|
|
190
|
+
- Use the component's `active`, `selected`, `value` or `pressed` API. Neutral
|
|
191
|
+
Button variants honor `aria-pressed` / `aria-current`; application controls must
|
|
192
|
+
expose that state instead of switching to a gray secondary variant alone.
|
|
193
|
+
Checkbox/radio/switch glyphs, primary/destructive actions and semantic diff
|
|
194
|
+
colors keep their semantic fills. Color swatches retain their actual palette.
|
|
195
|
+
- Keyboard focus is separate from selection. Navigation uses an inset focus ring
|
|
196
|
+
so overflow and collapsed groups cannot clip it. Disabled controls retain
|
|
197
|
+
subdued opacity and cannot become moving-hover targets; selection never lowers
|
|
198
|
+
opacity or mutes its primary label.
|
|
199
|
+
- SidebarPartition is a major section label (12px, semibold, uppercase, 16px top
|
|
200
|
+
spacing). SidebarGroup is a compact disclosure label (11px, semibold, uppercase,
|
|
201
|
+
8px inset, 12px group separation), not a destination or hover-highlight target.
|
|
202
|
+
Ordinary destinations use 14px text and the shared 8px/6px row insets. Groups
|
|
203
|
+
preserve keyboard expansion and chevron motion; collapsed rails omit labels.
|
|
204
|
+
- Content wells use the actual surface hierarchy, not selected tokens or muted
|
|
205
|
+
fills. Skeletons, progress tracks and decorative code marks may remain subdued.
|
|
206
|
+
|
|
207
|
+
## Motion and performance
|
|
208
|
+
|
|
209
|
+
Motion is on by default and owned by the component, never by a required example
|
|
210
|
+
prop. Use shared durations (120 / 180 / 280ms) and nonlinear
|
|
211
|
+
`cubic-bezier(.22, 1, .36, 1)` for interaction. Portal enter/exit and sheet motion
|
|
212
|
+
have dedicated shared duration/easing tokens. Continuous progress spinners may
|
|
213
|
+
use linear motion; decorative motion pauses off-screen/in background tabs.
|
|
214
|
+
|
|
215
|
+
- Prefer transform and opacity. Rotate disclosure chevrons and smoothly reveal
|
|
216
|
+
content with the shared Radix measured-height animations. Avoid transition-all,
|
|
217
|
+
animated blur on every hovered row, permanent will-change, or a timer per row.
|
|
218
|
+
- One moving hover background per list. Coalesce reads into one animation frame,
|
|
219
|
+
do not remeasure the same row for pointer movement, and write geometry without
|
|
220
|
+
React rerenders. Nested lists are isolated. Disabled and hidden rows cannot
|
|
221
|
+
become targets; keyboard selection/focus works independently of pointer hover.
|
|
222
|
+
- Selection indicators snap to the first valid measured selection before paint.
|
|
223
|
+
Never animate from `(0, 0)`, including controlled initial values, non-first
|
|
224
|
+
segments, remounts or initially hidden panels. Animate only between established
|
|
225
|
+
user selections. Resize/font/layout changes snap; redundant observer delivery
|
|
226
|
+
must not interrupt an in-flight selection animation.
|
|
227
|
+
- Do not observe the moving highlight as content or respond to its own transition
|
|
228
|
+
completion. Disconnect observers/listeners and cancel frames on unmount.
|
|
229
|
+
- `prefers-reduced-motion: reduce` disables spatial motion, entrance effects and
|
|
230
|
+
shimmer without hiding content or delaying access. Keep exit nodes mounted
|
|
231
|
+
through the primitive's closing state, and preserve focus restoration.
|
|
232
|
+
|
|
233
|
+
## Page composition
|
|
234
|
+
|
|
235
|
+
Application pages, including every catalog category overview, use the same
|
|
236
|
+
composition: `ContentIsland` owns the outside inset, `PageHeader` owns the page
|
|
237
|
+
title/actions/filters, `SectionRule` owns region headings, and `LayerCard` owns
|
|
238
|
+
content surfaces. The catalog's app-local `ShowcasePage` composes the header and
|
|
239
|
+
section gap. All routes under `DashboardLayout` use it, including missing/planned
|
|
240
|
+
catalog states and source viewers. Do not add a second `main`, viewport height,
|
|
241
|
+
page background, wrapper card or page padding inside the island. A bounded chat
|
|
242
|
+
workspace can use `h-full min-h-0`; it must not create a nested viewport.
|
|
243
|
+
|
|
244
|
+
Every catalog route uses the same ShowcasePage header: 30px display titles,
|
|
245
|
+
16px descriptions on a 24px line box, 8px title separation and a 65ch maximum
|
|
246
|
+
reading width. Page sections use 24px separation regardless of route category.
|
|
247
|
+
The standalone PageHeader API retains its size choices for consumers, but catalog
|
|
248
|
+
pages do not override the shared scale. ShowcasePage marks `variant="document"`
|
|
249
|
+
for the library index, category guides, component documentation and source viewers.
|
|
250
|
+
The shell owns the complete breadcrumb trail from Dashboard through the library,
|
|
251
|
+
category and component to the current route. Ancestors are links; the current
|
|
252
|
+
route appears once as nonlinked text with aria-current. Source views include their
|
|
253
|
+
component parent. Narrow headers keep every segment reachable by scrolling the
|
|
254
|
+
breadcrumb region without overflowing the page.
|
|
255
|
+
Document sections use `SectionRule variant="heading"`: 20px sentence-case
|
|
256
|
+
headings without the compact dashed rule. Component previews retain their own
|
|
257
|
+
scope; document typography must not cascade into copied controls. Headers have
|
|
258
|
+
natural height, no scenic wrappers, negative insets or fixed empty openings.
|
|
259
|
+
|
|
260
|
+
Scrollable gallery previews reserve 8px of internal space on every edge for
|
|
261
|
+
control rings, focus outlines and shadows. Padding outside the scroll viewport
|
|
262
|
+
does not protect that paint. Center previews safely so oversized content keeps
|
|
263
|
+
its leading edge reachable.
|
|
264
|
+
The component library uses one LayerCard per category, separated by 24px. Each
|
|
265
|
+
category uses LayerCard.Header above its grid, not individual cards per component.
|
|
266
|
+
Its light surface is white-toned; dark mode uses the same surface hierarchy rather
|
|
267
|
+
than a fixed white fill.
|
|
268
|
+
|
|
269
|
+
Cards with headings use `LayerCard.Header` and `LayerCard.Body`; use one Body for
|
|
270
|
+
related content with a shared internal gap, not a padded Body for every line.
|
|
271
|
+
Structured roots and slots must not receive extra outer padding or margins.
|
|
272
|
+
Unstructured cards select `padding` rather than overriding it with utilities.
|
|
273
|
+
Do not paint a fixed surface onto LayerCard or recreate cards with rounded,
|
|
274
|
+
painted divs. Use library controls and tables instead of rebuilding their spacing,
|
|
275
|
+
focus, selection and motion in page CSS. Semantic color overrides and purposeful
|
|
276
|
+
chart/canvas geometry remain separate from shared control geometry.
|
|
277
|
+
|
|
278
|
+
### Container boundary ownership
|
|
279
|
+
|
|
280
|
+
Choose the boundary before choosing a spacing token. A valid token on the wrong
|
|
281
|
+
owner is still a design error:
|
|
282
|
+
|
|
283
|
+
| Boundary | Owner | Composition |
|
|
284
|
+
| --- | --- | --- |
|
|
285
|
+
| Page/region separation | `ShowcasePage` / `SectionRule` | Layout gaps, no second page inset |
|
|
286
|
+
| Painted content or navigation panel | `LayerCard` | Header and Body slots, never an unpadded painted div |
|
|
287
|
+
| Full-width disclosure heading | `LayerCard.Header asChild` | Slot onto `CollapsibleTrigger`; one hit target, 16/12px insets |
|
|
288
|
+
| Expanded prose or fields | `LayerCard.Body` | Inside `CollapsibleContent unstyled`; one 16px inset |
|
|
289
|
+
| Attached code | `CodeBlock attached` / `CodeHighlighted attached` | Direct child of unstyled disclosure; code owns its 16/12px insets |
|
|
290
|
+
| Edge-to-edge table/list | Its row/cell components | Direct card child; no Body with `p-0` or compensating margins |
|
|
291
|
+
| Compact status/action strip | `Banner` | Control spacing, not a hand-drawn card |
|
|
292
|
+
|
|
293
|
+
Collapsible owns visibility, focus semantics and motion; it does not add another
|
|
294
|
+
surface. Its default inset is for plain standalone text. Use `unstyled` when a
|
|
295
|
+
child already owns spacing. Compose a full collapsible card as `Collapsible asChild`
|
|
296
|
+
around `LayerCard`, keeping Header directly under the card so slot detection works.
|
|
297
|
+
Never bury all card slots inside an opaque wrapper and rely on inferred padding.
|
|
298
|
+
|
|
299
|
+
Do not use native details/summary for dashboard or catalog disclosures; they bypass
|
|
300
|
+
the shared inset and motion contracts. The independent public landing FAQ remains
|
|
301
|
+
a deliberate no-JavaScript exception. Example preview, disclosure label, code title
|
|
302
|
+
and source text must align to the same horizontal inset. Attached code selects a
|
|
303
|
+
public prop, not caller border/radius/padding overrides. Sticky placement wrappers
|
|
304
|
+
own only position; their panel owns its background and inset.
|
|
305
|
+
|
|
306
|
+
Landing, login, loading, error, static documents and full-page layout recipes keep
|
|
307
|
+
their independent root contracts; do not apply dashboard chrome to them. The landing
|
|
308
|
+
route additionally owns its marketing spacing, radius and display type scale, which
|
|
309
|
+
the compact global tiers cannot express; its CSS is exempt from those token rules and
|
|
310
|
+
keeps motion tokens only. Explicit
|
|
311
|
+
specialist controls remain in the palette demos: color swatches and native color
|
|
312
|
+
pickers display the colors being edited. Hidden file inputs and theme-preview
|
|
313
|
+
radio inputs preserve native form behavior. The catalog Login visitor badge keeps
|
|
314
|
+
its accepted independent 54:86 artwork composition, bespoke spacing/type/radii,
|
|
315
|
+
provider-button padding and reserved footer clearance. Do not normalize it to
|
|
316
|
+
dashboard/control tiers. The exception is scoped to `src/pages/LoginPage.tsx`;
|
|
317
|
+
motion, intrinsic action sizing and library-control requirements still apply.
|
|
318
|
+
These exceptions are not permission
|
|
319
|
+
to recreate ordinary actions, selects or inputs.
|
|
320
|
+
|
|
321
|
+
## Enforcement and acceptance
|
|
322
|
+
|
|
323
|
+
`bun run design:check` scans library components/helpers and catalog examples,
|
|
324
|
+
including CSS, for raw spacing/type/radius/motion values, fixed action overrides
|
|
325
|
+
and inline design repairs. The landing route's own CSS is exempt from the spacing,
|
|
326
|
+
radius and type rules and still keeps motion tokens. It derives dashboard page requirements from App routes
|
|
327
|
+
and checks template ownership, duplicate slot spacing, recreated card surfaces,
|
|
328
|
+
ordinary native controls in pages and page-level control padding overrides.
|
|
329
|
+
It rejects compact control padding on content panels, raw application disclosures,
|
|
330
|
+
duplicate disclosure/body insets, zero-padding card-slot repairs and code-frame CSS
|
|
331
|
+
overrides. Navigation rows, tooltips and decorative marks retain their own roles.
|
|
332
|
+
Structural checks inspect JSX, not illustrative source strings. It also checks
|
|
333
|
+
this category inventory. It runs in
|
|
334
|
+
`.husky/pre-push`, **not** in dev, build or pre-commit. Unit tests exercise isolated
|
|
335
|
+
rule fixtures only; they do not run the full repository scan.
|
|
336
|
+
|
|
337
|
+
Static checking is a guard, not proof of appearance. Acceptance also requires
|
|
338
|
+
Tailwind and standalone builds, strict types/lint, unit coverage, keyboard and
|
|
339
|
+
reduced-motion behavior, both themes, narrow screens, wrapped text and enlarged
|
|
340
|
+
root fonts. Browser tests measure actual geometry and animation state; changing
|
|
341
|
+
class-name assertions alone does not certify visual correctness. Do not claim
|
|
342
|
+
browser acceptance when the environment cannot run it.
|