@kerfjs/ui 5.0.0-beta.7 → 5.0.0-beta.8

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.
@@ -488,7 +488,9 @@
488
488
  "small",
489
489
  "placeholder (loading)"
490
490
  ],
491
- "accessibility": [],
491
+ "accessibility": [
492
+ "Plain text is not a heading; pass headingLevel to expose role=heading + aria-level for a page/section title."
493
+ ],
492
494
  "delivery": {
493
495
  "browserImport": "@kerfjs/ui/toolbar-text",
494
496
  "manualCssImport": "@kerfjs/ui/toolbar-text.css",
@@ -614,11 +616,13 @@
614
616
  "optional summary",
615
617
  "icon",
616
618
  "actions",
617
- "placeholder (loading)"
619
+ "placeholder (loading)",
620
+ "page heading (headingLevel)"
618
621
  ],
619
622
  "accessibility": [
620
623
  "Connect the title id and any provided summary id to the dialog or panel host.",
621
- "Pass the trailing actions as a labeled ToolbarControlGroup when the group needs an accessible name."
624
+ "Pass the trailing actions as a labeled ToolbarControlGroup when the group needs an accessible name.",
625
+ "For a page/view title pass headingLevel (usually 1) so the title exposes role=heading + aria-level as a heading landmark; omit it for a dialog title, which is referenced via aria-labelledby to titleId."
622
626
  ],
