@kerfjs/ui 5.0.0-beta.48 → 5.0.0-beta.49
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 +8 -2
- package/ai/component-catalog-v2.json +85 -0
- package/ai/component-catalog.json +98 -0
- package/ai/public-api-signatures-v1.md +24 -1
- package/ai/skill.md +5 -4
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/dist/browser/grid.js +3 -0
- package/dist/catalog.js +2 -2
- package/dist/chunk-IU4QUY5I.js +45 -0
- package/dist/chunk-IU4QUY5I.js.map +1 -0
- package/dist/grid.d.ts +18 -0
- package/dist/grid.js +4 -0
- package/dist/grid.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -3
- package/dist/styles/grid.css +11 -0
- package/dist/styles/styles.css +1 -0
- package/dist/styles/webawesome.css +16 -0
- package/docs/component-selection.md +8 -5
- package/docs/layout.md +24 -1
- package/docs/webawesome-theme.md +7 -4
- package/llms.txt +7 -0
- package/package.json +7 -1
package/README.md
CHANGED
|
@@ -126,7 +126,7 @@ Do not concatenate a count into `label` or pass a numeric `badge`; the mutually
|
|
|
126
126
|
exclusive legacy `badge` slot remains available for non-count `SafeHtml` such
|
|
127
127
|
as a `New` marker.
|
|
128
128
|
|
|
129
|
-
`Row.gap`, `List.gap`, and `Spacer` dimensions accept a direct spacing name such as
|
|
129
|
+
`Row.gap`, `Grid.gap`, `List.gap`, and `Spacer` dimensions accept a direct spacing name such as
|
|
130
130
|
`gap="xs"` or `gap="m"`, or a branded `CssLength`. Import `space`, `rem`, `em`,
|
|
131
131
|
`px`, `pct`, `lengthVar`, `plus`, and `calc` from the CSS-free
|
|
132
132
|
`@kerfjs/ui/css-values` subpath when a named step is not enough. `plus` returns
|
|
@@ -148,8 +148,13 @@ precedence where both select the same side. `ListInsetText` and
|
|
|
148
148
|
grammar for selective insets. Nested Rows and Lists resolve their inset sides
|
|
149
149
|
independently, so an unselected inner side does not inherit its parent's inset.
|
|
150
150
|
|
|
151
|
+
Use `Grid` for a fixed positive number of evenly distributed columns. Its
|
|
152
|
+
`minmax(0, 1fr)` tracks stay equal when children have different intrinsic
|
|
153
|
+
widths; the application owns responsive count changes. Use application CSS grid
|
|
154
|
+
for asymmetric or intrinsic tracks and `ResizableRegion` for adjustable ones.
|
|
155
|
+
|
|
151
156
|
The same property-specific boundary applies beyond spacing: use `flex()` (or a
|
|
152
|
-
finite keyword) for `Row.flex` and `List.flex`; length builders and intrinsic-size keywords for
|
|
157
|
+
finite keyword) for `Row.flex`, `Grid.flex`, and `List.flex`; length builders and intrinsic-size keywords for
|
|
153
158
|
`Skeleton.width`/`height`; length builders for `Skeleton.radius`; and
|
|
154
159
|
`uiColor()` or `colorVar()` for `SelectChoice.color`. These grammars are not
|
|
155
160
|
interchangeable. `ListItem` and `ListActionRow` deliberately expose no raw
|
|
@@ -169,6 +174,7 @@ interchangeable. `ListItem` and `ListActionRow` deliberately expose no raw
|
|
|
169
174
|
| `Text` | `@kerfjs/ui/text` | `@kerfjs/ui/text.css` |
|
|
170
175
|
| `List` | `@kerfjs/ui/list` | `@kerfjs/ui/list.css` |
|
|
171
176
|
| `Row` | `@kerfjs/ui/row` | `@kerfjs/ui/row.css` |
|
|
177
|
+
| `Grid` | `@kerfjs/ui/grid` | `@kerfjs/ui/grid.css` |
|
|
172
178
|
| `Spacer` | `@kerfjs/ui/spacer` | `@kerfjs/ui/spacer.css` |
|
|
173
179
|
| Typed CSS dimension builders | `@kerfjs/ui/css-values` | — |
|
|
174
180
|
| `ListActionRow` | `@kerfjs/ui/list-action-row` | `@kerfjs/ui/list-action-row.css` |
|
|
@@ -1494,6 +1494,91 @@
|
|
|
1494
1494
|
"composition": "docs/layout.md#row-and-list-alignment"
|
|
1495
1495
|
}
|
|
1496
1496
|
},
|
|
1497
|
+
{
|
|
1498
|
+
"key": "@kerfjs/ui:grid",
|
|
1499
|
+
"package": "@kerfjs/ui",
|
|
1500
|
+
"id": "grid",
|
|
1501
|
+
"name": "Grid",
|
|
1502
|
+
"kind": "component",
|
|
1503
|
+
"source": "kerf",
|
|
1504
|
+
"parents": { "mode": "any", "entries": [] },
|
|
1505
|
+
"contexts": ["application-ui"],
|
|
1506
|
+
"zones": [],
|
|
1507
|
+
"children": { "mode": "any", "concepts": [], "requiredConcepts": [] },
|
|
1508
|
+
"state": [
|
|
1509
|
+
{
|
|
1510
|
+
"id": "child semantics and content",
|
|
1511
|
+
"owner": "application",
|
|
1512
|
+
"required": false
|
|
1513
|
+
},
|
|
1514
|
+
{
|
|
1515
|
+
"id": "column count and responsive changes",
|
|
1516
|
+
"owner": "application",
|
|
1517
|
+
"required": false
|
|
1518
|
+
},
|
|
1519
|
+
{
|
|
1520
|
+
"id": "typed gap and flex choices",
|
|
1521
|
+
"owner": "application",
|
|
1522
|
+
"required": false
|
|
1523
|
+
}
|
|
1524
|
+
],
|
|
1525
|
+
"wiring": { "required": false, "helpers": [], "obligations": [] },
|
|
1526
|
+
"responsive": { "owner": "not-applicable", "behaviors": [] },
|
|
1527
|
+
"layout": {
|
|
1528
|
+
"roles": ["structure"],
|
|
1529
|
+
"geometry": {
|
|
1530
|
+
"margin": "none",
|
|
1531
|
+
"border": "none",
|
|
1532
|
+
"padding": "none",
|
|
1533
|
+
"notes": [
|
|
1534
|
+
"Every track uses minmax(0, 1fr), so unequal intrinsic widths cannot break equal distribution."
|
|
1535
|
+
]
|
|
1536
|
+
}
|
|
1537
|
+
},
|
|
1538
|
+
"accessibility": {
|
|
1539
|
+
"obligations": [
|
|
1540
|
+
"Grid adds layout only and no grid role; children retain responsibility for native or ARIA semantics.",
|
|
1541
|
+
"Responsive column-count changes must preserve source and focus order."
|
|
1542
|
+
]
|
|
1543
|
+
},
|
|
1544
|
+
"cssValueProps": [
|
|
1545
|
+
{
|
|
1546
|
+
"path": "gap",
|
|
1547
|
+
"grammar": "length",
|
|
1548
|
+
"helpers": ["px", "rem", "em", "pct", "space", "lengthVar", "calc"],
|
|
1549
|
+
"nonStandaloneHelpers": ["plus"],
|
|
1550
|
+
"shorthands": ["none", "2xs", "xs", "s", "m", "l", "xl"],
|
|
1551
|
+
"canonicalShorthands": ["none", "2xs", "xs", "m", "l"],
|
|
1552
|
+
"exceptionalShorthands": ["s", "xl"],
|
|
1553
|
+
"rawPolicy": "forbid",
|
|
1554
|
+
"examples": [
|
|
1555
|
+
"gap=\"m\"",
|
|
1556
|
+
"gap={space(\"m\")}",
|
|
1557
|
+
"gap={calc(plus(rem(0.25), pct(10)))}"
|
|
1558
|
+
]
|
|
1559
|
+
},
|
|
1560
|
+
{
|
|
1561
|
+
"path": "flex",
|
|
1562
|
+
"grammar": "flex",
|
|
1563
|
+
"helpers": ["flex"],
|
|
1564
|
+
"shorthands": ["none", "auto", "initial"],
|
|
1565
|
+
"canonicalShorthands": ["none", "auto", "initial"],
|
|
1566
|
+
"exceptionalShorthands": [],
|
|
1567
|
+
"rawPolicy": "forbid",
|
|
1568
|
+
"examples": ["flex", "flex=\"none\"", "flex={flex(1, 1, rem(20))}"]
|
|
1569
|
+
}
|
|
1570
|
+
],
|
|
1571
|
+
"boundaries": {
|
|
1572
|
+
"rootClass": "kui-grid",
|
|
1573
|
+
"publicClasses": ["kui-grid"],
|
|
1574
|
+
"publicTokens": ["--kui-grid-gap", "--kui-layout-item-gap"]
|
|
1575
|
+
},
|
|
1576
|
+
"diagnostics": [],
|
|
1577
|
+
"provenance": {
|
|
1578
|
+
"selection": "ai/component-catalog.json",
|
|
1579
|
+
"composition": "generated-permissive-default"
|
|
1580
|
+
}
|
|
1581
|
+
},
|
|
1497
1582
|
{
|
|
1498
1583
|
"key": "@kerfjs/ui:spacer",
|
|
1499
1584
|
"package": "@kerfjs/ui",
|
|
@@ -1680,6 +1680,104 @@
|
|
|
1680
1680
|
"recipe": "docs/layout.md#row-and-list-alignment"
|
|
1681
1681
|
}
|
|
1682
1682
|
},
|
|
1683
|
+
{
|
|
1684
|
+
"id": "grid",
|
|
1685
|
+
"name": "Grid",
|
|
1686
|
+
"category": "Structure",
|
|
1687
|
+
"kind": "component",
|
|
1688
|
+
"source": "kerf",
|
|
1689
|
+
"description": "A fixed positive number of evenly distributed minmax columns with a typed xs gap by default and optional flex participation.",
|
|
1690
|
+
"uses": [],
|
|
1691
|
+
"purpose": "Arrange related siblings in equal-width columns without repeating application-owned grid-template-columns CSS.",
|
|
1692
|
+
"publicExports": ["Grid"],
|
|
1693
|
+
"cssValueProps": [
|
|
1694
|
+
{
|
|
1695
|
+
"path": "gap",
|
|
1696
|
+
"grammar": "length",
|
|
1697
|
+
"helpers": ["px", "rem", "em", "pct", "space", "lengthVar", "calc"],
|
|
1698
|
+
"nonStandaloneHelpers": ["plus"],
|
|
1699
|
+
"shorthands": ["none", "2xs", "xs", "s", "m", "l", "xl"],
|
|
1700
|
+
"canonicalShorthands": ["none", "2xs", "xs", "m", "l"],
|
|
1701
|
+
"exceptionalShorthands": ["s", "xl"],
|
|
1702
|
+
"rawPolicy": "forbid",
|
|
1703
|
+
"examples": ["gap=\"m\"", "gap={space(\"m\")}", "gap={calc(plus(rem(0.25), pct(10)))}"]
|
|
1704
|
+
},
|
|
1705
|
+
{
|
|
1706
|
+
"path": "flex",
|
|
1707
|
+
"grammar": "flex",
|
|
1708
|
+
"helpers": ["flex"],
|
|
1709
|
+
"shorthands": ["none", "auto", "initial"],
|
|
1710
|
+
"canonicalShorthands": ["none", "auto", "initial"],
|
|
1711
|
+
"exceptionalShorthands": [],
|
|
1712
|
+
"rawPolicy": "forbid",
|
|
1713
|
+
"examples": ["flex", "flex=\"none\"", "flex={flex(1, 1, rem(20))}"]
|
|
1714
|
+
}
|
|
1715
|
+
],
|
|
1716
|
+
"useWhen": [
|
|
1717
|
+
"Arrange related siblings into a fixed positive number of equal-width columns.",
|
|
1718
|
+
"Prevent wider intrinsic content from making one fractional track wider than its peers.",
|
|
1719
|
+
"Use a finite flex keyword or the flex() builder when Grid participates in a flexible parent layout."
|
|
1720
|
+
],
|
|
1721
|
+
"avoidWhen": [
|
|
1722
|
+
"Do not use Grid for intrinsic, asymmetric, spanning, auto-fit, or masonry tracks; use application-owned CSS grid.",
|
|
1723
|
+
"Do not use Grid when columns need a user-operable separator; use ResizableRegion.",
|
|
1724
|
+
"Do not expect Grid to choose responsive breakpoints or change the column count; the application owns that policy.",
|
|
1725
|
+
"Do not pass raw CSS strings to gap or flex, mix their distinct grammars, or use s/xl spacing steps without a deliberate exception."
|
|
1726
|
+
],
|
|
1727
|
+
"alternatives": [
|
|
1728
|
+
{
|
|
1729
|
+
"id": "row",
|
|
1730
|
+
"relationship": "axis-alternative",
|
|
1731
|
+
"when": "Use Row for one horizontal flex line, alignment, or wrapping rather than fixed equal tracks."
|
|
1732
|
+
},
|
|
1733
|
+
{
|
|
1734
|
+
"id": "list",
|
|
1735
|
+
"relationship": "axis-alternative",
|
|
1736
|
+
"when": "Use List when the main layout axis is vertical."
|
|
1737
|
+
},
|
|
1738
|
+
{
|
|
1739
|
+
"id": "resize",
|
|
1740
|
+
"relationship": "interactive-alternative",
|
|
1741
|
+
"when": "Use ResizableRegion when people must adjust the boundary between tracks."
|
|
1742
|
+
}
|
|
1743
|
+
],
|
|
1744
|
+
"appOwns": [
|
|
1745
|
+
"child semantics and content",
|
|
1746
|
+
"column count and responsive changes",
|
|
1747
|
+
"typed gap and flex choices"
|
|
1748
|
+
],
|
|
1749
|
+
"variants": [
|
|
1750
|
+
"any positive safe-integer equal-track count",
|
|
1751
|
+
"named none/2xs/xs/s/m/l/xl token gap",
|
|
1752
|
+
"typed CssLength gap",
|
|
1753
|
+
"boolean, finite-keyword, or typed CssFlex flex"
|
|
1754
|
+
],
|
|
1755
|
+
"accessibility": [
|
|
1756
|
+
"Grid adds layout only and no grid role; children retain responsibility for native or ARIA semantics.",
|
|
1757
|
+
"Responsive column-count changes must preserve source and focus order."
|
|
1758
|
+
],
|
|
1759
|
+
"geometry": {
|
|
1760
|
+
"margin": "none",
|
|
1761
|
+
"border": "none",
|
|
1762
|
+
"padding": "none",
|
|
1763
|
+
"notes": [
|
|
1764
|
+
"Every track uses minmax(0, 1fr), so unequal intrinsic widths cannot break equal distribution."
|
|
1765
|
+
]
|
|
1766
|
+
},
|
|
1767
|
+
"delivery": {
|
|
1768
|
+
"browserImport": "@kerfjs/ui/grid",
|
|
1769
|
+
"manualCssImport": "@kerfjs/ui/grid.css",
|
|
1770
|
+
"sideEffects": ["browser-condition-css"]
|
|
1771
|
+
},
|
|
1772
|
+
"wiring": [],
|
|
1773
|
+
"publicClasses": ["kui-grid"],
|
|
1774
|
+
"publicTokens": ["--kui-grid-gap", "--kui-layout-item-gap"],
|
|
1775
|
+
"links": {
|
|
1776
|
+
"catalogRoute": "?component=grid",
|
|
1777
|
+
"documentation": "docs/layout.md",
|
|
1778
|
+
"recipe": "docs/layout.md#grid"
|
|
1779
|
+
}
|
|
1780
|
+
},
|
|
1683
1781
|
{
|
|
1684
1782
|
"id": "spacer",
|
|
1685
1783
|
"name": "Spacer",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Public API signatures for the UI authoring corpus
|
|
2
2
|
|
|
3
|
-
Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.
|
|
3
|
+
Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.49` and `kerfjs@5.0.0-beta.49`. This bounded reference covers only APIs used by the seven-task corpus. It is interface evidence, not an implementation or runtime guarantee.
|
|
4
4
|
|
|
5
5
|
## `@kerfjs/ui/css-values`
|
|
6
6
|
|
|
@@ -2072,6 +2072,29 @@ declare function Row({ children, hAlign, vAlign, gap, flex, wrap, textInsets, co
|
|
|
2072
2072
|
export { CssFlex, CssFlexKeyword, CssLength, HorizontalAlignment, Row, type RowProps, Sides, UiSpaceName, VerticalAlignment };
|
|
2073
2073
|
```
|
|
2074
2074
|
|
|
2075
|
+
## `@kerfjs/ui/grid`
|
|
2076
|
+
|
|
2077
|
+
```ts
|
|
2078
|
+
import * as kerfjs from 'kerfjs';
|
|
2079
|
+
import { UiSpaceName, CssLength, CssFlexKeyword, CssFlex } from './css-values.js';
|
|
2080
|
+
import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
|
|
2081
|
+
|
|
2082
|
+
interface GridProps {
|
|
2083
|
+
children?: KerfUiContent;
|
|
2084
|
+
/** Number of equal-width columns. Must be a positive safe integer. */
|
|
2085
|
+
columns: number;
|
|
2086
|
+
/** A named UI spacing token or typed CSS length. Defaults to xs. */
|
|
2087
|
+
gap?: UiSpaceName | CssLength;
|
|
2088
|
+
/** Allow this grid to grow/shrink, use a keyword, or supply a typed CSS flex shorthand. */
|
|
2089
|
+
flex?: boolean | CssFlexKeyword | CssFlex;
|
|
2090
|
+
className?: string;
|
|
2091
|
+
}
|
|
2092
|
+
/** A fixed-count grid whose columns share the available width equally. */
|
|
2093
|
+
declare function Grid({ children, columns, gap, flex, className, }: GridProps): kerfjs.SafeHtml;
|
|
2094
|
+
|
|
2095
|
+
export { CssFlex, CssFlexKeyword, CssLength, Grid, type GridProps, UiSpaceName };
|
|
2096
|
+
```
|
|
2097
|
+
|
|
2075
2098
|
## `@kerfjs/ui/spacer`
|
|
2076
2099
|
|
|
2077
2100
|
```ts
|
package/ai/skill.md
CHANGED
|
@@ -79,12 +79,13 @@ Quick routing:
|
|
|
79
79
|
| ------------------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
80
80
|
| Navigation row | `ListItem` | Use an ordinary link or button when sidebar/menu anatomy and state do not apply. Its rounded root clips overflowing descendants; set `multiline` when the primary label should wrap. Multiline leading icons stay aligned with the first text line. |
|
|
81
81
|
| Horizontal flex layout | `Row` | Use `hAlign`/`vAlign`, a typed `gap`, and opt-in `wrap`; use `List` when the main axis is vertical. |
|
|
82
|
+
| Equal-width columns | `Grid` | Use a positive fixed `columns` count plus typed `gap`/`flex`. The app owns responsive count changes; use CSS grid for asymmetric/intrinsic tracks and `ResizableRegion` for adjustable boundaries. |
|
|
82
83
|
| Navigation row with a trailing action | `ListActionRow` | Use `ListItem` when the trailing region is dormant; never put controls inside either component's SafeHtml slots. Multiline leading icons stay aligned with the first text line. |
|
|
83
84
|
| Page, panel, or dialog heading | `Toolbar` + `ToolbarText` | Use a direct extra-large `ToolbarText`, optional grouped icon, grouped trailing controls, and app-owned supporting copy below. |
|
|
84
85
|
| Exclusive choice | `TabBar`, `SegmentedControl`, or `Select` | Tabs switch tabpanels; segments expose a few choices; Select handles a longer value list. |
|
|
85
86
|
| Status or absent content | `StateBanner` or `EmptyState` | `StateBanner` accepts an optional terse, tone-tinted `badge` beside its title for a count or compact status; do not rely on color alone. Web Awesome callouts suit ecosystem content; toasts are transient and never the only record of important state. |
|
|
86
87
|
| Loading placeholder | a component's `placeholder` prop, or `Skeleton` | Set `placeholder` on a value-bearing component (`Select`, `ListHeader`, `ListItem`, `ValueTableRow`, `SegmentedControl`, `StateBanner`, `AppTab`, `ToolbarText`, `ListActionRow`) to render its real chrome with value slots as subtle **unanimated** skeletons and interactivity disabled — do not hand-rebuild an empty state. `Skeleton` is the standalone block for a custom slot. Use `LoadingSpinner` for known busy activity, not a skeleton; never animate a skeleton; prefer it over `wa-skeleton`. |
|
|
87
|
-
| Adjustable or
|
|
88
|
+
| Adjustable or asymmetric columns | `ResizableRegion` or CSS grid | Use `ResizableRegion` only for a user-operable controlled separator, CSS grid for asymmetric/intrinsic tracks, and `Grid` for static equal-width tracks. |
|
|
88
89
|
| Structured or ordinary search | `TokenSearchField` or an input | Use token search only when text and ordered filter chips form one editor. |
|
|
89
90
|
| Key/value facts | `ValueTable` with `ValueTableRow` | Use rows with `icon` only when the optional 24px leading visual adds context. |
|
|
90
91
|
| Command search | Application-local semantics using shared layout vocabulary | No runtime component or production recipe is exported; the app owns behavior, policy, and copy. |
|
|
@@ -126,16 +127,16 @@ Hard rules:
|
|
|
126
127
|
10. Compose `AppTab` inside controlled `TabBar`; call `wireTabBars()` once and retain its disposer. It owns same-bar drag mechanics, including proximity-based horizontal edge autoscroll, while the app applies `onReorder` and owns order, selection, panels, close policy, routing, and persistence. Arrow/Home/End select on move by default and restore focus by bar/tab identity when controlled activation replaces the strip; pass `activation: 'manual'` (or `TabBar activation="manual"` per strip) so arrow keys move focus only and the user selects with Enter/Space/click — use it when selecting a tab is a heavy action. Use runtime-filtered `rootAttributes` for domain metadata and keep an optional `closeIcon` decorative and noninteractive.
|
|
127
128
|
11. Use token-controlled `TokenSearchField` when free text and removable structured filters share one editor. Editable text stays DOM-owned between token changes. The leading icon, first text line, clear action, and trailing slot share one fixed row when content wraps. The app owns parsing and suggestions; call `readTokenSearchField()` on input, empty `textContent` on clear, use `placeTokenSearchCaret()` after explicit controlled focus changes, and call `wireTokenSearchFields()` once so Enter submits without inserting a line break and keyboard chip deletion restores focus plus the text-relative caret after controlled replacement. Enable `collapsible` for an animated iconic closed state, standalone or inside `ToolbarControlGroup`; the field keeps text or tokens expanded, and `wireTokenSearchFields()` manages the transient expand/collapse/focus by default (activate to reveal + focus, Escape or empty blur to collapse). Bind the field's `expanded` to the returned handle's `expanded(id)` signal or adopt your own via `collapsible.signals`; opt a behavior out only when the app must own it. Do not hand-roll the open handler, the focusout collapse, a clear-button mousedown guard, or reopening after controlled clear or Select All deletion — the helper keeps the replacement editor open and focused. Clear and deletion restoration finish at the replacement mutation checkpoint before the next input task, so shortcut-letter typing cannot escape to the page and delayed animation frames cannot overwrite a later selection. Persist both query and tokens returned by the DOM read. For real-app adoption it also provides a focusout keep-open exception (`data-token-search-keep-open` regions or `collapsible.keepOpenOn(target)`, so a sibling suggestions/date/help surface does not collapse an empty field), opt-in atomic-chip keyboard (`keyboard`: Backspace/Delete remove the adjacent chip via `onRemoveToken`, ArrowRight moves the caret past a trailing chip), and an `onEdit({id, editor, event})` input callback (the `InputEvent` lets you gate on `inputType`/`data`) — reach for these instead of re-adding hand-rolled keydown/input handlers around the field.
|
|
128
129
|
12. Demo work uses public production component subpaths and their browser-selected CSS. Give every public visual component its own category-grouped catalog route; list themed third-party components under a clearly labeled collapsible ecosystem section, with a focused route for each. For the complete focused/composition decision, `CatalogExample` / `CatalogExampleStack` row/group nesting, exact specimen selection, geometry-overlay legend and exclusions, skip-marker behavior, and metadata ownership, follow the single [Catalog demo authoring contract](../docs/catalog.md#catalog-demo-authoring-contract), discovered machine-readably through [`catalog-authoring.json`](./catalog-authoring.json). Never infer structure from private `kui-catalog-*` classes. Project each component's deterministic repository-relative demo source and existing documentation path so the detail can expose `View demo source` and `Read guidance` links without a runtime export; also derive first-party component implementation paths from their canonical browser imports, and label Web Awesome documentation as Kerf integration guidance. Declare direct `uses` relationships so `Used by` stays derivable, and theme shell chrome through the same semantic tokens as the stage instead of drawing a substitute. Enable `wireCatalog({ revealSelection: true })` for long desktop sidebars so controlled selections remain visible without moving focus; keep its default compact media guard unless compact scrolling is an explicit product behavior, and use `revealCatalogEntry` for an initial deep link.
|
|
129
|
-
13. The Web Awesome theme makes Tooltip and Popover arrowless by default. Keep that default unless a pointer materially clarifies the anchor; opt back in with `--wa-tooltip-arrow-size`, `--kui-wa-popover-arrow-size`, or a popover's public `--arrow-size`, and use `without-arrow` when local no-arrow intent should survive theme changes. Its non-field chrome uses `--kui-wa-control-inset` (8px controls/items), `--kui-wa-surface-margin` / `--kui-wa-surface-inset` (8px around/inside Accordion, Card, Details, Callout, and Include), and `--kui-wa-container-inset` (16px Tab Panel content); Dialog maps its body to the 8px surface tier and its footer to the 16px container tier independently of `--spacing`. Override those tiers instead of restyling individual parts. Filled badges use each variant's quiet fill with normal text so their compact copy stays WCAG-AA readable; override the pair with `--kui-wa-badge-filled-background` / `--kui-wa-badge-filled-foreground`, not host selectors. When a dialog provides another dismissal affordance, put `hide-actions` on the `wa-dialog` host to hide its directly exported `header-actions` part; never chain `::part()` selectors through internal parts. Checkbox and Radio Group option regions, the Color Picker trigger, and Slider's complete interactive region receive the shared 8px logical inline outer inset because those controls have no bordered field shell. Known Date field captions and bordered text-like field hints align with values at the 9px border-plus-padding inset. OTP Input's label uses the same uppercase xs/650 treatment as other field labels, and both its label and hint use that 9px inset.
|
|
130
|
+
13. The Web Awesome theme makes Tooltip and Popover arrowless by default. Keep that default unless a pointer materially clarifies the anchor; opt back in with `--wa-tooltip-arrow-size`, `--kui-wa-popover-arrow-size`, or a popover's public `--arrow-size`, and use `without-arrow` when local no-arrow intent should survive theme changes. Its non-field chrome uses `--kui-wa-control-inset` (8px controls/items), `--kui-wa-surface-margin` / `--kui-wa-surface-inset` (8px around/inside Accordion, Card, Details, Callout, and Include), and `--kui-wa-container-inset` (16px Tab Panel content and outlined/sunken disclosure headers); plain Accordion and Details remove inline trigger/body padding. Dialog maps its body to the 8px surface tier and its footer to the 16px container tier independently of `--spacing`. Override those tiers instead of restyling individual parts. Filled badges use each variant's quiet fill with normal text so their compact copy stays WCAG-AA readable; override the pair with `--kui-wa-badge-filled-background` / `--kui-wa-badge-filled-foreground`, not host selectors. When a dialog provides another dismissal affordance, put `hide-actions` on the `wa-dialog` host to hide its directly exported `header-actions` part; never chain `::part()` selectors through internal parts. Checkbox and Radio Group option regions, the Color Picker trigger, and Slider's complete interactive region receive the shared 8px logical inline outer inset because those controls have no bordered field shell. Known Date field captions and bordered text-like field hints align with values at the 9px border-plus-padding inset. OTP Input's label uses the same uppercase xs/650 treatment as other field labels, and both its label and hint use that 9px inset.
|
|
130
131
|
14. Treat the complete Web Awesome catalog as support coverage, not a recommendation list. Its UX sidebar marks superseded and exceptional entries `Discouraged`. Consider Popup when it replaces custom anchored positioning. Prefer Kerf `Select` over direct Dropdown/Dropdown Item/Select/Option composition, `SegmentedControl` over Button Group, `TabBar` or `SegmentedControl` over Web Awesome Tabs, `LucideIcon` over Web Awesome Icon, and `ResizableRegion` over Split Panel. Use Tree/Tree Item, Animated Image, and Comparison only for a specific required behavior; avoid Zoomable Frame.
|
|
131
|
-
15. Build sidebars, main areas, inspectors, and dialogs from `@kerfjs/ui/layout.css`: an unpadded `.kui-pane`, optional `.kui-pane__toolbar`, one scrolling `.kui-pane__content`, and optional `.kui-pane__footer`. Use `Row` instead of a hand-written flex-row wrapper
|
|
132
|
+
15. Build sidebars, main areas, inspectors, and dialogs from `@kerfjs/ui/layout.css`: an unpadded `.kui-pane`, optional `.kui-pane__toolbar`, one scrolling `.kui-pane__content`, and optional `.kui-pane__footer`. Use `Row` instead of a hand-written flex-row wrapper, `List` instead of a hand-written flex-column wrapper, and `Grid` instead of repeated equal-track CSS when children need a fixed positive count of evenly distributed columns. `Row` defaults to left/full with an `xs` gap and no wrapping; Grid defaults to an `xs` gap and keeps each track at `minmax(0, 1fr)`; List retains full/top and zero-gap defaults. The app owns Grid's responsive column-count changes. Use `List` when rows or sections also need flex growth, one vertical scroll owner, or physical-edge dividers. `dividerSides`, `textInsets`, and `controlInsets` use canonical physical `t`/`r`/`b`/`l` order; text geometry wins where text and control selections overlap. `ListInsetText` and `ListInsetControl` inset all four sides by default and accept the same `sides` grammar for selective edges. A dialog body is generally a `List`: set `DialogSurface bodyInset="none"` when its list children own geometry, and wrap bare dialog prose in `ListInsetText` so it aligns with bordered siblings without a second inset. Add `.kui-content` for 24px major vertical separation and `.kui-content-item` for a child-owned 8px inline margin, 1px transparent-or-visible border, 8px padding, and 12px radius. Use the pill modifier for 22px. Do not pad pane shells, duplicate item geometry in wrappers, or create nested scroll owners.
|
|
132
133
|
15a. Use `Text` from `@kerfjs/ui/text` for ordinary headings and paragraphs outside toolbar title zones. Omit `variant` for the default `p`, or pass `h1`–`h6` according to the document outline; ordinary native attributes pass through. Express supporting, error, compact, or code text with the independent finite `tone="quiet|danger"`, `size="compact"`, and `font="monospace"` props instead of global utility classes or appearance-only heading choices. Text owns a transparent 1px border and the standard item padding. Keep toolbar identity/title content on `ToolbarText` and list-aligned bare prose on `ListInsetText`.
|
|
133
134
|
16. Keep a visible collapsible pane's collapse control in its own toolbar. When hidden, move its restore control into the adjacent main toolbar on the corresponding logical edge: leading for an inline-start sidebar and trailing for an inline-end inspector. Collapse the pane completely; do not preserve an empty icon-only rail.
|
|
134
135
|
17. The only direct children of a `Toolbar` zone (`leading`/`center`/`trailing`) are `ToolbarText` (identity/title text) and `ToolbarControlGroup`; never drop bare buttons, inputs, links, or arbitrary markup straight into a zone. Put identity/title text directly in the zone as `ToolbarText`; wrap interactive controls and icon tiles in `ToolbarControlGroup`. `SegmentedControl`, `Select`, a collapsible `TokenSearchField`, and Web Awesome controls all live inside a group. For an ordinary icon/action control inside a group, use a plain `<button>` (the group styles `> button` fully) — that is the default; reach for `wa-button` only when you need a Web Awesome feature, chiefly a `wa-dropdown` popup trigger. A popup menu in a toolbar is a `single` group wrapping a `wa-dropdown` whose `slot="trigger"` `wa-button` is the toolbar button and whose `wa-dropdown-item`s are the menu, with the dropdown kept under `data-morph-skip-children`. For a compact mixed group, keep the standard item padding and raised selected chrome; the selected item paints over the outer border without an internal separator. For an avatar control, set `content="avatar"` and `avatarImage` on the group instead of inserting an `img`: a lone control paints the contained image on the outer group and a multi-button group paints it only on the pressed selection highlight. Compose panel/dialog/page headings with a direct extra-large `ToolbarText`, optional grouped icon, grouped trailing controls, and app-owned supporting copy below. A group remains 44px outside (`calc(2px + remify(42px))`) when its border/background are transparent; use 8px between groups and inside items. Split dormant and interactive regions: `ListHeader` fills the available inline width by default; set `inline` only when it should shrink-wrap in surrounding content without outer margin, border, or padding. It keeps its label and mutually exclusive semantic count or non-count `badge` together, with an independent logical-end action unless disclosure mode makes the title cluster the button. Its action visual defaults to 18px through `--kui-list-header-action-icon-size`; never shrink the target to match it. Pass every non-negative safe-integer section quantity through `count` with a localized full spoken `countLabel`; never concatenate it into `label` or put a number in `badge`. `ListItem.trailing` is dormant; use `ListActionRow` when primary and trailing actions need sibling native buttons. Its `label`, `icon`, and `trailingActionIcon` slots are also dormant and cannot contain controls. Let panes relocate at narrow widths instead of shrinking targets.
|
|
135
136
|
18. When a recurring concept has no matching export or production recipe, keep its semantics in a thin application adapter while reusing the public layout vocabulary. The composer recipe uses one visible form surface, toolbar title/supporting-copy ids, shared 8px field/action gutters, 24px major rhythm, and a conditional StateBanner as its only nested semantic surface; do not turn every section into a card or double-inset intrinsically bordered controls. The application-local `../docs/examples/command-palette-adapter.tsx` is reference source for one such missing concept, not an `@kerfjs/ui` runtime export or catalog recipe. The application owns its registration, ranking, history, permissions, availability, shortcut policy, focus policy, dispatch, and copy. If a missing concept recurs across products, open an upstream component or recipe request.
|
|
136
137
|
19. Compose `ValueTable` from typed `ValueTableRow` entries instead of handwritten `dt`/`dd` wrappers. Pass `icon` for the optional 24px leading visual; the row owns 8px of root-scaled top and bottom padding, the 8px iconless or 40px icon-bearing separator start, and the common 8px right inset.
|
|
137
138
|
20. Use the standard direct `Toolbar` composition for a panel, dialog, or page heading, not a private wrapper or custom heading row. Put an optional icon in a `ToolbarControlGroup`, the title directly in the leading zone as extra-large `ToolbarText`, and actions in a trailing group. Set `headingLevel` for page/section landmarks. Supporting copy stays below the toolbar as app-owned content. The app owns modal behavior, focus, dismissal, command policy, ids, and action handling.
|
|
138
|
-
21. Space with the official five-step scale, picked by how connected two elements are — not by eye. `0` `--kui-space-none` = no separation (one unit); `4px` `--kui-space-2xs` = very minor air on a connected cluster; `8px` `--kui-space-xs` = standard, between elements within a group; `16px` `--kui-space-m` = minor, between homogeneous groups; `24px` `--kui-space-l` = major, between heterogeneous groups (the `.kui-content` rhythm). The 8px-vs-24px distinction is inside-a-group vs between-major-differing-regions. `--kui-space-s` (12px) and `--kui-space-xl` (32px) are off-scale exceptions. For `Row.gap` or `List.gap`, pass a finite shorthand such as `gap="xs"` or `gap="m"`; use `Spacer` for one intentional typed empty width/height or a flexible main-axis gap. When one token is insufficient, import typed builders from the CSS-free `@kerfjs/ui/css-values` subpath. Preserve property grammar: lengths for gap/Spacer/Skeleton geometry, `flex()` for List flex, and `uiColor()`/`colorVar()` for choice icons. Never cast between brands or emit raw row `style` declarations. `plus` is not standalone and must be wrapped in `calc`; `remify()` remains source-CSS syntax and is never a runtime prop value. See `docs/layout.md` "Spacing scale".
|
|
139
|
+
21. Space with the official five-step scale, picked by how connected two elements are — not by eye. `0` `--kui-space-none` = no separation (one unit); `4px` `--kui-space-2xs` = very minor air on a connected cluster; `8px` `--kui-space-xs` = standard, between elements within a group; `16px` `--kui-space-m` = minor, between homogeneous groups; `24px` `--kui-space-l` = major, between heterogeneous groups (the `.kui-content` rhythm). The 8px-vs-24px distinction is inside-a-group vs between-major-differing-regions. `--kui-space-s` (12px) and `--kui-space-xl` (32px) are off-scale exceptions. For `Row.gap`, `Grid.gap`, or `List.gap`, pass a finite shorthand such as `gap="xs"` or `gap="m"`; use `Spacer` for one intentional typed empty width/height or a flexible main-axis gap. When one token is insufficient, import typed builders from the CSS-free `@kerfjs/ui/css-values` subpath. Preserve property grammar: lengths for gap/Spacer/Skeleton geometry, `flex()` for Row/Grid/List flex, and `uiColor()`/`colorVar()` for choice icons. Never cast between brands or emit raw row `style` declarations. `plus` is not standalone and must be wrapped in `calc`; `remify()` remains source-CSS syntax and is never a runtime prop value. See `docs/layout.md` "Spacing scale".
|
|
139
140
|
22. Pick a whole-screen layout from the opt-in, tree-shakeable subpaths by data + interaction + device, and derive responsiveness from `@kerfjs/ui/device-class`'s `deviceClass()` (`compact` = handset or portrait tablet = one pane at a time). Simple/flat → `NavStack` with one entry (single pane), plus `TabScaffold` (`@kerfjs/ui/tab-scaffold`, iOS bottom tabs, each tab its own `NavStack`) for 2–5 co-equal sections on `compact`. Drill-down → `NavStack` (`@kerfjs/ui/nav-stack`), upgrading to `SplitView` (`@kerfjs/ui/split-view`, list-detail) once both panes fit (`atLeast('tablet')` landscape); `SplitView` collapses to a `NavStack` on `compact`. Keep each stack's ordered views controlled; put view-specific bottom chrome on `NavStackView.bottomToolbar` (or use the component-level persistent fallback), then call `wireNavStack` so content slides while the active view's top and bottom chrome cross-fade and focus moves into the new top view/restores on pop. Mark a preferred initial heading or control with `data-nav-focus` when DOM order is not sufficient. Complex tool with peripheral panels → `Workbench` (`@kerfjs/ui/workbench`, collapsible rails + drawer) `atLeast('desktop')`, degrading to `NavStack`/overlays below. These are declarative (the app owns the stack/selection/collapsed/active state as signals) with disposer-returning `wire…` helpers; each ships a companion CSS import and stays out of the barrel. For a standalone collapsible rail or bottom drawer outside a full shell, use `CollapsiblePanel` + `CollapsiblePanelToggle` (`@kerfjs/ui/collapsible-panel`) with `wireSidebar` (`@kerfjs/ui/wire-sidebar`): the standard collapse animation and per-side icon convention (`PanelLeft*`/`PanelRight*`/`PanelBottom*`) plus toggle, focus, compact overlay, and persistence semantics. Dialogs pick the same inner layout, then present per device class (full-screen modal on `compact`, inline on desktop). See `docs/app-layouts.md` and `docs/collapsible-panel.md`.
|
|
140
141
|
|
|
141
142
|
Common mistakes:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Web Awesome JSX signatures for the UI authoring corpus
|
|
2
2
|
|
|
3
|
-
Generated from the emitted `@kerfjs/ui@5.0.0-beta.
|
|
3
|
+
Generated from the emitted `@kerfjs/ui@5.0.0-beta.49` declaration boundary. Import `@kerfjs/ui/webawesome` for type effects when authoring direct `wa-*` JSX. The module emits no runtime behavior and does not register custom elements.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
6
|
import { KerfCustomElement } from 'kerfjs/jsx-runtime';
|
package/dist/catalog.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { ToolbarControlGroup } from './chunk-B6JYRX3P.js';
|
|
2
2
|
import { Toolbar } from './chunk-VXFGMDA7.js';
|
|
3
|
+
import { List } from './chunk-WVLMZ5SG.js';
|
|
3
4
|
import { Pane } from './chunk-I4V3UDSA.js';
|
|
5
|
+
|
|
4
6
|
import { ListHeader } from './chunk-GYGM363P.js';
|
|
5
7
|
import { Text } from './chunk-XKFRMGMW.js';
|
|
6
8
|
import { ListItem } from './chunk-I45QO2IZ.js';
|
|
7
|
-
import { List } from './chunk-WVLMZ5SG.js';
|
|
8
|
-
|
|
9
9
|
import { filterDataAttributes } from './chunk-SRSJO5QE.js';
|
|
10
10
|
|
|
11
11
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { space } from './chunk-OL4TC3U2.js';
|
|
2
|
+
import { jsx } from 'kerfjs/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
var spaceNames = [
|
|
5
|
+
"none",
|
|
6
|
+
"2xs",
|
|
7
|
+
"xs",
|
|
8
|
+
"s",
|
|
9
|
+
"m",
|
|
10
|
+
"l",
|
|
11
|
+
"xl"
|
|
12
|
+
];
|
|
13
|
+
function Grid({
|
|
14
|
+
children,
|
|
15
|
+
columns,
|
|
16
|
+
gap = "xs",
|
|
17
|
+
flex = false,
|
|
18
|
+
className = ""
|
|
19
|
+
}) {
|
|
20
|
+
if (!Number.isSafeInteger(columns) || columns < 1) {
|
|
21
|
+
throw new RangeError("Grid columns must be a positive safe integer");
|
|
22
|
+
}
|
|
23
|
+
const gapValue = spaceNames.includes(gap) ? space(gap) : gap;
|
|
24
|
+
const flexValue = flex === true ? "1 1 auto" : flex || void 0;
|
|
25
|
+
const style = [
|
|
26
|
+
`--_kui-grid-columns:${columns}`,
|
|
27
|
+
`--_kui-grid-gap:${gapValue}`,
|
|
28
|
+
flexValue ? `--_kui-grid-flex:${flexValue}` : ""
|
|
29
|
+
].filter(Boolean).join(";");
|
|
30
|
+
return /* @__PURE__ */ jsx(
|
|
31
|
+
"div",
|
|
32
|
+
{
|
|
33
|
+
class: `kui-grid ${className}`.trim(),
|
|
34
|
+
"data-component": "grid",
|
|
35
|
+
"data-columns": String(columns),
|
|
36
|
+
"data-flex": String(Boolean(flex)),
|
|
37
|
+
style,
|
|
38
|
+
children
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export { Grid };
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=chunk-IU4QUY5I.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/grid.tsx"],"names":[],"mappings":";;;AASA,IAAM,UAAA,GAAqC;AAAA,EACzC,MAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,GAAA;AAAA,EACA,GAAA;AAAA,EACA,GAAA;AAAA,EACA;AACF,CAAA;AAcO,SAAS,IAAA,CAAK;AAAA,EACnB,QAAA;AAAA,EACA,OAAA;AAAA,EACA,GAAA,GAAM,IAAA;AAAA,EACN,IAAA,GAAO,KAAA;AAAA,EACP,SAAA,GAAY;AACd,CAAA,EAAc;AACZ,EAAA,IAAI,CAAC,MAAA,CAAO,aAAA,CAAc,OAAO,CAAA,IAAK,UAAU,CAAA,EAAG;AACjD,IAAA,MAAM,IAAI,WAAW,8CAA8C,CAAA;AAAA,EACrE;AAEA,EAAA,MAAM,WAAW,UAAA,CAAW,QAAA,CAAS,GAAkB,CAAA,GACnD,KAAA,CAAM,GAAkB,CAAA,GACxB,GAAA;AACJ,EAAA,MAAM,SAAA,GAAY,IAAA,KAAS,IAAA,GAAO,UAAA,GAAa,IAAA,IAAQ,MAAA;AACvD,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,uBAAuB,OAAO,CAAA,CAAA;AAAA,IAC9B,mBAAmB,QAAQ,CAAA,CAAA;AAAA,IAC3B,SAAA,GAAY,CAAA,iBAAA,EAAoB,SAAS,CAAA,CAAA,GAAK;AAAA,GAChD,CACG,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAEX,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,CAAA,SAAA,EAAY,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK;AAAA,MACpC,gBAAA,EAAe,MAAA;AAAA,MACf,cAAA,EAAc,OAAO,OAAO,CAAA;AAAA,MAC5B,WAAA,EAAW,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAC,CAAA;AAAA,MAC/B,KAAA;AAAA,MAEC;AAAA;AAAA,GACH;AAEJ","file":"chunk-IU4QUY5I.js","sourcesContent":["import {\n type CssFlex,\n type CssFlexKeyword,\n type CssLength,\n space,\n type UiSpaceName,\n} from './css-values.js';\nimport type { KerfUiContent } from './semantic-content.js';\n\nconst spaceNames: readonly UiSpaceName[] = [\n 'none',\n '2xs',\n 'xs',\n 's',\n 'm',\n 'l',\n 'xl',\n];\n\nexport interface GridProps {\n children?: KerfUiContent;\n /** Number of equal-width columns. Must be a positive safe integer. */\n columns: number;\n /** A named UI spacing token or typed CSS length. Defaults to xs. */\n gap?: UiSpaceName | CssLength;\n /** Allow this grid to grow/shrink, use a keyword, or supply a typed CSS flex shorthand. */\n flex?: boolean | CssFlexKeyword | CssFlex;\n className?: string;\n}\n\n/** A fixed-count grid whose columns share the available width equally. */\nexport function Grid({\n children,\n columns,\n gap = 'xs',\n flex = false,\n className = '',\n}: GridProps) {\n if (!Number.isSafeInteger(columns) || columns < 1) {\n throw new RangeError('Grid columns must be a positive safe integer');\n }\n\n const gapValue = spaceNames.includes(gap as UiSpaceName)\n ? space(gap as UiSpaceName)\n : gap;\n const flexValue = flex === true ? '1 1 auto' : flex || undefined;\n const style = [\n `--_kui-grid-columns:${columns}`,\n `--_kui-grid-gap:${gapValue}`,\n flexValue ? `--_kui-grid-flex:${flexValue}` : '',\n ]\n .filter(Boolean)\n .join(';');\n\n return (\n <div\n class={`kui-grid ${className}`.trim()}\n data-component=\"grid\"\n data-columns={String(columns)}\n data-flex={String(Boolean(flex))}\n style={style}\n >\n {children}\n </div>\n );\n}\n\nexport type {\n CssFlex,\n CssFlexKeyword,\n CssLength,\n UiSpaceName,\n} from './css-values.js';\n"]}
|
package/dist/grid.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as kerfjs from 'kerfjs';
|
|
2
|
+
import { UiSpaceName, CssLength, CssFlexKeyword, CssFlex } from './css-values.js';
|
|
3
|
+
import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
|
|
4
|
+
|
|
5
|
+
interface GridProps {
|
|
6
|
+
children?: KerfUiContent;
|
|
7
|
+
/** Number of equal-width columns. Must be a positive safe integer. */
|
|
8
|
+
columns: number;
|
|
9
|
+
/** A named UI spacing token or typed CSS length. Defaults to xs. */
|
|
10
|
+
gap?: UiSpaceName | CssLength;
|
|
11
|
+
/** Allow this grid to grow/shrink, use a keyword, or supply a typed CSS flex shorthand. */
|
|
12
|
+
flex?: boolean | CssFlexKeyword | CssFlex;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
/** A fixed-count grid whose columns share the available width equally. */
|
|
16
|
+
declare function Grid({ children, columns, gap, flex, className, }: GridProps): kerfjs.SafeHtml;
|
|
17
|
+
|
|
18
|
+
export { CssFlex, CssFlexKeyword, CssLength, Grid, type GridProps, UiSpaceName };
|
package/dist/grid.js
ADDED
package/dist/grid.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"grid.js"}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { CssColor, CssFlex, CssFlexBasis, CssFlexKeyword, CssLength, CssLengthEx
|
|
|
3
3
|
export { DisclosureArrow, DisclosureArrowProps, DisclosureDirection } from './disclosure-arrow.js';
|
|
4
4
|
export { EmptyState, EmptyStateProps } from './empty-state.js';
|
|
5
5
|
export { FloatingToolbar, FloatingToolbarPosition, FloatingToolbarProps } from './floating-toolbar.js';
|
|
6
|
+
export { Grid, GridProps } from './grid.js';
|
|
6
7
|
export { List, ListProps } from './list.js';
|
|
7
8
|
export { ListActionRow, ListActionRowProps } from './list-action-row.js';
|
|
8
9
|
export { ListHeader, ListHeaderProps } from './list-header.js';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { wireResizableRegions } from './chunk-WN52USHV.js';
|
|
2
2
|
export { reorderTabs, wireTabBars } from './chunk-UKKSMZYT.js';
|
|
3
3
|
export { wireTokenSearchFields } from './chunk-VDUJZF5G.js';
|
|
4
|
+
export { TabBar } from './chunk-ZPWZIVI6.js';
|
|
4
5
|
export { TokenSearchField, placeTokenSearchCaret, readTokenSearchField } from './chunk-TIGSG6BX.js';
|
|
5
6
|
export { ValueTable, ValueTableRow } from './chunk-V6HCTCVD.js';
|
|
6
7
|
export { Select } from './chunk-CK6P5AUK.js';
|
|
@@ -8,24 +9,24 @@ export { Spacer } from './chunk-OGTJNHRG.js';
|
|
|
8
9
|
export { StateBanner } from './chunk-UDHHKZWO.js';
|
|
9
10
|
export { SunkenPanel } from './chunk-SOK5EUF7.js';
|
|
10
11
|
export { DialogSurface, PopupSurface } from './chunk-WSXUPSID.js';
|
|
11
|
-
export { TabBar } from './chunk-ZPWZIVI6.js';
|
|
12
12
|
export { ToolbarText } from './chunk-V6GQKOX2.js';
|
|
13
13
|
export { ResizableRegion, clampRegionSize, resizeRegionFromPointer } from './chunk-CAB6NQ2T.js';
|
|
14
14
|
export { Row } from './chunk-OGNE3OFT.js';
|
|
15
15
|
export { SegmentedControl } from './chunk-E34TE2ZI.js';
|
|
16
16
|
export { FloatingToolbar } from './chunk-DYBPI5O2.js';
|
|
17
|
+
export { Grid } from './chunk-IU4QUY5I.js';
|
|
17
18
|
export { ListActionRow } from './chunk-DAO2VFTT.js';
|
|
18
19
|
export { ListInsetControl } from './chunk-2TYUFZUC.js';
|
|
19
20
|
export { ListInsetText } from './chunk-EYALJQQD.js';
|
|
20
21
|
export { AppTab } from './chunk-OMSRSL3B.js';
|
|
21
22
|
export { ToolbarControlGroup } from './chunk-B6JYRX3P.js';
|
|
22
23
|
export { Toolbar } from './chunk-VXFGMDA7.js';
|
|
24
|
+
export { List } from './chunk-WVLMZ5SG.js';
|
|
23
25
|
export { Pane } from './chunk-I4V3UDSA.js';
|
|
26
|
+
|
|
24
27
|
export { ListHeader } from './chunk-GYGM363P.js';
|
|
25
28
|
export { Text } from './chunk-XKFRMGMW.js';
|
|
26
29
|
export { ListItem } from './chunk-I45QO2IZ.js';
|
|
27
|
-
export { List } from './chunk-WVLMZ5SG.js';
|
|
28
|
-
|
|
29
30
|
|
|
30
31
|
export { Skeleton } from './chunk-T7DOWS6T.js';
|
|
31
32
|
export { calc, colorVar, em, flex, lengthVar, pct, plus, px, rem, space, uiColor } from './chunk-OL4TC3U2.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
.kui-grid {
|
|
2
|
+
--kui-grid-gap: var(--kui-layout-item-gap, 0.5rem);
|
|
3
|
+
|
|
4
|
+
display: grid;
|
|
5
|
+
min-width: 0;
|
|
6
|
+
min-height: 0;
|
|
7
|
+
box-sizing: border-box;
|
|
8
|
+
flex: var(--_kui-grid-flex, initial);
|
|
9
|
+
grid-template-columns: repeat(var(--_kui-grid-columns), minmax(0, 1fr));
|
|
10
|
+
gap: var(--_kui-grid-gap, var(--kui-grid-gap));
|
|
11
|
+
}
|
package/dist/styles/styles.css
CHANGED
|
@@ -336,6 +336,22 @@
|
|
|
336
336
|
box-shadow: none;
|
|
337
337
|
}
|
|
338
338
|
|
|
339
|
+
/* Unframed disclosures align directly with their surrounding content.
|
|
340
|
+
Framed disclosure headers use the roomier container tier so the trigger
|
|
341
|
+
reads as the surface heading while the body keeps its compact inset. */
|
|
342
|
+
wa-details[appearance="plain"]::part(header),
|
|
343
|
+
wa-details[appearance="plain"]::part(content),
|
|
344
|
+
wa-accordion[appearance="plain"] > wa-accordion-item::part(button),
|
|
345
|
+
wa-accordion[appearance="plain"] > wa-accordion-item::part(content) {
|
|
346
|
+
padding-inline: 0;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
wa-details:is([appearance="outlined"], [appearance="sunken"])::part(header),
|
|
350
|
+
wa-accordion:is([appearance="outlined"], [appearance="sunken"])
|
|
351
|
+
> wa-accordion-item::part(button) {
|
|
352
|
+
padding-inline: var(--kui-wa-container-inset);
|
|
353
|
+
}
|
|
354
|
+
|
|
339
355
|
wa-card,
|
|
340
356
|
wa-details,
|
|
341
357
|
wa-accordion-item {
|
|
@@ -38,7 +38,7 @@ foreground/background contrast relationships and visible focus ring.
|
|
|
38
38
|
|
|
39
39
|
### Typed runtime dimensions
|
|
40
40
|
|
|
41
|
-
Use `Row` or `List` spacing shorthands for repeated sibling spacing: `gap="xs"`,
|
|
41
|
+
Use `Row`, `Grid`, or `List` spacing shorthands for repeated sibling spacing: `gap="xs"`,
|
|
42
42
|
`gap="m"`, and the other `UiSpaceName` values resolve to their matching
|
|
43
43
|
`--kui-space-*` token. Use `Spacer` for one deliberate empty width or height, or
|
|
44
44
|
pass `flex` to consume the remaining space along a flex parent's main axis.
|
|
@@ -53,23 +53,25 @@ application-owned length tokens. `plus` creates a non-standalone
|
|
|
53
53
|
|
|
54
54
|
```tsx
|
|
55
55
|
import { calc, pct, plus, rem, space } from "@kerfjs/ui/css-values";
|
|
56
|
+
import { Grid } from "@kerfjs/ui/grid";
|
|
56
57
|
import { List } from "@kerfjs/ui/list";
|
|
57
58
|
import { Row } from "@kerfjs/ui/row";
|
|
58
59
|
|
|
59
60
|
<List gap="xs">...</List>;
|
|
61
|
+
<Grid columns={3} gap="m">...</Grid>;
|
|
60
62
|
<Row hAlign="full" vAlign="middle" gap="m">...</Row>;
|
|
61
63
|
<List gap={space("m")}>...</List>;
|
|
62
64
|
<List gap={calc(plus(rem(0.25), pct(10)))}>...</List>;
|
|
63
65
|
```
|
|
64
66
|
|
|
65
67
|
`CssValue` is the common branded base, not an arbitrary-string constructor.
|
|
66
|
-
Raw strings such as `"0.25rem"`
|
|
68
|
+
Raw strings such as `"0.25rem"` do not satisfy `Row.gap`, `Grid.gap`, or `List.gap`; this
|
|
67
69
|
contract lands before the 5.0 stable release so misspelled tokens and incomplete
|
|
68
70
|
expressions fail during typechecking rather than in the browser.
|
|
69
71
|
|
|
70
72
|
Other CSS-valued props use distinct contracts: `Spacer.width` and
|
|
71
73
|
`Spacer.height` take `UiSpaceName | CssLength`; `flex()` creates `CssFlex` for
|
|
72
|
-
`Row.flex` and `List.flex`; `Skeleton` dimensions take typed lengths (plus finite intrinsic
|
|
74
|
+
`Row.flex`, `Grid.flex`, and `List.flex`; `Skeleton` dimensions take typed lengths (plus finite intrinsic
|
|
73
75
|
keywords for width/height); and `uiColor()`/`colorVar()` create `CssColor` for
|
|
74
76
|
`SelectChoice.color`. Do not substitute one brand for another. Row components
|
|
75
77
|
have no declaration-string `style` prop; use `className`, documented public
|
|
@@ -126,6 +128,7 @@ an upstream component or recipe request.
|
|
|
126
128
|
| Toolbar identity text — `ToolbarText` | A toolbar needs extra-large (page/panel title), large, default, or compact textual identity. | Plain text is not a heading by default; when a title needs heading semantics pass `headingLevel`. | Optional `headingLevel` for `role="heading"` + `aria-level`. Defaults to one line, ellipsized when it does not fit; `wrap` flows onto multiple lines, `ellipsis` toggles the trailing …, and `maxLines` caps a wrap. | Text, heading level, overflow behavior, and responsive priority. | `@kerfjs/ui/toolbar-text` | [Toolbar composition](../README.md#component-subpaths) |
|
|
127
129
|
| Semantic heading or paragraph — `Text` | Ordinary application copy needs native `h1`–`h6` or `p` semantics plus standard geometry, or a semantic quiet/danger tone, compact size, or monospace font. | Do not choose heading levels for appearance alone or recreate muted, error, small, or code utility classes. Use `ToolbarText` for toolbar identity/title content and `ListInsetText` when list-aligned prose needs full margin/border/padding geometry. | Omit `variant` for the default `p`, or choose `h1`–`h6` from the document outline. Independently compose `tone="quiet | danger"`, `size="compact"`, and `font="monospace"`; ordinary native global, `data-_`, and `aria-_` attributes pass through. | Copy, localization, semantic variant, presentation roles, and document heading hierarchy. | `@kerfjs/ui/text` | [Text](./layout.md#text) |
|
|
128
130
|
| Vertical stack — `List` | Rows, sections, or arbitrary components need a consistent vertical stretch layout, optional standard/custom gap, flex growth, one vertical scroll owner, or edge dividers. | It is layout-only and does not provide `ul`/`ol` semantics. Do not nest scroll owners or use it when a horizontal layout is required. | Choose `gap`, `flex`, `scrollable`, and canonical `dividerSides` (`t`, `r`, `b`, `l` combinations in that order); bound the block size when scrolling. | Child semantics/content, containing height, and which optional layout behaviors apply. | `@kerfjs/ui/list` | [Pane geometry](../README.md#pane-and-content-geometry) |
|
|
131
|
+
| Equal-width columns — `Grid` | A fixed positive number of sibling columns must divide the available width evenly, including when child content has different intrinsic widths. | Do not use it for intrinsic, asymmetric, spanning, auto-fit, or masonry tracks; use application-owned CSS grid. Do not use it for a user-operable separator; use `ResizableRegion`. | Choose `columns`, a typed `gap`, and optional typed `flex`; preserve source order when the app changes the count responsively. | Child semantics/content, the column count and responsive policy, and typed gap/flex choices. | `@kerfjs/ui/grid` | [Grid](./layout.md#grid) |
|
|
129
132
|
| Navigation row — `ListItem` | A pane or navigation area needs a selectable, disabled, dormant-trailing, or multiline action row. | Do not put a control in `trailing`; use `ListActionRow` when the trailing region must be independently interactive. Use an `<a>` for navigation that must retain link behavior, a native `<button>` for an ordinary action, or implement the complete ARIA menu widget. | Delegate its `data-action`; compose inside a `.kui-content` section. Put domain event/drop metadata in `rootAttributes` rather than adding wrapper markup. The rounded root clips overflowing descendants; set `multiline` when the primary label should wrap. | Routing, selection, permissions, copy, action handling, and domain `data-*` values. | `@kerfjs/ui/list-item` | [Pane geometry](../README.md#pane-and-content-geometry) |
|
|
130
133
|
| Navigation row with trailing action — `ListActionRow` | A full-width row needs a selectable primary action and an independently focusable trailing action. | Use `ListItem` when trailing content is dormant metadata. Do not put controls inside the row's `label`, `icon`, or `trailingActionIcon` SafeHtml slots. Do not use `AppTab` outside tablist semantics or `ToolbarControlGroup` outside a toolbar. | Delegate both action strings; update controlled selection and any popover/context-menu state in the app. | Routing, selection, both action policies, domain metadata, and popover/context-menu behavior. | `@kerfjs/ui/list-action-row` | [Accessibility](./accessibility.md#listactionrow) |
|
|
131
134
|
| Navigation section heading — `ListHeader` | A menu section needs a full-width label, semantic count, non-count badge, logical-end action, or real disclosure state. | Do not concatenate counts into `label` or put numeric content in `badge`; use `count` with the localized full phrase in `countLabel`. Do not add a disclosure arrow to navigation that reveals nothing. Do not shrink its 44px action target to the 18px visual. Do not use it as a page, panel, or dialog title; use a heading `Toolbar`. | Delegate its optional action; the app controls expanded state and revealed content. Toggle mode supplies `DisclosureArrow` unless `actionIcon` replaces it. Use `triggerAttributes` only for domain `data-*` or a native popover relationship. | Section organization, valid count and localized count label, disclosure state and content, non-count badge content, popover target behavior, and policy. | `@kerfjs/ui/list-header` | [Pane geometry](../README.md#pane-and-content-geometry) |
|
|
@@ -139,7 +142,7 @@ an upstream component or recipe request.
|
|
|
139
142
|
| Standalone rail or drawer — `CollapsiblePanel` | One left/right rail or bottom drawer needs controlled collapse without adopting the complete `Workbench` shell. | Do not use it for several coordinated workspace panels or retain an empty icon-only rail while collapsed. | Pair it with `CollapsiblePanelToggle`; call `wireSidebar` for focus transfer, Escape/backdrop dismissal, compact overlay trapping, and persistence integration. | Panel content/size, collapsed state, toggle placement, persistence, and compact policy. | `@kerfjs/ui/collapsible-panel` | [App-layout decision matrix](./app-layouts.md#decision-matrix) |
|
|
140
143
|
| Lowered content surface — `SunkenPanel` | A main work area or nested content group needs one visually lowered surface with a compact inset and vertical stack. | Do not use it merely to add padding, as a replacement for `Pane` anatomy, or around children that already own the same outer surface. | Compose the application-owned content as children, choose the default `rounded` shape or `square` for a flush edge-to-edge area, and pass `ariaLabel` only when the surface is a distinct named region. | Region semantics, accessible name, shape, scroll ownership, child ordering, and content. | `@kerfjs/ui/sunken-panel` | [SunkenPanel](./sunken-panel.md) |
|
|
141
144
|
| Menu composition | Navigation sections need full-size rows and the same content-item geometry as every other pane. | Do not add sidebar-specific wrapper padding, shrink targets to icon size, nest an interactive trailing control in `ListItem`, or use a chevron on a row that does not disclose content. Use ordinary links for a different navigation contract. | Compose `ListHeader`, `ListItem`, and `ListActionRow` in `.kui-content`; use `ListHeader` toggle mode with real controlled content, and use `.kui-content-item` for other surfaces plus a pane footer for toolbar actions. | Information architecture, disclosure content and state, responsive drawer/shell behavior, and token overrides. | `@kerfjs/ui/layout.css` | [Pane geometry](../README.md#pane-and-content-geometry) |
|
|
142
|
-
| Resizable application pane — `ResizableRegion`, `clampRegionSize`, `resizeRegionFromPointer` | A controlled split pane needs the Kerf separator, collapse state, pointer plus keyboard resizing, or a product-specific decorative grip. | Do not use it for
|
|
145
|
+
| Resizable application pane — `ResizableRegion`, `clampRegionSize`, `resizeRegionFromPointer` | A controlled split pane needs the Kerf separator, collapse state, pointer plus keyboard resizing, or a product-specific decorative grip. | Do not use it for static equal columns; use `Grid`. Use application CSS grid for static asymmetric or intrinsic tracks. Prefer it over Web Awesome `wa-split-panel` unless that component's distinct API is required. Keep `handleIcon` noninteractive. | Call `wireResizableRegions` from `@kerfjs/ui/wire-resizable-regions` once and retain its disposer. | Size signal, min/max policy, collapse policy, persistence, and optional decorative handle icon. | `@kerfjs/ui/resizable-region` | [ResizableRegion contract](./accessibility.md#resizableregion) |
|
|
143
146
|
| One application tab — `AppTab` | A controlled app tab needs selection, close, drag, leading/trailing anatomy, compact/segmented/icon-only presentation, label truncation, safe domain metadata, or a product-specific close glyph. | Do not render it alone or use it for a small settings choice; compose in `TabBar`, or use `SegmentedControl`. Keep `closeIcon` noninteractive. | Compose in `TabBar`; let `wireTabBars` manage interaction. Put only domain `data-*` values in `rootAttributes`; use typed appearance props instead of descendant CSS. | Tab identity, order, selection, close policy, content, domain metadata values, and outer placement. | `@kerfjs/ui/app-tab` | [Tabs contract](./accessibility.md#tabs) |
|
|
144
147
|
| Application tab strip — `TabBar`, `wireTabBars`, `reorderTabs` | Tabs switch page regions and may overflow, close, reorder, fill a segmented inspector strip, or sit beside a trailing action. | Do not use it for a compact local view toggle; use `SegmentedControl`. Do not use it for a long choice list; use `Select`. Prefer it over Web Awesome `wa-tab-group`, `wa-tab`, and `wa-tab-panel` for Kerf app tabs. | Call `wireTabBars` once, retain the disposer, and apply `onReorder` synchronously; `reorderTabs` is the default array helper. Choose typed presentation/allocation props while the parent owns outer placement. | Ordered tabs, selection, panels, routing, closing, persistence, and outer placement. | `@kerfjs/ui/tab-bar` plus `@kerfjs/ui/wire-tab-bars` | [Tabs contract](./accessibility.md#tabs) |
|
|
145
148
|
| Panel, dialog, or page heading — `Toolbar` + `ToolbarText` | A panel, dialog, or page needs an extra-large title, optional icon, grouped trailing actions, and optional supporting copy. | Do not add a private heading wrapper or bespoke layout. The toolbar supplies structure, not modal behavior; use an application overlay or Web Awesome `wa-dialog` for that behavior. | Connect title/supporting-copy ids to the host, group controls, and delegate actions. **For a page or view title set `headingLevel` (usually `1`)** on `ToolbarText`; omit it for a dialog title referenced by `aria-labelledby`. | Open state, focus lifecycle, dismissal, controls, ids, copy, and heading level. | `@kerfjs/ui/toolbar` + `@kerfjs/ui/toolbar-text` | [Toolbar headings](./accessibility.md#toolbar-headings) |
|
|
@@ -158,7 +161,7 @@ an upstream component or recipe request.
|
|
|
158
161
|
- `Toolbar` serves persistent app chrome and headings; the zone contents and accessible naming distinguish the purpose.
|
|
159
162
|
- `TabBar` changes tabpanels and supports overflow/reorder; `SegmentedControl` chooses among a few compact views; `Select` handles a longer value list.
|
|
160
163
|
- `StateBanner` persists beside affected work; `EmptyState` replaces absent content; `wa-callout` is contextual ecosystem content; `wa-toast` and `wa-toast-item` are transient and must not carry the only copy of important state.
|
|
161
|
-
- `ResizableRegion` is an interactive controlled pane.
|
|
164
|
+
- `ResizableRegion` is an interactive controlled pane. `Grid` is the right answer for static equal-width columns; application CSS grid remains the answer for asymmetric or intrinsic tracks.
|
|
162
165
|
- A `ResizableRegion` overlay automatically clamps both its track and fixed-size
|
|
163
166
|
animated content to the responsive overlay maximum. Set the policy and maximum
|
|
164
167
|
on the component instead of adding application descendant width/height fixes.
|
package/docs/layout.md
CHANGED
|
@@ -112,7 +112,7 @@ The two relationships that get confused most are 8px vs 24px: 8px is _inside_ a
|
|
|
112
112
|
group, 24px is _between_ major, differing regions. 16px sits between them for
|
|
113
113
|
same-kind groups.
|
|
114
114
|
|
|
115
|
-
For `Row.gap` and `List.gap`, pass these token names directly (`gap="xs"`, `gap="m"`) or use
|
|
115
|
+
For `Row.gap`, `Grid.gap`, and `List.gap`, pass these token names directly (`gap="xs"`, `gap="m"`) or use
|
|
116
116
|
`space('xs')` from `@kerfjs/ui/css-values` when composing a value in JavaScript.
|
|
117
117
|
Use `rem`, `em`, `px`, `pct`, `lengthVar`, and `calc(plus(...))` only when a
|
|
118
118
|
named spacing relationship does not express the requirement; do not pass raw
|
|
@@ -169,6 +169,29 @@ uses physical width and height. Prefer `Row.gap` or `List.gap` for uniform
|
|
|
169
169
|
sibling rhythm, and never use Spacer to cancel or duplicate component-owned
|
|
170
170
|
insets.
|
|
171
171
|
|
|
172
|
+
## Grid
|
|
173
|
+
|
|
174
|
+
Use `Grid` from `@kerfjs/ui/grid` when a fixed positive number of columns must
|
|
175
|
+
share the available width evenly. Every track is `minmax(0, 1fr)`, so a child
|
|
176
|
+
with wider intrinsic content cannot make its column wider than its peers. Grid
|
|
177
|
+
defaults to the `xs` gap and accepts the same finite spacing names, complete
|
|
178
|
+
typed `CssLength` values, and typed flex-participation contract as Row.
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
import { Grid } from "@kerfjs/ui/grid";
|
|
182
|
+
|
|
183
|
+
<Grid columns={2} gap="m">
|
|
184
|
+
<label>Quantity <input /></label>
|
|
185
|
+
<label>Unit <input /></label>
|
|
186
|
+
</Grid>;
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
`columns` must be a positive safe integer; invalid counts throw instead of
|
|
190
|
+
silently producing invalid CSS. Grid is layout-only and adds no ARIA grid role.
|
|
191
|
+
The application owns child semantics and responsive count changes. Use
|
|
192
|
+
application-owned CSS grid for intrinsic, asymmetric, spanning, auto-fit, or
|
|
193
|
+
masonry tracks, and use `ResizableRegion` when people must adjust a boundary.
|
|
194
|
+
|
|
172
195
|
## Row and List alignment
|
|
173
196
|
|
|
174
197
|
Use `Row` for a horizontal flex layout and `List` for a vertical one. `Row`
|
package/docs/webawesome-theme.md
CHANGED
|
@@ -97,6 +97,10 @@ tiers:
|
|
|
97
97
|
complete surface and the inset within it. Accordion applies the outer margin
|
|
98
98
|
once to the group rather than separating connected items; Card's header,
|
|
99
99
|
body, and footer all receive the full inset.
|
|
100
|
+
- Plain Accordion and Details remove inline padding from both their trigger and
|
|
101
|
+
content so their text aligns directly with the surrounding flow. Outlined and
|
|
102
|
+
sunken disclosure triggers use the 16px `--kui-wa-container-inset`, one 8px
|
|
103
|
+
step beyond their compact body inset.
|
|
100
104
|
- `appearance="sunken"` is a Kerf theme extension for Accordion, Card, and
|
|
101
105
|
Details. It removes raised chrome, paints the lowered semantic surface, and
|
|
102
106
|
uses the shared rounded-rectangle radius. Override
|
|
@@ -177,10 +181,9 @@ component should declare the no-arrow choice independent of theme context.
|
|
|
177
181
|
The UX catalog includes a focused, addressable specimen for every component in
|
|
178
182
|
this list. Because these are themed ecosystem components rather than
|
|
179
183
|
first-class `@kerfjs/ui` exports, the sidebar keeps them under a collapsible
|
|
180
|
-
`Web Awesome` heading with category subgroups.
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
state at once.
|
|
184
|
+
`Web Awesome` heading with category subgroups. There is no aggregate theme
|
|
185
|
+
route: the focused modal, drawer, toast, media, and helper routes make each
|
|
186
|
+
component's behavior inspectable without opening every state at once.
|
|
184
187
|
|
|
185
188
|
## Badge and tag guidance
|
|
186
189
|
|
package/llms.txt
CHANGED
|
@@ -107,10 +107,17 @@ maintain a central style list. Configure JSX with `"jsxImportSource": "kerfjs"`.
|
|
|
107
107
|
for List flex, typed lengths for Skeleton geometry, and
|
|
108
108
|
`uiColor()`/`colorVar()` for choice-icon colors. These brands are intentionally
|
|
109
109
|
not interchangeable; rows use classes/tokens/props rather than raw `style`.
|
|
110
|
+
- **Use `Grid` for a fixed positive count of equal-width columns.** It uses
|
|
111
|
+
zero-minimum fractional tracks, so intrinsic content cannot make one column
|
|
112
|
+
wider than its peers. The app owns responsive count changes; use custom CSS
|
|
113
|
+
grid for asymmetric/intrinsic tracks and `ResizableRegion` for adjustable
|
|
114
|
+
boundaries. `Grid.gap` and `Grid.flex` use the same typed grammars as Row.
|
|
110
115
|
- **Keep Web Awesome on the shared inset tiers.** `webawesome.css` uses
|
|
111
116
|
`--kui-wa-control-inset` (8px controls/items) and
|
|
112
117
|
`--kui-wa-surface-margin` / `--kui-wa-surface-inset` (8px around/inside
|
|
113
118
|
Accordion, Card, Details, Callout, and Include), while
|
|
119
|
+
plain Accordion/Details remove inline trigger/body padding and their
|
|
120
|
+
outlined/sunken headers use the 16px container inset,
|
|
114
121
|
`--kui-wa-container-inset` keeps Tab Panel at 16px. Dialog body and footer use
|
|
115
122
|
the surface (8px) and container (16px) tiers respectively, independent of the
|
|
116
123
|
dialog's shared `--spacing`. Override the tier at the narrowest useful scope
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kerfjs/ui",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.49",
|
|
4
4
|
"description": "Accessible, composable UI primitives for kerf applications.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -98,6 +98,11 @@
|
|
|
98
98
|
"browser": "./dist/browser/row.js",
|
|
99
99
|
"import": "./dist/row.js"
|
|
100
100
|
},
|
|
101
|
+
"./grid": {
|
|
102
|
+
"types": "./dist/grid.d.ts",
|
|
103
|
+
"browser": "./dist/browser/grid.js",
|
|
104
|
+
"import": "./dist/grid.js"
|
|
105
|
+
},
|
|
101
106
|
"./spacer": {
|
|
102
107
|
"types": "./dist/spacer.d.ts",
|
|
103
108
|
"browser": "./dist/browser/spacer.js",
|
|
@@ -295,6 +300,7 @@
|
|
|
295
300
|
"./text.css": "./dist/styles/text.css",
|
|
296
301
|
"./list.css": "./dist/styles/list.css",
|
|
297
302
|
"./row.css": "./dist/styles/row.css",
|
|
303
|
+
"./grid.css": "./dist/styles/grid.css",
|
|
298
304
|
"./spacer.css": "./dist/styles/spacer.css",
|
|
299
305
|
"./list-action-row.css": "./dist/styles/list-action-row.css",
|
|
300
306
|
"./list-item.css": "./dist/styles/list-item.css",
|