@nocoo/basalt 3.0.0 → 3.1.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/ai/DESIGN.md +64 -8
- package/ai/INTEGRATION.md +83 -8
- package/ai/USAGE.md +2 -2
- package/ai/registry.json +198 -17
- package/dist/components/alert-dialog.js +1 -1
- package/dist/components/alert-dialog.js.map +1 -1
- package/dist/components/data-table.d.ts +7 -1
- package/dist/components/data-table.js +127 -132
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/dialog.js +2 -2
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/diff-table.js +18 -13
- package/dist/components/diff-table.js.map +1 -1
- package/dist/components/sidebar.js +18 -15
- package/dist/components/sidebar.js.map +1 -1
- package/dist/components/table.d.ts +39 -2
- package/dist/components/table.js +48 -17
- package/dist/components/table.js.map +1 -1
- package/dist/styles/standalone.css +29 -7
- package/dist/styles/tailwind.css +1 -0
- package/dist/styles/tokens.css +2 -0
- package/dist/utils/use-hover-highlight.js +38 -36
- package/dist/utils/use-hover-highlight.js.map +1 -1
- package/package.json +28 -28
package/ai/DESIGN.md
CHANGED
|
@@ -64,6 +64,12 @@ Dialog and AlertDialog panels use 16px outer insets on mobile and 24px from
|
|
|
64
64
|
640px. Their buttons and fields retain compact control spacing. Sheets and
|
|
65
65
|
small floating menus have separate inset contracts.
|
|
66
66
|
|
|
67
|
+
Form rhythm distinguishes a field from a group: label/control/hint spacing stays
|
|
68
|
+
8px, related fields use 16px layout gaps, and separate sections use 24px. A form's
|
|
69
|
+
stack owns those gaps; individual Field components do not add outer margins.
|
|
70
|
+
DialogFooter owns 16px separation from content and keeps 8px between its actions.
|
|
71
|
+
Do not add a matching margin at every caller or enlarge controls to open a form.
|
|
72
|
+
|
|
67
73
|
Metric cards use the shared `StatCard`, not a hand-built Header/Body split. A single
|
|
68
74
|
16px inset owns the title, value, comparison and supporting chart; 12px separates
|
|
69
75
|
the heading, metric and content groups, and 4px separates value/supporting text.
|
|
@@ -79,9 +85,12 @@ Zero, auto margins and hairline seams are structural exceptions, not new density
|
|
|
79
85
|
levels. Negative margins may cancel an owned boundary, not invent a new gap.
|
|
80
86
|
Use `p-basalt-card`, `gap-basalt-layout`, `gap-basalt-space-sm`, etc. Default nav
|
|
81
87
|
insets and field gaps remain 8px. Selectable rows use 8px horizontal / 6px vertical
|
|
82
|
-
insets and an 8px icon gap.
|
|
83
|
-
|
|
84
|
-
|
|
88
|
+
insets and an 8px icon gap. Sidebar destinations alone use 8px vertical padding;
|
|
89
|
+
menus, editable navigation and chat rows retain their compact role. One component
|
|
90
|
+
owns each boundary: nested sections must not accidentally double the same inset.
|
|
91
|
+
Distinct surface, column and semantic-slot boundaries may compose their spacing.
|
|
92
|
+
Indented detail content may derive its alignment from the row inset, icon width
|
|
93
|
+
and gap; this is not another density tier.
|
|
85
94
|
|
|
86
95
|
Existing numbered `--basalt-space-*` tokens are a geometry scale for icons,
|
|
87
96
|
media and shell widths. They are not an alternative margin/padding scale.
|
|
@@ -133,6 +142,8 @@ The shared classes calculate natural size as follows:
|
|
|
133
142
|
side = 34px. Body prose/code retain the 20px line box. Compound inputs own one
|
|
134
143
|
outer border; inset children do not add another. Segmented tracks keep 12px text
|
|
135
144
|
on a 20px line box: 30px items + 2px track inset per side = 34px.
|
|
145
|
+
- Sidebar destination and disclosure rows use the same 22px line box with 8px
|
|
146
|
+
vertical padding, yielding 38px reference rows without changing shared controls.
|
|
136
147
|
- Cards, dialogs and layout containers have no mandatory height. Textareas and
|
|
137
148
|
chat inputs grow with content (chat: up to five lines, then scroll).
|
|
138
149
|
|
|
@@ -198,9 +209,12 @@ interaction contracts; do not change their containment as a global workaround.
|
|
|
198
209
|
opacity or mutes its primary label.
|
|
199
210
|
- SidebarPartition is a major section label (12px, semibold, uppercase, 16px top
|
|
200
211
|
spacing). SidebarGroup is a compact disclosure label (11px, semibold, uppercase,
|
|
201
|
-
8px inset, 12px group separation), not a destination or
|
|
202
|
-
Ordinary destinations use 14px text and
|
|
203
|
-
preserve keyboard expansion and chevron motion; collapsed
|
|
212
|
+
22px line box, 8px inset, 12px group separation), not a destination or
|
|
213
|
+
hover-highlight target. Ordinary sidebar destinations use 14px text and 8px
|
|
214
|
+
row insets. Groups preserve keyboard expansion and chevron motion; collapsed
|
|
215
|
+
rails omit labels. Icons stay centered on the 68px collapsed rail, and the brand
|
|
216
|
+
mark keeps the same center when expanded. Do not trade that axis for a global
|
|
217
|
+
left-edge alignment.
|
|
204
218
|
- Content wells use the actual surface hierarchy, not selected tokens or muted
|
|
205
219
|
fills. Skeletons, progress tracks and decorative code marks may remain subdued.
|
|
206
220
|
|
|
@@ -219,6 +233,10 @@ use linear motion; decorative motion pauses off-screen/in background tabs.
|
|
|
219
233
|
do not remeasure the same row for pointer movement, and write geometry without
|
|
220
234
|
React rerenders. Nested lists are isolated. Disabled and hidden rows cannot
|
|
221
235
|
become targets; keyboard selection/focus works independently of pointer hover.
|
|
236
|
+
Sidebar hover starts at the pointer's row and disappears there. It never uses
|
|
237
|
+
the current route or stale pointer focus as an entry/exit destination. Only
|
|
238
|
+
continuous movement between hovered rows animates; gaps and disclosure labels
|
|
239
|
+
end that sequence. Keyboard focus retains its independent focus indicator.
|
|
222
240
|
- Selection indicators snap to the first valid measured selection before paint.
|
|
223
241
|
Never animate from `(0, 0)`, including controlled initial values, non-first
|
|
224
242
|
segments, remounts or initially hidden panels. Animate only between established
|
|
@@ -260,7 +278,9 @@ natural height, no scenic wrappers, negative insets or fixed empty openings.
|
|
|
260
278
|
Scrollable gallery previews reserve 8px of internal space on every edge for
|
|
261
279
|
control rings, focus outlines and shadows. Padding outside the scroll viewport
|
|
262
280
|
does not protect that paint. Center previews safely so oversized content keeps
|
|
263
|
-
its leading edge reachable.
|
|
281
|
+
its leading edge reachable. Multi-column Table, DataTable and DiffTable examples
|
|
282
|
+
span the category grid; do not squeeze a working data surface into a half-width
|
|
283
|
+
thumbnail. Compact examples such as TablePager retain their smaller grid cells.
|
|
264
284
|
The component library uses one LayerCard per category, separated by 24px. Each
|
|
265
285
|
category uses LayerCard.Header above its grid, not individual cards per component.
|
|
266
286
|
Its light surface is white-toned; dark mode uses the same surface hierarchy rather
|
|
@@ -275,6 +295,42 @@ painted divs. Use library controls and tables instead of rebuilding their spacin
|
|
|
275
295
|
focus, selection and motion in page CSS. Semantic color overrides and purposeful
|
|
276
296
|
chart/canvas geometry remain separate from shared control geometry.
|
|
277
297
|
|
|
298
|
+
### Alignment hierarchy
|
|
299
|
+
|
|
300
|
+
Alignment is local to a meaningful scope, not a requirement that every text node
|
|
301
|
+
start at the page edge. Establish the outer rail before composing the inner one:
|
|
302
|
+
|
|
303
|
+
| Scope | Alignment rule |
|
|
304
|
+
| --- | --- |
|
|
305
|
+
| Page | PageHeader and region edges share the ContentIsland rail |
|
|
306
|
+
| Surface | Header, body and footer share their panel inset |
|
|
307
|
+
| Field or column | Labels, controls and values follow that group's start or end rail |
|
|
308
|
+
| Semantic slot | Checkboxes, row numbers and status glyphs reserve their own consistent space |
|
|
309
|
+
|
|
310
|
+
Related text keeps its rail across sorting, selection and missing optional icons.
|
|
311
|
+
Numeric headings and values share the end rail; a sort glyph sits inward of that
|
|
312
|
+
label rather than pushing it away from the values. Reserve the same glyph slot
|
|
313
|
+
for Keep, Add and Remove instead of indenting only changed rows. Ordinary button
|
|
314
|
+
padding is not a table-header inset. Preserve the focus target through a shared
|
|
315
|
+
header control rather than compensating with negative page margins.
|
|
316
|
+
|
|
317
|
+
Table cells keep 8px horizontal / 6px vertical insets and 36px reference rows.
|
|
318
|
+
An edge attached to a panel uses `--basalt-space-table-edge` (the panel's 16px
|
|
319
|
+
horizontal inset), independently of the space between columns. The owner of the
|
|
320
|
+
column structure marks the actual edge cells; DOM first/last-child selectors
|
|
321
|
+
cannot infer that boundary across rowSpan. DataTable owns this through
|
|
322
|
+
`edge="attached"`; native Table compositions use `ps-basalt-table-edge` and
|
|
323
|
+
`pe-basalt-table-edge` only on the corresponding edge cells. A full-width cell
|
|
324
|
+
uses both. Row fills and header rules remain full width, and nested tables keep
|
|
325
|
+
their own insets. An already inset table retains the default cell spacing.
|
|
326
|
+
TableCaption owns its 16px horizontal and 12px vertical panel insets, without an
|
|
327
|
+
outside margin. Its text must not touch an enclosing table frame's bottom edge.
|
|
328
|
+
|
|
329
|
+
Purposeful nesting, such as a preview's focus clearance around a self-contained
|
|
330
|
+
surface, remains valid. Increase the separation between groups before increasing
|
|
331
|
+
every inner gap; breathing room comes from distinguishable groups and adequate
|
|
332
|
+
content width, not uniformly loose controls or one global density multiplier.
|
|
333
|
+
|
|
278
334
|
### Container boundary ownership
|
|
279
335
|
|
|
280
336
|
Choose the boundary before choosing a spacing token. A valid token on the wrong
|
|
@@ -287,7 +343,7 @@ owner is still a design error:
|
|
|
287
343
|
| Full-width disclosure heading | `LayerCard.Header asChild` | Slot onto `CollapsibleTrigger`; one hit target, 16/12px insets |
|
|
288
344
|
| Expanded prose or fields | `LayerCard.Body` | Inside `CollapsibleContent unstyled`; one 16px inset |
|
|
289
345
|
| 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 |
|
|
346
|
+
| Edge-to-edge table/list | Its row/cell components | Direct card child; panel inset on edge cells, no Body with `p-0` or compensating margins |
|
|
291
347
|
| Compact status/action strip | `Banner` | Control spacing, not a hand-drawn card |
|
|
292
348
|
|
|
293
349
|
Collapsible owns visibility, focus semantics and motion; it does not add another
|
package/ai/INTEGRATION.md
CHANGED
|
@@ -428,9 +428,9 @@ Do not wrap those regions in another full-viewport column. Do not set `h-screen`
|
|
|
428
428
|
|
|
429
429
|
### Shared navigation geometry
|
|
430
430
|
|
|
431
|
-
`SidebarNav` and `NavigationMenuList` own one `--basalt-space-nav-inset` (8px) boundary and `--basalt-space-nav-gap` (2px) between rows. Sidebar groups do not add another horizontal inset.
|
|
431
|
+
`SidebarNav` and `NavigationMenuList` own one `--basalt-space-nav-inset` (8px) boundary and `--basalt-space-nav-gap` (2px) between rows. Sidebar groups do not add another horizontal inset. Sidebar destinations and search use 8px horizontal/vertical padding, an 8px icon gap and a 22px line box for a 38px reference row. This is local to Sidebar: editable/folder rows, horizontal navigation links and menus retain 6px vertical padding and 34px rows. Header, search wrapper and footer share the same navigation inset. Do not add caller-owned `px-basalt-space-lg`, `pt-basalt-space-sm` or item-stack padding to compensate for missing package geometry.
|
|
432
432
|
|
|
433
|
-
Use `SidebarNav` for vertical lists, including standalone lists of `EditableNavItem` / `FolderNavItem`; `NavigationMenuList` owns horizontal/vertical Radix navigation. Both compose the existing list-local hover adapter. One background moves with transform between enabled rows
|
|
433
|
+
Use `SidebarNav` for vertical lists, including standalone lists of `EditableNavItem` / `FolderNavItem`; `NavigationMenuList` owns horizontal/vertical Radix navigation. Both compose the existing list-local hover adapter. One background moves with transform between enabled rows. Sidebar hover appears at the actual pointer row and disappears there on leave or over a gap/disclosure label; it never launches from or returns to the active route or stale pointer focus. Only continuous row-to-row hover animates. Keyboard focus remains independent. NavigationMenuList retains its focus/selection-following behavior. Nested lists own separate highlights. Hidden, disabled and actively renamed rows are excluded. Geometry reads are batched per animation frame, same-row pointer motion causes no updates, and reduced motion disables transitions. Navigation state, routes and rename operations remain application-owned; the adapter is View-only.
|
|
434
434
|
|
|
435
435
|
`SidebarHeader` and `SidebarFooter` already pad horizontally. Brand, version pill, and collapse control go directly in the header. The version string is read from the app `package.json` at build time. Never hardcode it. `SidebarPartition` aligns with row text. `SidebarGroup` adds only section spacing, never a second item gutter.
|
|
436
436
|
|
|
@@ -486,13 +486,13 @@ Use `SidebarNav` for vertical lists, including standalone lists of `EditableNavI
|
|
|
486
486
|
</Sidebar>
|
|
487
487
|
```
|
|
488
488
|
|
|
489
|
-
SidebarPartition marks a major section; SidebarGroup is a smaller uppercase, semibold disclosure label with
|
|
489
|
+
SidebarPartition marks a major section; SidebarGroup is a smaller uppercase, semibold disclosure label with a 22px line box, 8px insets and 12px group separation. Group labels do not participate in the destination hover layer. Do not restyle them as ordinary SidebarItem rows or add per-page indentation repairs.
|
|
490
490
|
|
|
491
491
|
### Collapsed tree
|
|
492
492
|
|
|
493
493
|
Pass `collapsed` on `Sidebar`. The element becomes 68px. Children are icon-sized and centered. Still no inner width/height wrapper.
|
|
494
494
|
|
|
495
|
-
The 68px rail uses `--basalt-size-rail`. Header and footer center their content automatically; SidebarIconItem
|
|
495
|
+
The 68px rail uses `--basalt-size-rail`. Header and footer center their content automatically; SidebarIconItem keeps the 34px control width and derives its 38px minimum height from the sidebar line box and padding. The navigation region centers its icon rows on that same rail axis without caller margin overrides. Render icon-only content with an accessible name and tooltip when collapsed; the library does not hide arbitrary application text. Keep a brand mark's expanded inset consistent with the collapsed axis instead of adding collapse-only offsets.
|
|
496
496
|
|
|
497
497
|
```tsx excerpt:sidebar-collapsed-structure
|
|
498
498
|
<Sidebar collapsed={collapsed}>
|
|
@@ -1021,6 +1021,12 @@ Stack one `SectionRule` per region. Live recipe: `/layout`. Catalog: `/ui/page-h
|
|
|
1021
1021
|
|
|
1022
1022
|
Basalt form controls participate in standard forms and controlled state pipelines.
|
|
1023
1023
|
|
|
1024
|
+
Keep the Field's label/control/hint gap at 8px. Compose related fields with
|
|
1025
|
+
`space-y-basalt-layout` or `gap-basalt-layout` (16px); separate sections with the
|
|
1026
|
+
24px `layout-lg` role. The form owns the group gap, not each Field's margin.
|
|
1027
|
+
Action buttons keep their 8px internal gap. DialogFooter owns 16px separation
|
|
1028
|
+
from preceding content, so callers do not need a repeated margin override.
|
|
1029
|
+
|
|
1024
1030
|
### Working Native HTML Form & FormData Pattern
|
|
1025
1031
|
|
|
1026
1032
|
Standard inputs (`Input`, `InputArea`, `Checkbox`, `Radio`, `Switch`) reliably supply their values via standard `FormData(event.currentTarget)`:
|
|
@@ -1039,7 +1045,7 @@ export function ProfileForm() {
|
|
|
1039
1045
|
};
|
|
1040
1046
|
|
|
1041
1047
|
return (
|
|
1042
|
-
<form onSubmit={handleSubmit}>
|
|
1048
|
+
<form onSubmit={handleSubmit} className="space-y-basalt-layout">
|
|
1043
1049
|
<Field label="Email" hint="Your primary email address">
|
|
1044
1050
|
<Input name="email" type="email" required />
|
|
1045
1051
|
</Field>
|
|
@@ -1048,7 +1054,7 @@ export function ProfileForm() {
|
|
|
1048
1054
|
<Switch name="notifications" defaultChecked />
|
|
1049
1055
|
</Field>
|
|
1050
1056
|
|
|
1051
|
-
<div className="flex gap-basalt-space-lg
|
|
1057
|
+
<div className="flex gap-basalt-space-lg">
|
|
1052
1058
|
<Button type="reset" variant="secondary">Reset</Button>
|
|
1053
1059
|
<Button type="submit" variant="default">Save Changes</Button>
|
|
1054
1060
|
</div>
|
|
@@ -1203,7 +1209,7 @@ export function ProjectSettingsForm() {
|
|
|
1203
1209
|
};
|
|
1204
1210
|
|
|
1205
1211
|
return (
|
|
1206
|
-
<form onSubmit={handleSubmit(onSubmit)} className="space-y-basalt-
|
|
1212
|
+
<form onSubmit={handleSubmit(onSubmit)} className="space-y-basalt-layout">
|
|
1207
1213
|
<Field
|
|
1208
1214
|
label="Project Name"
|
|
1209
1215
|
hint="Unique name for your project workspace"
|
|
@@ -1728,7 +1734,7 @@ export function UserPreferencesForm() {
|
|
|
1728
1734
|
};
|
|
1729
1735
|
|
|
1730
1736
|
return (
|
|
1731
|
-
<form onSubmit={handleSubmit} onReset={handleReset} className="space-y-basalt-
|
|
1737
|
+
<form onSubmit={handleSubmit} onReset={handleReset} className="space-y-basalt-layout max-w-sm">
|
|
1732
1738
|
<Field label="Username" hint="Public profile handle">
|
|
1733
1739
|
<Input name="username" defaultValue="johndoe" required />
|
|
1734
1740
|
</Field>
|
|
@@ -1807,6 +1813,7 @@ Basalt geometry no longer depends on a host's Tailwind `--spacing`. Both CSS ent
|
|
|
1807
1813
|
| Field label gap | `--basalt-space-field-gap` | 8px |
|
|
1808
1814
|
| Textarea minimum height | `--basalt-size-textarea-sm`, `--basalt-size-textarea`, `--basalt-size-textarea-lg` | 64 / 80 / 96px |
|
|
1809
1815
|
| Table row / horizontal / vertical inset | `--basalt-size-table-row`, `--basalt-space-table-x`, `--basalt-space-table-y` | 36 / 8 / 6px |
|
|
1816
|
+
| Attached table outer edge | `--basalt-space-table-edge` | Panel horizontal inset, 16px |
|
|
1810
1817
|
|
|
1811
1818
|
Defaults use rem and unitless line-height, preserving browser font-size preferences. [DESIGN.md](DESIGN.md) defines compact 2/4/6/8px control spacing, separate 12/16/24/32px card and layout spacing, and natural 22/34/46px inline/action/banner categories. The size tokens describe reference geometry, not fixed text-control heights. Use the semantic spacing role for the boundary being laid out; numbered geometry tokens are not padding alternatives. LayerCard accepts `padding="sm|md|lg|xl"` for unstructured content; Grid accepts `gap="sm|md|lg|xl"`. Both default to `md`; 32px `xl` is opt-in. ContentIsland owns a 16px mobile, 24px tablet, and 32px horizontal / 24px vertical desktop inset. Examples must use component size props rather than fixed-height overrides. Textareas, avatars and panels retain content-specific geometry.
|
|
1812
1819
|
|
|
@@ -1814,6 +1821,66 @@ Defaults use rem and unitless line-height, preserving browser font-size preferen
|
|
|
1814
1821
|
|
|
1815
1822
|
DataTable uses 13px single-line content, 36px minimum rows, tokenized horizontal/vertical insets and a native horizontally scrollable region. A column's `width` is also its minimum width; the browser must not squeeze names/dates into accidental multi-line rows. Use `column.wrap: true` for actual prose fields, or an explicitly sized inner `truncate` element with a title for long record names and URLs. `maxHeight` bounds the existing scroll region, with sticky opaque headers that stay inside it. Sorting uses a fixed 12px icon slot and retains `aria-sort`; row selection uses the shared Checkbox rather than an unstyled native checkbox. Rich `headerContent` composes icons and labels without changing the plain accessible sort name. Empty/loading/error content remains readable and wraps independently of data-cell defaults.
|
|
1816
1823
|
|
|
1824
|
+
Use `column.textAlign: "end"` for comparable numbers: the header and values share
|
|
1825
|
+
a logical end rail, with the sort glyph inward of the header label. `"start"` is
|
|
1826
|
+
the other explicit direction; omitted body-cell alignment remains inherited.
|
|
1827
|
+
The same `textAlign` prop is available on TableHead, TableCell and
|
|
1828
|
+
TableSortableHeader from `@nocoo/basalt/components/table`. It does not replace
|
|
1829
|
+
native HTML `align` attributes. Logical directions follow LTR/RTL consistently.
|
|
1830
|
+
|
|
1831
|
+
TableSortableHeader is a flush, ref-forwarding button, not a generic Button with
|
|
1832
|
+
extra padding. Pass its `sorted` direction (`"asc"` / `"desc"`, or omitted) and
|
|
1833
|
+
sort callback; the enclosing TableHead owns `aria-sort`. Unsortable headers remain
|
|
1834
|
+
plain text, not disabled sort controls. DataTable handles those details for its
|
|
1835
|
+
own columns.
|
|
1836
|
+
|
|
1837
|
+
For a DataTable directly attached to a LayerCard, set `edge="attached"`. It uses
|
|
1838
|
+
the 16px panel rail only at the outermost cells, including optional number/select
|
|
1839
|
+
columns and full-width state rows. Intercolumn spacing stays 8px per cell side.
|
|
1840
|
+
Built-in pagination shares that panel rail and its 12px bottom inset.
|
|
1841
|
+
The default `edge="inset"` keeps ordinary table spacing inside an already padded
|
|
1842
|
+
region; do not add a zero-padding Body around an attached table.
|
|
1843
|
+
|
|
1844
|
+
```tsx compile:integration-attached-table
|
|
1845
|
+
import { DataTable, type DataTableColumn } from "@nocoo/basalt/components/data-table";
|
|
1846
|
+
import { LayerCard } from "@nocoo/basalt/components/layer-card";
|
|
1847
|
+
|
|
1848
|
+
type Invoice = { id: string; amount: number };
|
|
1849
|
+
const columns: DataTableColumn<Invoice>[] = [
|
|
1850
|
+
{ id: "id", header: "Invoice", accessor: (row) => row.id },
|
|
1851
|
+
{ id: "amount", header: "Amount", accessor: (row) => row.amount, textAlign: "end" },
|
|
1852
|
+
];
|
|
1853
|
+
|
|
1854
|
+
export function InvoicePanel() {
|
|
1855
|
+
return (
|
|
1856
|
+
<LayerCard>
|
|
1857
|
+
<LayerCard.Header>Invoices</LayerCard.Header>
|
|
1858
|
+
<DataTable
|
|
1859
|
+
aria-label="Invoices"
|
|
1860
|
+
edge="attached"
|
|
1861
|
+
columns={columns}
|
|
1862
|
+
data={[{ id: "INV-01", amount: 1240 }, { id: "INV-02", amount: 80 }]}
|
|
1863
|
+
getRowId={(row) => row.id}
|
|
1864
|
+
/>
|
|
1865
|
+
</LayerCard>
|
|
1866
|
+
);
|
|
1867
|
+
}
|
|
1868
|
+
```
|
|
1869
|
+
|
|
1870
|
+
Native Table does not infer a grid from its children. For an attached native
|
|
1871
|
+
composition, mark the true inline-start cells with `ps-basalt-table-edge`, the
|
|
1872
|
+
inline-end cells with `pe-basalt-table-edge`, and a full-width cell with both.
|
|
1873
|
+
Rows continuing a preceding `rowSpan` do not gain a new edge at their first DOM
|
|
1874
|
+
child. These token utilities keep cell backgrounds, sticky headers and separators
|
|
1875
|
+
full width without affecting nested tables. Use ordinary Table cells when no
|
|
1876
|
+
panel edge is being attached.
|
|
1877
|
+
|
|
1878
|
+
TableCaption owns balanced `--basalt-space-panel-x` / `--basalt-space-panel-y`
|
|
1879
|
+
insets (16px horizontal / 12px vertical), not an outside top margin. Keep it
|
|
1880
|
+
inside the native table; do not pad the entire scroll region or compensate with
|
|
1881
|
+
an extra footer wrapper. This preserves full-width row paint and readable space
|
|
1882
|
+
above and below the description inside an enclosing frame.
|
|
1883
|
+
|
|
1817
1884
|
### Recommendations
|
|
1818
1885
|
|
|
1819
1886
|
`RecommendationCard` (`components/recommendation-card`) accepts stable-ID options with a label, plain-text description, confidence (`high`, `review`, `none`) and optional action label/disabled state. Alternatives expand with the existing disclosure and shared hover layer; choosing one changes the recommendation, never executes it. `onAccept` runs only after the explicit action. Promise rejection preserves the selection and shows retry feedback; pending acceptance locks controls and successful acceptance cannot be repeated for the current option. Remount with a new key for a new recommendation request. The application must perform authorization and persist any real action. Private model/ViewModel modules own confidence metadata and state, without View or DOM imports.
|
|
@@ -1846,6 +1913,14 @@ All model names, progress summaries, searches and tool outputs on this route are
|
|
|
1846
1913
|
|
|
1847
1914
|
Use one padding owner per boundary: `--basalt-space-panel-x/y` (16/12px) for composite card/header/body/footer sections, `--basalt-space-row-x/y/gap` (8/6/8px) for selectable rows, and `--basalt-space-content-gap` (8px) between related controls inside a composite. Page section gaps instead use `--basalt-space-layout-lg` (24px). `--basalt-space-row-content` derives the detail inset from row padding + a 16px icon slot + the row gap. Selectable action rows use the 22px `--basalt-line-row`, producing 34px single-line rows and growing by full lines when content wraps. Status icons occupy a first-line-height slot, not an arbitrary top margin. Body prose and code keep the 20px body line-height. Ordinary controls use 34px; inline message actions use the 34px `--basalt-size-action` target and 14px glyphs. Align visible glyphs with prose without removing their pointer target.
|
|
1848
1915
|
|
|
1916
|
+
These are local alignment rails, not one universal left edge. Page headings align
|
|
1917
|
+
to the island; card slots align to their panel; columns align their own labels and
|
|
1918
|
+
values. A checkbox, row number or optional status glyph has a consistent semantic
|
|
1919
|
+
slot. Distinct boundaries may add spacing, but the same boundary has one owner.
|
|
1920
|
+
See [alignment hierarchy](DESIGN.md#alignment-hierarchy). Keep nested preview focus
|
|
1921
|
+
clearance and give wide table examples enough columns rather than shrinking all
|
|
1922
|
+
their padding to fit a thumbnail.
|
|
1923
|
+
|
|
1849
1924
|
Thinking and ToolChips share row padding; disclosures rotate only their own chevron, never content icons. Approval, recommendation, retrieved context and diff sections share panel insets rather than adding another padding layer. ChatComposer owns its field inset, not an outer painted/padded card; the application owns placement in the page. ChatMessage `sources` renders a compact disclosure beside actions and a flat source list, with the same validated URL policy as ContextCards. Use ContextCards only for actual retrieved text chunks, not as a citation footer. No additional remote images are loaded.
|
|
1850
1925
|
|
|
1851
1926
|
The standalone build generates every Tailwind utility once in canonical order. Do not append handwritten copies of `.p-0`, `.bg-transparent` or other native utilities after generated axis/state rules: a later shorthand can silently erase semantic padding. Browser acceptance measures actual computed insets in both CSS entrypoints, under foreign host spacing and semantic overrides.
|
package/ai/USAGE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Basalt AI & Machine Usage Guide
|
|
2
2
|
|
|
3
|
-
This document describes how AI code assistants, automated agents, and developers can consume `@nocoo/basalt` (v3.
|
|
3
|
+
This document describes how AI code assistants, automated agents, and developers can consume `@nocoo/basalt` (v3.1.0).
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -14,7 +14,7 @@ Document anchors formatted as `ai/registry.json#<slug>` reference specific catal
|
|
|
14
14
|
It contains:
|
|
15
15
|
- **131 Exported Modules** (1 root barrel, components, charts, providers)
|
|
16
16
|
- **120 Ready Catalog Entries** with full API definitions
|
|
17
|
-
- **
|
|
17
|
+
- **781 Public Symbols** (406 runtime values, 375 TypeScript types)
|
|
18
18
|
- **Detailed Component API**: Props, types, defaults, descriptions, and function callable signatures (including all `toast()` variants)
|
|
19
19
|
- **Exact Peer Dependency Closures**: Identifies optional peers required per subpath (e.g., Recharts)
|
|
20
20
|
|