@kerfjs/ui 5.0.0-beta.33 → 5.0.0-beta.35

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.
@@ -38,7 +38,7 @@ foreground/background contrast relationships and visible focus ring.
38
38
 
39
39
  ### Typed runtime dimensions
40
40
 
41
- Use `List` spacing shorthands for the common case: `gap="xs"`, `gap="m"`, and
41
+ Use `Row` or `List` spacing shorthands for the common case: `gap="xs"`, `gap="m"`, and
42
42
  the other `UiSpaceName` values resolve to their matching `--kui-space-*` token.
43
43
  The canonical rhythm is `none`, `2xs`, `xs`, `m`, and `l`; use `s` and `xl`
44
44
  only as deliberate exceptions.
@@ -47,24 +47,26 @@ When a value cannot be expressed by one spacing step, import the CSS-free
47
47
  `@kerfjs/ui/css-values` subpath. `px`, `rem`, `em`, and `pct` create typed
48
48
  `CssLength` values; `space` and `lengthVar` reference spacing or
49
49
  application-owned length tokens. `plus` creates a non-standalone
50
- `CssLengthExpression`, so wrap it with `calc` before passing it to `List.gap`:
50
+ `CssLengthExpression`, so wrap it with `calc` before passing it to a gap prop:
51
51
 
52
52
  ```tsx
53
53
  import { calc, pct, plus, rem, space } from "@kerfjs/ui/css-values";
54
54
  import { List } from "@kerfjs/ui/list";
55
+ import { Row } from "@kerfjs/ui/row";
55
56
 
56
57
  <List gap="xs">...</List>;
58
+ <Row hAlign="full" vAlign="middle" gap="m">...</Row>;
57
59
  <List gap={space("m")}>...</List>;
58
60
  <List gap={calc(plus(rem(0.25), pct(10)))}>...</List>;
59
61
  ```
60
62
 
61
63
  `CssValue` is the common branded base, not an arbitrary-string constructor.
62
- Raw strings such as `"0.25rem"` no longer satisfy `List.gap`; this breaking
64
+ Raw strings such as `"0.25rem"` no longer satisfy `Row.gap` or `List.gap`; this breaking
63
65
  contract lands before the 5.0 stable release so misspelled tokens and incomplete
64
66
  expressions fail during typechecking rather than in the browser.
65
67
 
66
68
  Other CSS-valued props use distinct contracts: `flex()` creates `CssFlex` for
