@kerfjs/ui 5.0.0-beta.66 → 5.0.0-beta.67

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 CHANGED
@@ -189,7 +189,7 @@ interchangeable. `ListItem` and `ListActionRow` deliberately expose no raw
189
189
  | `FloatingToolbar` | `@kerfjs/ui/floating-toolbar` | `@kerfjs/ui/floating-toolbar.css` |
190
190
  | `PopupMenu` (register with `@kerfjs/ui/popup-menu/register`) | `@kerfjs/ui/popup-menu` | `@kerfjs/ui/popup-menu.css` |
191
191
  | `ToolbarText` | `@kerfjs/ui/toolbar-text` | `@kerfjs/ui/toolbar-text.css` |
192
- | `Text` | `@kerfjs/ui/text` | `@kerfjs/ui/text.css` |
192
+ | `Text`, `FieldLabel` | `@kerfjs/ui/text` | `@kerfjs/ui/text.css` |
193
193
  | `List` | `@kerfjs/ui/list` | `@kerfjs/ui/list.css` |
194
194
  | `Row` | `@kerfjs/ui/row` | `@kerfjs/ui/row.css` |
195
195
  | `Grid` | `@kerfjs/ui/grid` | `@kerfjs/ui/grid.css` |
@@ -1942,14 +1942,16 @@
1942
1942
  "category": "Structure",
1943
1943
  "kind": "component",
1944
1944
  "source": "kerf",
1945
- "description": "Semantic native paragraph text by default, with heading and inline-span variants plus composable semantic presentation roles.",
1945
+ "description": "Semantic native text plus a FieldLabel heading for read-only field previews that matches themed Web Awesome form labels.",
1946
1946
  "uses": [],
1947
1947
  "purpose": "Render paragraph semantics by default, h1 through h6 when selected, or geometry-free inline secondary text as a span while independently configuring quiet or danger tone, compact through extra-large size, or monospace font.",
1948
1948
  "publicExports": [
1949
- "Text"
1949
+ "Text",
1950
+ "FieldLabel"
1950
1951
  ],
1951
1952
  "useWhen": [
1952
- "Render ordinary application headings or paragraphs with native document semantics, or inline secondary text inside rows, labels, and table cells."
1953
+ "Render ordinary application headings or paragraphs with native document semantics, or inline secondary text inside rows, labels, and table cells.",
1954
+ "Render FieldLabel over a read-only or click-to-edit preview that replaces a Web Awesome form control."
1953
1955
  ],
1954
1956
  "avoidWhen": [
1955
1957
  "Do not use Text for toolbar identity or title content; use ToolbarText inside a Toolbar zone.",
@@ -1971,7 +1973,8 @@
1971
1973
  "size",
1972
1974
  "font",
1973
1975
  "copy",
1974
- "document heading hierarchy"
1976
+ "document heading hierarchy",
1977
+ "FieldLabel copy, preview/edit state, and aria-labelledby association"
1975
1978
  ],
1976
1979
  "variants": [
1977
1980
  "p, h1 through h6, or inline span semantic variant",
@@ -1983,14 +1986,15 @@
1983
1986
  "accessibility": [
1984
1987
  "Text renders a native paragraph by default; choose an h1 through h6 variant by document outline rather than appearance, or span for inline secondary text.",
1985
1988
  "Ordinary global, data, and ARIA attributes pass through to the native element.",
1986
- "Choose tone, size, and font independently of the heading level so appearance does not distort the document outline."
1989
+ "Choose tone, size, and font independently of the heading level so appearance does not distort the document outline.",
1990
+ "FieldLabel is plain text, not a native label; give it an id and associate the preview group with aria-labelledby."
1987
1991
  ],
1988
1992
  "geometry": {
1989
1993
  "margin": "none",
1990
1994
  "border": "self",
1991
1995
  "padding": "self",
1992
1996
  "notes": [
1993
- "Block Text variants reset native margins and add a 1px transparent border plus the standard 8px item padding; flush removes the border and padding. Tight line height is available for compact copy. Span has no margin, border, or padding."
1997
+ "Block Text variants reset native margins and add a 1px transparent border plus the standard 8px item padding; flush removes the border and padding. Tight line height is available for compact copy. Span has no margin, border, or padding. FieldLabel mirrors the themed Web Awesome label typography, 9px inline inset, and bottom gap."
1994
1998
  ]
1995
1999
  },
1996
2000
  "delivery": {
@@ -2002,7 +2006,8 @@
2002
2006
  },
2003
2007
  "wiring": [],
2004
2008
  "publicClasses": [
2005
- "kui-text"
2009
+ "kui-text",
2010
+ "kui-text__field-label"
2006
2011
  ],
2007
2012
  "publicTokens": [
2008
2013
  "--kui-color-danger-on-quiet",
@@ -89,7 +89,7 @@
89
89
  },
90
90
  "parents": {
91
91
  "mode": "listed",
92
- "entries": ["@kerfjs/ui:toolbar"]
92
+ "entries": ["@kerfjs/ui:toolbar", "@kerfjs/ui:floating-toolbar"]
93
93
  },
94
94
  "contexts": ["toolbar-zone"],
95
95
  "zones": [
@@ -1521,7 +1521,10 @@
1521
1521
  "name": "ToolbarControlGroup",
1522
1522
  "kind": "component",
1523
1523
  "source": "kerf",
1524
- "parents": { "mode": "listed", "entries": ["@kerfjs/ui:toolbar"] },
1524
+ "parents": {
1525
+ "mode": "listed",
1526
+ "entries": ["@kerfjs/ui:toolbar", "@kerfjs/ui:floating-toolbar"]
1527
+ },
1525
1528
  "contexts": ["toolbar-zone"],
1526
1529
  "zones": [
1527
1530
  {
@@ -1805,6 +1808,11 @@
1805
1808
  "id": "document heading hierarchy",
1806
1809
  "owner": "application",
1807
1810
  "required": false
1811
+ },
1812
+ {
1813
+ "id": "FieldLabel copy, preview/edit state, and aria-labelledby association",
1814
+ "owner": "application",
1815
+ "required": false
1808
1816
  }
1809
1817
  ],
1810
1818
  "wiring": {
@@ -1821,7 +1829,7 @@
1821
1829
  "border": "self",
1822
1830
  "padding": "self",
1823
1831
  "notes": [
1824
- "Block Text variants reset native margins and add a 1px transparent border plus the standard 8px item padding; flush removes the border and padding. Tight line height is available for compact copy. Span has no margin, border, or padding."
1832
+ "Block Text variants reset native margins and add a 1px transparent border plus the standard 8px item padding; flush removes the border and padding. Tight line height is available for compact copy. Span has no margin, border, or padding. FieldLabel mirrors the themed Web Awesome label typography, 9px inline inset, and bottom gap."
1825
1833
  ]
1826
1834
  }
1827
1835
  },
@@ -1829,13 +1837,14 @@
1829
1837
  "obligations": [
1830
1838
  "Text renders a native paragraph by default; choose an h1 through h6 variant by document outline rather than appearance, or span for inline secondary text.",
1831
1839
  "Ordinary global, data, and ARIA attributes pass through to the native element.",
1832
- "Choose tone, size, and font independently of the heading level so appearance does not distort the document outline."
1840
+ "Choose tone, size, and font independently of the heading level so appearance does not distort the document outline.",
1841
+ "FieldLabel is plain text, not a native label; give it an id and associate the preview group with aria-labelledby."
1833
1842
  ]
1834
1843
  },
1835
1844
  "cssValueProps": [],
