@kerfjs/ui 5.0.0-beta.100 → 5.0.0-beta.101

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.
Files changed (148) hide show
  1. package/README.md +3 -1
  2. package/ai/component-catalog.json +214 -18
  3. package/ai/component-composition.json +216 -8
  4. package/ai/components/README.md +2 -0
  5. package/ai/components/backdrop-image.md +84 -0
  6. package/ai/components/nav-stack.md +6 -1
  7. package/ai/components/pane.md +11 -1
  8. package/ai/components/recipe-media-detail.md +57 -0
  9. package/ai/components/surface-scaffold.md +13 -6
  10. package/ai/components/tab-navigator.md +6 -1
  11. package/ai/components/toolbar-control-group.md +1 -0
  12. package/ai/public-api-signatures-v1.md +356 -32
  13. package/ai/skill.md +53 -5
  14. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  15. package/dist/backdrop-image.d.ts +132 -0
  16. package/dist/backdrop-image.js +5 -0
  17. package/dist/backdrop-image.js.map +1 -0
  18. package/dist/browser/backdrop-image.js +3 -0
  19. package/dist/catalog-resources.d.ts +2 -2
  20. package/dist/catalog.d.ts +2 -2
  21. package/dist/catalog.js +10 -9
  22. package/dist/catalog.js.map +1 -1
  23. package/dist/{chunk-QIG4IGUP.js → chunk-2PXZBFEC.js} +3 -1
  24. package/dist/chunk-2PXZBFEC.js.map +1 -0
  25. package/dist/{chunk-T4WJ5VGP.js → chunk-3SKAEPPZ.js} +2 -2
  26. package/dist/{chunk-T4WJ5VGP.js.map → chunk-3SKAEPPZ.js.map} +1 -1
  27. package/dist/chunk-5NQF35VO.js +67 -0
  28. package/dist/chunk-5NQF35VO.js.map +1 -0
  29. package/dist/{chunk-CMETHPKR.js → chunk-6E2H2E5A.js} +29 -8
  30. package/dist/chunk-6E2H2E5A.js.map +1 -0
  31. package/dist/{chunk-PIVY32AE.js → chunk-BYFTHA4I.js} +16 -3
  32. package/dist/chunk-BYFTHA4I.js.map +1 -0
  33. package/dist/{chunk-HGV7J4T6.js → chunk-EKHDLBRP.js} +1 -1
  34. package/dist/chunk-EKHDLBRP.js.map +1 -0
  35. package/dist/{chunk-QROYYGWU.js → chunk-FNZQOUZ5.js} +2 -2
  36. package/dist/{chunk-QROYYGWU.js.map → chunk-FNZQOUZ5.js.map} +1 -1
  37. package/dist/{chunk-EOO6PYGF.js → chunk-IXLUZHGT.js} +4 -4
  38. package/dist/{chunk-EOO6PYGF.js.map → chunk-IXLUZHGT.js.map} +1 -1
  39. package/dist/{chunk-UMKV7YVQ.js → chunk-LPHU44S3.js} +5 -1
  40. package/dist/chunk-LPHU44S3.js.map +1 -0
  41. package/dist/{chunk-INI4WDWC.js → chunk-M5KZ26VV.js} +27 -4
  42. package/dist/chunk-M5KZ26VV.js.map +1 -0
  43. package/dist/{chunk-TLMMFQWM.js → chunk-NS762OVM.js} +3 -3
  44. package/dist/{chunk-TLMMFQWM.js.map → chunk-NS762OVM.js.map} +1 -1
  45. package/dist/{chunk-CXZXHZTR.js → chunk-OZ6X76G5.js} +34 -1
  46. package/dist/chunk-OZ6X76G5.js.map +1 -0
  47. package/dist/{chunk-YOA5W5ZH.js → chunk-PKL6QJKK.js} +31 -3
  48. package/dist/chunk-PKL6QJKK.js.map +1 -0
  49. package/dist/chunk-QTSMHH5J.js +85 -0
  50. package/dist/chunk-QTSMHH5J.js.map +1 -0
  51. package/dist/chunk-SCDWURBO.js +136 -0
  52. package/dist/chunk-SCDWURBO.js.map +1 -0
  53. package/dist/{chunk-RHD7RKGI.js → chunk-SIW64V65.js} +3 -3
  54. package/dist/{chunk-RHD7RKGI.js.map → chunk-SIW64V65.js.map} +1 -1
  55. package/dist/chunk-SQ5DH66U.js +37 -0
  56. package/dist/chunk-SQ5DH66U.js.map +1 -0
  57. package/dist/{chunk-PYBBYSZ3.js → chunk-YBWQR2OK.js} +5 -5
  58. package/dist/{chunk-PYBBYSZ3.js.map → chunk-YBWQR2OK.js.map} +1 -1
  59. package/dist/{chunk-3GLYIIFR.js → chunk-ZYU5WRC3.js} +2 -2
  60. package/dist/{chunk-3GLYIIFR.js.map → chunk-ZYU5WRC3.js.map} +1 -1
  61. package/dist/collapsible-panel.js +3 -2
  62. package/dist/collapsible-panel.js.map +1 -1
  63. package/dist/index.d.ts +5 -3
  64. package/dist/index.js +24 -20
  65. package/dist/list-action-row.js +1 -1
  66. package/dist/list-header.js +1 -1
  67. package/dist/list-item.js +1 -1
  68. package/dist/{nav-stack-VXTumzKa.d.ts → nav-stack-CU_0dKtI.d.ts} +41 -5
  69. package/dist/nav-stack.d.ts +4 -4
  70. package/dist/nav-stack.js +2 -1
  71. package/dist/pane.d.ts +76 -4
  72. package/dist/pane.js +2 -1
  73. package/dist/select.js +1 -1
  74. package/dist/split-view.d.ts +4 -4
  75. package/dist/split-view.js +3 -2
  76. package/dist/split-view.js.map +1 -1
  77. package/dist/state-banner.js +1 -1
  78. package/dist/styles/backdrop-image.css +241 -0
  79. package/dist/styles/components/actions/toolbar/toolbar.css +9 -0
  80. package/dist/styles/components/actions/toolbar-control-group/toolbar-control-group.css +128 -0
  81. package/dist/styles/components/layout/pane/pane.css +121 -1
  82. package/dist/styles/components/navigation/nav-stack/nav-stack.css +207 -6
  83. package/dist/styles/components/navigation/tab-navigator/tab-navigator.css +121 -3
  84. package/dist/styles/components/surfaces/backdrop-image/backdrop-image.css +241 -0
  85. package/dist/styles/components/surfaces/surface-scaffold/surface-scaffold.css +166 -2
  86. package/dist/styles/foundation.css +165 -8
  87. package/dist/styles/nav-stack.css +207 -6
  88. package/dist/styles/overlay-sheet.css +211 -0
  89. package/dist/styles/pane.css +121 -1
  90. package/dist/styles/styles.css +1 -0
  91. package/dist/styles/surface-scaffold.css +166 -2
  92. package/dist/styles/tab-navigator.css +121 -3
  93. package/dist/styles/toolbar-control-group.css +128 -0
  94. package/dist/styles/toolbar.css +9 -0
  95. package/dist/styles/webawesome.css +10 -0
  96. package/dist/surface-scaffold-register.d.ts +3 -2
  97. package/dist/surface-scaffold-register.js +113 -10
  98. package/dist/surface-scaffold-register.js.map +1 -1
  99. package/dist/surface-scaffold.d.ts +38 -5
  100. package/dist/surface-scaffold.js +1 -1
  101. package/dist/tab-navigator.d.ts +43 -3
  102. package/dist/tab-navigator.js +35 -6
  103. package/dist/tab-navigator.js.map +1 -1
  104. package/dist/toolbar-control-group.d.ts +13 -2
  105. package/dist/toolbar-control-group.js +1 -1
  106. package/dist/toolbar-text.d.ts +6 -1
  107. package/dist/toolbar-text.js +1 -1
  108. package/dist/toolbar.d.ts +1 -0
  109. package/dist/wire-catalog.d.ts +2 -2
  110. package/dist/wire-catalog.js +1 -1
  111. package/dist/wire-nav-stack.js +29 -3
  112. package/dist/wire-nav-stack.js.map +1 -1
  113. package/dist/wire-overlay-sheets.d.ts +20 -0
  114. package/dist/wire-overlay-sheets.js +4 -0
  115. package/dist/wire-overlay-sheets.js.map +1 -0
  116. package/dist/wire-scroll-dividers.js +1 -1
  117. package/dist/wire-token-search-fields.js +1 -1
  118. package/dist/workbench.d.ts +2 -2
  119. package/dist/workbench.js +2 -1
  120. package/docs/accessibility.md +35 -0
  121. package/docs/app-layouts.md +13 -0
  122. package/docs/backdrop-image.md +128 -0
  123. package/docs/component-contract.md +2 -0
  124. package/docs/component-selection.md +11 -2
  125. package/docs/design/templates/toolbar-control-group/glass-dark.svg +1 -0
  126. package/docs/design/templates/toolbar-control-group/glass.svg +1 -0
  127. package/docs/design/templates/toolbar-control-group-dark.svg +1 -1
  128. package/docs/design/templates/toolbar-control-group.svg +1 -1
  129. package/docs/design/templates.md +8 -0
  130. package/docs/layout.md +135 -5
  131. package/docs/manual-test-plan.md +29 -0
  132. package/docs/nav-stack.md +37 -1
  133. package/docs/recipes.md +24 -0
  134. package/docs/surface-scaffold.md +149 -3
  135. package/docs/tab-navigator.md +36 -0
  136. package/docs/ux-demo.md +11 -1
  137. package/llms.txt +42 -4
  138. package/package.json +13 -1
  139. package/ux-demo/recipes/loaders.ts +2 -0
  140. package/ux-demo/recipes/media-detail.tsx +272 -0
  141. package/dist/chunk-CMETHPKR.js.map +0 -1
  142. package/dist/chunk-CXZXHZTR.js.map +0 -1
  143. package/dist/chunk-HGV7J4T6.js.map +0 -1
  144. package/dist/chunk-INI4WDWC.js.map +0 -1
  145. package/dist/chunk-PIVY32AE.js.map +0 -1
  146. package/dist/chunk-QIG4IGUP.js.map +0 -1
  147. package/dist/chunk-UMKV7YVQ.js.map +0 -1
  148. package/dist/chunk-YOA5W5ZH.js.map +0 -1
@@ -1,6 +1,108 @@
1
+ import { syncSheetHandleValues, createSheetHandle, wireSheetHandle } from './chunk-QTSMHH5J.js';
1
2
  import WaDialog from '@awesome.me/webawesome/dist/components/dialog/dialog.js';
2
3
 