623
627
  "delivery": {
624
628
  "browserImport": "@kerfjs/ui/panel-header",
@@ -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.7` and `kerfjs@5.0.0-beta.7`. 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.8` and `kerfjs@5.0.0-beta.8`. 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/disclosure-arrow`
6
6
 
@@ -45,18 +45,26 @@ export { Toolbar, type ToolbarProps };
45
45
  import * as kerfjs from 'kerfjs';
46
46
 
47
47
  type ToolbarTextSize = 'xlarge' | 'large' | 'default' | 'small';
48
+ /** ARIA heading level for a title exposed as a heading landmark. */
49
+ type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
48
50
  interface ToolbarTextProps {
49
51
  text: string;
50
52
  size?: ToolbarTextSize;
51
53
  className?: string;
52
54
  /** Optional id, e.g. so a dialog can reference the title via aria-labelledby. */
53
55
  id?: string;
56
+ /**
57
+ * Expose heading semantics (`role="heading"` + `aria-level`) so the text acts as
58
+ * a heading landmark — e.g. a page's primary title. Omit to keep the plain span
59
+ * (the default), which suits a dialog title referenced via `aria-labelledby`.
60
+ */
61
+ headingLevel?: HeadingLevel;
54
62
  /** Render the text as an unanimated loading skeleton instead of its value. */
55
63
  placeholder?: boolean;
56
64
  }
57
- declare function ToolbarText({ text, size, className, id, placeholder }: ToolbarTextProps): kerfjs.SafeHtml;
65
+ declare function ToolbarText({ text, size, className, id, headingLevel, placeholder }: ToolbarTextProps): kerfjs.SafeHtml;
58
66
 
59
- export { ToolbarText, type ToolbarTextProps, type ToolbarTextSize };
67
+ export { type HeadingLevel, ToolbarText, type ToolbarTextProps, type ToolbarTextSize };
60
68
  ```
61
69
 
62
70
  ## `@kerfjs/ui/toolbar-control-group`
@@ -226,6 +234,7 @@ export { MenuItem, type MenuItemProps };
226
234
 
227
235
  ```ts
228
236
  import { SafeHtml } from 'kerfjs';
237
+ import { HeadingLevel } from './toolbar-text.js';
229
238
 
230
239
  interface PanelHeaderProps {
231
240
  title: string;
@@ -235,6 +244,13 @@ interface PanelHeaderProps {
235
244
  icon?: SafeHtml;
236
245
  iconClassName?: string;
237
246
  actions?: SafeHtml;
247
+ /**
248
+ * Expose the title as a heading landmark (`role="heading"` + `aria-level`). Set it
249
+ * for a PAGE or view heading so screen-reader heading navigation works and the view
250
+ * has a primary heading; omit it (the default) for a dialog title, which is instead
251
+ * referenced via `aria-labelledby={titleId}` and needs no heading landmark.
252
+ */
253
+ headingLevel?: HeadingLevel;
238
254
  /** Render the title and summary as unanimated loading skeletons, keeping the icon and actions. */
239
255
  placeholder?: boolean;
240
256
  }
@@ -250,7 +266,7 @@ interface PanelHeaderProps {
250
266
  * is passed straight into the toolbar's trailing zone; the app supplies whatever
251
267
  * trailing controls it needs (typically a `ToolbarControlGroup`).
252
268
  */
253
- declare function PanelHeader({ title, titleId, summary, summaryId, icon, iconClassName, actions, placeholder }: PanelHeaderProps): SafeHtml;
269
+ declare function PanelHeader({ title, titleId, summary, summaryId, icon, iconClassName, actions, headingLevel, placeholder }: PanelHeaderProps): SafeHtml;
254
270
 
255
271
  export { PanelHeader, type PanelHeaderProps };
256
272
  ```
@@ -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.7` 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.8` 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';
@@ -1,4 +1,4 @@
1
- import { ToolbarText } from './chunk-KJYXOTG3.js';
1
+ import { ToolbarText } from './chunk-RUNWEPR4.js';
2
2
  import { jsxs, jsx } from 'kerfjs/jsx-runtime';
3
3
 
4
4
  function NavStack({ id, label, views, backLabel = "Back", hideToolbar = false, bottomToolbar, className = "" }) {
@@ -20,4 +20,4 @@ function NavStack({ id, label, views, backLabel = "Back", hideToolbar = false, b
20
20
 
21
21
  export { NavStack };
22
22
 
23
- //# sourceMappingURL=chunk-N3SUXLLS.js.map
23
+ //# sourceMappingURL=chunk-BLK3UEEI.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/nav-stack.tsx"],"names":[],"mappings":";;;AAuCO,SAAS,QAAA,CAAS,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,SAAA,GAAY,MAAA,EAAQ,WAAA,GAAc,KAAA,EAAO,aAAA,EAAe,SAAA,GAAY,EAAA,EAAG,EAAkB;AACpI,EAAA,MAAM,QAAA,GAAW,MAAM,MAAA,GAAS,CAAA;AAChC,EAAA,MAAM,GAAA,GAAM,MAAM,QAAQ,CAAA;AAC1B,EAAA,MAAM,MAAA,GAAS,MAAM,MAAA,GAAS,CAAA;AAC9B,EAAA,4BAAQ,SAAA,EAAA,EAAQ,KAAA,EAAO,iBAAiB,SAAS,CAAA,CAAA,CAAG,MAAK,EAAG,EAAA,EAAQ,kBAAe,WAAA,EAAY,mBAAA,EAAmB,IAAI,YAAA,EAAY,MAAA,CAAO,MAAM,MAAM,CAAA,EAAG,cAAY,KAAA,EACjK,QAAA,EAAA;AAAA,IAAA,CAAC,+BAAe,IAAA,CAAC,QAAA,EAAA,EAAO,KAAA,EAAM,uBAAA,EAAwB,yBAAqB,IAAA,EAC1E,QAAA,EAAA;AAAA,sBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,OAAM,qBAAA,EACR,QAAA,EAAA;AAAA,QAAA,MAAA,wBAAW,QAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,KAAA,EAAM,uBAAsB,eAAA,EAAa,IAAA,EAAC,YAAA,EAAY,SAAA,EACrF,8BAAC,KAAA,EAAA,EAAI,KAAA,EAAM,0BAAA,EAA2B,OAAA,EAAQ,aAAY,KAAA,EAAM,IAAA,EAAK,MAAA,EAAO,IAAA,EAAK,eAAY,MAAA,EAAO,IAAA,EAAK,MAAA,EAAO,MAAA,EAAO,gBAAe,cAAA,EAAa,GAAA,EAAI,gBAAA,EAAe,OAAA,EAAQ,mBAAgB,OAAA,EAAQ,QAAA,kBAAA,GAAA,CAAC,UAAK,CAAA,EAAE,gBAAA,EAAiB,GAAE,CAAA,EACnO,CAAA;AAAA,wBACA,GAAA,CAAC,eAAY,IAAA,EAAM,GAAA,EAAK,SAAS,EAAA,EAAI,IAAA,EAAK,OAAA,EAAQ,SAAA,EAAU,sBAAA,EAAuB;AAAA,OAAA,EACrF,CAAA;AAAA,MACC,KAAK,OAAA,oBAAW,GAAA,CAAC,SAAI,KAAA,EAAM,wBAAA,EAA0B,cAAI,OAAA,EAAQ;AAAA,KAAA,EACpE,CAAA;AAAA,oBACA,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,yBAAA,EAA0B,2BAAuB,IAAA,EACzD,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,MAAM,KAAA,qBAAU,GAAA,CAAC,SAAA,EAAA,EAAQ,KAAA,EAAM,uBAAsB,UAAA,EAAU,IAAA,CAAK,GAAA,EAAK,cAAA,EAAc,IAAA,CAAK,GAAA,EAAK,iBAAA,EAAiB,MAAA,CAAO,UAAU,QAAQ,CAAA,EAAG,aAAA,EAAa,MAAA,CAAO,UAAU,QAAQ,CAAA,EAAI,QAAA,EAAA,IAAA,CAAK,OAAA,EAAQ,CAAU,CAAA,EAC7N,CAAA;AAAA,IACC,iCAAiB,GAAA,CAAC,QAAA,EAAA,EAAO,OAAM,uBAAA,EAAwB,uBAAA,EAAqB,MAAE,QAAA,EAAA,aAAA,EAAc;AAAA,GAAA,EAC/F,CAAA;AACF","file":"chunk-N3SUXLLS.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport { ToolbarText } from './toolbar-text.js';\n\n/**\n * One entry in a {@link NavStack}. The app owns the stack as an array (usually a\n * signal); `NavStack` renders it and `wireNavStack` animates the transitions.\n */\nexport interface NavStackView {\n /** Stable identity for keyed reconcile and transition direction. */\n key: string;\n content: SafeHtml;\n /** Title shown in the top toolbar for this view. */\n title?: string;\n /** Trailing actions for this view's top toolbar. */\n toolbar?: SafeHtml;\n}\n\nexport interface NavStackProps {\n id: string;\n /** Accessible name for the stack region. */\n label: string;\n /** The stack, root first; the last entry is the active top view. */\n views: NavStackView[];\n /** Accessible label for the back control (default \"Back\"). */\n backLabel?: string;\n /** Hide the top toolbar entirely (rare — a fully custom-chrome view). */\n hideToolbar?: boolean;\n /** Optional persistent bottom toolbar. */\n bottomToolbar?: SafeHtml;\n className?: string;\n}\n\n/**\n * A navigation stack (iOS-style push/pop). Renders every entry stacked, the last\n * one active; `@kerfjs/ui/wire-nav-stack`'s `wireNavStack` slides the content and\n * cross-fades the chrome across a change. A single-pane layout is a `NavStack`\n * with one entry. See `docs/23-app-layouts.md` §3.1.\n */\nexport function NavStack({ id, label, views, backLabel = 'Back', hideToolbar = false, bottomToolbar, className = '' }: NavStackProps) {\n const topIndex = views.length - 1;\n const top = views[topIndex];\n const canPop = views.length > 1;\n return <section class={`kui-nav-stack ${className}`.trim()} id={id} data-component=\"nav-stack\" data-nav-stack-id={id} data-depth={String(views.length)} aria-label={label}>\n {!hideToolbar && <header class=\"kui-nav-stack__chrome\" data-nav-stack-chrome>\n <div class=\"kui-nav-stack__lead\">\n {canPop && <button type=\"button\" class=\"kui-nav-stack__back\" data-nav-back aria-label={backLabel}>\n <svg class=\"kui-nav-stack__back-icon\" viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" aria-hidden=\"true\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m15 18-6-6 6-6\" /></svg>\n </button>}\n <ToolbarText text={top?.title ?? ''} size=\"large\" className=\"kui-nav-stack__title\" />\n </div>\n {top?.toolbar && <div class=\"kui-nav-stack__actions\">{top.toolbar}</div>}\n </header>}\n <div class=\"kui-nav-stack__viewport\" data-nav-stack-viewport>\n {views.map((view, index) => <article class=\"kui-nav-stack__view\" data-key={view.key} data-nav-key={view.key} data-nav-active={String(index === topIndex)} aria-hidden={String(index !== topIndex)}>{view.content}</article>)}\n </div>\n {bottomToolbar && <footer class=\"kui-nav-stack__bottom\" data-nav-stack-bottom>{bottomToolbar}</footer>}\n </section>;\n}\n"]}
1
+ {"version":3,"sources":["../src/nav-stack.tsx"],"names":[],"mappings":";;;AAuCO,SAAS,QAAA,CAAS,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,SAAA,GAAY,MAAA,EAAQ,WAAA,GAAc,KAAA,EAAO,aAAA,EAAe,SAAA,GAAY,EAAA,EAAG,EAAkB;AACpI,EAAA,MAAM,QAAA,GAAW,MAAM,MAAA,GAAS,CAAA;AAChC,EAAA,MAAM,GAAA,GAAM,MAAM,QAAQ,CAAA;AAC1B,EAAA,MAAM,MAAA,GAAS,MAAM,MAAA,GAAS,CAAA;AAC9B,EAAA,4BAAQ,SAAA,EAAA,EAAQ,KAAA,EAAO,iBAAiB,SAAS,CAAA,CAAA,CAAG,MAAK,EAAG,EAAA,EAAQ,kBAAe,WAAA,EAAY,mBAAA,EAAmB,IAAI,YAAA,EAAY,MAAA,CAAO,MAAM,MAAM,CAAA,EAAG,cAAY,KAAA,EACjK,QAAA,EAAA;AAAA,IAAA,CAAC,+BAAe,IAAA,CAAC,QAAA,EAAA,EAAO,KAAA,EAAM,uBAAA,EAAwB,yBAAqB,IAAA,EAC1E,QAAA,EAAA;AAAA,sBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,OAAM,qBAAA,EACR,QAAA,EAAA;AAAA,QAAA,MAAA,wBAAW,QAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,KAAA,EAAM,uBAAsB,eAAA,EAAa,IAAA,EAAC,YAAA,EAAY,SAAA,EACrF,8BAAC,KAAA,EAAA,EAAI,KAAA,EAAM,0BAAA,EAA2B,OAAA,EAAQ,aAAY,KAAA,EAAM,IAAA,EAAK,MAAA,EAAO,IAAA,EAAK,eAAY,MAAA,EAAO,IAAA,EAAK,MAAA,EAAO,MAAA,EAAO,gBAAe,cAAA,EAAa,GAAA,EAAI,gBAAA,EAAe,OAAA,EAAQ,mBAAgB,OAAA,EAAQ,QAAA,kBAAA,GAAA,CAAC,UAAK,CAAA,EAAE,gBAAA,EAAiB,GAAE,CAAA,EACnO,CAAA;AAAA,wBACA,GAAA,CAAC,eAAY,IAAA,EAAM,GAAA,EAAK,SAAS,EAAA,EAAI,IAAA,EAAK,OAAA,EAAQ,SAAA,EAAU,sBAAA,EAAuB;AAAA,OAAA,EACrF,CAAA;AAAA,MACC,KAAK,OAAA,oBAAW,GAAA,CAAC,SAAI,KAAA,EAAM,wBAAA,EAA0B,cAAI,OAAA,EAAQ;AAAA,KAAA,EACpE,CAAA;AAAA,oBACA,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,yBAAA,EAA0B,2BAAuB,IAAA,EACzD,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,MAAM,KAAA,qBAAU,GAAA,CAAC,SAAA,EAAA,EAAQ,KAAA,EAAM,uBAAsB,UAAA,EAAU,IAAA,CAAK,GAAA,EAAK,cAAA,EAAc,IAAA,CAAK,GAAA,EAAK,iBAAA,EAAiB,MAAA,CAAO,UAAU,QAAQ,CAAA,EAAG,aAAA,EAAa,MAAA,CAAO,UAAU,QAAQ,CAAA,EAAI,QAAA,EAAA,IAAA,CAAK,OAAA,EAAQ,CAAU,CAAA,EAC7N,CAAA;AAAA,IACC,iCAAiB,GAAA,CAAC,QAAA,EAAA,EAAO,OAAM,uBAAA,EAAwB,uBAAA,EAAqB,MAAE,QAAA,EAAA,aAAA,EAAc;AAAA,GAAA,EAC/F,CAAA;AACF","file":"chunk-BLK3UEEI.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport { ToolbarText } from './toolbar-text.js';\n\n/**\n * One entry in a {@link NavStack}. The app owns the stack as an array (usually a\n * signal); `NavStack` renders it and `wireNavStack` animates the transitions.\n */\nexport interface NavStackView {\n /** Stable identity for keyed reconcile and transition direction. */\n key: string;\n content: SafeHtml;\n /** Title shown in the top toolbar for this view. */\n title?: string;\n /** Trailing actions for this view's top toolbar. */\n toolbar?: SafeHtml;\n}\n\nexport interface NavStackProps {\n id: string;\n /** Accessible name for the stack region. */\n label: string;\n /** The stack, root first; the last entry is the active top view. */\n views: NavStackView[];\n /** Accessible label for the back control (default \"Back\"). */\n backLabel?: string;\n /** Hide the top toolbar entirely (rare — a fully custom-chrome view). */\n hideToolbar?: boolean;\n /** Optional persistent bottom toolbar. */\n bottomToolbar?: SafeHtml;\n className?: string;\n}\n\n/**\n * A navigation stack (iOS-style push/pop). Renders every entry stacked, the last\n * one active; `@kerfjs/ui/wire-nav-stack`'s `wireNavStack` slides the content and\n * cross-fades the chrome across a change. A single-pane layout is a `NavStack`\n * with one entry. See `docs/23-app-layouts.md` §3.1.\n */\nexport function NavStack({ id, label, views, backLabel = 'Back', hideToolbar = false, bottomToolbar, className = '' }: NavStackProps) {\n const topIndex = views.length - 1;\n const top = views[topIndex];\n const canPop = views.length > 1;\n return <section class={`kui-nav-stack ${className}`.trim()} id={id} data-component=\"nav-stack\" data-nav-stack-id={id} data-depth={String(views.length)} aria-label={label}>\n {!hideToolbar && <header class=\"kui-nav-stack__chrome\" data-nav-stack-chrome>\n <div class=\"kui-nav-stack__lead\">\n {canPop && <button type=\"button\" class=\"kui-nav-stack__back\" data-nav-back aria-label={backLabel}>\n <svg class=\"kui-nav-stack__back-icon\" viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" aria-hidden=\"true\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m15 18-6-6 6-6\" /></svg>\n </button>}\n <ToolbarText text={top?.title ?? ''} size=\"large\" className=\"kui-nav-stack__title\" />\n </div>\n {top?.toolbar && <div class=\"kui-nav-stack__actions\">{top.toolbar}</div>}\n </header>}\n <div class=\"kui-nav-stack__viewport\" data-nav-stack-viewport>\n {views.map((view, index) => <article class=\"kui-nav-stack__view\" data-key={view.key} data-nav-key={view.key} data-nav-active={String(index === topIndex)} aria-hidden={String(index !== topIndex)}>{view.content}</article>)}\n </div>\n {bottomToolbar && <footer class=\"kui-nav-stack__bottom\" data-nav-stack-bottom>{bottomToolbar}</footer>}\n </section>;\n}\n"]}
@@ -1,13 +1,13 @@
1
1
  import { Toolbar } from './chunk-DAFFDO33.js';
2
2
  import { ToolbarControlGroup } from './chunk-MFKMHK5W.js';
3
- import { ToolbarText } from './chunk-KJYXOTG3.js';
3
+ import { ToolbarText } from './chunk-RUNWEPR4.js';
4
4
  import { Skeleton } from './chunk-B24C4A6T.js';
5
5
  import { jsxs, jsx, Fragment } from 'kerfjs/jsx-runtime';
6
6
 
7
- function PanelHeader({ title, titleId, summary, summaryId, icon, iconClassName = "", actions, placeholder = false }) {
7
+ function PanelHeader({ title, titleId, summary, summaryId, icon, iconClassName = "", actions, headingLevel, placeholder = false }) {
8
8
  const identity = /* @__PURE__ */ jsxs(Fragment, { children: [
9
9
  icon && /* @__PURE__ */ jsx(ToolbarControlGroup, { single: true, className: `kui-panel-header__icon ${iconClassName}`.trim(), children: icon }),
10
- /* @__PURE__ */ jsx(ToolbarText, { text: title, size: "xlarge", id: titleId, className: "kui-panel-header__title", placeholder })
10
+ /* @__PURE__ */ jsx(ToolbarText, { text: title, size: "xlarge", id: titleId, className: "kui-panel-header__title", headingLevel, placeholder })
11
11
  ] });
12
12
  return /* @__PURE__ */ jsxs("div", { class: "kui-panel-header", "data-component": "panel-header", "data-has-icon": String(Boolean(icon)), "data-has-actions": String(Boolean(actions)), "data-has-summary": String(Boolean(summary)), "data-placeholder": placeholder ? "true" : void 0, children: [
13
13
  /* @__PURE__ */ jsx(Toolbar, { leading: identity, trailing: actions, divider: false }),
@@ -17,4 +17,4 @@ function PanelHeader({ title, titleId, summary, summaryId, icon, iconClassName =
17
17
 
18
18
  export { PanelHeader };
19
19
 
20
- //# sourceMappingURL=chunk-TZNCCM5H.js.map
20
+ //# sourceMappingURL=chunk-BNQ2YDV4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/panel-header.tsx"],"names":[],"mappings":";;;;;;AAsCO,SAAS,WAAA,CAAY,EAAE,KAAA,EAAO,OAAA,EAAS,OAAA,EAAS,SAAA,EAAW,IAAA,EAAM,aAAA,GAAgB,EAAA,EAAI,OAAA,EAAS,YAAA,EAAc,WAAA,GAAc,OAAM,EAAqB;AAC1J,EAAA,MAAM,2BAAW,IAAA,CAAA,QAAA,EAAA,EACd,QAAA,EAAA;AAAA,IAAA,IAAA,oBAAQ,GAAA,CAAC,mBAAA,EAAA,EAAoB,MAAA,EAAM,IAAA,EAAC,SAAA,EAAW,0BAA0B,aAAa,CAAA,CAAA,CAAG,IAAA,EAAK,EAAI,QAAA,EAAA,IAAA,EAAK,CAAA;AAAA,oBACxG,GAAA,CAAC,WAAA,EAAA,EAAY,IAAA,EAAM,KAAA,EAAO,IAAA,EAAK,QAAA,EAAS,EAAA,EAAI,OAAA,EAAS,SAAA,EAAU,yBAAA,EAA0B,YAAA,EAA4B,WAAA,EAA0B;AAAA,GAAA,EACjJ,CAAA;AAEA,EAAA,uBAAO,IAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,kBAAA,EAAmB,gBAAA,EAAe,cAAA,EAAe,eAAA,EAAe,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAC,CAAA,EAAG,kBAAA,EAAkB,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAC,CAAA,EAAG,kBAAA,EAAkB,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAC,CAAA,EAAG,kBAAA,EAAkB,WAAA,GAAc,MAAA,GAAS,MAAA,EACxO,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,WAAQ,OAAA,EAAS,QAAA,EAAU,QAAA,EAAU,OAAA,EAAS,SAAS,KAAA,EAAO,CAAA;AAAA,IAC9D,OAAA,oBAAW,GAAA,CAAC,GAAA,EAAA,EAAE,KAAA,EAAM,2BAAA,EAA4B,EAAA,EAAI,SAAA,EAAY,QAAA,EAAA,WAAA,mBAAc,GAAA,CAAC,QAAA,EAAA,EAAS,KAAA,EAAM,MAAA,EAAO,IAAK,OAAA,EAAQ;AAAA,GAAA,EACrH,CAAA;AACF","file":"chunk-BNQ2YDV4.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport { Skeleton } from './skeleton.js';\nimport { Toolbar } from './toolbar.js';\nimport { ToolbarControlGroup } from './toolbar-control-group.js';\nimport { type HeadingLevel, ToolbarText } from './toolbar-text.js';\n\nexport interface PanelHeaderProps {\n title: string;\n titleId: string;\n summary?: string;\n summaryId?: string;\n icon?: SafeHtml;\n iconClassName?: string;\n actions?: SafeHtml;\n /**\n * Expose the title as a heading landmark (`role=\"heading\"` + `aria-level`). Set it\n * for a PAGE or view heading so screen-reader heading navigation works and the view\n * has a primary heading; omit it (the default) for a dialog title, which is instead\n * referenced via `aria-labelledby={titleId}` and needs no heading landmark.\n */\n headingLevel?: HeadingLevel;\n /** Render the title and summary as unanimated loading skeletons, keeping the icon and actions. */\n placeholder?: boolean;\n}\n\n/**\n * The heading of a panel, dialog, or page: a plain `Toolbar` whose leading zone\n * holds an optional icon control group and the title as extra-large `ToolbarText`,\n * whose trailing zone holds the app's action controls, and with an optional\n * subtitle on its own row, left-aligned with the title.\n *\n * PanelHeader overrides no Toolbar styles — it is just a Toolbar with an xl title.\n * The only styling it adds is the icon group's fill/border color and the subtitle.\n * When no icon is provided, the icon group is omitted entirely. The `actions` slot\n * is passed straight into the toolbar's trailing zone; the app supplies whatever\n * trailing controls it needs (typically a `ToolbarControlGroup`).\n */\nexport function PanelHeader({ title, titleId, summary, summaryId, icon, iconClassName = '', actions, headingLevel, placeholder = false }: PanelHeaderProps) {\n const identity = <>\n {icon && <ToolbarControlGroup single className={`kui-panel-header__icon ${iconClassName}`.trim()}>{icon}</ToolbarControlGroup>}\n <ToolbarText text={title} size=\"xlarge\" id={titleId} className=\"kui-panel-header__title\" headingLevel={headingLevel} placeholder={placeholder} />\n </>;\n\n return <div class=\"kui-panel-header\" data-component=\"panel-header\" data-has-icon={String(Boolean(icon))} data-has-actions={String(Boolean(actions))} data-has-summary={String(Boolean(summary))} data-placeholder={placeholder ? 'true' : undefined}>\n <Toolbar leading={identity} trailing={actions} divider={false} />\n {summary && <p class=\"kui-panel-header__summary\" id={summaryId}>{placeholder ? <Skeleton width=\"18em\" /> : summary}</p>}\n </div>;\n}\n"]}
@@ -1,10 +1,10 @@
1
1
  import { Skeleton } from './chunk-B24C4A6T.js';
2
2
  import { jsx } from 'kerfjs/jsx-runtime';
3
3
 
4
- function ToolbarText({ text, size = "default", className = "", id, placeholder = false }) {
5
- return /* @__PURE__ */ jsx("span", { class: `kui-toolbar-text ${className}`.trim(), "data-component": "toolbar-text", "data-size": size, "data-placeholder": placeholder ? "true" : void 0, id, "aria-busy": placeholder ? "true" : void 0, children: placeholder ? /* @__PURE__ */ jsx(Skeleton, { width: "8em" }) : text });
4
+ function ToolbarText({ text, size = "default", className = "", id, headingLevel, placeholder = false }) {
5
+ return /* @__PURE__ */ jsx("span", { class: `kui-toolbar-text ${className}`.trim(), "data-component": "toolbar-text", "data-size": size, "data-placeholder": placeholder ? "true" : void 0, id, role: headingLevel ? "heading" : void 0, "aria-level": headingLevel ? String(headingLevel) : void 0, "aria-busy": placeholder ? "true" : void 0, children: placeholder ? /* @__PURE__ */ jsx(Skeleton, { width: "8em" }) : text });
6
6
  }
7
7
 
8
8
  export { ToolbarText };
9
9
 
10
- //# sourceMappingURL=chunk-KJYXOTG3.js.map
10
+ //# sourceMappingURL=chunk-RUNWEPR4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/toolbar-text.tsx"],"names":[],"mappings":";;;AAuBO,SAAS,WAAA,CAAY,EAAE,IAAA,EAAM,IAAA,GAAO,SAAA,EAAW,SAAA,GAAY,EAAA,EAAI,EAAA,EAAI,YAAA,EAAc,WAAA,GAAc,KAAA,EAAM,EAAqB;AAC/H,EAAA,2BAAQ,MAAA,EAAA,EAAK,KAAA,EAAO,CAAA,iBAAA,EAAoB,SAAS,GAAG,IAAA,EAAK,EAAG,gBAAA,EAAe,cAAA,EAAe,aAAW,IAAA,EAAM,kBAAA,EAAkB,WAAA,GAAc,MAAA,GAAS,QAAW,EAAA,EAAQ,IAAA,EAAM,YAAA,GAAe,SAAA,GAAY,QAAW,YAAA,EAAY,YAAA,GAAe,MAAA,CAAO,YAAY,IAAI,MAAA,EAAW,WAAA,EAAW,WAAA,GAAc,MAAA,GAAS,QAAY,QAAA,EAAA,WAAA,mBAAc,GAAA,CAAC,YAAS,KAAA,EAAM,KAAA,EAAM,IAAK,IAAA,EAAK,CAAA;AAC9W","file":"chunk-RUNWEPR4.js","sourcesContent":["import { Skeleton } from './skeleton.js';\n\nexport type ToolbarTextSize = 'xlarge' | 'large' | 'default' | 'small';\n\n/** ARIA heading level for a title exposed as a heading landmark. */\nexport type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;\n\nexport interface ToolbarTextProps {\n text: string;\n size?: ToolbarTextSize;\n className?: string;\n /** Optional id, e.g. so a dialog can reference the title via aria-labelledby. */\n id?: string;\n /**\n * Expose heading semantics (`role=\"heading\"` + `aria-level`) so the text acts as\n * a heading landmark — e.g. a page's primary title. Omit to keep the plain span\n * (the default), which suits a dialog title referenced via `aria-labelledby`.\n */\n headingLevel?: HeadingLevel;\n /** Render the text as an unanimated loading skeleton instead of its value. */\n placeholder?: boolean;\n}\n\nexport function ToolbarText({ text, size = 'default', className = '', id, headingLevel, placeholder = false }: ToolbarTextProps) {\n return <span class={`kui-toolbar-text ${className}`.trim()} data-component=\"toolbar-text\" data-size={size} data-placeholder={placeholder ? 'true' : undefined} id={id} role={headingLevel ? 'heading' : undefined} aria-level={headingLevel ? String(headingLevel) : undefined} aria-busy={placeholder ? 'true' : undefined}>{placeholder ? <Skeleton width=\"8em\" /> : text}</span>;\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -16,7 +16,7 @@ export { TabBar, TabBarProps } from './tab-bar.js';
16
16
  export { TokenSearchField, TokenSearchFieldProps, TokenSearchFieldValue, TokenSearchToken, placeTokenSearchCaret, readTokenSearchField } from './token-search-field.js';
17
17
  export { Toolbar, ToolbarProps } from './toolbar.js';
18
18
  export { ToolbarControlGroup, ToolbarControlGroupProps } from './toolbar-control-group.js';
19
- export { ToolbarText, ToolbarTextProps, ToolbarTextSize } from './toolbar-text.js';
19
+ export { HeadingLevel, ToolbarText, ToolbarTextProps, ToolbarTextSize } from './toolbar-text.js';
20
20
  export { ValueTable, ValueTableProps, ValueTableRow, ValueTableRowProps } from './value-table.js';
21
21
  export { ResizeCommit, WireResizableRegionsOptions, wireResizableRegions } from './wire-resizable-regions.js';
22
22
  export { TabDropPosition, TabReorder, TabReorderSource, WireTabBarsOptions, reorderTabs, wireTabBars } from './wire-tab-bars.js';
package/dist/index.js CHANGED
@@ -7,10 +7,10 @@ export { TabBar } from './chunk-MBR3TYNL.js';
7
7
  export { TokenSearchField, placeTokenSearchCaret, readTokenSearchField } from './chunk-7LDCTU7D.js';
8
8
  export { MenuHeader } from './chunk-H6URQGJI.js';
9
9
  export { MenuItem } from './chunk-YKUUZPED.js';
10
- export { PanelHeader } from './chunk-TZNCCM5H.js';
10
+ export { PanelHeader } from './chunk-BNQ2YDV4.js';
11
11
  export { Toolbar } from './chunk-DAFFDO33.js';
12
12
  export { ToolbarControlGroup } from './chunk-MFKMHK5W.js';
13
- export { ToolbarText } from './chunk-KJYXOTG3.js';
13
+ export { ToolbarText } from './chunk-RUNWEPR4.js';
14
14
  export { ResizableRegion, clampRegionSize, resizeRegionFromPointer } from './chunk-M5JRI6MN.js';
15
15
  export { SegmentedControl } from './chunk-YGN7OMLT.js';
16
16
  export { Select } from './chunk-LC3YSAZC.js';
package/dist/nav-stack.js CHANGED
@@ -1,4 +1,4 @@
1
- export { NavStack } from './chunk-N3SUXLLS.js';
1
+ export { NavStack } from './chunk-BLK3UEEI.js';
2
2
 
3
3
 
4
4
 
@@ -1,4 +1,5 @@
1
1
  import { SafeHtml } from 'kerfjs';
2
+ import { HeadingLevel } from './toolbar-text.js';
2
3
 
3
4
  interface PanelHeaderProps {
4
5
  title: string;
@@ -8,6 +9,13 @@ interface PanelHeaderProps {
8
9
  icon?: SafeHtml;
9
10
  iconClassName?: string;
10
11
  actions?: SafeHtml;
12
+ /**
13
+ * Expose the title as a heading landmark (`role="heading"` + `aria-level`). Set it
14
+ * for a PAGE or view heading so screen-reader heading navigation works and the view
15
+ * has a primary heading; omit it (the default) for a dialog title, which is instead
16
+ * referenced via `aria-labelledby={titleId}` and needs no heading landmark.
17
+ */
18
+ headingLevel?: HeadingLevel;
11
19
  /** Render the title and summary as unanimated loading skeletons, keeping the icon and actions. */
12
20
  placeholder?: boolean;
13
21
  }
@@ -23,6 +31,6 @@ interface PanelHeaderProps {
23
31
  * is passed straight into the toolbar's trailing zone; the app supplies whatever
24
32
  * trailing controls it needs (typically a `ToolbarControlGroup`).
25
33
  */
26
- declare function PanelHeader({ title, titleId, summary, summaryId, icon, iconClassName, actions, placeholder }: PanelHeaderProps): SafeHtml;
34
+ declare function PanelHeader({ title, titleId, summary, summaryId, icon, iconClassName, actions, headingLevel, placeholder }: PanelHeaderProps): SafeHtml;
27
35
 
28
36
  export { PanelHeader, type PanelHeaderProps };
@@ -1,4 +1,4 @@
1
- export { PanelHeader } from './chunk-TZNCCM5H.js';
1
+ export { PanelHeader } from './chunk-BNQ2YDV4.js';
2
2
 
3
3
 
4
4
 
@@ -1,4 +1,4 @@
1
- import { NavStack } from './chunk-N3SUXLLS.js';
1
+ import { NavStack } from './chunk-BLK3UEEI.js';
2
2
 
3
3
  import { ResizableRegion } from './chunk-M5JRI6MN.js';
4
4
 
@@ -1,15 +1,23 @@
1
1
  import * as kerfjs from 'kerfjs';
2
2
 
3
3
  type ToolbarTextSize = 'xlarge' | 'large' | 'default' | 'small';
4
+ /** ARIA heading level for a title exposed as a heading landmark. */
5
+ type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
4
6
  interface ToolbarTextProps {
5
7
  text: string;
6
8
  size?: ToolbarTextSize;
7
9
  className?: string;
8
10
  /** Optional id, e.g. so a dialog can reference the title via aria-labelledby. */
9
11
  id?: string;
12
+ /**
13
+ * Expose heading semantics (`role="heading"` + `aria-level`) so the text acts as
14
+ * a heading landmark — e.g. a page's primary title. Omit to keep the plain span
15
+ * (the default), which suits a dialog title referenced via `aria-labelledby`.
16
+ */
17
+ headingLevel?: HeadingLevel;
10
18
  /** Render the text as an unanimated loading skeleton instead of its value. */
11
19
  placeholder?: boolean;
12
20
  }
13
- declare function ToolbarText({ text, size, className, id, placeholder }: ToolbarTextProps): kerfjs.SafeHtml;
21
+ declare function ToolbarText({ text, size, className, id, headingLevel, placeholder }: ToolbarTextProps): kerfjs.SafeHtml;
14
22
 
15
- export { ToolbarText, type ToolbarTextProps, type ToolbarTextSize };
23
+ export { type HeadingLevel, ToolbarText, type ToolbarTextProps, type ToolbarTextSize };
@@ -1,4 +1,4 @@
1
- export { ToolbarText } from './chunk-KJYXOTG3.js';
1
+ export { ToolbarText } from './chunk-RUNWEPR4.js';
2
2
 
3
3
 
4
4
  //# sourceMappingURL=toolbar-text.js.map
@@ -46,11 +46,16 @@ The application owns persistence and collapsed/expanded policy. Keep the last ex
46
46
  `PanelHeader` is a plain `Toolbar` heading. Its leading zone holds an optional
47
47
  icon (a normal bordered `ToolbarControlGroup`) and the title as extra-large
48
48
  `ToolbarText`, and the app's trailing controls go straight into the trailing
49
- zone. The title carries no native heading role, so the application connects
50
- `titleId` and an optional `summaryId` to the owning dialog or panel through
51
- `aria-labelledby` and `aria-describedby` (and provides a document heading
52
- separately when one is required). Pass the trailing controls as a labeled
53
- `ToolbarControlGroup` when that group needs an accessible name.
49
+ zone. By default the title carries no native heading role, so for a **dialog or
50
+ panel** the application connects `titleId` and an optional `summaryId` to the
51
+ owning host through `aria-labelledby` and `aria-describedby`. For a **page or
52
+ view** title, pass `headingLevel` (usually `1`): the title then exposes
53
+ `role="heading"` with a matching `aria-level`, giving the view a heading landmark
54
+ so screen-reader heading navigation and "main heading" semantics work — the same
55
+ role/level pair `ToolbarText` exposes when it is given `headingLevel` directly.
56
+ Keep the levels meaningful and non-skipping within a view. Pass the trailing
57
+ controls as a labeled `ToolbarControlGroup` when that group needs an accessible
58
+ name.
54
59
 
55
60
  ## Tabs
56
61
 
@@ -62,7 +62,7 @@ an upstream component or recipe request.
62
62
  | Disclosure indicator — `DisclosureArrow` | A control needs one animated 18px root-scaled visual for open and closed state, including configurable directions or a replacement icon. | Do not use it as the interactive control or accessible name; place it inside the button or control that exposes expanded state. | Pass the controlled `open` state, render it inside the owning control, author replacement icon content facing right before transforms, and override `--kui-disclosure-arrow-size` only when another visual size is required. Direction changes use the shortest rotation path, with counterclockwise chosen for a 180-degree closed-to-open tie. | Open state, interaction, accessible name, size override, replacement glyph, direction choices, and shortest-path rotation. | `@kerfjs/ui/disclosure-arrow` | [Component ownership](./component-contract.md#ownership-boundaries) |
63
63
  | Application toolbar — `Toolbar` | Leading identity, optional centered content, and trailing controls form one horizontal app bar. | Do not use it for a page, panel, or dialog heading; use `PanelHeader`. | Compose `ToolbarText` and `ToolbarControlGroup` where their contracts fit. | Actions, command availability, responsive relocation, and state. | `@kerfjs/ui/toolbar` | [Toolbar composition](../README.md#component-subpaths) |
64
64
  | Toolbar control cluster — `ToolbarControlGroup` | Related toolbar controls need contained, borderless, pressed, or single-control treatment. | Do not use it merely to align unrelated buttons; use toolbar slots or ordinary layout. Web Awesome `wa-button-group` is only for an exceptional grouped-action contract. | Delegate child actions; use `SegmentedControl` for an exclusive choice. | Actions, pressed/expanded state, and policy. | `@kerfjs/ui/toolbar-control-group` | [Component ownership](./component-contract.md#ownership-boundaries) |
65
- | Toolbar identity text — `ToolbarText` | A toolbar needs extra-large (page/panel title), large, default, or compact textual identity. | Do not substitute it for document heading semantics; use `PanelHeader` or native headings. | None. | Text and responsive priority. | `@kerfjs/ui/toolbar-text` | [Toolbar composition](../README.md#component-subpaths) |
65
+ | 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` (or prefer `PanelHeader`, which forwards it). | Optional `headingLevel` for `role="heading"` + `aria-level`. | Text, heading level, and responsive priority. | `@kerfjs/ui/toolbar-text` | [Toolbar composition](../README.md#component-subpaths) |
66
66
  | Navigation row — `MenuItem` | A pane or navigation area needs a selectable, disabled, dormant-trailing, or multiline action row. | Do not put a control in `trailing`; use `MenuActionRow` 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. | Routing, selection, permissions, copy, action handling, and domain `data-*` values. | `@kerfjs/ui/menu-item` | [Pane geometry](../README.md#pane-and-content-geometry) |
67
67
  | Navigation row with trailing action — `MenuActionRow` | A full-width row needs a selectable primary action and an independently focusable trailing action. | Use `MenuItem` 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/menu-action-row` | [Accessibility](./accessibility.md#menuactionrow) |
68
68
  | Navigation section heading — `MenuHeader` | 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 `PanelHeader`. | 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/menu-header` | [Pane geometry](../README.md#pane-and-content-geometry) |
@@ -71,7 +71,7 @@ an upstream component or recipe request.
71
71
  | 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 a static two-column layout; use CSS grid. 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) |
72
72
  | One application tab — `AppTab` | A controlled app tab needs selection, close, drag, leading/trailing anatomy, 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`. | Tab identity, order, selection, close policy, content, and domain metadata values. | `@kerfjs/ui/app-tab` | [Tabs contract](./accessibility.md#tabs) |
73
73
  | Application tab strip — `TabBar`, `wireTabBars`, `reorderTabs` | Tabs switch page regions and may overflow, close, or reorder. | 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. | Ordered tabs, selection, panels, routing, closing, and persistence. | `@kerfjs/ui/tab-bar` plus `@kerfjs/ui/wire-tab-bars` | [Tabs contract](./accessibility.md#tabs) |
74
- | Panel, dialog, or page heading — `PanelHeader` | A panel, dialog, or page needs a heading with an extra-large title, an optional icon and subtitle, and trailing actions. | Do not use it as persistent app chrome; use `Toolbar`. It supplies header structure, not modal behavior; use an application overlay or Web Awesome `wa-dialog` for that behavior. | Connect the title id and any provided summary id to the dialog or panel host, pass the trailing controls (typically a `ToolbarControlGroup`), and delegate their actions. | Open state, focus lifecycle, dismissal, the trailing controls, labels, and copy. | `@kerfjs/ui/panel-header` | [Header ownership](./component-contract.md#extracted-versus-application-specific) |
74
+ | Panel, dialog, or page heading — `PanelHeader` | A panel, dialog, or page needs a heading with an extra-large title, an optional icon and subtitle, and trailing actions. | Do not use it as persistent app chrome; use `Toolbar`. It supplies header structure, not modal behavior; use an application overlay or Web Awesome `wa-dialog` for that behavior. | Connect the title id and any provided summary id to the dialog or panel host, pass the trailing controls (typically a `ToolbarControlGroup`), and delegate their actions. **For a page or view title set `headingLevel` (usually `1`)** so the title is a real heading landmark (`role="heading"` + `aria-level`) for screen-reader heading navigation; omit it for a dialog title, which is referenced via `aria-labelledby` to `titleId` and needs no heading. | Open state, focus lifecycle, dismissal, the trailing controls, labels, copy, and the heading level for page use. | `@kerfjs/ui/panel-header` | [Header ownership](./component-contract.md#extracted-versus-application-specific) |
75
75
  | Key/value facts — `ValueTable`, `ValueTableRow` | Read-only labels and values form a semantic definition list, optionally with a leading icon. | Do not use it for editable form fields or a row/column data grid; use native form or table semantics. | Compose typed `ValueTableRow` entries; pass `icon` when a 24px leading icon adds useful context. | Values, formatting, icon meaning, and empty/loading policy. | `@kerfjs/ui/value-table` | [Component ownership](./component-contract.md#ownership-boundaries) |
76
76
  | Indeterminate activity — `LoadingSpinner` | A Kerf surface needs compact, labeled or decorative indeterminate progress. | Do not use it for known progress; use Web Awesome `wa-progress-bar` or `wa-progress-ring`. Direct Web Awesome UI may use `wa-spinner`; do not mix spinner systems within one surface. | None; pass a label when the spinner conveys status. | Loading lifecycle and adjacent status copy. | `@kerfjs/ui/loading-spinner` | [Accessibility](./accessibility.md#shared-rules) |
77
77
  | Loading placeholder — `Skeleton` + a component's `placeholder` prop | A value or a whole component is still loading and should hold its space as a subtle, unanimated block, keeping the layout stable — an inspector or detail view rendering its real chrome with per-record values absent. | Do not use it for known progress (use `LoadingSpinner`), do not animate it, and do not hand-rebuild a component's empty state — set `placeholder` on the component instead. Prefer it over `wa-skeleton`, which the pure-Kerf primitives avoid to stay Web-Awesome-free. | Set `placeholder` on a value-bearing component (`Select`, `MenuHeader`, `MenuItem`, `ValueTableRow`, `PanelHeader`, `SegmentedControl`, `StateBanner`, `AppTab`, `ToolbarText`, `MenuActionRow`) to render skeletons in its value slots with interactivity disabled; use the standalone `Skeleton` for a custom slot. | Loading lifecycle, which slots are unknown, and announcing the loading region. | `@kerfjs/ui/skeleton` | [Accessibility](./accessibility.md#shared-rules) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kerfjs/ui",
3
- "version": "5.0.0-beta.7",
3
+ "version": "5.0.0-beta.8",
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/toolbar-text.tsx"],"names":[],"mappings":";;;AAcO,SAAS,WAAA,CAAY,EAAE,IAAA,EAAM,IAAA,GAAO,SAAA,EAAW,YAAY,EAAA,EAAI,EAAA,EAAI,WAAA,GAAc,KAAA,EAAM,EAAqB;AACjH,EAAA,uBAAO,GAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAO,CAAA,iBAAA,EAAoB,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK,EAAG,gBAAA,EAAe,cAAA,EAAe,WAAA,EAAW,IAAA,EAAM,kBAAA,EAAkB,WAAA,GAAc,MAAA,GAAS,MAAA,EAAW,EAAA,EAAQ,WAAA,EAAW,WAAA,GAAc,MAAA,GAAS,MAAA,EAAY,QAAA,EAAA,WAAA,mBAAc,GAAA,CAAC,QAAA,EAAA,EAAS,KAAA,EAAM,KAAA,EAAM,CAAA,GAAK,IAAA,EAAK,CAAA;AACrQ","file":"chunk-KJYXOTG3.js","sourcesContent":["import { Skeleton } from './skeleton.js';\n\nexport type ToolbarTextSize = 'xlarge' | 'large' | 'default' | 'small';\n\nexport interface ToolbarTextProps {\n text: string;\n size?: ToolbarTextSize;\n className?: string;\n /** Optional id, e.g. so a dialog can reference the title via aria-labelledby. */\n id?: string;\n /** Render the text as an unanimated loading skeleton instead of its value. */\n placeholder?: boolean;\n}\n\nexport function ToolbarText({ text, size = 'default', className = '', id, placeholder = false }: ToolbarTextProps) {\n return <span class={`kui-toolbar-text ${className}`.trim()} data-component=\"toolbar-text\" data-size={size} data-placeholder={placeholder ? 'true' : undefined} id={id} aria-busy={placeholder ? 'true' : undefined}>{placeholder ? <Skeleton width=\"8em\" /> : text}</span>;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/panel-header.tsx"],"names":[],"mappings":";;;;;;AA+BO,SAAS,WAAA,CAAY,EAAE,KAAA,EAAO,OAAA,EAAS,OAAA,EAAS,SAAA,EAAW,IAAA,EAAM,aAAA,GAAgB,EAAA,EAAI,OAAA,EAAS,WAAA,GAAc,KAAA,EAAM,EAAqB;AAC5I,EAAA,MAAM,2BAAW,IAAA,CAAA,QAAA,EAAA,EACd,QAAA,EAAA;AAAA,IAAA,IAAA,oBAAQ,GAAA,CAAC,mBAAA,EAAA,EAAoB,MAAA,EAAM,IAAA,EAAC,SAAA,EAAW,0BAA0B,aAAa,CAAA,CAAA,CAAG,IAAA,EAAK,EAAI,QAAA,EAAA,IAAA,EAAK,CAAA;AAAA,oBACxG,GAAA,CAAC,WAAA,EAAA,EAAY,IAAA,EAAM,KAAA,EAAO,IAAA,EAAK,UAAS,EAAA,EAAI,OAAA,EAAS,SAAA,EAAU,yBAAA,EAA0B,WAAA,EAA0B;AAAA,GAAA,EACrH,CAAA;AAEA,EAAA,uBAAO,IAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,kBAAA,EAAmB,gBAAA,EAAe,cAAA,EAAe,eAAA,EAAe,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAC,CAAA,EAAG,kBAAA,EAAkB,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAC,CAAA,EAAG,kBAAA,EAAkB,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAC,CAAA,EAAG,kBAAA,EAAkB,WAAA,GAAc,MAAA,GAAS,MAAA,EACxO,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,WAAQ,OAAA,EAAS,QAAA,EAAU,QAAA,EAAU,OAAA,EAAS,SAAS,KAAA,EAAO,CAAA;AAAA,IAC9D,OAAA,oBAAW,GAAA,CAAC,GAAA,EAAA,EAAE,KAAA,EAAM,2BAAA,EAA4B,EAAA,EAAI,SAAA,EAAY,QAAA,EAAA,WAAA,mBAAc,GAAA,CAAC,QAAA,EAAA,EAAS,KAAA,EAAM,MAAA,EAAO,IAAK,OAAA,EAAQ;AAAA,GAAA,EACrH,CAAA;AACF","file":"chunk-TZNCCM5H.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport { Skeleton } from './skeleton.js';\nimport { Toolbar } from './toolbar.js';\nimport { ToolbarControlGroup } from './toolbar-control-group.js';\nimport { ToolbarText } from './toolbar-text.js';\n\nexport interface PanelHeaderProps {\n title: string;\n titleId: string;\n summary?: string;\n summaryId?: string;\n icon?: SafeHtml;\n iconClassName?: string;\n actions?: SafeHtml;\n /** Render the title and summary as unanimated loading skeletons, keeping the icon and actions. */\n placeholder?: boolean;\n}\n\n/**\n * The heading of a panel, dialog, or page: a plain `Toolbar` whose leading zone\n * holds an optional icon control group and the title as extra-large `ToolbarText`,\n * whose trailing zone holds the app's action controls, and with an optional\n * subtitle on its own row, left-aligned with the title.\n *\n * PanelHeader overrides no Toolbar styles — it is just a Toolbar with an xl title.\n * The only styling it adds is the icon group's fill/border color and the subtitle.\n * When no icon is provided, the icon group is omitted entirely. The `actions` slot\n * is passed straight into the toolbar's trailing zone; the app supplies whatever\n * trailing controls it needs (typically a `ToolbarControlGroup`).\n */\nexport function PanelHeader({ title, titleId, summary, summaryId, icon, iconClassName = '', actions, placeholder = false }: PanelHeaderProps) {\n const identity = <>\n {icon && <ToolbarControlGroup single className={`kui-panel-header__icon ${iconClassName}`.trim()}>{icon}</ToolbarControlGroup>}\n <ToolbarText text={title} size=\"xlarge\" id={titleId} className=\"kui-panel-header__title\" placeholder={placeholder} />\n </>;\n\n return <div class=\"kui-panel-header\" data-component=\"panel-header\" data-has-icon={String(Boolean(icon))} data-has-actions={String(Boolean(actions))} data-has-summary={String(Boolean(summary))} data-placeholder={placeholder ? 'true' : undefined}>\n <Toolbar leading={identity} trailing={actions} divider={false} />\n {summary && <p class=\"kui-panel-header__summary\" id={summaryId}>{placeholder ? <Skeleton width=\"18em\" /> : summary}</p>}\n </div>;\n}\n"]}