1836
1845
  "boundaries": {
1837
1846
  "rootClass": "kui-text",
1838
- "publicClasses": ["kui-text"],
1847
+ "publicClasses": ["kui-text", "kui-text__field-label"],
1839
1848
  "publicTokens": [
1840
1849
  "--kui-color-danger-on-quiet",
1841
1850
  "--kui-color-text-quiet",
@@ -4,13 +4,14 @@
4
4
 
5
5
  `@kerfjs/ui:text` · Kerf UI · component · Structure
6
6
 
7
- Semantic native paragraph text by default, with heading and inline-span variants plus composable semantic presentation roles.
7
+ Semantic native text plus a FieldLabel heading for read-only field previews that matches themed Web Awesome form labels.
8
8
 
9
9
  ## When to use
10
10
 
11
11
  Render paragraph semantics by default, h1 through h6 when selected, or geometry-free inline secondary text as a span while independently configuring quiet or danger tone, compact through extra-large size, or monospace font.
12
12
 
13
13
  - Render ordinary application headings or paragraphs with native document semantics, or inline secondary text inside rows, labels, and table cells.
14
+ - Render FieldLabel over a read-only or click-to-edit preview that replaces a Web Awesome form control.
14
15
 
15
16
  **Not when:**
16
17
 
@@ -24,7 +25,7 @@ Render paragraph semantics by default, h1 through h6 when selected, or geometry-
24
25
 
25
26
  ## Imports
26
27
 
27
- - JavaScript: `@kerfjs/ui/text` — exports `Text`.
28
+ - JavaScript: `@kerfjs/ui/text` — exports `Text`, `FieldLabel`.
28
29
  - CSS: the browser build of `@kerfjs/ui/text` pulls its CSS automatically; import `@kerfjs/ui/text.css` manually only without the `browser` export condition.
29
30
  - Declared side effects: browser-condition-css.
30
31
 
@@ -48,7 +49,7 @@ Exact prop names and types: [`@kerfjs/ui/text`](../public-api-signatures-v1.md#k
48
49
 
49
50
  ## State and wiring
50
51
 
51
- **The app owns:** semantic variant; tone; size; font; copy; document heading hierarchy.
52
+ **The app owns:** semantic variant; tone; size; font; copy; document heading hierarchy; FieldLabel copy, preview/edit state, and aria-labelledby association.
52
53
 
53
54
  No wiring helper.
54
55
 
@@ -56,21 +57,22 @@ No wiring helper.
56
57
 
57
58
  Margin: none · border: self · padding: self (layout role: structure). `self` means the component already owns it — do not add wrapper padding, margin, or borders around it.
58
59
 
59
- - Block Text variants reset native margins and add a 1px transparent border plus the standard 8px item padding; flush removes the border and padding. Tight line height is available for compact copy. Span has no margin, border, or padding.
60
+ - Block Text variants reset native margins and add a 1px transparent border plus the standard 8px item padding; flush removes the border and padding. Tight line height is available for compact copy. Span has no margin, border, or padding. FieldLabel mirrors the themed Web Awesome label typography, 9px inline inset, and bottom gap.
60
61
 
61
62
  ## Accessibility
62
63
 
63
64
  - Text renders a native paragraph by default; choose an h1 through h6 variant by document outline rather than appearance, or span for inline secondary text.
64
65
  - Ordinary global, data, and ARIA attributes pass through to the native element.
65
66
  - Choose tone, size, and font independently of the heading level so appearance does not distort the document outline.
67
+ - FieldLabel is plain text, not a native label; give it an id and associate the preview group with aria-labelledby.
66
68
 
67
69
  ## Styling boundary
68
70
 
69
71
  The component owns its own styles. Configure it through its props and variants; do not override its internals.
70
72
 
71
- Public class hooks (select for layout placement only, never to change the component's look): `kui-text`.
73
+ Public class hooks (select for layout placement only, never to change the component's look): `kui-text`, `kui-text__field-label`.
72
74
 
73
- Never put `kui-text` on an element you write; render `Text` instead (`KUI-L103`).
75
+ Never put `kui-text`, `kui-text__field-label` on an element you write; render `Text` instead (`KUI-L103`).
74
76
 
75
77
  Public tokens it reads: `--kui-color-danger-on-quiet`, `--kui-color-text-quiet`, `--kui-font-2xl`, `--kui-font-l`, `--kui-font-mono`, `--kui-font-xs`, `--kui-layout-item-padding`. Set a token only where its public contract allows; prefer a prop.
76
78
 
@@ -57,7 +57,7 @@ Exact prop names and types: [`@kerfjs/ui/toolbar-control-group`](../public-api-s
57
57
 
58
58
  ## Composition
59
59
 
60
- - Parents: only inside [Toolbar](./toolbar.md).
60
+ - Parents: only inside [Toolbar](./toolbar.md) or [FloatingToolbar](./floating-toolbar.md).
61
61
  - Contexts: `toolbar-zone`.
62
62
  - Children: only `control` (required: `control`).
63
63
  - Built from: [LucideIcon](./lucide-icon.md), [SegmentedControl](./segmented-control.md).
@@ -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.66` and `kerfjs@5.0.0-beta.66`. This bounded reference covers only APIs used by the seven-task corpus. It is interface evidence, not an implementation or runtime guarantee.
3
+ Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.67` and `kerfjs@5.0.0-beta.67`. 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
 
@@ -3301,6 +3301,13 @@ type TextBorder = 'transparent' | 'none';
3301
3301
  type TextLineHeight = 'default' | 'tight';
3302
3302
  type TextWrap = 'normal' | 'anywhere' | 'nowrap' | 'truncate';
3303
3303
  type TextContent = KerfUiContent | string | number | readonly TextContent[];
3304
+ type FieldLabelProps = Omit<KerfBaseAttrs, 'children' | 'class' | 'className'> & {
3305
+ children: string;
3306
+ class?: string;
3307
+ className?: string;
3308
+ };
3309
+ /** Visible field heading for a read-only preview; use its id with aria-labelledby on the preview group. */
3310
+ declare function FieldLabel({ children, class: classValue, className, ...attributes }: FieldLabelProps): kerfjs.SafeHtml;
3304
3311
  type TextCommonProps = Omit<KerfBaseAttrs, 'children' | 'class' | 'className'> & {
3305
3312
  /** Native heading, paragraph, or inline span element to render. Defaults to `p`. */
3306
3313
  variant?: TextVariant;
@@ -3337,7 +3344,7 @@ type TextProps = TextCommonProps & ({
3337
3344
  */
3338
3345
  declare function Text({ variant: Variant, tone, size, font, border, flush, lineHeight, wrap, maxLines, children, class: classValue, className, ...attributes }: TextProps): kerfjs.SafeHtml;
3339
3346
 
3340
- export { Text, type TextBorder, type TextContent, type TextFont, type TextLineHeight, type TextProps, type TextSize, type TextTone, type TextVariant, type TextWrap };
3347
+ export { FieldLabel, type FieldLabelProps, Text, type TextBorder, type TextContent, type TextFont, type TextLineHeight, type TextProps, type TextSize, type TextTone, type TextVariant, type TextWrap };
3341
3348
  ```
3342
3349
 
3343
3350
  ## `@kerfjs/ui/row`
package/ai/skill.md CHANGED
@@ -246,6 +246,8 @@ Set `--kui-toolbar-inset: 0px` on an embedded Toolbar to remove its outer paddin
246
246
 
247
247
  For compact dialog copy, use `Text flush lineHeight="tight"`; for compact metadata, use `ValueTable density="compact"` and its public row columns/padding/gap tokens. `ToolbarText size="xsmall"` fits a dense rail heading. A `TokenSearchField` editor shrinks inside a narrow group by default; set `--kui-token-search-editor-min-width` when a minimum is needed. A full-height shell uses the one `.kui-app-root` mount container documented in `docs/document-baseline.md`.
248
248
 
249
+ For a read-only field preview that replaces a Web Awesome input, use `FieldLabel` from `@kerfjs/ui/text` above the preview. Put it in `ListInsetControl sides="trl"` beside a `ContentItem` value; give it an id and use `aria-labelledby` on the preview group. The app owns preview/edit state and hint copy.
250
+
249
251
  Common mistakes:
250
252
 
251
253
  | Mistake | Fix |
@@ -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.66` 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.
3
+ Generated from the emitted `@kerfjs/ui@5.0.0-beta.67` 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';
@@ -22,7 +22,7 @@ export interface ComponentOwnershipFacts {
22
22
 
23
23
  export interface RestyledComponent {
24
24
  entry: OwnershipCatalogEntry;
25
- via: 'class' | 'data-component' | 'tag';
25
+ via: 'class' | 'data-component' | 'tag' | 'descendant';
26
26
  name: string;
27
27
  }
28
28
 
@@ -87,10 +87,11 @@ export function componentOwnershipFacts(entries) {
87
87
  }
88
88
 
89
89
  /**
90
- * The cataloged components a selector list makes its subject: the rightmost
91
- * compound of each complex selector, with `:has()` / `:not()` arguments
92
- * removed because keying on or excluding a component does not style it. A
93
- * subject that is a `::part()` is left to the shadow-part rule (`KUI-L011`).
90
+ * The cataloged components a selector list restyles: the rightmost compound
91
+ * of each complex selector, or an unclassed descendant reached through a
92
+ * cataloged anatomy class. `:has()` / `:not()` arguments are removed because
93
+ * keying on or excluding a component does not style it. A subject that is a
94
+ * `::part()` is left to the shadow-part rule (`KUI-L011`).
94
95
  * Returns `{ entry, via, name }` records; `isForeign(entry)` decides which
95
96
  * entries the stylesheet does not own.
96
97
  */
@@ -108,6 +109,7 @@ export function restyledComponents(selectorList, facts, isForeign) {
108
109
  const subject = parts.at(-1)?.compound;
109
110
  if (!subject || /::part\(/i.test(subject)) continue;
110
111
  const bare = withoutRelationalArguments(subject);
112
+ const subjectClasses = classNames(bare);
111
113
  for (const className of classNames(bare))
112
114
  add(facts.classOwners.get(className), 'class', `.${className}`);
113
115
  for (const value of dataComponents(bare))
@@ -118,9 +120,26 @@ export function restyledComponents(selectorList, facts, isForeign) {
118
120
  );
119
121
  // An application class on the subject scopes a Web Awesome tag to the
120
122
  // application's own element; a component package never places one there.
121
- if (classNames(bare).some((name) => !facts.classOwners.has(name))) continue;
123
+ if (subjectClasses.some((name) => !facts.classOwners.has(name))) continue;
122
124
  for (const type of subjectTypes(subject) ?? [])
123
125
  add(facts.tagOwners.get(type), 'tag', type);
126
+ // A raw descendant of a component's cataloged anatomy is still inside
127
+ // that component. Do not infer ownership through its root, where an app
128
+ // may place its own children, or through an app-named intermediate node.
129
+ if (subjectClasses.length || parts.length < 2) continue;
130
+ for (let index = parts.length - 2; index >= 0; index -= 1) {
131
+ const classes = classNames(
132
+ withoutRelationalArguments(parts[index].compound),
133
+ );
134
+ if (classes.some((name) => !facts.classOwners.has(name))) break;
135
+ const anatomy = classes.find(
136
+ (name) => name.includes('__') && facts.classOwners.has(name),
137
+ );
138
+ if (anatomy) {
139
+ add(facts.classOwners.get(anatomy), 'descendant', `.${anatomy}`);
140
+ break;
141
+ }
142
+ }
124
143
  }
125
144
  return found;
126
145
  }
@@ -435,7 +435,9 @@ function inspectComponentOwnership(
435
435
  diagnostic(
436
436
  'KUI-L019',
437
437
  location(file, rule),
438
- `\`${name}\` makes ${componentLabel(entry)} the subject of an application rule (${properties.join(', ')}); components own their styles. Configure it through ${configurationFor(entry)}. To place your own content in its context, style your own element (\`${name} > .your-element\`). ${reportGap(entry)}`,
438
+ via === 'descendant'
439
+ ? `\`${name}\` reaches an unclassed descendant inside ${componentLabel(entry)} (${properties.join(', ')}); components own their styles. Configure it through ${configurationFor(entry)}. To place your own content in its context, style your own element. ${reportGap(entry)}`
440
+ : `\`${name}\` makes ${componentLabel(entry)} the subject of an application rule (${properties.join(', ')}); components own their styles. Configure it through ${configurationFor(entry)}. To place your own content in its context, style your own element (\`${name} > .your-element\`). ${reportGap(entry)}`,
439
441
  {
440
442
  selector: rule.selector,
441
443
  component: entry.key,
package/dist/catalog.js CHANGED
@@ -4,8 +4,8 @@ import { Workbench } from './chunk-TGM424PI.js';
4
4
  import { PopupMenu } from './chunk-J3KGJ6P6.js';
5
5
 
6
6
  import { Row } from './chunk-VZOFZPSO.js';
7
- import { ListHeader } from './chunk-5IJ6UGNZ.js';
8
- import { Text } from './chunk-CQHN45XR.js';
7
+ import { ListHeader } from './chunk-3BCJGM36.js';
8
+ import { Text } from './chunk-YDGNU2OD.js';
9
9
  import { ListInsetText } from './chunk-DG6G5EPF.js';
10
10
  import { ListItem } from './chunk-EN4LDR5Y.js';
11
11
  import { ToolbarText } from './chunk-V3DX3K65.js';
@@ -1,4 +1,4 @@
1
- import { Text } from './chunk-CQHN45XR.js';
1
+ import { Text } from './chunk-YDGNU2OD.js';
2
2
  import { DisclosureArrow } from './chunk-AUVG54KC.js';
3
3
  import { Skeleton } from './chunk-AHEG27M7.js';
4
4
  import { Badge } from './chunk-MP2GDBQZ.js';
@@ -153,4 +153,4 @@ function ListHeader({
153
153
 
154
154
  export { ListHeader };
155
155
 
156
- //# sourceMappingURL=chunk-5IJ6UGNZ.js.map
156
+ //# sourceMappingURL=chunk-3BCJGM36.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/list-header.tsx"],"names":[],"mappings":"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","file":"chunk-5IJ6UGNZ.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport { Badge, type BadgeTone } from './badge.js';\nimport { em } from './css-values.js';\nimport { DisclosureArrow } from './disclosure-arrow.js';\nimport {\n filterControlAttributes,\n filterDataAttributes,\n} from './extension-attributes.js';\nimport { Skeleton } from './skeleton.js';\nimport { Text } from './text.js';\nimport type { HeadingLevel } from './toolbar-text.js';\n\nconst PROTECTED_ROOT_DATA_ATTRIBUTES = new Set([\n 'data-component',\n 'data-action',\n 'data-has-badge',\n 'data-has-count',\n 'data-density',\n 'data-divider',\n 'data-inline',\n 'data-width',\n 'data-indicator-tone',\n 'data-toggle',\n]);\nconst PROTECTED_TRIGGER_DATA_ATTRIBUTES = new Set([\n 'data-action',\n 'data-kui-disabled',\n]);\n\ntype ListHeaderRootAttributes = Readonly<\n Record<`data-${string}`, string | undefined> & {\n 'data-component'?: never;\n 'data-action'?: never;\n 'data-has-badge'?: never;\n 'data-has-count'?: never;\n 'data-density'?: never;\n 'data-divider'?: never;\n 'data-inline'?: never;\n 'data-width'?: never;\n 'data-indicator-tone'?: never;\n 'data-toggle'?: never;\n }\n>;\n\ntype ListHeaderTriggerAttributes = Readonly<\n Record<`data-${string}`, string | undefined> & {\n 'data-action'?: never;\n 'data-kui-disabled'?: never;\n popoverTarget?: string;\n popoverTargetAction?: 'toggle' | 'show' | 'hide';\n 'aria-controls'?: string;\n 'aria-haspopup'?: 'dialog' | 'menu' | 'listbox' | 'tree' | 'grid' | 'true';\n }\n>;\n\ninterface ListHeaderBaseProps {\n label: string;\n density?: 'standard' | 'compact';\n divider?: 'none' | 'before' | 'after' | 'both';\n /** Shrink-wrap the header without its default outer margin, border, or padding. */\n inline?: boolean;\n /** Fill the available row or shrink-wrap while retaining normal header geometry. */\n width?: 'fill' | 'content';\n indicatorTone?: 'neutral' | 'accent' | 'pop' | 'danger';\n /** Render as an unanimated loading skeleton: keep the label and action affordance, disable interaction. */\n placeholder?: boolean;\n rootAttributes?: ListHeaderRootAttributes;\n triggerAttributes?: ListHeaderTriggerAttributes;\n /** Native named-slot assignment when composed inside a web component. */\n slot?: string;\n}\n\ntype ListHeaderModeProps =\n | {\n /** Render the title as a controlled disclosure trigger. */\n toggle: true;\n /** A toggle's label is its button text, not a heading. */\n headingLevel?: never;\n action: string;\n expanded: boolean;\n actionIcon?: SafeHtml;\n actionLabel?: never;\n actionDisabled?: boolean;\n disabledReason?: string;\n }\n | {\n /** Render a separately named trailing action. */\n toggle?: false;\n /**\n * Native heading level (`h1`–`h6`) of the label. Default `2`. Match the\n * document outline; the visual treatment does not change.\n */\n headingLevel?: HeadingLevel;\n action: string;\n actionLabel: string;\n actionIcon: SafeHtml;\n expanded?: never;\n actionDisabled?: boolean;\n disabledReason?: string;\n }\n | {\n /** Render a passive section heading. */\n toggle?: false;\n /**\n * Native heading level (`h1`–`h6`) of the label. Default `2`. Match the\n * document outline; the visual treatment does not change.\n */\n headingLevel?: HeadingLevel;\n action?: never;\n actionLabel?: never;\n actionIcon?: never;\n expanded?: never;\n actionDisabled?: never;\n disabledReason?: never;\n };\n\ntype ListHeaderIndicatorProps =\n | { count: number; countLabel: string; badge?: never; status?: never }\n | { count?: never; countLabel?: never; badge: SafeHtml; status?: never }\n | { count?: never; countLabel?: never; badge?: never; status?: SafeHtml };\n\nexport type ListHeaderProps = ListHeaderBaseProps &\n ListHeaderIndicatorProps &\n ListHeaderModeProps;\n\nexport function ListHeader({\n label,\n headingLevel = 2,\n count,\n countLabel,\n badge,\n status,\n density = 'standard',\n divider = 'none',\n inline = false,\n width = 'fill',\n indicatorTone = 'neutral',\n action,\n actionLabel,\n actionIcon,\n actionDisabled = false,\n disabledReason,\n expanded,\n toggle = false,\n placeholder = false,\n rootAttributes = {},\n triggerAttributes = {},\n slot,\n}: ListHeaderProps) {\n const extensionRootAttributes = filterDataAttributes(\n rootAttributes,\n PROTECTED_ROOT_DATA_ATTRIBUTES,\n );\n const extensionTriggerAttributes = filterControlAttributes(\n triggerAttributes,\n PROTECTED_TRIGGER_DATA_ATTRIBUTES,\n );\n const normalizedCount =\n typeof count === 'number' && Number.isSafeInteger(count) && count >= 0\n ? count\n : undefined;\n const normalizedCountLabel =\n normalizedCount === undefined\n ? undefined\n : typeof countLabel === 'string' && countLabel.trim()\n ? countLabel\n : String(normalizedCount);\n const renderedBadge =\n normalizedCount === undefined ? (status ?? badge) : undefined;\n const renderedActionIcon =\n actionIcon ??\n (toggle ? <DisclosureArrow open={Boolean(expanded)} /> : undefined);\n const accessibleLabel =\n normalizedCount === undefined\n ? undefined\n : `${label}, ${normalizedCountLabel}`;\n const badgeTone: BadgeTone =\n indicatorTone === 'accent' ? 'brand' : indicatorTone;\n const indicator = placeholder ? (\n (normalizedCount !== undefined || renderedBadge) && (\n <Badge size=\"compact\" tone={badgeTone}>\n <Skeleton width={em(1.75)} />\n </Badge>\n )\n ) : normalizedCount === undefined ? (\n renderedBadge && (\n <Badge size=\"compact\" tone={badgeTone}>\n {renderedBadge}\n </Badge>\n )\n ) : (\n <Badge size=\"compact\" tone={badgeTone} ariaHidden>\n {normalizedCount}\n </Badge>\n );\n const busy = placeholder ? ('true' as const) : undefined;\n if (toggle) {\n return (\n <header\n {...extensionRootAttributes}\n class=\"kui-list-header\"\n data-component=\"list-header\"\n data-has-badge={String(Boolean(renderedBadge))}\n data-has-count={String(normalizedCount !== undefined)}\n data-density={density}\n data-divider={divider}\n data-inline={String(inline)}\n data-width={width}\n data-indicator-tone={indicatorTone}\n data-toggle=\"true\"\n data-placeholder={placeholder ? 'true' : undefined}\n aria-busy={busy}\n slot={slot}\n >\n <button\n {...extensionTriggerAttributes}\n type=\"button\"\n class=\"kui-list-header__title kui-list-header__toggle\"\n data-action={placeholder ? undefined : action}\n title={actionDisabled ? disabledReason : undefined}\n disabled={actionDisabled || placeholder || undefined}\n data-kui-disabled={actionDisabled ? 'true' : undefined}\n aria-label={accessibleLabel}\n aria-expanded={String(Boolean(expanded))}\n >\n <Text variant=\"span\">{label}</Text>\n {indicator}\n {renderedActionIcon && (\n <span class=\"kui-list-header__action-layer\">\n {renderedActionIcon}\n </span>\n )}\n </button>\n </header>\n );\n }\n return (\n <header\n {...extensionRootAttributes}\n class=\"kui-list-header\"\n data-component=\"list-header\"\n data-has-badge={String(Boolean(renderedBadge))}\n data-has-count={String(normalizedCount !== undefined)}\n data-density={density}\n data-divider={divider}\n data-inline={String(inline)}\n data-width={width}\n data-indicator-tone={indicatorTone}\n data-toggle=\"false\"\n data-placeholder={placeholder ? 'true' : undefined}\n aria-busy={busy}\n slot={slot}\n >\n <div class=\"kui-list-header__title\">\n <Text\n variant={`h${headingLevel}`}\n border=\"none\"\n aria-label={accessibleLabel}\n >\n {label}\n </Text>\n {indicator}\n </div>\n {action && (\n <button\n {...extensionTriggerAttributes}\n type=\"button\"\n class=\"kui-list-header__action\"\n data-action={placeholder ? undefined : action}\n aria-label={actionLabel}\n title={actionDisabled ? disabledReason : actionLabel}\n disabled={actionDisabled || placeholder || undefined}\n data-kui-disabled={actionDisabled ? 'true' : undefined}\n >\n {renderedActionIcon}\n </button>\n )}\n </header>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/list-header.tsx"],"names":[],"mappings":"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","file":"chunk-3BCJGM36.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport { Badge, type BadgeTone } from './badge.js';\nimport { em } from './css-values.js';\nimport { DisclosureArrow } from './disclosure-arrow.js';\nimport {\n filterControlAttributes,\n filterDataAttributes,\n} from './extension-attributes.js';\nimport { Skeleton } from './skeleton.js';\nimport { Text } from './text.js';\nimport type { HeadingLevel } from './toolbar-text.js';\n\nconst PROTECTED_ROOT_DATA_ATTRIBUTES = new Set([\n 'data-component',\n 'data-action',\n 'data-has-badge',\n 'data-has-count',\n 'data-density',\n 'data-divider',\n 'data-inline',\n 'data-width',\n 'data-indicator-tone',\n 'data-toggle',\n]);\nconst PROTECTED_TRIGGER_DATA_ATTRIBUTES = new Set([\n 'data-action',\n 'data-kui-disabled',\n]);\n\ntype ListHeaderRootAttributes = Readonly<\n Record<`data-${string}`, string | undefined> & {\n 'data-component'?: never;\n 'data-action'?: never;\n 'data-has-badge'?: never;\n 'data-has-count'?: never;\n 'data-density'?: never;\n 'data-divider'?: never;\n 'data-inline'?: never;\n 'data-width'?: never;\n 'data-indicator-tone'?: never;\n 'data-toggle'?: never;\n }\n>;\n\ntype ListHeaderTriggerAttributes = Readonly<\n Record<`data-${string}`, string | undefined> & {\n 'data-action'?: never;\n 'data-kui-disabled'?: never;\n popoverTarget?: string;\n popoverTargetAction?: 'toggle' | 'show' | 'hide';\n 'aria-controls'?: string;\n 'aria-haspopup'?: 'dialog' | 'menu' | 'listbox' | 'tree' | 'grid' | 'true';\n }\n>;\n\ninterface ListHeaderBaseProps {\n label: string;\n density?: 'standard' | 'compact';\n divider?: 'none' | 'before' | 'after' | 'both';\n /** Shrink-wrap the header without its default outer margin, border, or padding. */\n inline?: boolean;\n /** Fill the available row or shrink-wrap while retaining normal header geometry. */\n width?: 'fill' | 'content';\n indicatorTone?: 'neutral' | 'accent' | 'pop' | 'danger';\n /** Render as an unanimated loading skeleton: keep the label and action affordance, disable interaction. */\n placeholder?: boolean;\n rootAttributes?: ListHeaderRootAttributes;\n triggerAttributes?: ListHeaderTriggerAttributes;\n /** Native named-slot assignment when composed inside a web component. */\n slot?: string;\n}\n\ntype ListHeaderModeProps =\n | {\n /** Render the title as a controlled disclosure trigger. */\n toggle: true;\n /** A toggle's label is its button text, not a heading. */\n headingLevel?: never;\n action: string;\n expanded: boolean;\n actionIcon?: SafeHtml;\n actionLabel?: never;\n actionDisabled?: boolean;\n disabledReason?: string;\n }\n | {\n /** Render a separately named trailing action. */\n toggle?: false;\n /**\n * Native heading level (`h1`–`h6`) of the label. Default `2`. Match the\n * document outline; the visual treatment does not change.\n */\n headingLevel?: HeadingLevel;\n action: string;\n actionLabel: string;\n actionIcon: SafeHtml;\n expanded?: never;\n actionDisabled?: boolean;\n disabledReason?: string;\n }\n | {\n /** Render a passive section heading. */\n toggle?: false;\n /**\n * Native heading level (`h1`–`h6`) of the label. Default `2`. Match the\n * document outline; the visual treatment does not change.\n */\n headingLevel?: HeadingLevel;\n action?: never;\n actionLabel?: never;\n actionIcon?: never;\n expanded?: never;\n actionDisabled?: never;\n disabledReason?: never;\n };\n\ntype ListHeaderIndicatorProps =\n | { count: number; countLabel: string; badge?: never; status?: never }\n | { count?: never; countLabel?: never; badge: SafeHtml; status?: never }\n | { count?: never; countLabel?: never; badge?: never; status?: SafeHtml };\n\nexport type ListHeaderProps = ListHeaderBaseProps &\n ListHeaderIndicatorProps &\n ListHeaderModeProps;\n\nexport function ListHeader({\n label,\n headingLevel = 2,\n count,\n countLabel,\n badge,\n status,\n density = 'standard',\n divider = 'none',\n inline = false,\n width = 'fill',\n indicatorTone = 'neutral',\n action,\n actionLabel,\n actionIcon,\n actionDisabled = false,\n disabledReason,\n expanded,\n toggle = false,\n placeholder = false,\n rootAttributes = {},\n triggerAttributes = {},\n slot,\n}: ListHeaderProps) {\n const extensionRootAttributes = filterDataAttributes(\n rootAttributes,\n PROTECTED_ROOT_DATA_ATTRIBUTES,\n );\n const extensionTriggerAttributes = filterControlAttributes(\n triggerAttributes,\n PROTECTED_TRIGGER_DATA_ATTRIBUTES,\n );\n const normalizedCount =\n typeof count === 'number' && Number.isSafeInteger(count) && count >= 0\n ? count\n : undefined;\n const normalizedCountLabel =\n normalizedCount === undefined\n ? undefined\n : typeof countLabel === 'string' && countLabel.trim()\n ? countLabel\n : String(normalizedCount);\n const renderedBadge =\n normalizedCount === undefined ? (status ?? badge) : undefined;\n const renderedActionIcon =\n actionIcon ??\n (toggle ? <DisclosureArrow open={Boolean(expanded)} /> : undefined);\n const accessibleLabel =\n normalizedCount === undefined\n ? undefined\n : `${label}, ${normalizedCountLabel}`;\n const badgeTone: BadgeTone =\n indicatorTone === 'accent' ? 'brand' : indicatorTone;\n const indicator = placeholder ? (\n (normalizedCount !== undefined || renderedBadge) && (\n <Badge size=\"compact\" tone={badgeTone}>\n <Skeleton width={em(1.75)} />\n </Badge>\n )\n ) : normalizedCount === undefined ? (\n renderedBadge && (\n <Badge size=\"compact\" tone={badgeTone}>\n {renderedBadge}\n </Badge>\n )\n ) : (\n <Badge size=\"compact\" tone={badgeTone} ariaHidden>\n {normalizedCount}\n </Badge>\n );\n const busy = placeholder ? ('true' as const) : undefined;\n if (toggle) {\n return (\n <header\n {...extensionRootAttributes}\n class=\"kui-list-header\"\n data-component=\"list-header\"\n data-has-badge={String(Boolean(renderedBadge))}\n data-has-count={String(normalizedCount !== undefined)}\n data-density={density}\n data-divider={divider}\n data-inline={String(inline)}\n data-width={width}\n data-indicator-tone={indicatorTone}\n data-toggle=\"true\"\n data-placeholder={placeholder ? 'true' : undefined}\n aria-busy={busy}\n slot={slot}\n >\n <button\n {...extensionTriggerAttributes}\n type=\"button\"\n class=\"kui-list-header__title kui-list-header__toggle\"\n data-action={placeholder ? undefined : action}\n title={actionDisabled ? disabledReason : undefined}\n disabled={actionDisabled || placeholder || undefined}\n data-kui-disabled={actionDisabled ? 'true' : undefined}\n aria-label={accessibleLabel}\n aria-expanded={String(Boolean(expanded))}\n >\n <Text variant=\"span\">{label}</Text>\n {indicator}\n {renderedActionIcon && (\n <span class=\"kui-list-header__action-layer\">\n {renderedActionIcon}\n </span>\n )}\n </button>\n </header>\n );\n }\n return (\n <header\n {...extensionRootAttributes}\n class=\"kui-list-header\"\n data-component=\"list-header\"\n data-has-badge={String(Boolean(renderedBadge))}\n data-has-count={String(normalizedCount !== undefined)}\n data-density={density}\n data-divider={divider}\n data-inline={String(inline)}\n data-width={width}\n data-indicator-tone={indicatorTone}\n data-toggle=\"false\"\n data-placeholder={placeholder ? 'true' : undefined}\n aria-busy={busy}\n slot={slot}\n >\n <div class=\"kui-list-header__title\">\n <Text\n variant={`h${headingLevel}`}\n border=\"none\"\n aria-label={accessibleLabel}\n >\n {label}\n </Text>\n {indicator}\n </div>\n {action && (\n <button\n {...extensionTriggerAttributes}\n type=\"button\"\n class=\"kui-list-header__action\"\n data-action={placeholder ? undefined : action}\n aria-label={actionLabel}\n title={actionDisabled ? disabledReason : actionLabel}\n disabled={actionDisabled || placeholder || undefined}\n data-kui-disabled={actionDisabled ? 'true' : undefined}\n >\n {renderedActionIcon}\n </button>\n )}\n </header>\n );\n}\n"]}
@@ -1,6 +1,15 @@
1
1
  import { jsx } from 'kerfjs/jsx-runtime';
2
2
 
3
3
  // src/text.tsx
4
+ function FieldLabel({
5
+ children,
6
+ class: classValue = "",
7
+ className = "",
8
+ ...attributes
9
+ }) {
10
+ const classes = ["kui-text__field-label", classValue, className].filter(Boolean).join(" ");
11
+ return /* @__PURE__ */ jsx("div", { ...attributes, class: classes, "data-component": "field-label", children });
12
+ }
4
13
  function Text({
5
14
  variant: Variant = "p",
6
15
  tone = "default",
@@ -47,6 +56,6 @@ function Text({
47
56
  );
48
57
  }
49
58
 
50
- export { Text };
59
+ export { FieldLabel, Text };
51
60
 
52
- //# sourceMappingURL=chunk-CQHN45XR.js.map
61
+ //# sourceMappingURL=chunk-YDGNU2OD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/text.tsx"],"names":[],"mappings":";;;AA0BO,SAAS,UAAA,CAAW;AAAA,EACzB,QAAA;AAAA,EACA,OAAO,UAAA,GAAa,EAAA;AAAA,EACpB,SAAA,GAAY,EAAA;AAAA,EACZ,GAAG;AACL,CAAA,EAAoB;AAClB,EAAA,MAAM,OAAA,GAAU,CAAC,uBAAA,EAAyB,UAAA,EAAY,SAAS,EAC5D,MAAA,CAAO,OAAO,CAAA,CACd,IAAA,CAAK,GAAG,CAAA;AACX,EAAA,uBACE,GAAA,CAAC,SAAK,GAAG,UAAA,EAAY,OAAO,OAAA,EAAS,gBAAA,EAAe,eACjD,QAAA,EACH,CAAA;AAEJ;AA6CO,SAAS,IAAA,CAAK;AAAA,EACnB,SAAS,OAAA,GAAU,GAAA;AAAA,EACnB,IAAA,GAAO,SAAA;AAAA,EACP,IAAA,GAAO,SAAA;AAAA,EACP,IAAA,GAAO,SAAA;AAAA,EACP,MAAA,GAAS,aAAA;AAAA,EACT,KAAA,GAAQ,KAAA;AAAA,EACR,UAAA,GAAa,SAAA;AAAA,EACb,IAAA,GAAO,QAAA;AAAA,EACP,QAAA;AAAA,EACA,QAAA;AAAA,EACA,OAAO,UAAA,GAAa,EAAA;AAAA,EACpB,SAAA,GAAY,EAAA;AAAA,EACZ,GAAG;AACL,CAAA,EAAc;AACZ,EAAA,IACE,QAAA,KAAa,MAAA,KACZ,CAAC,MAAA,CAAO,aAAA,CAAc,QAAQ,CAAA,IAC7B,QAAA,GAAW,CAAA,IACX,IAAA,KAAS,QAAA,IACT,IAAA,KAAS,UAAA,CAAA;AAEX,IAAA,MAAM,IAAI,UAAA;AAAA,MACR;AAAA,KACF;AACF,EAAA,MAAM,OAAA,GAAU,CAAC,UAAA,EAAY,UAAA,EAAY,SAAS,EAAE,MAAA,CAAO,OAAO,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AAC5E,EAAA,uBACE,GAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACE,GAAG,UAAA;AAAA,MACJ,KAAA,EAAO,OAAA;AAAA,MACP,gBAAA,EAAe,MAAA;AAAA,MACf,WAAA,EAAW,IAAA;AAAA,MACX,WAAA,EAAW,IAAA;AAAA,MACX,WAAA,EAAW,IAAA;AAAA,MACX,aAAA,EAAa,MAAA;AAAA,MACb,YAAA,EAAY,QAAQ,MAAA,GAAS,MAAA;AAAA,MAC7B,kBAAA,EAAkB,UAAA,KAAe,OAAA,GAAU,OAAA,GAAU,MAAA;AAAA,MACrD,WAAA,EAAW,IAAA,KAAS,QAAA,GAAW,MAAA,GAAY,IAAA;AAAA,MAC3C,gBAAA,EAAgB,QAAA,KAAa,MAAA,GAAY,MAAA,GAAY,OAAO,QAAQ,CAAA;AAAA,MAEnE,QAAA,EAAA,QAAA,KAAa,SACZ,QAAA,mBAEA,GAAA;AAAA,QAAC,MAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAM,iBAAA;AAAA,UACN,KAAA,EAAO,yBAAyB,QAAQ,CAAA,CAAA;AAAA,UAEvC;AAAA;AAAA;AACH;AAAA,GAEJ;AAEJ","file":"chunk-YDGNU2OD.js","sourcesContent":["import type { KerfBaseAttrs } from 'kerfjs/jsx-runtime';\n\nimport type { KerfUiContent } from './semantic-content.js';\n\nexport type TextVariant =\n 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span';\nexport type TextTone = 'default' | 'quiet' | 'danger';\nexport type TextSize = 'compact' | 'default' | 'large' | 'xlarge';\nexport type TextFont = 'default' | 'monospace';\nexport type TextBorder = 'transparent' | 'none';\nexport type TextLineHeight = 'default' | 'tight';\nexport type TextWrap = 'normal' | 'anywhere' | 'nowrap' | 'truncate';\n\nexport type TextContent =\n KerfUiContent | string | number | readonly TextContent[];\n\nexport type FieldLabelProps = Omit<\n KerfBaseAttrs,\n 'children' | 'class' | 'className'\n> & {\n children: string;\n class?: string;\n className?: string;\n};\n\n/** Visible field heading for a read-only preview; use its id with aria-labelledby on the preview group. */\nexport function FieldLabel({\n children,\n class: classValue = '',\n className = '',\n ...attributes\n}: FieldLabelProps) {\n const classes = ['kui-text__field-label', classValue, className]\n .filter(Boolean)\n .join(' ');\n return (\n <div {...attributes} class={classes} data-component=\"field-label\">\n {children}\n </div>\n );\n}\n\ntype TextCommonProps = Omit<\n KerfBaseAttrs,\n 'children' | 'class' | 'className'\n> & {\n /** Native heading, paragraph, or inline span element to render. Defaults to `p`. */\n variant?: TextVariant;\n /** Semantic foreground treatment. Defaults to the inherited foreground. */\n tone?: TextTone;\n /** Text sizing independent of the native semantic element. */\n size?: TextSize;\n /** Font family independent of the native semantic element. */\n font?: TextFont;\n /** Transparent alignment border or no border when embedded in owner chrome. */\n border?: TextBorder;\n /** Remove the block variant's item padding and border in compact content. */\n flush?: boolean;\n /** Use compact leading for short dialog or metadata copy. */\n lineHeight?: TextLineHeight;\n children: TextContent;\n class?: string;\n className?: string;\n};\n\nexport type TextProps = TextCommonProps &\n (\n | {\n /** Wrap normally or break long unbroken strings. Defaults to normal. */\n wrap?: 'normal' | 'anywhere';\n /** Cap wrapped text to this positive number of lines. */\n maxLines?: number;\n }\n | {\n /** Keep one line, with or without an ellipsis. */\n wrap: 'nowrap' | 'truncate';\n maxLines?: never;\n }\n );\n\n/**\n * Semantic heading, paragraph, or inline text. Block variants use the standard\n * content-item padding; `span` adds no box geometry.\n * All ordinary native heading/paragraph attributes pass through to the element.\n */\nexport function Text({\n variant: Variant = 'p',\n tone = 'default',\n size = 'default',\n font = 'default',\n border = 'transparent',\n flush = false,\n lineHeight = 'default',\n wrap = 'normal',\n maxLines,\n children,\n class: classValue = '',\n className = '',\n ...attributes\n}: TextProps) {\n if (\n maxLines !== undefined &&\n (!Number.isSafeInteger(maxLines) ||\n maxLines < 1 ||\n wrap === 'nowrap' ||\n wrap === 'truncate')\n )\n throw new RangeError(\n 'Text maxLines requires a positive integer and wrapping',\n );\n const classes = ['kui-text', classValue, className].filter(Boolean).join(' ');\n return (\n <Variant\n {...attributes}\n class={classes}\n data-component=\"text\"\n data-tone={tone}\n data-size={size}\n data-font={font}\n data-border={border}\n data-flush={flush ? 'true' : undefined}\n data-line-height={lineHeight === 'tight' ? 'tight' : undefined}\n data-wrap={wrap === 'normal' ? undefined : wrap}\n data-max-lines={maxLines === undefined ? undefined : String(maxLines)}\n >\n {maxLines === undefined ? (\n children\n ) : (\n <span\n class=\"kui-text__clamp\"\n style={`--_kui-text-max-lines:${maxLines}`}\n >\n {children}\n </span>\n )}\n </Variant>\n );\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -28,7 +28,7 @@ export { StateBanner, StateBannerProps, StateBannerTone, StateBannerUrgency } fr
28
28
  export { SunkenPanel, SunkenPanelProps, SunkenPanelShape } from './sunken-panel.js';
29
29
  export { DialogSurface, DialogSurfacePresentation, DialogSurfaceProps, DialogSurfaceSize, PopupSurface, PopupSurfaceInset, PopupSurfaceProps, SurfaceInset } from './surface-scaffold.js';
30
30
  export { TabActivation, TabBar, TabBarAllocation, TabBarPresentation, TabBarProps, TabBarTrailingPlacement } from './tab-bar.js';
31
- export { Text, TextContent, TextFont, TextProps, TextSize, TextTone, TextVariant } from './text.js';
31
+ export { FieldLabel, FieldLabelProps, Text, TextContent, TextFont, TextProps, TextSize, TextTone, TextVariant } from './text.js';
32
32
  export { T as TokenSearchEditorAttributes, a as TokenSearchField, b as TokenSearchFieldProps, c as TokenSearchFieldValue, d as TokenSearchModel, e as TokenSearchModelOptions, f as TokenSearchResolvedToken, g as TokenSearchRule, h as TokenSearchState, i as TokenSearchSuggestion, j as TokenSearchToken, k as TokenSearchTrailingAction, l as createTokenSearchModel, p as placeTokenSearchCaret, r as readTokenSearchField } from './token-search-field-CVGwDn2y.js';
33
33
  export { Toolbar, ToolbarConfig, ToolbarPosition, ToolbarProps } from './toolbar.js';
34
34
  export { ToolbarActionLink, ToolbarActionLinkProps, ToolbarControlGroup, ToolbarControlGroupAppearance, ToolbarControlGroupButtonAppearance, ToolbarControlGroupContent, ToolbarControlGroupDensity, ToolbarControlGroupMenuInset, ToolbarControlGroupOverflow, ToolbarControlGroupProps, ToolbarControlGroupSelectedChrome, ToolbarControlGroupSelectedTone, ToolbarControlGroupShape, ToolbarControlGroupSize, ToolbarControlGroupTone, ToolbarControlGroupVisibility } from './toolbar-control-group.js';
package/dist/index.js CHANGED
@@ -21,8 +21,8 @@ export { AppTab } from './chunk-Q6YU3BT7.js';
21
21
  export { PopupMenu, closePopupMenu, openPopupMenuAt } from './chunk-J3KGJ6P6.js';
22
22
  export { ResizableRegion, clampRegionSize, resizeRegionFromPointer } from './chunk-KLJKU6ZL.js';
23
23
  export { Row } from './chunk-VZOFZPSO.js';
24
- export { ListHeader } from './chunk-5IJ6UGNZ.js';
25
- export { Text } from './chunk-CQHN45XR.js';
24
+ export { ListHeader } from './chunk-3BCJGM36.js';
25
+ export { FieldLabel, Text } from './chunk-YDGNU2OD.js';
26
26
  export { ListInsetText } from './chunk-DG6G5EPF.js';
27
27
  export { ListItem, ListItemLink } from './chunk-EN4LDR5Y.js';
28
28
  export { ToolbarText } from './chunk-V3DX3K65.js';
@@ -1,4 +1,4 @@
1
- export { ListHeader } from './chunk-5IJ6UGNZ.js';
1
+ export { ListHeader } from './chunk-3BCJGM36.js';
2
2
 
3
3
 
4
4
 
@@ -7,6 +7,24 @@
7
7
  overflow-wrap: normal;
8
8
  }
9
9
 
10
+ /* Match the themed Web Awesome form-control label without introducing a
11
+ native <label> that would falsely point at a non-form preview. */
12
+ .kui-text__field-label {
13
+ box-sizing: border-box;
14
+ min-width: 0;
15
+ padding-inline: calc(
16
+ var(--wa-form-control-border-width, 1px) +
17
+ var(--wa-form-control-padding-inline, 0.5rem)
18
+ );
19
+ margin: 0 0 0.5em;
20
+ color: var(--kui-color-neutral-on-quiet, var(--wa-color-text-quiet));
21
+ font-size: var(--kui-font-xs, var(--wa-font-size-xs));
22
+ font-weight: 650;
23
+ letter-spacing: 0.04em;
24
+ line-height: var(--wa-line-height-condensed);
25
+ text-transform: uppercase;
26
+ }
27
+
10
28
  .kui-text[data-wrap="anywhere"] {
11
29
  overflow-wrap: anywhere;
12
30
  }
package/dist/text.d.ts CHANGED
@@ -10,6 +10,13 @@ type TextBorder = 'transparent' | 'none';
10
10
  type TextLineHeight = 'default' | 'tight';
11
11
  type TextWrap = 'normal' | 'anywhere' | 'nowrap' | 'truncate';
12
12
  type TextContent = KerfUiContent | string | number | readonly TextContent[];
13
+ type FieldLabelProps = Omit<KerfBaseAttrs, 'children' | 'class' | 'className'> & {
14
+ children: string;
15
+ class?: string;
16
+ className?: string;
17
+ };
18
+ /** Visible field heading for a read-only preview; use its id with aria-labelledby on the preview group. */
19
+ declare function FieldLabel({ children, class: classValue, className, ...attributes }: FieldLabelProps): kerfjs.SafeHtml;
13
20
  type TextCommonProps = Omit<KerfBaseAttrs, 'children' | 'class' | 'className'> & {
14
21
  /** Native heading, paragraph, or inline span element to render. Defaults to `p`. */
15
22
  variant?: TextVariant;
@@ -46,4 +53,4 @@ type TextProps = TextCommonProps & ({
46
53
  */
47
54
  declare function Text({ variant: Variant, tone, size, font, border, flush, lineHeight, wrap, maxLines, children, class: classValue, className, ...attributes }: TextProps): kerfjs.SafeHtml;
48
55
 
49
- export { Text, type TextBorder, type TextContent, type TextFont, type TextLineHeight, type TextProps, type TextSize, type TextTone, type TextVariant, type TextWrap };
56
+ export { FieldLabel, type FieldLabelProps, Text, type TextBorder, type TextContent, type TextFont, type TextLineHeight, type TextProps, type TextSize, type TextTone, type TextVariant, type TextWrap };
package/dist/text.js CHANGED
@@ -1,3 +1,3 @@
1
- export { Text } from './chunk-CQHN45XR.js';
1
+ export { FieldLabel, Text } from './chunk-YDGNU2OD.js';
2
2
 
3
3
  //# sourceMappingURL=text.js.map
@@ -132,6 +132,12 @@ an upstream component or recipe request.
132
132
 
133
133
  ## Problem-to-component matrix
134
134
 
135
+ For a read-only or click-to-edit field preview, use `FieldLabel` from
136
+ `@kerfjs/ui/text` above the preview instead of a `ListHeader`. It matches the
137
+ themed Web Awesome form-control label. Put it in `ListInsetControl sides="trl"`
138
+ beside a `ContentItem` value, and connect its id to the preview group's
139
+ `aria-labelledby`; see [Field labels](./layout.md#text).
140
+
135
141
  | Interface need | Use when | Do not use when; nearest alternative | Required wiring | Application owns | Import | Recipe |
136
142
  | ----------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
137
143
  | Icon — `LucideIcon` | A decorative or explicitly labeled Lucide-compatible icon belongs in app UI. | Do not use an icon as the only name of an unfamiliar action; add visible or accessible text. Prefer it over Web Awesome `wa-icon`. | None. | Icon choice and meaningful label. | `@kerfjs/ui/lucide-icon` | [Accessibility](./accessibility.md#shared-rules) |
@@ -351,6 +357,10 @@ their compact widths when collapsed.
351
357
 
352
358
  ## Toolbar composition
353
359
 
360
+ A `FloatingToolbar` accepts `ToolbarControlGroup` directly as its children in
361
+ both floating and inline placement. Name the toolbar with `label`; group its
362
+ controls as you would in a `Toolbar` zone.
363
+
354
364
  A `Toolbar` has three zones — `leading`, `center`, and `trailing`. In almost
355
365
  every case the only things that go **directly** in a zone are `ToolbarText`
356
366
  (identity/title text) and `ToolbarControlGroup` (any control or cluster of
package/docs/layout.md CHANGED
@@ -331,6 +331,27 @@ CSS strings.
331
331
 
332
332
  ## Text
333
333
 
334
+ `FieldLabel` from `@kerfjs/ui/text` gives a read-only or click-to-edit field
335
+ preview the same visible heading as a themed Web Awesome form control. Put it
336
+ in `ListInsetControl sides="trl"` above the preview so its text starts at the
337
+ same 17px content column as a `ContentItem` value. Unlike a native `<label>`, it
338
+ is a plain element: give it an `id` and name the preview's group with
339
+ `aria-labelledby`. Keep the app's preview/edit switching and hint copy beside
340
+ the preview; use the live control's own `label` when editing.
341
+
342
+ ```tsx
343
+ import { ContentItem } from "@kerfjs/ui/content-item";
344
+ import { ListInsetControl } from "@kerfjs/ui/list-inset-control";
345
+ import { FieldLabel } from "@kerfjs/ui/text";
346
+
347
+ <div role="group" aria-labelledby="needed-by-label">
348
+ <ListInsetControl sides="trl">
349
+ <FieldLabel id="needed-by-label">Needed by</FieldLabel>
350
+ </ListInsetControl>
351
+ <ContentItem>October 16, 2026</ContentItem>
352
+ </div>;
353
+ ```
354
+
334
355
  Use `Text` from `@kerfjs/ui/text` for ordinary semantic headings, paragraphs,
335
356
  and inline secondary text. It renders a native `p` by default; set `variant` to
336
357
  `h1`–`h6` when the document outline calls for a heading, or `span` for inline
@@ -125,7 +125,11 @@ which element a selector styles.
125
125
  arguments) names a public class of a cataloged component (`.kui-toolbar`,
126
126
  `.kui-list-item__label`, `.acme-meter`), its `[data-component="…"]` root, or
127
127
  a Web Awesome tag the package themes (`wa-button`, `wa-select`), and the rule
128
- sets at least one ordinary property. A `::part()` subject is left to
128
+ sets at least one ordinary property. It also catches a raw descendant of
129
+ cataloged component anatomy, such as `.kui-app-tab__select > svg`, even when
130
+ the component class is not the final compound. A component root used only as
131
+ context (`.kui-toolbar > .my-widget`) and app-named descendants remain
132
+ available for app-owned content. A `::part()` subject is left to
129
133
  `KUI-L011`; a rule that only sets custom properties is configuration, judged
130
134
  by the token rules. Forcing a component's dimensions is one such restyle
131
135
  and reports here once: `.kui-pane { width: 300px }`.
package/llms.txt CHANGED
@@ -157,6 +157,10 @@ headingLevel`, `TokenSearchField clearIcon`, `ContentItem frame="framed"` for a
157
157
  `ToolbarText size="xsmall"` suits a dense rail heading. The
158
158
  `TokenSearchField` editor shrinks in narrow groups; its minimum width can be
159
159
  set with `--kui-token-search-editor-min-width`.
160
+ - **Label read-only field previews.** Use `FieldLabel` from `@kerfjs/ui/text`
161
+ in `ListInsetControl sides="trl"` above a `ContentItem` value. Connect its
162
+ id to the preview group's `aria-labelledby`; use the live control's own
163
+ `label` while editing.
160
164
  - **Use Toolbar zone options.** `responsive="trailing-priority"` moves an
161
165
  expanded trailing control to a full second row at `responsiveAt`; the leading
162
166
  title remains above it. Public leading-min-width, trailing-gap/justify, and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kerfjs/ui",
3
- "version": "5.0.0-beta.66",
3
+ "version": "5.0.0-beta.67",
4
4
  "description": "Accessible, composable UI primitives for kerf applications.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/text.tsx"],"names":[],"mappings":";;;AA2DO,SAAS,IAAA,CAAK;AAAA,EACnB,SAAS,OAAA,GAAU,GAAA;AAAA,EACnB,IAAA,GAAO,SAAA;AAAA,EACP,IAAA,GAAO,SAAA;AAAA,EACP,IAAA,GAAO,SAAA;AAAA,EACP,MAAA,GAAS,aAAA;AAAA,EACT,KAAA,GAAQ,KAAA;AAAA,EACR,UAAA,GAAa,SAAA;AAAA,EACb,IAAA,GAAO,QAAA;AAAA,EACP,QAAA;AAAA,EACA,QAAA;AAAA,EACA,OAAO,UAAA,GAAa,EAAA;AAAA,EACpB,SAAA,GAAY,EAAA;AAAA,EACZ,GAAG;AACL,CAAA,EAAc;AACZ,EAAA,IACE,QAAA,KAAa,MAAA,KACZ,CAAC,MAAA,CAAO,aAAA,CAAc,QAAQ,CAAA,IAC7B,QAAA,GAAW,CAAA,IACX,IAAA,KAAS,QAAA,IACT,IAAA,KAAS,UAAA,CAAA;AAEX,IAAA,MAAM,IAAI,UAAA;AAAA,MACR;AAAA,KACF;AACF,EAAA,MAAM,OAAA,GAAU,CAAC,UAAA,EAAY,UAAA,EAAY,SAAS,EAAE,MAAA,CAAO,OAAO,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AAC5E,EAAA,uBACE,GAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACE,GAAG,UAAA;AAAA,MACJ,KAAA,EAAO,OAAA;AAAA,MACP,gBAAA,EAAe,MAAA;AAAA,MACf,WAAA,EAAW,IAAA;AAAA,MACX,WAAA,EAAW,IAAA;AAAA,MACX,WAAA,EAAW,IAAA;AAAA,MACX,aAAA,EAAa,MAAA;AAAA,MACb,YAAA,EAAY,QAAQ,MAAA,GAAS,MAAA;AAAA,MAC7B,kBAAA,EAAkB,UAAA,KAAe,OAAA,GAAU,OAAA,GAAU,MAAA;AAAA,MACrD,WAAA,EAAW,IAAA,KAAS,QAAA,GAAW,MAAA,GAAY,IAAA;AAAA,MAC3C,gBAAA,EAAgB,QAAA,KAAa,MAAA,GAAY,MAAA,GAAY,OAAO,QAAQ,CAAA;AAAA,MAEnE,QAAA,EAAA,QAAA,KAAa,SACZ,QAAA,mBAEA,GAAA;AAAA,QAAC,MAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAM,iBAAA;AAAA,UACN,KAAA,EAAO,yBAAyB,QAAQ,CAAA,CAAA;AAAA,UAEvC;AAAA;AAAA;AACH;AAAA,GAEJ;AAEJ","file":"chunk-CQHN45XR.js","sourcesContent":["import type { KerfBaseAttrs } from 'kerfjs/jsx-runtime';\n\nimport type { KerfUiContent } from './semantic-content.js';\n\nexport type TextVariant =\n 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span';\nexport type TextTone = 'default' | 'quiet' | 'danger';\nexport type TextSize = 'compact' | 'default' | 'large' | 'xlarge';\nexport type TextFont = 'default' | 'monospace';\nexport type TextBorder = 'transparent' | 'none';\nexport type TextLineHeight = 'default' | 'tight';\nexport type TextWrap = 'normal' | 'anywhere' | 'nowrap' | 'truncate';\n\nexport type TextContent =\n KerfUiContent | string | number | readonly TextContent[];\n\ntype TextCommonProps = Omit<\n KerfBaseAttrs,\n 'children' | 'class' | 'className'\n> & {\n /** Native heading, paragraph, or inline span element to render. Defaults to `p`. */\n variant?: TextVariant;\n /** Semantic foreground treatment. Defaults to the inherited foreground. */\n tone?: TextTone;\n /** Text sizing independent of the native semantic element. */\n size?: TextSize;\n /** Font family independent of the native semantic element. */\n font?: TextFont;\n /** Transparent alignment border or no border when embedded in owner chrome. */\n border?: TextBorder;\n /** Remove the block variant's item padding and border in compact content. */\n flush?: boolean;\n /** Use compact leading for short dialog or metadata copy. */\n lineHeight?: TextLineHeight;\n children: TextContent;\n class?: string;\n className?: string;\n};\n\nexport type TextProps = TextCommonProps &\n (\n | {\n /** Wrap normally or break long unbroken strings. Defaults to normal. */\n wrap?: 'normal' | 'anywhere';\n /** Cap wrapped text to this positive number of lines. */\n maxLines?: number;\n }\n | {\n /** Keep one line, with or without an ellipsis. */\n wrap: 'nowrap' | 'truncate';\n maxLines?: never;\n }\n );\n\n/**\n * Semantic heading, paragraph, or inline text. Block variants use the standard\n * content-item padding; `span` adds no box geometry.\n * All ordinary native heading/paragraph attributes pass through to the element.\n */\nexport function Text({\n variant: Variant = 'p',\n tone = 'default',\n size = 'default',\n font = 'default',\n border = 'transparent',\n flush = false,\n lineHeight = 'default',\n wrap = 'normal',\n maxLines,\n children,\n class: classValue = '',\n className = '',\n ...attributes\n}: TextProps) {\n if (\n maxLines !== undefined &&\n (!Number.isSafeInteger(maxLines) ||\n maxLines < 1 ||\n wrap === 'nowrap' ||\n wrap === 'truncate')\n )\n throw new RangeError(\n 'Text maxLines requires a positive integer and wrapping',\n );\n const classes = ['kui-text', classValue, className].filter(Boolean).join(' ');\n return (\n <Variant\n {...attributes}\n class={classes}\n data-component=\"text\"\n data-tone={tone}\n data-size={size}\n data-font={font}\n data-border={border}\n data-flush={flush ? 'true' : undefined}\n data-line-height={lineHeight === 'tight' ? 'tight' : undefined}\n data-wrap={wrap === 'normal' ? undefined : wrap}\n data-max-lines={maxLines === undefined ? undefined : String(maxLines)}\n >\n {maxLines === undefined ? (\n children\n ) : (\n <span\n class=\"kui-text__clamp\"\n style={`--_kui-text-max-lines:${maxLines}`}\n >\n {children}\n </span>\n )}\n </Variant>\n );\n}\n"]}