3
- // src/components/surfaces/surface-scaffold/register/surface-scaffold-register.ts
4
+ // src/components/surfaces/surface-scaffold/internal/install-bottom-sheet.ts
5
+ var SHEET_HANDLE_PART = "sheet-handle";
6
+ var SHEET_HEIGHT_PROPERTY = "--_kui-dialog-surface-sheet-height";
7
+ var KEYBOARD_INSET_PROPERTY = "--_kui-dialog-surface-keyboard-inset";
8
+ var SHEET_MOTION_ATTRIBUTE = "data-kui-sheet-motion";
9
+ var installed = /* @__PURE__ */ new WeakSet();
10
+ var viewportCleanups = /* @__PURE__ */ new WeakMap();
11
+ var surfaceOf = (host) => host.parentElement?.classList.contains("kui-dialog-surface") ? host.parentElement : null;
12
+ var isBottomSheet = (host) => surfaceOf(host)?.getAttribute("data-presentation") === "bottom-sheet";
13
+ var isResizable = (host) => isBottomSheet(host) && surfaceOf(host).hasAttribute("data-resizable");
14
+ function installBottomSheet(prototype) {
15
+ if (installed.has(prototype)) return;
16
+ installed.add(prototype);
17
+ const target = prototype;
18
+ const { update, show, requestClose } = target;
19
+ target.update = function(changed) {
20
+ update.call(this, changed);
21
+ if (!surfaceOf(this)) return;
22
+ const panel = this.dialog;
23
+ if (!panel) return;
24
+ syncHandle(this, panel);
25
+ if (this.open) followViewport(this, panel);
26
+ else unfollowViewport(this);
27
+ };
28
+ target.show = function() {
29
+ const panel = this.dialog;
30
+ if (panel && surfaceOf(this)) {
31
+ panel.style.removeProperty(SHEET_HEIGHT_PROPERTY);
32
+ syncHandle(this, panel);
33
+ }
34
+ const result = show.call(this);
35
+ markMotion(this, "show", "enter", result);
36
+ void result.then(() => {
37
+ const handle = panel?.querySelector(
38
+ `:scope > [part~="${SHEET_HANDLE_PART}"]`
39
+ );
40
+ if (panel && handle && isResizable(this))
41
+ syncSheetHandleValues(handle, panel);
42
+ });
43
+ return result;
44
+ };
45
+ target.requestClose = function(source) {
46
+ const result = requestClose.call(this, source);
47
+ markMotion(this, "hide", "exit", result);
48
+ return result;
49
+ };
50
+ }
51
+ function markMotion(host, className, value, result) {
52
+ if (!surfaceOf(host) || !host.dialog?.classList.contains(className)) return;
53
+ host.setAttribute(SHEET_MOTION_ATTRIBUTE, value);
54
+ const clear = () => {
55
+ if (host.getAttribute(SHEET_MOTION_ATTRIBUTE) === value)
56
+ host.removeAttribute(SHEET_MOTION_ATTRIBUTE);
57
+ };
58
+ void result.then(clear, clear);
59
+ }
60
+ function syncHandle(host, panel) {
61
+ const existing = panel.querySelector(
62
+ `:scope > [part~="${SHEET_HANDLE_PART}"]`
63
+ );
64
+ const resizable = isResizable(host);
65
+ if (existing) existing.hidden = !resizable;
66
+ else if (resizable) createHandle(host, panel);
67
+ }
68
+ function createHandle(host, panel) {
69
+ const handle = createSheetHandle({ part: SHEET_HANDLE_PART });
70
+ panel.prepend(handle);
71
+ wireSheetHandle(handle, {
72
+ panel,
73
+ host: panel,
74
+ property: SHEET_HEIGHT_PROPERTY,
75
+ enabled: () => isResizable(host)
76
+ });
77
+ }
78
+ function keyboardInset(viewport, layoutHeight) {
79
+ if (viewport.scale > 1.01) return 0;
80
+ const inset = Math.round(layoutHeight - viewport.height - viewport.offsetTop);
81
+ return inset > 0 ? inset : 0;
82
+ }
83
+ function followViewport(host, panel) {
84
+ const viewport = globalThis.visualViewport;
85
+ if (!viewport || viewportCleanups.has(host)) return;
86
+ const publish = () => {
87
+ const inset = host.isConnected && host.open && isBottomSheet(host) ? keyboardInset(viewport, globalThis.innerHeight) : 0;
88
+ if (inset > 0)
89
+ panel.style.setProperty(KEYBOARD_INSET_PROPERTY, `${inset}px`);
90
+ else panel.style.removeProperty(KEYBOARD_INSET_PROPERTY);
91
+ if (!host.isConnected) unfollowViewport(host);
92
+ };
93
+ viewport.addEventListener("resize", publish);
94
+ viewport.addEventListener("scroll", publish);
95
+ viewportCleanups.set(host, () => {
96
+ viewport.removeEventListener("resize", publish);
97
+ viewport.removeEventListener("scroll", publish);
98
+ panel.style.removeProperty(KEYBOARD_INSET_PROPERTY);
99
+ });
100
+ publish();
101
+ }
102
+ function unfollowViewport(host) {
103
+ viewportCleanups.get(host)?.();
104
+ viewportCleanups.delete(host);
105
+ }
4
106
 
5
107
  // src/components/surfaces/surface-scaffold/internal/install-chrome-block-size.ts
6
108
  var HEADER_BLOCK_SIZE_PROPERTY = "--_kui-dialog-surface-header-block-size";
@@ -9,11 +111,11 @@ var CHROME_PARTS = [
9
111
  ["header", HEADER_BLOCK_SIZE_PROPERTY],
10
112
  ["footer", FOOTER_BLOCK_SIZE_PROPERTY]
11
113
  ];
12
- var installed = /* @__PURE__ */ new WeakSet();
114
+ var installed2 = /* @__PURE__ */ new WeakSet();
13
115
  var observedParts = /* @__PURE__ */ new WeakSet();