67
- `List.flex`; `Skeleton` dimensions take typed lengths (plus finite intrinsic
69
+ `Row.flex` and `List.flex`; `Skeleton` dimensions take typed lengths (plus finite intrinsic
68
70
  keywords for width/height); and `uiColor()`/`colorVar()` create `CssColor` for
69
71
  `SelectChoice.color`. Do not substitute one brand for another. Row components
70
72
  have no declaration-string `style` prop; use `className`, documented public
package/docs/layout.md CHANGED
@@ -112,12 +112,37 @@ 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 `List.gap`, pass these token names directly (`gap="xs"`, `gap="m"`) or use
115
+ For `Row.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
119
119
  CSS strings.
120
120
 
121
+ ## Row and List alignment
122
+
123
+ Use `Row` for a horizontal flex layout and `List` for a vertical one. `Row`
124
+ defaults to `hAlign="left"`, `vAlign="full"`, `gap="xs"`, and no wrapping;
125
+ `List` retains its existing full-width, top-aligned defaults and zero gap.
126
+ Both components accept the same physical-axis vocabulary:
127
+
128
+ | Axis | Values and aliases | Flex behavior |
129
+ | ---------- | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------- |
130
+ | Horizontal | `left` / `l` / `flex-start`; `center` / `c` / `space-around`; `right` / `r` / `flex-end`; `full` / `f` / `space-between` | Distributes a Row's children; aligns a List's children across its width. |
131
+ | Vertical | `top` / `t` / `flex-start`; `middle` / `m` / `c` / `space-around`; `bottom` / `b` / `flex-end`; `full` / `f` / `space-between` | Aligns a Row's children across its height; distributes a List's children. |
132
+
133
+ Cross-axis `space-around` and `space-between` are not valid `align-items`
134
+ values. Kerf therefore maps `middle` to centered items and `full` to stretched
135
+ items, while applying the requested distribution to `align-content` when a
136
+ Row wraps. Prefer the descriptive values in application code; the short and
137
+ CSS-shaped aliases are provided for compact or migrated call sites.
138
+
139
+ `Row.flex` and `List.flex` share one typed participation contract. Omit the prop
140
+ for the CSS initial value, pass `true` for `1 1 auto`, select the finite
141
+ `"none"`, `"auto"`, or `"initial"` keyword, or use
142
+ `flex(grow, shrink, basis)` from `@kerfjs/ui/css-values` for a complete branded
143
+ shorthand. A `CssLength` is not a flex shorthand, and arbitrary strings are
144
+ rejected by the type contract.
145
+
121
146
  `--kui-space-s` (12px) and `--kui-space-xl` (32px) exist but are **off the
122
147
  canonical rhythm** — reach for them only as a deliberate exception, never as a
123
148
  default step. Prefer the five canonical tokens so spacing stays legible and
package/docs/ux-demo.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  Run `npm run dev` from `ui/`. The catalog is a development and review surface, not a second implementation. The development server allows repo-owned assets used by the catalog, and its production bundle uses relative asset URLs so the complete catalog remains intact below preview and proxy paths.
4
4
 
5
+ Every Playwright entry point builds current source before the preview server
6
+ starts. `npm run test:e2e -- tests/browser/row.spec.ts` and a direct focused
7
+ `npx playwright test tests/browser/row.spec.ts` both run catalog generation and
8
+ demo-conformance preflights, build the package and production catalog, then
9
+ launch Chromium, Firefox, and WebKit. The build emits
10
+ `source-freshness.json`; browser coverage compares it with an independent hash
11
+ of the current `src/` and `ux-demo/` inputs, so a stale `dist-demo` cannot pass
12
+ after a route or component edit. `npm run demo:serve` remains a preview-only
13
+ command for an already-built catalog.
14
+
5
15
  Seven lazy production-composition routes live under the `Recipes` category.
6
16
  Each `?component=recipe-*` route uses public package primitives, real wiring,
7
17
  deterministic state, and semantic layout owners from the [recipe guide](./recipes.md).
package/llms.txt CHANGED
@@ -91,7 +91,10 @@ maintain a central style list. Configure JSX with `"jsxImportSource": "kerfjs"`.
91
91
  own the geometry (8px inline margin + 1px border + 8px padding). Do not add a
92
92
  container padding on top of a content-item's own margin — pick one owner. Use
93
93
  `.kui-content` for 24px major vertical rhythm.
94
- - **Use `List` for vertical layout.** It supplies a stretch-aligned column plus
94
+ - **Use `Row` for horizontal and `List` for vertical layout.** Both expose
95
+ physical `hAlign`/`vAlign` props and typed gaps. Row defaults to left/full,
96
+ an `xs` gap, and no wrapping; List retains full/top and zero-gap defaults.
97
+ List additionally supplies
95
98
  optional typed `gap`, `flex`, vertical scrolling, and canonical
96
99
  `dividerSides` (`t`/`r`/`b`/`l` order). It adds no list semantics; children own
97
100
  those, and only one bounded region should own scrolling. Pass a finite spacing
@@ -154,7 +157,7 @@ maintain a central style list. Configure JSX with `"jsxImportSource": "kerfjs"`.
154
157
  - **Space by the five-step scale, by relationship not by eye.** `0`
155
158
  `--kui-space-none`, `4px` `--kui-space-2xs`, `8px` `--kui-space-xs` (inside a
156
159
  group), `16px` `--kui-space-m`, `24px` `--kui-space-l` (between major differing
157
- regions). 12px/32px are off-scale exceptions. Prefer direct `List.gap`
160
+ regions). 12px/32px are off-scale exceptions. Prefer direct `Row.gap`/`List.gap`
158
161
  shorthands; use `space`, `px`, `rem`, `em`, `pct`, `lengthVar`, and
159
162
  `calc(plus(...))` for typed runtime composition. `remify()` is source-CSS only.
160
163
  - **Keep nested highlight corners concentric.** Inset hover and selection surfaces
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kerfjs/ui",
3
- "version": "5.0.0-beta.33",
3
+ "version": "5.0.0-beta.35",
4
4
  "description": "Accessible, composable UI primitives for kerf applications.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -88,6 +88,11 @@
88
88
  "browser": "./dist/browser/list.js",
89
89
  "import": "./dist/list.js"
90
90
  },
91
+ "./row": {
92
+ "types": "./dist/row.d.ts",
93
+ "browser": "./dist/browser/row.js",
94
+ "import": "./dist/row.js"
95
+ },
91
96
  "./list-action-row": {
92
97
  "types": "./dist/list-action-row.d.ts",
93
98
  "browser": "./dist/browser/list-action-row.js",
@@ -278,6 +283,7 @@
278
283
  "./floating-toolbar.css": "./dist/styles/floating-toolbar.css",
279
284
  "./toolbar-text.css": "./dist/styles/toolbar-text.css",
280
285
  "./list.css": "./dist/styles/list.css",
286
+ "./row.css": "./dist/styles/row.css",
281
287
  "./list-action-row.css": "./dist/styles/list-action-row.css",
282
288
  "./list-item.css": "./dist/styles/list-item.css",
283
289
  "./list-header.css": "./dist/styles/list-header.css",
@@ -323,11 +329,15 @@
323
329
  "dev": "npm run build && vite --config ux-demo/vite.config.ts",
324
330
  "demo:build": "npm run build && vite build --config ux-demo/vite.config.ts && node scripts/check-demo-bundle.mjs",
325
331
  "demo:serve": "vite preview --config ux-demo/vite.config.ts",
332
+ "test:e2e:serve": "npm run check:catalog && npm run check:demo-conformance && npm run demo:build && npm run demo:serve",
326
333
  "format": "prettier --write . --ignore-unknown",
327
334
  "format:css": "prettier --write \"src/**/*.css\" \"ux-demo/**/*.css\"",
328
335
  "check:format": "prettier --check . --ignore-unknown",
329
336
  "catalog:sync": "node scripts/sync-component-catalog.mjs && node scripts/sync-component-catalog-v2.mjs",
330
337
  "catalog:v2:sync": "node scripts/sync-component-catalog-v2.mjs",
338
+ "check:component-integrations": "node scripts/check-component-integrations.mjs",
339
+ "component-integrations:dry-run": "node scripts/check-component-integrations.mjs --dry-run",
340
+ "check:change": "node scripts/check-ui-change.mjs",
331
341
  "check:catalog": "node scripts/sync-component-catalog.mjs --check && node scripts/sync-component-catalog-v2.mjs --check && node scripts/check-component-catalog.mjs",
332
342
  "check:profile": "node scripts/check-application-ui-profile.mjs",
333
343
  "check:demo-conformance": "node scripts/check-catalog-demo-conformance.mjs",
@@ -335,6 +345,8 @@
335
345
  "check:ai-regressions": "node scripts/check-ai-regressions.mjs && node scripts/audit-ai-regression-results.mjs && node scripts/audit-ai-regression-results-v3.mjs",
336
346
  "check:ai-signatures": "node scripts/sync-ai-public-signatures.mjs --check",
337
347
  "ai:signatures:sync": "npm run build && node scripts/sync-ai-public-signatures.mjs",
348
+ "check:ai-compatibility": "node scripts/sync-ai-compatibility.mjs",
349
+ "ai:compatibility:sync": "node scripts/sync-ai-compatibility.mjs --write",
338
350
  "ai:regressions:compile": "node scripts/compile-ai-regression-response.mjs",
339
351
  "ai:regressions:prepare": "node scripts/prepare-ai-regression.mjs",
340
352
  "ai:regressions:record": "node scripts/record-ai-regression-run.mjs",
@@ -354,8 +366,8 @@
354
366
  "test:contract-types:source": "node node_modules/typescript7/bin/tsc -p tests/consumer-types/contracts/tsconfig.source.json",
355
367
  "test:contract-types:packed": "node scripts/check-packed-type-contracts.mjs",
356
368
  "test:consumer-types": "npm run test:contract-types:source && npm run build && node node_modules/typescript7/bin/tsc -p tests/consumer-types/webawesome/tsconfig.json && npm run test:contract-types:packed",
357
- "test:e2e": "npm run demo:build && playwright test",
358
- "check": "npm run check:catalog && npm run check:profile && npm run check:demo-conformance && npm run check:recipes && npm run check:guidance && npm run check:ai-regressions && npm run lint && npm run typecheck && npm test && npm run test:consumer-types && npm run check:ai-signatures && npm run demo:build && npm run check:design-templates && npm pack --dry-run",
369
+ "test:e2e": "playwright test",
370
+ "check": "npm run check:catalog && npm run check:component-integrations && npm run check:profile && npm run check:demo-conformance && npm run check:recipes && npm run check:guidance && npm run check:ai-compatibility && npm run check:ai-regressions && npm run lint && npm run typecheck && npm test && npm run test:consumer-types && npm run check:ai-signatures && npm run demo:build && npm run check:design-templates && npm pack --dry-run",
359
371
  "prepublishOnly": "npm run check",
360
372
  "check:design-templates": "node scripts/check-design-templates.mjs",
361
373
  "check:design-templates:drift": "node scripts/check-design-templates-drift.mjs",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/list.tsx"],"names":[],"mappings":";;;AAUA,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;AAgBO,SAAS,IAAA,CAAK;AAAA,EACnB,QAAA;AAAA,EACA,GAAA,GAAM,KAAA;AAAA,EACN,IAAA,GAAO,KAAA;AAAA,EACP,UAAA,GAAa,KAAA;AAAA,EACb,YAAA,GAAe,EAAA;AAAA,EACf,SAAA,GAAY;AACd,CAAA,EAAc;AACZ,EAAA,MAAM,QAAA,GACJ,GAAA,KAAQ,IAAA,GACJ,qBAAA,GACA,UAAA,CAAW,QAAA,CAAS,GAAkB,CAAA,GACpC,KAAA,CAAM,GAAkB,CAAA,GACxB,GAAA,IAAO,MAAA;AACf,EAAA,MAAM,SAAA,GAAY,IAAA,KAAS,IAAA,GAAO,UAAA,GAAa,IAAA,IAAQ,MAAA;AACvD,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,QAAA,GAAW,CAAA,gBAAA,EAAmB,QAAQ,CAAA,CAAA,GAAK,EAAA;AAAA,IAC3C,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,UAAA,EAAU,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAC,CAAA;AAAA,MAC7B,WAAA,EAAW,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAC,CAAA;AAAA,MAC/B,iBAAA,EAAiB,OAAO,UAAU,CAAA;AAAA,MAClC,iBAAe,YAAA,IAAgB,MAAA;AAAA,MAC/B,OAAO,KAAA,IAAS,MAAA;AAAA,MAEf;AAAA;AAAA,GACH;AAEJ","file":"chunk-RL6COPKF.js","sourcesContent":["import {\n type CssFlex,\n type CssFlexKeyword,\n type CssLength,\n space,\n type UiSpaceName,\n} from './css-values.js';\nimport type { DividerSides } from './divider-sides.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 ListProps {\n children?: KerfUiContent;\n /** Use the standard item gap, a named UI spacing token, or a typed CSS length. Defaults to no gap. */\n gap?: boolean | UiSpaceName | CssLength;\n /** Allow this list to grow/shrink, use a keyword, or supply a typed CSS flex shorthand. */\n flex?: boolean | CssFlexKeyword | CssFlex;\n /** Own vertical scrolling and overscroll containment. */\n scrollable?: boolean;\n /** Physical divider edges in canonical top/right/bottom/left order. */\n dividerSides?: DividerSides;\n className?: string;\n}\n\n/** A stretch-aligned vertical stack with optional gap, flex, scroll, and dividers. */\nexport function List({\n children,\n gap = false,\n flex = false,\n scrollable = false,\n dividerSides = '',\n className = '',\n}: ListProps) {\n const gapValue =\n gap === true\n ? 'var(--kui-list-gap)'\n : spaceNames.includes(gap as UiSpaceName)\n ? space(gap as UiSpaceName)\n : gap || undefined;\n const flexValue = flex === true ? '1 1 auto' : flex || undefined;\n const style = [\n gapValue ? `--_kui-list-gap:${gapValue}` : '',\n flexValue ? `--_kui-list-flex:${flexValue}` : '',\n ]\n .filter(Boolean)\n .join(';');\n\n return (\n <div\n class={`kui-list ${className}`.trim()}\n data-component=\"list\"\n data-gap={String(Boolean(gap))}\n data-flex={String(Boolean(flex))}\n data-scrollable={String(scrollable)}\n divider-sides={dividerSides || undefined}\n style={style || undefined}\n >\n {children}\n </div>\n );\n}\n\nexport type {\n CssFlex,\n CssFlexKeyword,\n CssLength,\n UiSpaceName,\n} from './css-values.js';\nexport type { DividerSides } from './divider-sides.js';\n"]}