14
116
  function installChromeBlockSize(prototype) {
15
- if (installed.has(prototype)) return;
16
- installed.add(prototype);
117
+ if (installed2.has(prototype)) return;
118
+ installed2.add(prototype);
17
119
  const target = prototype;
18
120
  const update = target.update;
19
121
  target.update = function(changed) {
@@ -46,12 +148,12 @@ function observePart(panel, element, property) {
46
148
  }
47
149
 
48
150
  // src/components/surfaces/surface-scaffold/internal/install-dialog-label.ts
49
- var installed2 = /* @__PURE__ */ new WeakSet();
151
+ var installed3 = /* @__PURE__ */ new WeakSet();
50
152
  var observed = /* @__PURE__ */ new WeakSet();
51
153
  var ownedNames = /* @__PURE__ */ new WeakMap();
52
154
  function installDialogLabel(prototype) {
53
- if (installed2.has(prototype)) return;
54
- installed2.add(prototype);
155
+ if (installed3.has(prototype)) return;
156
+ installed3.add(prototype);
55
157
  const target = prototype;
56
158
  const update = target.update;
57
159
  target.update = function(changed) {
@@ -103,11 +205,11 @@ function syncDialogLabel(host) {
103
205
  var HEADER_DIVIDER_PROPERTY = "--_kui-dialog-surface-header-divider";
104
206
  var SHOWN = "var(--_kui-dialog-surface-header-divider-color)";
105
207
  var THRESHOLD = 1;
106
- var installed3 = /* @__PURE__ */ new WeakSet();
208
+ var installed4 = /* @__PURE__ */ new WeakSet();
107
209
  var wiredPanels = /* @__PURE__ */ new WeakSet();
108
210
  function installHeaderScrollDivider(prototype) {
109
- if (installed3.has(prototype)) return;
110
- installed3.add(prototype);
211
+ if (installed4.has(prototype)) return;
212
+ installed4.add(prototype);
111
213
  const target = prototype;
112
214
  const update = target.update;
113
215
  target.update = function(changed) {
@@ -144,6 +246,7 @@ function wire(host, panel) {
144
246
  installDialogLabel(WaDialog.prototype);
145
247
  installChromeBlockSize(WaDialog.prototype);
146
248
  installHeaderScrollDivider(WaDialog.prototype);
249
+ installBottomSheet(WaDialog.prototype);
147
250
  var surfaceScaffoldElementsRegistered = true;
148
251
 
149
252
  export { surfaceScaffoldElementsRegistered };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/surfaces/surface-scaffold/internal/install-chrome-block-size.ts","../src/components/surfaces/surface-scaffold/internal/install-dialog-label.ts","../src/components/surfaces/surface-scaffold/internal/install-header-scroll-divider.ts","../src/components/surfaces/surface-scaffold/register/surface-scaffold-register.ts"],"names":["installed","attribute","value"],"mappings":"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","file":"surface-scaffold-register.js","sourcesContent":["interface ChromeDialog extends HTMLElement {\n dialog?: HTMLDialogElement;\n update(changed: unknown): void;\n}\n\n/** The panel variable a floating header's body clearance reads. */\nexport const HEADER_BLOCK_SIZE_PROPERTY =\n '--_kui-dialog-surface-header-block-size';\n\n/** The panel variable a floating footer's body clearance reads. */\nexport const FOOTER_BLOCK_SIZE_PROPERTY =\n '--_kui-dialog-surface-footer-block-size';\n\n/** Each measured dialog part, with the panel variable it publishes. */\nconst CHROME_PARTS = [\n ['header', HEADER_BLOCK_SIZE_PROPERTY],\n ['footer', FOOTER_BLOCK_SIZE_PROPERTY],\n] as const;\n\nconst installed = new WeakSet<object>();\nconst observedParts = new WeakSet<Element>();\n\n/**\n * Publish a DialogSurface's header and footer block sizes on its shadow\n * panel, where Kerf rerenders never reach, so a floating header's or footer's\n * body clearance follows that chrome as its content grows, wraps, or hides.\n */\nexport function installChromeBlockSize(prototype: object): void {\n if (installed.has(prototype)) return;\n installed.add(prototype);\n const target = prototype as ChromeDialog;\n const update = target.update;\n target.update = function (this: ChromeDialog, changed: unknown): void {\n update.call(this, changed);\n if (!this.parentElement?.classList.contains('kui-dialog-surface')) return;\n const panel = this.dialog;\n if (!panel) return;\n for (const [part, property] of CHROME_PARTS) {\n const element = this.shadowRoot?.querySelector(`[part~=\"${part}\"]`);\n // Web Awesome drops the header part under `without-header`; with no\n // part to clear, the floating clearance falls back to zero.\n if (element) observePart(panel, element, property);\n else panel.style.removeProperty(property);\n }\n };\n}\n\nfunction observePart(\n panel: HTMLElement,\n element: Element,\n property: string,\n): void {\n if (observedParts.has(element)) return;\n observedParts.add(element);\n const publish = (blockSize: number): void => {\n const value = `${blockSize}px`;\n if (panel.style.getPropertyValue(property) !== value)\n panel.style.setProperty(property, value);\n };\n publish(element.getBoundingClientRect().height);\n if (typeof ResizeObserver === 'undefined') return;\n new ResizeObserver((entries) => {\n // A part Web Awesome has since removed no longer owns the variable.\n if (!element.isConnected) return;\n const box = entries[entries.length - 1]?.borderBoxSize?.[0];\n publish(box ? box.blockSize : element.getBoundingClientRect().height);\n }).observe(element);\n}\n","interface NamedDialog extends HTMLElement {\n dialog?: HTMLDialogElement;\n label: string;\n withoutHeader: boolean;\n update(changed: unknown): void;\n}\n\nconst installed = new WeakSet<object>();\nconst observed = new WeakSet<HTMLElement>();\nconst ownedNames = new WeakMap<\n HTMLElement,\n { attribute: string; value: string }\n>();\n\n/** Repair Web Awesome's missing native dialog name before its first modal open. */\nexport function installDialogLabel(prototype: object): void {\n if (installed.has(prototype)) return;\n installed.add(prototype);\n const target = prototype as NamedDialog;\n const update = target.update;\n target.update = function (this: NamedDialog, changed: unknown): void {\n update.call(this, changed);\n if (!this.parentElement?.classList.contains('kui-dialog-surface')) return;\n if (!observed.has(this)) {\n observed.add(this);\n new MutationObserver(() => syncDialogLabel(this)).observe(this, {\n attributes: true,\n attributeFilter: ['aria-label', 'role'],\n });\n }\n syncDialogLabel(this);\n };\n}\n\nfunction syncDialogLabel(host: NamedDialog): void {\n if (!host.parentElement?.classList.contains('kui-dialog-surface')) return;\n const panel = host.dialog;\n if (!panel) return;\n const previous = ownedNames.get(panel);\n // A host that is itself the named dialog (an explicit role=\"dialog\" plus\n // its own name) owns that name; naming the panel too would expose two\n // dialogs with one name.\n if (/^(alert)?dialog$/.test(host.getAttribute('role')?.trim() ?? '')) {\n if (previous && panel.getAttribute(previous.attribute) === previous.value)\n panel.removeAttribute(previous.attribute);\n ownedNames.delete(panel);\n return;\n }\n const externalName = ['aria-label', 'aria-labelledby'].some((attribute) => {\n const value = panel.getAttribute(attribute);\n return (\n value !== null &&\n !(previous?.attribute === attribute && previous.value === value)\n );\n });\n if (externalName) {\n if (previous && panel.getAttribute(previous.attribute) === previous.value)\n panel.removeAttribute(previous.attribute);\n ownedNames.delete(panel);\n return;\n }\n const explicit = host.getAttribute('aria-label')?.trim();\n const title = host.shadowRoot?.getElementById('title');\n const attribute =\n !explicit && !host.withoutHeader && title\n ? 'aria-labelledby'\n : 'aria-label';\n const value =\n attribute === 'aria-labelledby' ? 'title' : explicit || host.label;\n if (previous && previous.attribute !== attribute)\n panel.removeAttribute(previous.attribute);\n if (panel.getAttribute(attribute) !== value)\n panel.setAttribute(attribute, value);\n ownedNames.set(panel, { attribute, value });\n}\n","interface ChromeDialog extends HTMLElement {\n dialog?: HTMLDialogElement;\n update(changed: unknown): void;\n}\n\n/**\n * The panel variable a floating header's divider reads: set while content\n * is scrolled away beneath the header, unset (no divider) otherwise.\n */\nexport const HEADER_DIVIDER_PROPERTY = '--_kui-dialog-surface-header-divider';\n\n/** The value published while the divider shows: the color the CSS owns. */\nconst SHOWN = 'var(--_kui-dialog-surface-header-divider-color)';\n\n/**\n * Scroll distance, in px, that counts as \"away from the top\": a scroller at\n * rest can report a fractional offset.\n */\nconst THRESHOLD = 1;\n\nconst installed = new WeakSet<object>();\nconst wiredPanels = new WeakSet<Element>();\n\n/**\n * Draw a floating DialogSurface header's divider while content is scrolled\n * beneath it, the way a Pane's overlay header does. Capture-phase `scroll`\n * listeners on the shadow panel and the host see both the body part (flowing\n * content) and a slotted filling child that reaches beneath the header (a\n * transcript `List` or `Pane` with block-start `scrollClearance`); a nested\n * scroller that starts below the header never counts. The state is published\n * on the panel, where Kerf rerenders never reach.\n */\nexport function installHeaderScrollDivider(prototype: object): void {\n if (installed.has(prototype)) return;\n installed.add(prototype);\n const target = prototype as ChromeDialog;\n const update = target.update;\n target.update = function (this: ChromeDialog, changed: unknown): void {\n update.call(this, changed);\n if (!this.parentElement?.classList.contains('kui-dialog-surface')) return;\n const panel = this.dialog;\n if (panel && !wiredPanels.has(panel)) wire(this, panel);\n };\n}\n\nfunction wire(host: ChromeDialog, panel: HTMLElement): void {\n wiredPanels.add(panel);\n const scrolled = new Set<Element>();\n const onScroll = (event: Event): void => {\n const scroller = event.target;\n if (!(scroller instanceof Element)) return;\n const header = host.shadowRoot?.querySelector('[part~=\"header\"]');\n const floating =\n host.parentElement?.getAttribute('data-header-presentation') ===\n 'floating';\n if (\n floating &&\n header &&\n scroller.scrollTop > THRESHOLD &&\n // Only a scroller that reaches beneath the header.\n scroller.getBoundingClientRect().top <=\n header.getBoundingClientRect().bottom\n )\n scrolled.add(scroller);\n else scrolled.delete(scroller);\n for (const element of scrolled)\n if (!element.isConnected) scrolled.delete(element);\n const value = scrolled.size > 0 ? SHOWN : '';\n if (panel.style.getPropertyValue(HEADER_DIVIDER_PROPERTY) === value) return;\n if (value) panel.style.setProperty(HEADER_DIVIDER_PROPERTY, value);\n else panel.style.removeProperty(HEADER_DIVIDER_PROPERTY);\n };\n // `scroll` does not bubble or leave a shadow root: the panel's capture\n // listener sees the body part, the host's sees slotted scrollers.\n for (const root of [panel, host])\n root.addEventListener('scroll', onScroll, { capture: true, passive: true });\n}\n","import WaDialog from '@awesome.me/webawesome/dist/components/dialog/dialog.js';\n\nimport { installChromeBlockSize } from '../internal/install-chrome-block-size.js';\nimport { installDialogLabel } from '../internal/install-dialog-label.js';\nimport { installHeaderScrollDivider } from '../internal/install-header-scroll-divider.js';\n\ninstallDialogLabel(WaDialog.prototype);\ninstallChromeBlockSize(WaDialog.prototype);\ninstallHeaderScrollDivider(WaDialog.prototype);\n\n/**\n * Importing this module registers wa-dialog, repairs wrapped native names, and\n * measures each DialogSurface header and footer for a floating header's or\n * footer's body clearance, and shows a floating header's divider while\n * content is scrolled beneath it.\n */\nexport const surfaceScaffoldElementsRegistered = true;\n"]}
1
+ {"version":3,"sources":["../src/components/surfaces/surface-scaffold/internal/install-bottom-sheet.ts","../src/components/surfaces/surface-scaffold/internal/install-chrome-block-size.ts","../src/components/surfaces/surface-scaffold/internal/install-dialog-label.ts","../src/components/surfaces/surface-scaffold/internal/install-header-scroll-divider.ts","../src/components/surfaces/surface-scaffold/register/surface-scaffold-register.ts"],"names":["installed","attribute","value"],"mappings":"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","file":"surface-scaffold-register.js","sourcesContent":["import {\n createSheetHandle,\n syncSheetHandleValues,\n wireSheetHandle,\n} from './sheet-handle.js';\n\ninterface SheetDialog extends HTMLElement {\n dialog?: HTMLDialogElement;\n open?: boolean;\n update(changed: unknown): void;\n show(): Promise<void>;\n requestClose(source: Element): Promise<void>;\n}\n\n/** The shadow part of a resizable bottom sheet's grabber. */\nexport const SHEET_HANDLE_PART = 'sheet-handle';\n\n/** The panel variable holding a resized sheet's visible height. */\nexport const SHEET_HEIGHT_PROPERTY = '--_kui-dialog-surface-sheet-height';\n\n/** The panel variable holding the virtual keyboard's overlap. */\nexport const KEYBOARD_INSET_PROPERTY = '--_kui-dialog-surface-keyboard-inset';\n\n/**\n * The host attribute marking the show (`enter`) or hide (`exit`) animation\n * while it runs, so the CSS can swap only those keyframes (never the pulse).\n */\nexport const SHEET_MOTION_ATTRIBUTE = 'data-kui-sheet-motion';\n\nconst installed = new WeakSet<object>();\nconst viewportCleanups = new WeakMap<SheetDialog, () => void>();\n\nconst surfaceOf = (host: SheetDialog): HTMLElement | null =>\n host.parentElement?.classList.contains('kui-dialog-surface')\n ? host.parentElement\n : null;\n\nconst isBottomSheet = (host: SheetDialog): boolean =>\n surfaceOf(host)?.getAttribute('data-presentation') === 'bottom-sheet';\n\nconst isResizable = (host: SheetDialog): boolean =>\n isBottomSheet(host) && surfaceOf(host)!.hasAttribute('data-resizable');\n\n/**\n * Wire DialogSurface's `presentation=\"bottom-sheet\"`: inject the resize\n * grabber into the shadow panel (a `role=\"separator\"` the CSS shows only for\n * a resizable sheet), follow the virtual keyboard through `visualViewport`\n * while the dialog is open, and mark the show and hide animations so the\n * sheet can slide instead of scaling. Every state lives on the shadow panel\n * or the host, where Kerf rerenders never reach.\n */\nexport function installBottomSheet(prototype: object): void {\n if (installed.has(prototype)) return;\n installed.add(prototype);\n const target = prototype as SheetDialog;\n const { update, show, requestClose } = target;\n target.update = function (this: SheetDialog, changed: unknown): void {\n update.call(this, changed);\n if (!surfaceOf(this)) return;\n const panel = this.dialog;\n if (!panel) return;\n syncHandle(this, panel);\n if (this.open) followViewport(this, panel);\n else unfollowViewport(this);\n };\n target.show = function (this: SheetDialog): Promise<void> {\n // Each opening starts at the configured (or content) height.\n const panel = this.dialog;\n if (panel && surfaceOf(this)) {\n panel.style.removeProperty(SHEET_HEIGHT_PROPERTY);\n syncHandle(this, panel);\n }\n const result = show.call(this);\n markMotion(this, 'show', 'enter', result);\n // The host only displays once Lit reflects `open`: report the values\n // when the opening settles.\n void result.then(() => {\n const handle = panel?.querySelector(\n `:scope > [part~=\"${SHEET_HANDLE_PART}\"]`,\n );\n if (panel && handle && isResizable(this))\n syncSheetHandleValues(handle, panel);\n });\n return result;\n };\n target.requestClose = function (\n this: SheetDialog,\n source: Element,\n ): Promise<void> {\n const result = requestClose.call(this, source);\n markMotion(this, 'hide', 'exit', result);\n return result;\n };\n}\n\n/**\n * Web Awesome adds its animation class synchronously before its first await,\n * so the class tells a real show or hide from a prevented (pulsing) close.\n */\nfunction markMotion(\n host: SheetDialog,\n className: string,\n value: string,\n result: Promise<void>,\n): void {\n if (!surfaceOf(host) || !host.dialog?.classList.contains(className)) return;\n host.setAttribute(SHEET_MOTION_ATTRIBUTE, value);\n const clear = (): void => {\n if (host.getAttribute(SHEET_MOTION_ATTRIBUTE) === value)\n host.removeAttribute(SHEET_MOTION_ATTRIBUTE);\n };\n void result.then(clear, clear);\n}\n\n/** Show the grabber on a resizable bottom sheet only, creating it on first need. */\nfunction syncHandle(host: SheetDialog, panel: HTMLElement): void {\n const existing = panel.querySelector<HTMLElement>(\n `:scope > [part~=\"${SHEET_HANDLE_PART}\"]`,\n );\n const resizable = isResizable(host);\n if (existing) existing.hidden = !resizable;\n else if (resizable) createHandle(host, panel);\n}\n\nfunction createHandle(host: SheetDialog, panel: HTMLElement): void {\n const handle = createSheetHandle({ part: SHEET_HANDLE_PART });\n // Before Lit's first marker, outside every part Lit owns.\n panel.prepend(handle);\n wireSheetHandle(handle, {\n panel,\n host: panel,\n property: SHEET_HEIGHT_PROPERTY,\n enabled: () => isResizable(host),\n });\n}\n\n/**\n * The layout viewport's bottom band a virtual keyboard covers: what the\n * visual viewport no longer shows below itself. Zero while pinch-zoomed (the\n * visual viewport then shrinks for another reason) and wherever the keyboard\n * resizes the layout viewport instead (`interactive-widget=resizes-content`).\n */\nexport function keyboardInset(\n viewport: Pick<VisualViewport, 'height' | 'offsetTop' | 'scale'>,\n layoutHeight: number,\n): number {\n if (viewport.scale > 1.01) return 0;\n const inset = Math.round(layoutHeight - viewport.height - viewport.offsetTop);\n return inset > 0 ? inset : 0;\n}\n\nfunction followViewport(host: SheetDialog, panel: HTMLElement): void {\n const viewport = globalThis.visualViewport;\n if (!viewport || viewportCleanups.has(host)) return;\n const publish = (): void => {\n const inset =\n host.isConnected && host.open && isBottomSheet(host)\n ? keyboardInset(viewport, globalThis.innerHeight)\n : 0;\n if (inset > 0)\n panel.style.setProperty(KEYBOARD_INSET_PROPERTY, `${inset}px`);\n else panel.style.removeProperty(KEYBOARD_INSET_PROPERTY);\n if (!host.isConnected) unfollowViewport(host);\n };\n viewport.addEventListener('resize', publish);\n viewport.addEventListener('scroll', publish);\n viewportCleanups.set(host, () => {\n viewport.removeEventListener('resize', publish);\n viewport.removeEventListener('scroll', publish);\n panel.style.removeProperty(KEYBOARD_INSET_PROPERTY);\n });\n publish();\n}\n\nfunction unfollowViewport(host: SheetDialog): void {\n viewportCleanups.get(host)?.();\n viewportCleanups.delete(host);\n}\n","interface ChromeDialog extends HTMLElement {\n dialog?: HTMLDialogElement;\n update(changed: unknown): void;\n}\n\n/** The panel variable a floating header's body clearance reads. */\nexport const HEADER_BLOCK_SIZE_PROPERTY =\n '--_kui-dialog-surface-header-block-size';\n\n/** The panel variable a floating footer's body clearance reads. */\nexport const FOOTER_BLOCK_SIZE_PROPERTY =\n '--_kui-dialog-surface-footer-block-size';\n\n/** Each measured dialog part, with the panel variable it publishes. */\nconst CHROME_PARTS = [\n ['header', HEADER_BLOCK_SIZE_PROPERTY],\n ['footer', FOOTER_BLOCK_SIZE_PROPERTY],\n] as const;\n\nconst installed = new WeakSet<object>();\nconst observedParts = new WeakSet<Element>();\n\n/**\n * Publish a DialogSurface's header and footer block sizes on its shadow\n * panel, where Kerf rerenders never reach, so a floating header's or footer's\n * body clearance follows that chrome as its content grows, wraps, or hides.\n */\nexport function installChromeBlockSize(prototype: object): void {\n if (installed.has(prototype)) return;\n installed.add(prototype);\n const target = prototype as ChromeDialog;\n const update = target.update;\n target.update = function (this: ChromeDialog, changed: unknown): void {\n update.call(this, changed);\n if (!this.parentElement?.classList.contains('kui-dialog-surface')) return;\n const panel = this.dialog;\n if (!panel) return;\n for (const [part, property] of CHROME_PARTS) {\n const element = this.shadowRoot?.querySelector(`[part~=\"${part}\"]`);\n // Web Awesome drops the header part under `without-header`; with no\n // part to clear, the floating clearance falls back to zero.\n if (element) observePart(panel, element, property);\n else panel.style.removeProperty(property);\n }\n };\n}\n\nfunction observePart(\n panel: HTMLElement,\n element: Element,\n property: string,\n): void {\n if (observedParts.has(element)) return;\n observedParts.add(element);\n const publish = (blockSize: number): void => {\n const value = `${blockSize}px`;\n if (panel.style.getPropertyValue(property) !== value)\n panel.style.setProperty(property, value);\n };\n publish(element.getBoundingClientRect().height);\n if (typeof ResizeObserver === 'undefined') return;\n new ResizeObserver((entries) => {\n // A part Web Awesome has since removed no longer owns the variable.\n if (!element.isConnected) return;\n const box = entries[entries.length - 1]?.borderBoxSize?.[0];\n publish(box ? box.blockSize : element.getBoundingClientRect().height);\n }).observe(element);\n}\n","interface NamedDialog extends HTMLElement {\n dialog?: HTMLDialogElement;\n label: string;\n withoutHeader: boolean;\n update(changed: unknown): void;\n}\n\nconst installed = new WeakSet<object>();\nconst observed = new WeakSet<HTMLElement>();\nconst ownedNames = new WeakMap<\n HTMLElement,\n { attribute: string; value: string }\n>();\n\n/** Repair Web Awesome's missing native dialog name before its first modal open. */\nexport function installDialogLabel(prototype: object): void {\n if (installed.has(prototype)) return;\n installed.add(prototype);\n const target = prototype as NamedDialog;\n const update = target.update;\n target.update = function (this: NamedDialog, changed: unknown): void {\n update.call(this, changed);\n if (!this.parentElement?.classList.contains('kui-dialog-surface')) return;\n if (!observed.has(this)) {\n observed.add(this);\n new MutationObserver(() => syncDialogLabel(this)).observe(this, {\n attributes: true,\n attributeFilter: ['aria-label', 'role'],\n });\n }\n syncDialogLabel(this);\n };\n}\n\nfunction syncDialogLabel(host: NamedDialog): void {\n if (!host.parentElement?.classList.contains('kui-dialog-surface')) return;\n const panel = host.dialog;\n if (!panel) return;\n const previous = ownedNames.get(panel);\n // A host that is itself the named dialog (an explicit role=\"dialog\" plus\n // its own name) owns that name; naming the panel too would expose two\n // dialogs with one name.\n if (/^(alert)?dialog$/.test(host.getAttribute('role')?.trim() ?? '')) {\n if (previous && panel.getAttribute(previous.attribute) === previous.value)\n panel.removeAttribute(previous.attribute);\n ownedNames.delete(panel);\n return;\n }\n const externalName = ['aria-label', 'aria-labelledby'].some((attribute) => {\n const value = panel.getAttribute(attribute);\n return (\n value !== null &&\n !(previous?.attribute === attribute && previous.value === value)\n );\n });\n if (externalName) {\n if (previous && panel.getAttribute(previous.attribute) === previous.value)\n panel.removeAttribute(previous.attribute);\n ownedNames.delete(panel);\n return;\n }\n const explicit = host.getAttribute('aria-label')?.trim();\n const title = host.shadowRoot?.getElementById('title');\n const attribute =\n !explicit && !host.withoutHeader && title\n ? 'aria-labelledby'\n : 'aria-label';\n const value =\n attribute === 'aria-labelledby' ? 'title' : explicit || host.label;\n if (previous && previous.attribute !== attribute)\n panel.removeAttribute(previous.attribute);\n if (panel.getAttribute(attribute) !== value)\n panel.setAttribute(attribute, value);\n ownedNames.set(panel, { attribute, value });\n}\n","interface ChromeDialog extends HTMLElement {\n dialog?: HTMLDialogElement;\n update(changed: unknown): void;\n}\n\n/**\n * The panel variable a floating header's divider reads: set while content\n * is scrolled away beneath the header, unset (no divider) otherwise.\n */\nexport const HEADER_DIVIDER_PROPERTY = '--_kui-dialog-surface-header-divider';\n\n/** The value published while the divider shows: the color the CSS owns. */\nconst SHOWN = 'var(--_kui-dialog-surface-header-divider-color)';\n\n/**\n * Scroll distance, in px, that counts as \"away from the top\": a scroller at\n * rest can report a fractional offset.\n */\nconst THRESHOLD = 1;\n\nconst installed = new WeakSet<object>();\nconst wiredPanels = new WeakSet<Element>();\n\n/**\n * Draw a floating DialogSurface header's divider while content is scrolled\n * beneath it, the way a Pane's overlay header does. Capture-phase `scroll`\n * listeners on the shadow panel and the host see both the body part (flowing\n * content) and a slotted filling child that reaches beneath the header (a\n * transcript `List` or `Pane` with block-start `scrollClearance`); a nested\n * scroller that starts below the header never counts. The state is published\n * on the panel, where Kerf rerenders never reach.\n */\nexport function installHeaderScrollDivider(prototype: object): void {\n if (installed.has(prototype)) return;\n installed.add(prototype);\n const target = prototype as ChromeDialog;\n const update = target.update;\n target.update = function (this: ChromeDialog, changed: unknown): void {\n update.call(this, changed);\n if (!this.parentElement?.classList.contains('kui-dialog-surface')) return;\n const panel = this.dialog;\n if (panel && !wiredPanels.has(panel)) wire(this, panel);\n };\n}\n\nfunction wire(host: ChromeDialog, panel: HTMLElement): void {\n wiredPanels.add(panel);\n const scrolled = new Set<Element>();\n const onScroll = (event: Event): void => {\n const scroller = event.target;\n if (!(scroller instanceof Element)) return;\n const header = host.shadowRoot?.querySelector('[part~=\"header\"]');\n const floating =\n host.parentElement?.getAttribute('data-header-presentation') ===\n 'floating';\n if (\n floating &&\n header &&\n scroller.scrollTop > THRESHOLD &&\n // Only a scroller that reaches beneath the header.\n scroller.getBoundingClientRect().top <=\n header.getBoundingClientRect().bottom\n )\n scrolled.add(scroller);\n else scrolled.delete(scroller);\n for (const element of scrolled)\n if (!element.isConnected) scrolled.delete(element);\n const value = scrolled.size > 0 ? SHOWN : '';\n if (panel.style.getPropertyValue(HEADER_DIVIDER_PROPERTY) === value) return;\n if (value) panel.style.setProperty(HEADER_DIVIDER_PROPERTY, value);\n else panel.style.removeProperty(HEADER_DIVIDER_PROPERTY);\n };\n // `scroll` does not bubble or leave a shadow root: the panel's capture\n // listener sees the body part, the host's sees slotted scrollers.\n for (const root of [panel, host])\n root.addEventListener('scroll', onScroll, { capture: true, passive: true });\n}\n","import WaDialog from '@awesome.me/webawesome/dist/components/dialog/dialog.js';\n\nimport { installBottomSheet } from '../internal/install-bottom-sheet.js';\nimport { installChromeBlockSize } from '../internal/install-chrome-block-size.js';\nimport { installDialogLabel } from '../internal/install-dialog-label.js';\nimport { installHeaderScrollDivider } from '../internal/install-header-scroll-divider.js';\n\ninstallDialogLabel(WaDialog.prototype);\ninstallChromeBlockSize(WaDialog.prototype);\ninstallHeaderScrollDivider(WaDialog.prototype);\ninstallBottomSheet(WaDialog.prototype);\n\n/**\n * Importing this module registers wa-dialog, repairs wrapped native names, and\n * measures each DialogSurface header and footer for a floating header's or\n * footer's body clearance, shows a floating header's divider while content\n * is scrolled beneath it, and wires a bottom sheet's resize grabber,\n * virtual-keyboard clearance, and slide motion.\n */\nexport const surfaceScaffoldElementsRegistered = true;\n"]}
@@ -3,7 +3,19 @@ import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
3
3
  import { CssLength } from './css-values.js';
4
4
 
5
5
  type DialogSurfaceSize = 'small' | 'medium' | 'large';
6
- type DialogSurfacePresentation = 'modal' | 'side-sheet' | 'fullscreen';
6
+ /**
7
+ * How the dialog is presented: `modal` (default) centered on the screen,
8
+ * `side-sheet` against the inline end, `fullscreen`, or `bottom-sheet`
9
+ * attached to the bottom edge (square bottom corners, safe-area and
10
+ * virtual-keyboard clearance, optionally user-resizable).
11
+ */
12
+ type DialogSurfacePresentation = 'modal' | 'side-sheet' | 'fullscreen' | 'bottom-sheet';
13
+ /**
14
+ * How a bottom sheet appears or leaves: `slide` (default) moves the panel in
15
+ * from, or out to, the bottom edge; `standard` keeps Web Awesome's
16
+ * scale-and-fade. Both honor `prefers-reduced-motion`.
17
+ */
18
+ type DialogSurfaceSheetMotion = 'slide' | 'standard';
7
19
  type SurfaceInset = 'none' | 'compact' | 'comfortable';
8
20
  type DialogSurfaceMaxHeight = CssLength | 'viewport';
9
21
  /** A definite modal height: a length or the full viewport, minus both gutters. */
@@ -44,13 +56,34 @@ interface DialogSurfaceProps {
44
56
  footerInset?: SurfaceInset;
45
57
  /** Modal edge clearance. Omit to retain Web Awesome's default viewport cap. */
46
58
  viewportGutter?: CssLength;
47
- /** Modal height cap, bounded by the dynamic viewport minus both gutters. */
59
+ /**
60
+ * Modal height cap, bounded by the dynamic viewport minus both gutters. On a
61
+ * bottom sheet, the cap (and the resize ceiling), bounded by the dynamic
62
+ * viewport minus the top safe area and one gutter.
63
+ */
48
64
  maxHeight?: DialogSurfaceMaxHeight;
49
65
  /**
50
66
  * Modal definite height, bounded the same way, so a filling child has a
51
- * height to fill. Takes precedence over `maxHeight`.
67
+ * height to fill. Takes precedence over `maxHeight`. On a bottom sheet, the
68
+ * height it opens at (the visible height above the safe area or keyboard).
52
69
  */
53
70
  height?: DialogSurfaceHeight;
71
+ /**
72
+ * A resizable bottom sheet's resize floor (default 160px), the visible
73
+ * height above the safe area or keyboard.
74
+ */
75
+ minHeight?: CssLength;
76
+ /**
77
+ * Let the person resize a bottom sheet by its top grabber (drag, or the
78
+ * arrow, Page Up/Down, Home and End keys) between `minHeight` and the
79
+ * sheet's cap. Needs the `/register` entry; each opening starts at `height`
80
+ * (or the content height). Ignored by other presentations.
81
+ */
82
+ resizable?: boolean;
83
+ /** How a bottom sheet appears (default `slide` up from the bottom edge). */
84
+ enterMotion?: DialogSurfaceSheetMotion;
85
+ /** How a bottom sheet is dismissed (default `slide` down off the bottom edge). */
86
+ exitMotion?: DialogSurfaceSheetMotion;
54
87
  /**
55
88
  * Body layout (default `flow`); `fill` lets one child own the body and
56
89
  * `fill-last` stacks fixed rows above one filling last child.
@@ -100,7 +133,7 @@ interface DialogSurfaceProps {
100
133
  slot?: string;
101
134
  }
102
135
  /** Configure recurring Web Awesome dialog geometry without consumer ::part() CSS. */
103
- declare function DialogSurface({ children, size, presentation, preferredWidth, bodyInset, footerInset, viewportGutter, maxHeight, height, bodyLayout, headerPresentation, footerPresentation, footerOffset, rootAttributes, className, slot, }: DialogSurfaceProps): kerfjs.SafeHtml;
136
+ declare function DialogSurface({ children, size, presentation, preferredWidth, bodyInset, footerInset, viewportGutter, maxHeight, height, minHeight, resizable, enterMotion, exitMotion, bodyLayout, headerPresentation, footerPresentation, footerOffset, rootAttributes, className, slot, }: DialogSurfaceProps): kerfjs.SafeHtml;
104
137
  /** Where a PopoverDialogSurface appears: the top layer, or in flow. */
105
138
  type PopoverDialogSurfacePresentation = 'overlay' | 'embedded';
106
139
  /** Application `data-*` metadata on the surface root. */
@@ -167,4 +200,4 @@ interface PopupSurfaceProps {
167
200
  /** Configure recurring Web Awesome dropdown-menu geometry without consumer ::part() CSS. */
168
201
  declare function PopupSurface({ children, inset, className, slot, }: PopupSurfaceProps): kerfjs.SafeHtml;
169
202
 
170
- export { DialogSurface, type DialogSurfaceBodyLayout, type DialogSurfaceFooterPresentation, type DialogSurfaceHeaderPresentation, type DialogSurfaceHeight, type DialogSurfaceMaxHeight, type DialogSurfacePresentation, type DialogSurfaceProps, type DialogSurfaceRootAttributes, type DialogSurfaceSize, PopoverDialogSurface, type PopoverDialogSurfaceDataAttributes, type PopoverDialogSurfacePresentation, type PopoverDialogSurfaceProps, PopupSurface, type PopupSurfaceInset, type PopupSurfaceProps, type SurfaceInset };
203
+ export { DialogSurface, type DialogSurfaceBodyLayout, type DialogSurfaceFooterPresentation, type DialogSurfaceHeaderPresentation, type DialogSurfaceHeight, type DialogSurfaceMaxHeight, type DialogSurfacePresentation, type DialogSurfaceProps, type DialogSurfaceRootAttributes, type DialogSurfaceSheetMotion, type DialogSurfaceSize, PopoverDialogSurface, type PopoverDialogSurfaceDataAttributes, type PopoverDialogSurfacePresentation, type PopoverDialogSurfaceProps, PopupSurface, type PopupSurfaceInset, type PopupSurfaceProps, type SurfaceInset };
@@ -1,4 +1,4 @@
1
- export { DialogSurface, PopoverDialogSurface, PopupSurface } from './chunk-PIVY32AE.js';
1
+ export { DialogSurface, PopoverDialogSurface, PopupSurface } from './chunk-BYFTHA4I.js';
2
2
 
3
3
 
4
4
  //# sourceMappingURL=surface-scaffold.js.map
@@ -1,6 +1,7 @@
1
1
  import { SafeHtml } from 'kerfjs';
2
2
  import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
3
- import { PaneAppearance } from './pane.js';
3
+ import { PaneAppearance, SurfaceTint, ScrollEdge } from './pane.js';
4
+ import { CssColor } from './css-values.js';
4
5
  import './scroll-clearance-BikHljTc.js';
5
6
 
6
7
  interface TabNavigatorTabBase<Id extends string> {
@@ -12,6 +13,17 @@ interface TabNavigatorTabBase<Id extends string> {
12
13
  content: KerfUiContent;
13
14
  /** Background of this scene's scrolling work surface. */
14
15
  appearance?: PaneAppearance;
16
+ /**
17
+ * Paint this scene in an app-chosen color (a `@kerfjs/ui/css-values` color
18
+ * builder). It replaces the appearance's fill. Forced colors paint `Canvas`.
19
+ */
20
+ background?: CssColor;
21
+ /**
22
+ * A scoped tint (`{ color, scheme }`) for this scene: its surfaces and every
23
+ * descendant re-derive their surface and text tokens from the app's color
24
+ * in the declared scheme, with lightness clamped to keep text at WCAG AA.
25
+ */
26
+ tint?: SurfaceTint;
15
27
  /** Add 8px to every side of a plain scene's scrolling content. */
16
28
  deepInset?: boolean;
17
29
  /** Opt into keyboard (`0`) or programmatic (`-1`) focus on this scene. */
@@ -57,8 +69,13 @@ type TabNavigatorTab<Id extends string = string> = TabNavigatorTabBase<Id> & (Ta
57
69
  * How a {@link TabNavigator}'s tab bar relates to the active scene: `docked`
58
70
  * below it, or `overlay` laid over its bottom edge on the translucent chrome
59
71
  * material, so the scene's content scrolls visibly beneath the bar.
72
+ * `clear` lays it over
73
+ * the same edge fully transparent, for chrome over imagery: legibility comes
74
+ * from glass control groups or a scrim, and with `scrollEdge="material"` the
75
+ * chrome material fades in once content scrolls beneath
76
+ * it, until the scene scrolls to its end.
60
77
  */
61
- type TabNavigatorBarPresentation = 'docked' | 'overlay';
78
+ type TabNavigatorBarPresentation = 'docked' | 'overlay' | 'clear';
62
79
  interface TabNavigatorProps<Id extends string = string> {
63
80
  id: string;
64
81
  /** Accessible name for the tab bar. */
@@ -97,6 +114,29 @@ interface TabNavigatorProps<Id extends string = string> {
97
114
  * toward the normal text color to keep AA over the content beneath.
98
115
  */
99
116
  barPresentation?: TabNavigatorBarPresentation;
117
+ /**
118
+ * With `barPresentation="clear"`, `material` fades the chrome material in
119
+ * behind the bar while the active scene continues beneath it (default
120
+ * `none`).
121
+ */
122
+ scrollEdge?: ScrollEdge;
123
+ /**
124
+ * The scroll distance, in CSS pixels, over which the scroll edge fades in
125
+ * (default 60).
126
+ */
127
+ scrollEdgeDistance?: number;
128
+ /**
129
+ * Paint the navigator, and its docked tab bar, in an app-chosen color (a
130
+ * `@kerfjs/ui/css-values` color builder) instead of the surface. A tab's own
131
+ * `background` paints its scene. Forced colors paint `Canvas`.
132
+ */
133
+ background?: CssColor;
134
+ /**
135
+ * A scoped tint (`{ color, scheme }`) for the navigator, its bar, and every scene: its surfaces and every
136
+ * descendant re-derive their surface and text tokens from the app's color
137
+ * in the declared scheme, with lightness clamped to keep text at WCAG AA.
138
+ */
139
+ tint?: SurfaceTint;
100
140
  className?: string;
101
141
  /** Native named-slot assignment when composed inside a web component. */
102
142
  slot?: string;
@@ -109,6 +149,6 @@ interface TabNavigatorProps<Id extends string = string> {
109
149
  * On larger classes, promote the tabs to a `Workbench` rail or sidebar instead of
110
150
  * a bottom bar. See `docs/23-app-layouts.md` §3.4.
111
151
  */
112
- declare function TabNavigator<Id extends string>({ id, label, tabs, active, separator, chromeDividers, barPresentation, className, slot, }: TabNavigatorProps<Id>): SafeHtml;
152
+ declare function TabNavigator<Id extends string>({ id, label, tabs, active, separator, chromeDividers, barPresentation, scrollEdge, scrollEdgeDistance, background, tint, className, slot, }: TabNavigatorProps<Id>): SafeHtml;
113
153
 
114
154
  export { TabNavigator, type TabNavigatorBarPresentation, type TabNavigatorProps, type TabNavigatorTab };
@@ -1,5 +1,6 @@
1
- import { Badge } from './chunk-U6QYTMDB.js';
1
+ import { surfaceTintAttributes, joinStyles, scrollEdgeAttributes } from './chunk-SQ5DH66U.js';
2
2
  import { ensureSunkenTexture } from './chunk-IKS72C6P.js';
3
+ import { Badge } from './chunk-U6QYTMDB.js';
3
4
 
4
5
  import { jsxs, jsx } from 'kerfjs/jsx-runtime';
5
6
 
@@ -11,29 +12,57 @@ function TabNavigator({
11
12
  separator = "auto",
12
13
  chromeDividers = "scroll",
13
14
  barPresentation = "docked",
15
+ scrollEdge = "none",
16
+ scrollEdgeDistance,
17
+ background,
18
+ tint,
14
19
  className = "",
15
20
  slot
16
21
  }) {
17
- if (tabs.some((tab) => tab.appearance === "sunken")) ensureSunkenTexture();
22
+ const tinted = surfaceTintAttributes(tint);
23
+ if (tabs.some(
24
+ (tab) => tab.appearance === "sunken" && tab.background === void 0
25
+ ))
26
+ ensureSunkenTexture();
18
27
  return /* @__PURE__ */ jsxs(
19
28
  "section",
20
29
  {
21
- class: `kui-tab-scaffold ${className}`.trim(),
30
+ class: `kui-tab-scaffold ${tinted.className} ${className}`.replace(/\s+/g, " ").trim(),
22
31
  id,
23
32
  "data-component": "tab-scaffold",
24
33
  "data-tab-scaffold-id": id,
25
34
  "data-separator": separator,
26
35
  "data-chrome-dividers": chromeDividers === "always" || chromeDividers === "none" ? chromeDividers : void 0,
27
- "data-bar-presentation": barPresentation === "overlay" ? "overlay" : void 0,
36
+ "data-bar-presentation": barPresentation !== "docked" ? "overlay" : void 0,
37
+ "data-bar-material": barPresentation === "clear" ? "clear" : void 0,
38
+ ...scrollEdgeAttributes(
39
+ scrollEdge,
40
+ scrollEdgeDistance,
41
+ barPresentation === "clear"
42
+ ),
43
+ "data-background": background === void 0 ? void 0 : "",
44
+ "data-kui-tint": tinted["data-kui-tint"],
45
+ "data-kui-tint-accent": tinted["data-kui-tint-accent"],
46
+ style: joinStyles(
47
+ background === void 0 ? void 0 : `--_kui-tab-scaffold-background:${background}`,
48
+ tinted.style
49
+ ),
28
50
  slot,
29
51
  children: [
30
52
  /* @__PURE__ */ jsx("div", { class: "kui-tab-scaffold__scenes", children: tabs.map((tab) => /* @__PURE__ */ jsx(
31
53
  "div",
32
54
  {
33
- class: "kui-tab-scaffold__scene",
55
+ class: `kui-tab-scaffold__scene ${surfaceTintAttributes(tab.tint).className}`.trim(),
34
56
  "data-tab-scaffold-scene": tab.id,
35
57
  "data-active": String(tab.id === active),
36
- "data-appearance": tab.appearance === "sunken" ? "sunken" : void 0,
58
+ "data-appearance": tab.appearance === "sunken" && tab.background === void 0 ? "sunken" : void 0,
59
+ "data-background": tab.background === void 0 ? void 0 : "",
60
+ "data-kui-tint": surfaceTintAttributes(tab.tint)["data-kui-tint"],
61
+ "data-kui-tint-accent": surfaceTintAttributes(tab.tint)["data-kui-tint-accent"],
62
+ style: joinStyles(
63
+ tab.background === void 0 ? void 0 : `--_kui-tab-scaffold-scene-background:${tab.background}`,
64
+ surfaceTintAttributes(tab.tint).style
65
+ ),
37
66
  "data-deep-inset": tab.deepInset ? "true" : void 0,
38
67
  "data-outlined": tab.id === active && tab.outlined ? "true" : void 0,
39
68
  role: tab.tabIndex === void 0 ? void 0 : "tabpanel",
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/navigation/tab-navigator/tab-navigator.tsx"],"names":[],"mappings":"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","file":"tab-navigator.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport type { KerfUiContent } from '../../../shared/content/semantic-content.js';\nimport { ensureSunkenTexture } from '../../../shared/styles/sunken-texture.js';\nimport { Badge } from '../../feedback/badge/badge.js';\nimport type { PaneAppearance } from '../../layout/pane/pane.js';\n\ninterface TabNavigatorTabBase<Id extends string> {\n id: Id;\n label: string;\n /** Decorative icon shown above the label in the bottom bar. */\n icon?: SafeHtml;\n /** The tab's content — typically a `NavStack` so each tab keeps its own stack. */\n content: KerfUiContent;\n /** Background of this scene's scrolling work surface. */\n appearance?: PaneAppearance;\n /** Add 8px to every side of a plain scene's scrolling content. */\n deepInset?: boolean;\n /** Opt into keyboard (`0`) or programmatic (`-1`) focus on this scene. */\n tabIndex?: 0 | -1;\n /** Keep the standard focus outline visible while this scene is active. */\n outlined?: boolean;\n}\n\n/** A tab with an optional count or short-status badge. */\ninterface TabNavigatorTabCountBadge {\n /**\n * Optional count or short status shown as a solid danger `Badge` at the\n * top-trailing corner of the tab icon (the iOS tab-bar badge). Omitted, `''`,\n * or non-finite numbers render no badge. The visual badge is `aria-hidden`;\n * its meaning reaches assistive technology through `badgeLabel`.\n *\n * Pass `true` instead for the text-free dot (new content without a count).\n */\n badge?: string | number;\n /**\n * Localized phrase folded into the tab's accessible name as\n * `\"<label>, <badgeLabel>\"` (for example `\"3 unread\"` → `\"Inbox, 3 unread\"`).\n * Defaults to the badge text itself. Ignored when no badge renders.\n */\n badgeLabel?: string;\n}\n\n/** A tab with the text-free dot badge (new content without a count). */\ninterface TabNavigatorTabDotBadge {\n /**\n * `true` shows a solid danger dot `Badge` at the top-trailing corner of the\n * tab icon — the iOS tab-bar dot for new content without a count.\n */\n badge: true;\n /**\n * Required localized phrase folded into the tab's accessible name as\n * `\"<label>, <badgeLabel>\"` (for example `\"New activity\"` →\n * `\"Feed, New activity\"`). A dot has no text, so this is its only meaning.\n */\n badgeLabel: string;\n}\n\n/** One bottom-bar destination: its label, optional icon and badge, and content. */\nexport type TabNavigatorTab<Id extends string = string> =\n TabNavigatorTabBase<Id> &\n (TabNavigatorTabCountBadge | TabNavigatorTabDotBadge);\n\n/**\n * How a {@link TabNavigator}'s tab bar relates to the active scene: `docked`\n * below it, or `overlay` laid over its bottom edge on the translucent chrome\n * material, so the scene's content scrolls visibly beneath the bar.\n */\nexport type TabNavigatorBarPresentation = 'docked' | 'overlay';\n\nexport interface TabNavigatorProps<Id extends string = string> {\n id: string;\n /** Accessible name for the tab bar. */\n label: string;\n tabs: readonly TabNavigatorTab<Id>[];\n /** The controlled active tab id (the app owns selection). */\n active: NoInfer<Id>;\n /**\n * The bar's top separator. `auto` (default) draws it against a sunken active\n * work surface and otherwise follows `chromeDividers`; `hidden` suppresses\n * the line, including a scroll divider.\n */\n separator?: 'auto' | 'hidden';\n /**\n * The line over the tab bar, where it meets the active scene. `scroll`\n * (default) shows it only while more of the scene's content lies below —\n * never at the scroll end or when the content fits — once\n * `wireScrollDividers` (`@kerfjs/ui/wire-scroll-dividers`) is wired above\n * the scaffold; unwired, it does not show. `always` shows it without the\n * wiring; `none` suppresses that scroll divider. A sunken active work\n * surface still draws the separator unless `separator=\"hidden\"`. The line\n * is the bar's own 1px top border, so no state moves the bar or a tab.\n */\n chromeDividers?: 'scroll' | 'always' | 'none';\n /**\n * `docked` (default) gives the tab bar its own band below the scenes.\n * `overlay` lays it over the active scene's bottom edge on the translucent\n * chrome material (opaque under reduced transparency, increased contrast,\n * or without `backdrop-filter`; `Canvas` in forced colors), so content\n * scrolls visibly beneath it, as under an iOS tab bar. `wireTabNavigator`\n * measures the live bar (bottom safe area included) and the scenes hand\n * its height to their content as the block-end `--kui-edge-inset-*`\n * context, so a plain scene, a sole `Pane`, or a `NavStack` (and its own\n * bottom toolbar, which then sits above the bar) rests its last item clear\n * of it. Until then it stays docked. Unselected tab labels lift halfway\n * toward the normal text color to keep AA over the content beneath.\n */\n barPresentation?: TabNavigatorBarPresentation;\n className?: string;\n /** Native named-slot assignment when composed inside a web component. */\n slot?: string;\n}\n\n/**\n * A mobile-first, iOS-like bottom tab navigator: a bottom tab bar that switches\n * between major sections, each tab keeping its own content (usually a `NavStack`)\n * mounted so its stack and scroll survive a switch. Controlled — the app owns\n * `active`; wire selection with `@kerfjs/ui/wire-tab-navigator`'s `wireTabNavigator`.\n * On larger classes, promote the tabs to a `Workbench` rail or sidebar instead of\n * a bottom bar. See `docs/23-app-layouts.md` §3.4.\n */\nexport function TabNavigator<Id extends string>({\n id,\n label,\n tabs,\n active,\n separator = 'auto',\n chromeDividers = 'scroll',\n barPresentation = 'docked',\n className = '',\n slot,\n}: TabNavigatorProps<Id>) {\n if (tabs.some((tab) => tab.appearance === 'sunken')) ensureSunkenTexture();\n return (\n <section\n class={`kui-tab-scaffold ${className}`.trim()}\n id={id}\n data-component=\"tab-scaffold\"\n data-tab-scaffold-id={id}\n data-separator={separator}\n data-chrome-dividers={\n chromeDividers === 'always' || chromeDividers === 'none'\n ? chromeDividers\n : undefined\n }\n data-bar-presentation={\n barPresentation === 'overlay' ? 'overlay' : undefined\n }\n slot={slot}\n >\n <div class=\"kui-tab-scaffold__scenes\">\n {tabs.map((tab) => (\n <div\n class=\"kui-tab-scaffold__scene\"\n data-tab-scaffold-scene={tab.id}\n data-active={String(tab.id === active)}\n data-appearance={tab.appearance === 'sunken' ? 'sunken' : undefined}\n data-deep-inset={tab.deepInset ? 'true' : undefined}\n data-outlined={\n tab.id === active && tab.outlined ? 'true' : undefined\n }\n role={tab.tabIndex === undefined ? undefined : 'tabpanel'}\n aria-label={tab.tabIndex === undefined ? undefined : tab.label}\n aria-hidden={String(tab.id !== active)}\n tabindex={\n tab.id === active\n ? tab.tabIndex\n : tab.tabIndex === undefined\n ? undefined\n : -1\n }\n >\n {tab.content}\n </div>\n ))}\n </div>\n <nav class=\"kui-tab-scaffold__bar\" role=\"tablist\" aria-label={label}>\n {tabs.map((tab) => {\n const dot = tab.badge === true;\n const badgeText = dot ? undefined : normalizeBadge(tab.badge);\n const hasBadge = dot || badgeText !== undefined;\n const badge = hasBadge && (\n <span\n class=\"kui-tab-scaffold__tab-badge\"\n data-badge-kind={dot ? 'dot' : 'text'}\n >\n {badgeText === undefined ? (\n <Badge tone=\"danger\" size=\"dot\" ariaHidden />\n ) : (\n <Badge\n tone=\"danger\"\n appearance=\"solid\"\n size=\"compact\"\n ariaHidden\n >\n {badgeText}\n </Badge>\n )}\n </span>\n );\n // A dot has no text fallback: without a usable badgeLabel (reachable\n // only from untyped callers) the tab keeps its plain accessible name.\n const badgeLabel = hasBadge\n ? tab.badgeLabel?.trim() || badgeText\n : undefined;\n return (\n <button\n type=\"button\"\n class=\"kui-tab-scaffold__tab\"\n role=\"tab\"\n data-tab-scaffold-tab={tab.id}\n aria-selected={String(tab.id === active)}\n tabindex={tab.id === active ? '0' : '-1'}\n aria-label={\n badgeLabel === undefined\n ? undefined\n : `${tab.label}, ${badgeLabel}`\n }\n data-has-badge={hasBadge ? 'true' : undefined}\n >\n {tab.icon ? (\n <span class=\"kui-tab-scaffold__tab-icon\" aria-hidden=\"true\">\n {tab.icon}\n {badge}\n </span>\n ) : (\n badge\n )}\n <span class=\"kui-tab-scaffold__tab-label\">{tab.label}</span>\n </button>\n );\n })}\n </nav>\n </section>\n );\n}\n\nfunction normalizeBadge(\n badge: string | number | undefined,\n): string | undefined {\n if (typeof badge === 'number')\n return Number.isFinite(badge) ? String(badge) : undefined;\n if (typeof badge === 'string' && badge.trim()) return badge.trim();\n return undefined;\n}\n"]}
1
+ {"version":3,"sources":["../src/components/navigation/tab-navigator/tab-navigator.tsx"],"names":[],"mappings":"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","file":"tab-navigator.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport type { KerfUiContent } from '../../../shared/content/semantic-content.js';\nimport {\n type ScrollEdge,\n scrollEdgeAttributes,\n} from '../../../shared/layout/scroll-edge.js';\nimport type { CssColor } from '../../../shared/styles/css-values.js';\nimport { ensureSunkenTexture } from '../../../shared/styles/sunken-texture.js';\nimport {\n joinStyles,\n type SurfaceTint,\n surfaceTintAttributes,\n} from '../../../shared/styles/surface-tint.js';\nimport { Badge } from '../../feedback/badge/badge.js';\nimport type { PaneAppearance } from '../../layout/pane/pane.js';\n\ninterface TabNavigatorTabBase<Id extends string> {\n id: Id;\n label: string;\n /** Decorative icon shown above the label in the bottom bar. */\n icon?: SafeHtml;\n /** The tab's content — typically a `NavStack` so each tab keeps its own stack. */\n content: KerfUiContent;\n /** Background of this scene's scrolling work surface. */\n appearance?: PaneAppearance;\n /**\n * Paint this scene in an app-chosen color (a `@kerfjs/ui/css-values` color\n * builder). It replaces the appearance's fill. Forced colors paint `Canvas`.\n */\n background?: CssColor;\n /**\n * A scoped tint (`{ color, scheme }`) for this scene: its surfaces and every\n * descendant re-derive their surface and text tokens from the app's color\n * in the declared scheme, with lightness clamped to keep text at WCAG AA.\n */\n tint?: SurfaceTint;\n /** Add 8px to every side of a plain scene's scrolling content. */\n deepInset?: boolean;\n /** Opt into keyboard (`0`) or programmatic (`-1`) focus on this scene. */\n tabIndex?: 0 | -1;\n /** Keep the standard focus outline visible while this scene is active. */\n outlined?: boolean;\n}\n\n/** A tab with an optional count or short-status badge. */\ninterface TabNavigatorTabCountBadge {\n /**\n * Optional count or short status shown as a solid danger `Badge` at the\n * top-trailing corner of the tab icon (the iOS tab-bar badge). Omitted, `''`,\n * or non-finite numbers render no badge. The visual badge is `aria-hidden`;\n * its meaning reaches assistive technology through `badgeLabel`.\n *\n * Pass `true` instead for the text-free dot (new content without a count).\n */\n badge?: string | number;\n /**\n * Localized phrase folded into the tab's accessible name as\n * `\"<label>, <badgeLabel>\"` (for example `\"3 unread\"` → `\"Inbox, 3 unread\"`).\n * Defaults to the badge text itself. Ignored when no badge renders.\n */\n badgeLabel?: string;\n}\n\n/** A tab with the text-free dot badge (new content without a count). */\ninterface TabNavigatorTabDotBadge {\n /**\n * `true` shows a solid danger dot `Badge` at the top-trailing corner of the\n * tab icon — the iOS tab-bar dot for new content without a count.\n */\n badge: true;\n /**\n * Required localized phrase folded into the tab's accessible name as\n * `\"<label>, <badgeLabel>\"` (for example `\"New activity\"` →\n * `\"Feed, New activity\"`). A dot has no text, so this is its only meaning.\n */\n badgeLabel: string;\n}\n\n/** One bottom-bar destination: its label, optional icon and badge, and content. */\nexport type TabNavigatorTab<Id extends string = string> =\n TabNavigatorTabBase<Id> &\n (TabNavigatorTabCountBadge | TabNavigatorTabDotBadge);\n\n/**\n * How a {@link TabNavigator}'s tab bar relates to the active scene: `docked`\n * below it, or `overlay` laid over its bottom edge on the translucent chrome\n * material, so the scene's content scrolls visibly beneath the bar.\n * `clear` lays it over\n * the same edge fully transparent, for chrome over imagery: legibility comes\n * from glass control groups or a scrim, and with `scrollEdge=\"material\"` the\n * chrome material fades in once content scrolls beneath\n * it, until the scene scrolls to its end.\n */\nexport type TabNavigatorBarPresentation = 'docked' | 'overlay' | 'clear';\n\nexport interface TabNavigatorProps<Id extends string = string> {\n id: string;\n /** Accessible name for the tab bar. */\n label: string;\n tabs: readonly TabNavigatorTab<Id>[];\n /** The controlled active tab id (the app owns selection). */\n active: NoInfer<Id>;\n /**\n * The bar's top separator. `auto` (default) draws it against a sunken active\n * work surface and otherwise follows `chromeDividers`; `hidden` suppresses\n * the line, including a scroll divider.\n */\n separator?: 'auto' | 'hidden';\n /**\n * The line over the tab bar, where it meets the active scene. `scroll`\n * (default) shows it only while more of the scene's content lies below —\n * never at the scroll end or when the content fits — once\n * `wireScrollDividers` (`@kerfjs/ui/wire-scroll-dividers`) is wired above\n * the scaffold; unwired, it does not show. `always` shows it without the\n * wiring; `none` suppresses that scroll divider. A sunken active work\n * surface still draws the separator unless `separator=\"hidden\"`. The line\n * is the bar's own 1px top border, so no state moves the bar or a tab.\n */\n chromeDividers?: 'scroll' | 'always' | 'none';\n /**\n * `docked` (default) gives the tab bar its own band below the scenes.\n * `overlay` lays it over the active scene's bottom edge on the translucent\n * chrome material (opaque under reduced transparency, increased contrast,\n * or without `backdrop-filter`; `Canvas` in forced colors), so content\n * scrolls visibly beneath it, as under an iOS tab bar. `wireTabNavigator`\n * measures the live bar (bottom safe area included) and the scenes hand\n * its height to their content as the block-end `--kui-edge-inset-*`\n * context, so a plain scene, a sole `Pane`, or a `NavStack` (and its own\n * bottom toolbar, which then sits above the bar) rests its last item clear\n * of it. Until then it stays docked. Unselected tab labels lift halfway\n * toward the normal text color to keep AA over the content beneath.\n */\n barPresentation?: TabNavigatorBarPresentation;\n /**\n * With `barPresentation=\"clear\"`, `material` fades the chrome material in\n * behind the bar while the active scene continues beneath it (default\n * `none`).\n */\n scrollEdge?: ScrollEdge;\n /**\n * The scroll distance, in CSS pixels, over which the scroll edge fades in\n * (default 60).\n */\n scrollEdgeDistance?: number;\n /**\n * Paint the navigator, and its docked tab bar, in an app-chosen color (a\n * `@kerfjs/ui/css-values` color builder) instead of the surface. A tab's own\n * `background` paints its scene. Forced colors paint `Canvas`.\n */\n background?: CssColor;\n /**\n * A scoped tint (`{ color, scheme }`) for the navigator, its bar, and every scene: its surfaces and every\n * descendant re-derive their surface and text tokens from the app's color\n * in the declared scheme, with lightness clamped to keep text at WCAG AA.\n */\n tint?: SurfaceTint;\n className?: string;\n /** Native named-slot assignment when composed inside a web component. */\n slot?: string;\n}\n\n/**\n * A mobile-first, iOS-like bottom tab navigator: a bottom tab bar that switches\n * between major sections, each tab keeping its own content (usually a `NavStack`)\n * mounted so its stack and scroll survive a switch. Controlled — the app owns\n * `active`; wire selection with `@kerfjs/ui/wire-tab-navigator`'s `wireTabNavigator`.\n * On larger classes, promote the tabs to a `Workbench` rail or sidebar instead of\n * a bottom bar. See `docs/23-app-layouts.md` §3.4.\n */\nexport function TabNavigator<Id extends string>({\n id,\n label,\n tabs,\n active,\n separator = 'auto',\n chromeDividers = 'scroll',\n barPresentation = 'docked',\n scrollEdge = 'none',\n scrollEdgeDistance,\n background,\n tint,\n className = '',\n slot,\n}: TabNavigatorProps<Id>) {\n const tinted = surfaceTintAttributes(tint);\n if (\n tabs.some(\n (tab) => tab.appearance === 'sunken' && tab.background === undefined,\n )\n )\n ensureSunkenTexture();\n return (\n <section\n class={`kui-tab-scaffold ${tinted.className} ${className}`\n .replace(/\\s+/g, ' ')\n .trim()}\n id={id}\n data-component=\"tab-scaffold\"\n data-tab-scaffold-id={id}\n data-separator={separator}\n data-chrome-dividers={\n chromeDividers === 'always' || chromeDividers === 'none'\n ? chromeDividers\n : undefined\n }\n data-bar-presentation={\n barPresentation !== 'docked' ? 'overlay' : undefined\n }\n data-bar-material={barPresentation === 'clear' ? 'clear' : undefined}\n {...scrollEdgeAttributes(\n scrollEdge,\n scrollEdgeDistance,\n barPresentation === 'clear',\n )}\n data-background={background === undefined ? undefined : ''}\n data-kui-tint={tinted['data-kui-tint']}\n data-kui-tint-accent={tinted['data-kui-tint-accent']}\n style={joinStyles(\n background === undefined\n ? undefined\n : `--_kui-tab-scaffold-background:${background}`,\n tinted.style,\n )}\n slot={slot}\n >\n <div class=\"kui-tab-scaffold__scenes\">\n {tabs.map((tab) => (\n <div\n class={`kui-tab-scaffold__scene ${surfaceTintAttributes(tab.tint).className}`.trim()}\n data-tab-scaffold-scene={tab.id}\n data-active={String(tab.id === active)}\n data-appearance={\n tab.appearance === 'sunken' && tab.background === undefined\n ? 'sunken'\n : undefined\n }\n data-background={tab.background === undefined ? undefined : ''}\n data-kui-tint={surfaceTintAttributes(tab.tint)['data-kui-tint']}\n data-kui-tint-accent={\n surfaceTintAttributes(tab.tint)['data-kui-tint-accent']\n }\n style={joinStyles(\n tab.background === undefined\n ? undefined\n : `--_kui-tab-scaffold-scene-background:${tab.background}`,\n surfaceTintAttributes(tab.tint).style,\n )}\n data-deep-inset={tab.deepInset ? 'true' : undefined}\n data-outlined={\n tab.id === active && tab.outlined ? 'true' : undefined\n }\n role={tab.tabIndex === undefined ? undefined : 'tabpanel'}\n aria-label={tab.tabIndex === undefined ? undefined : tab.label}\n aria-hidden={String(tab.id !== active)}\n tabindex={\n tab.id === active\n ? tab.tabIndex\n : tab.tabIndex === undefined\n ? undefined\n : -1\n }\n >\n {tab.content}\n </div>\n ))}\n </div>\n <nav class=\"kui-tab-scaffold__bar\" role=\"tablist\" aria-label={label}>\n {tabs.map((tab) => {\n const dot = tab.badge === true;\n const badgeText = dot ? undefined : normalizeBadge(tab.badge);\n const hasBadge = dot || badgeText !== undefined;\n const badge = hasBadge && (\n <span\n class=\"kui-tab-scaffold__tab-badge\"\n data-badge-kind={dot ? 'dot' : 'text'}\n >\n {badgeText === undefined ? (\n <Badge tone=\"danger\" size=\"dot\" ariaHidden />\n ) : (\n <Badge\n tone=\"danger\"\n appearance=\"solid\"\n size=\"compact\"\n ariaHidden\n >\n {badgeText}\n </Badge>\n )}\n </span>\n );\n // A dot has no text fallback: without a usable badgeLabel (reachable\n // only from untyped callers) the tab keeps its plain accessible name.\n const badgeLabel = hasBadge\n ? tab.badgeLabel?.trim() || badgeText\n : undefined;\n return (\n <button\n type=\"button\"\n class=\"kui-tab-scaffold__tab\"\n role=\"tab\"\n data-tab-scaffold-tab={tab.id}\n aria-selected={String(tab.id === active)}\n tabindex={tab.id === active ? '0' : '-1'}\n aria-label={\n badgeLabel === undefined\n ? undefined\n : `${tab.label}, ${badgeLabel}`\n }\n data-has-badge={hasBadge ? 'true' : undefined}\n >\n {tab.icon ? (\n <span class=\"kui-tab-scaffold__tab-icon\" aria-hidden=\"true\">\n {tab.icon}\n {badge}\n </span>\n ) : (\n badge\n )}\n <span class=\"kui-tab-scaffold__tab-label\">{tab.label}</span>\n </button>\n );\n })}\n </nav>\n </section>\n );\n}\n\nfunction normalizeBadge(\n badge: string | number | undefined,\n): string | undefined {\n if (typeof badge === 'number')\n return Number.isFinite(badge) ? String(badge) : undefined;\n if (typeof badge === 'string' && badge.trim()) return badge.trim();\n return undefined;\n}\n"]}
@@ -4,6 +4,8 @@ import { CssLength } from './css-values.js';
4
4
 
5
5
  type ToolbarControlGroupAppearance = 'contained' | 'borderless';
6
6
  type ToolbarControlGroupTone = 'default' | 'dark';
7
+ /** Surface material: the opaque `solid` fill (default) or translucent `glass`. */
8
+ type ToolbarControlGroupMaterial = 'solid' | 'glass';
7
9
  /** Quiet palette for a contained, single decorative icon tile. */
8
10
  type ToolbarControlGroupTileTone = 'neutral' | 'brand' | 'success' | 'warning' | 'danger';
9
11
  type ToolbarControlGroupButtonAppearance = 'plain' | 'push';
@@ -44,6 +46,15 @@ interface ToolbarControlGroupProps {
44
46
  single?: boolean;
45
47
  appearance?: ToolbarControlGroupAppearance;
46
48
  tone?: ToolbarControlGroupTone;
49
+ /**
50
+ * `glass` paints the group on the translucent chrome material (backdrop
51
+ * blur and saturation) with a specular edge and a soft shadow, for a group
52
+ * floating over imagery or a clear toolbar. Controls take the normal text
53
+ * color so they keep AA over any content; the fill turns opaque under
54
+ * reduced transparency, increased contrast, static effects, or without
55
+ * backdrop-filter support. A borderless group has no surface and ignores it.
56
+ */
57
+ material?: ToolbarControlGroupMaterial;
47
58
  /** Quiet fill, matching border and foreground for a contained single group whose only child is a decorative SVG. Ignored for interactive or mixed content. */
48
59
  tileTone?: ToolbarControlGroupTileTone;
49
60
  buttonAppearance?: ToolbarControlGroupButtonAppearance;
@@ -99,6 +110,6 @@ interface ToolbarControlGroupProps {
99
110
  /** Native named-slot assignment when composed inside a web component. */
100
111
  slot?: string;
101
112
  }
102
- declare function ToolbarControlGroup({ children, label, className, expanded, single, appearance, tone, tileTone, buttonAppearance, shape, size, density, content, focusRing, selectedChrome, selectedTone, nestedDropdown, menuInset, overflow, expandedOverflow, visibility, hideBelow, showBelow, sizing, placement, growBasis, relocateOnCollapse, scrim, busy, busyLabel, avatarImage, slot, }: ToolbarControlGroupProps): kerfjs.SafeHtml;
113
+ declare function ToolbarControlGroup({ children, label, className, expanded, single, appearance, tone, material, tileTone, buttonAppearance, shape, size, density, content, focusRing, selectedChrome, selectedTone, nestedDropdown, menuInset, overflow, expandedOverflow, visibility, hideBelow, showBelow, sizing, placement, growBasis, relocateOnCollapse, scrim, busy, busyLabel, avatarImage, slot, }: ToolbarControlGroupProps): kerfjs.SafeHtml;
103
114
 
104
- export { ToolbarActionLink, type ToolbarActionLinkProps, ToolbarControlGroup, type ToolbarControlGroupAppearance, type ToolbarControlGroupButtonAppearance, type ToolbarControlGroupContent, type ToolbarControlGroupDensity, type ToolbarControlGroupExpandedOverflow, type ToolbarControlGroupFocusRing, type ToolbarControlGroupMenuInset, type ToolbarControlGroupOverflow, type ToolbarControlGroupPlacement, type ToolbarControlGroupProps, type ToolbarControlGroupSelectedChrome, type ToolbarControlGroupSelectedTone, type ToolbarControlGroupShape, type ToolbarControlGroupSize, type ToolbarControlGroupSizing, type ToolbarControlGroupTileTone, type ToolbarControlGroupTone, type ToolbarControlGroupVisibility };
115
+ export { ToolbarActionLink, type ToolbarActionLinkProps, ToolbarControlGroup, type ToolbarControlGroupAppearance, type ToolbarControlGroupButtonAppearance, type ToolbarControlGroupContent, type ToolbarControlGroupDensity, type ToolbarControlGroupExpandedOverflow, type ToolbarControlGroupFocusRing, type ToolbarControlGroupMaterial, type ToolbarControlGroupMenuInset, type ToolbarControlGroupOverflow, type ToolbarControlGroupPlacement, type ToolbarControlGroupProps, type ToolbarControlGroupSelectedChrome, type ToolbarControlGroupSelectedTone, type ToolbarControlGroupShape, type ToolbarControlGroupSize, type ToolbarControlGroupSizing, type ToolbarControlGroupTileTone, type ToolbarControlGroupTone, type ToolbarControlGroupVisibility };
@@ -1,4 +1,4 @@
1
- export { ToolbarActionLink, ToolbarControlGroup } from './chunk-QIG4IGUP.js';
1
+ export { ToolbarActionLink, ToolbarControlGroup } from './chunk-2PXZBFEC.js';
2
2
 
3
3
 
4
4