@kerfjs/ui 5.0.0-beta.3 → 5.0.0-beta.6

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 (97) hide show
  1. package/README.md +12 -9
  2. package/ai/component-catalog.json +314 -172
  3. package/ai/public-api-signatures-v1.md +333 -26
  4. package/ai/skill.md +17 -9
  5. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  6. package/dist/browser/{dialog-header.js → panel-header.js} +3 -2
  7. package/dist/{chunk-GY5WH7TO.js → chunk-24Z2XE6C.js} +3 -3
  8. package/dist/chunk-24Z2XE6C.js.map +1 -0
  9. package/dist/chunk-2RJBFNB6.js +172 -0
  10. package/dist/chunk-2RJBFNB6.js.map +1 -0
  11. package/dist/chunk-KZKSBUKC.js +19 -0
  12. package/dist/chunk-KZKSBUKC.js.map +1 -0
  13. package/dist/chunk-RBTVBGRD.js +23 -0
  14. package/dist/chunk-RBTVBGRD.js.map +1 -0
  15. package/dist/device-class.d.ts +62 -0
  16. package/dist/device-class.js +75 -0
  17. package/dist/device-class.js.map +1 -0
  18. package/dist/index.d.ts +2 -3
  19. package/dist/index.js +8 -9
  20. package/dist/nav-stack.d.ts +38 -0
  21. package/dist/nav-stack.js +4 -0
  22. package/dist/nav-stack.js.map +1 -0
  23. package/dist/panel-header.d.ts +26 -0
  24. package/dist/panel-header.js +6 -0
  25. package/dist/panel-header.js.map +1 -0
  26. package/dist/split-view.d.ts +42 -0
  27. package/dist/split-view.js +20 -0
  28. package/dist/split-view.js.map +1 -0
  29. package/dist/styles/foundation.css +21 -0
  30. package/dist/styles/menu-action-row.css +6 -0
  31. package/dist/styles/menu-header.css +19 -2
  32. package/dist/styles/menu-item.css +5 -0
  33. package/dist/styles/nav-stack.css +112 -0
  34. package/dist/styles/panel-header.css +59 -0
  35. package/dist/styles/split-view.css +35 -0
  36. package/dist/styles/styles.css +1 -2
  37. package/dist/styles/tab-scaffold.css +84 -0
  38. package/dist/styles/toolbar-control-group.css +52 -2
  39. package/dist/styles/toolbar-text.css +11 -0
  40. package/dist/styles/toolbar.css +9 -0
  41. package/dist/styles/workbench.css +94 -0
  42. package/dist/tab-scaffold.d.ts +30 -0
  43. package/dist/tab-scaffold.js +16 -0
  44. package/dist/tab-scaffold.js.map +1 -0
  45. package/dist/toolbar-text.d.ts +4 -2
  46. package/dist/toolbar-text.js +1 -1
  47. package/dist/wire-nav-stack.d.ts +15 -0
  48. package/dist/wire-nav-stack.js +88 -0
  49. package/dist/wire-nav-stack.js.map +1 -0
  50. package/dist/wire-tab-scaffold.d.ts +11 -0
  51. package/dist/wire-tab-scaffold.js +16 -0
  52. package/dist/wire-tab-scaffold.js.map +1 -0
  53. package/dist/wire-token-search-fields.d.ts +46 -4
  54. package/dist/wire-token-search-fields.js +1 -1
  55. package/dist/workbench.d.ts +33 -0
  56. package/dist/workbench.js +17 -0
  57. package/dist/workbench.js.map +1 -0
  58. package/docs/accessibility.md +10 -10
  59. package/docs/app-layouts.md +57 -0
  60. package/docs/component-contract.md +37 -9
  61. package/docs/component-selection.md +57 -8
  62. package/docs/design-philosophy.md +23 -1
  63. package/docs/device-class.md +54 -0
  64. package/docs/layout.md +44 -8
  65. package/docs/nav-stack.md +47 -0
  66. package/docs/recipes.md +29 -9
  67. package/docs/split-view.md +49 -0
  68. package/docs/tab-scaffold.md +41 -0
  69. package/docs/ux-demo.md +11 -9
  70. package/docs/workbench.md +47 -0
  71. package/llms.txt +107 -43
  72. package/package.json +37 -11
  73. package/ux-demo/recipes/app-shell.tsx +3 -3
  74. package/ux-demo/recipes/composer-form.tsx +5 -4
  75. package/ux-demo/recipes/list-workspace-states.tsx +2 -2
  76. package/ux-demo/recipes/loaders.ts +2 -0
  77. package/ux-demo/recipes/master-detail-dialog.tsx +2 -2
  78. package/ux-demo/recipes/mount-recipe.ts +3 -0
  79. package/ux-demo/recipes/navigation-stack.tsx +76 -0
  80. package/ux-demo/recipes/recipes.css +40 -13
  81. package/ux-demo/recipes/workspace-header.tsx +2 -2
  82. package/dist/browser/page-header.js +0 -3
  83. package/dist/chunk-2PES33HS.js +0 -13
  84. package/dist/chunk-2PES33HS.js.map +0 -1
  85. package/dist/chunk-GY5WH7TO.js.map +0 -1
  86. package/dist/chunk-H5AGGVU5.js +0 -75
  87. package/dist/chunk-H5AGGVU5.js.map +0 -1
  88. package/dist/chunk-K3G72I6D.js +0 -24
  89. package/dist/chunk-K3G72I6D.js.map +0 -1
  90. package/dist/dialog-header.d.ts +0 -15
  91. package/dist/dialog-header.js +0 -5
  92. package/dist/dialog-header.js.map +0 -1
  93. package/dist/page-header.d.ts +0 -9
  94. package/dist/page-header.js +0 -3
  95. package/dist/page-header.js.map +0 -1
  96. package/dist/styles/dialog-header.css +0 -87
  97. package/dist/styles/page-header.css +0 -26
@@ -113,13 +113,10 @@
113
113
  .recipe-header__context {
114
114
  margin: 0;
115
115
  }
116
- .recipe-header .kui-page-header__action {
117
- max-width: 100%;
118
- }
119
116
 
120
117
  .recipe-master-detail {
121
118
  display: grid;
122
- width: min(58rem, 100%);
119
+ width: 100%;
123
120
  min-height: 25rem;
124
121
  grid-template-columns: minmax(13rem, 0.8fr) minmax(18rem, 1.4fr);
125
122
  }
@@ -130,10 +127,19 @@
130
127
  min-width: 0;
131
128
  padding-block: var(--kui-layout-item-gap);
132
129
  }
130
+ .recipe-master-detail__title {
131
+ margin-inline: var(--kui-layout-inline-margin, remify(8px));
132
+ }
133
+ .recipe-master-detail__actions {
134
+ margin-inline: var(--kui-layout-inline-margin, remify(8px));
135
+ }
133
136
  .recipe-dialog {
134
137
  --spacing: 0;
135
138
  --width: min(62rem, calc(100vw - 2rem));
136
139
  }
140
+ .recipe-dialog .kui-panel-header {
141
+ margin-inline: 0;
142
+ }
137
143
 
138
144
  .recipe-form {
139
145
  width: min(38rem, 100%);
@@ -141,17 +147,24 @@
141
147
  padding-block: var(--kui-layout-item-gap);
142
148
  }
143
149
  .recipe-form__section {
144
- --kui-content-item-border: transparent;
145
- --kui-content-item-background: transparent;
146
150
  display: grid;
151
+ min-width: 0;
152
+ margin-inline: var(--kui-layout-inline-margin, remify(8px));
147
153
  gap: var(--kui-layout-item-gap);
148
154
  }
149
- .recipe-form__introduction > :where(h2, p) {
150
- margin: 0;
151
- }
152
155
  .recipe-form__fields {
153
156
  align-content: start;
154
157
  }
158
+ .recipe-form__fields wa-input::part(form-control-label),
159
+ .recipe-form__fields wa-input::part(hint),
160
+ .recipe-form__fields wa-textarea::part(form-control-label),
161
+ .recipe-form__fields wa-textarea::part(hint),
162
+ .recipe-form__fields .kui-select::part(form-control-label) {
163
+ padding-inline: remify(8px);
164
+ }
165
+ .recipe-form__fields wa-textarea::part(textarea) {
166
+ padding-inline: remify(8px);
167
+ }
155
168
  .recipe-form__footer {
156
169
  align-content: start;
157
170
  }
@@ -190,8 +203,11 @@
190
203
  gap: var(--kui-layout-content-gap);
191
204
  }
192
205
  .recipe-compact-toolbar__guide {
206
+ /* Span the toolbar's full width instead of the 8px content-item inset — under a
207
+ full-bleed toolbar/divider the inset read as the boxes floating too far in. */
193
208
  display: grid;
194
209
  grid-template-columns: repeat(4, minmax(0, 1fr));
210
+ margin-inline: 0;
195
211
  gap: var(--kui-layout-control-gap);
196
212
  }
197
213
  .recipe-compact-toolbar__guide > div {
@@ -305,10 +321,6 @@
305
321
  .recipe-compact-toolbar__guide {
306
322
  grid-template-columns: 1fr;
307
323
  }
308
- .recipe-header .kui-page-header {
309
- align-items: flex-start;
310
- flex-direction: column;
311
- }
312
324
  }
313
325
 
314
326
  @media (forced-colors: active) {
@@ -326,3 +338,18 @@
326
338
  transition-duration: 1ms !important;
327
339
  }
328
340
  }
341
+
342
+ .recipe-navstack {
343
+ display: flex;
344
+ width: min(28rem, 100%);
345
+ margin-inline: auto;
346
+ flex-direction: column;
347
+ }
348
+ .recipe-navstack__stage {
349
+ height: 24rem;
350
+ }
351
+ .recipe-navstack__view {
352
+ /* The view is a .kui-content stack whose rows own their 8px margins; add only a
353
+ little block breathing room, not an inline pad that would double-inset them. */
354
+ padding-block: var(--kui-space-2xs);
355
+ }
@@ -1,12 +1,12 @@
1
1
  import '@kerfjs/ui/layout.css';
2
2
  import './recipes.css';
3
3
 
4
- import { PageHeader } from '@kerfjs/ui/page-header';
4
+ import { PanelHeader } from '@kerfjs/ui/panel-header';
5
5
  import { StateBanner } from '@kerfjs/ui/state-banner';
6
6
 
7
7
  import type { RecipeFactory } from './types.js';
8
8
 
9
9
  export const createRecipe: RecipeFactory = (announce) => ({
10
- render: () => <section class="kui-recipe recipe-header kui-recipe__surface kui-content" data-recipe="recipe-workspace-header"><p class="recipe-header__context kui-inline-metadata kui-content-item"><span>Northstar workspace</span><span>·</span><span>Product planning</span></p><PageHeader title="Accessibility readiness and responsive navigation rollout" action={<div class="kui-control-cluster"><button class="kui-recipe__button" type="button" data-action="recipe-action" data-recipe-command="share">Share</button><button class="kui-recipe__button" type="button" data-action="recipe-action" data-recipe-command="more">More actions</button><button class="kui-recipe__button" data-primary="true" type="button" data-action="recipe-action" data-recipe-command="publish">Publish update</button></div>} /><StateBanner title="Ready for review" detail="All required checks passed 18 minutes ago." tone="success" /><p class="kui-recipe__ownership kui-content-item">The recipe owns page hierarchy and action relocation. The app owns authorization, command behavior, breadcrumbs, and product copy.</p></section>,
10
+ render: () => <section class="kui-recipe recipe-header kui-recipe__surface kui-content" data-recipe="recipe-workspace-header"><p class="recipe-header__context kui-inline-metadata kui-content-item"><span>Northstar workspace</span><span>·</span><span>Product planning</span></p><PanelHeader title="Accessibility readiness and responsive navigation rollout" titleId="recipe-workspace-title" actions={<div class="kui-control-cluster"><button class="kui-recipe__button" type="button" data-action="recipe-action" data-recipe-command="share">Share</button><button class="kui-recipe__button" type="button" data-action="recipe-action" data-recipe-command="more">More actions</button><button class="kui-recipe__button" data-primary="true" type="button" data-action="recipe-action" data-recipe-command="publish">Publish update</button></div>} /><StateBanner title="Ready for review" detail="All required checks passed 18 minutes ago." tone="success" /><p class="kui-recipe__ownership kui-content-item">The recipe owns page hierarchy and action relocation. The app owns authorization, command behavior, breadcrumbs, and product copy.</p></section>,
11
11
  action(command) { announce(`${command} requested`); },
12
12
  });
@@ -1,3 +0,0 @@
1
- import '../styles/foundation.css';
2
- import '../styles/page-header.css';
3
- export * from '../page-header.js';
@@ -1,13 +0,0 @@
1
- import { jsxs, jsx } from 'kerfjs/jsx-runtime';
2
-
3
- // src/page-header.tsx
4
- function PageHeader({ title, action }) {
5
- return /* @__PURE__ */ jsxs("header", { class: "kui-page-header", "data-component": "page-header", children: [
6
- /* @__PURE__ */ jsx("h1", { children: title }),
7
- action && /* @__PURE__ */ jsx("div", { class: "kui-page-header__action", children: action })
8
- ] });
9
- }
10
-
11
- export { PageHeader };
12
-
13
- //# sourceMappingURL=chunk-2PES33HS.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/page-header.tsx"],"names":[],"mappings":";;;AAOO,SAAS,UAAA,CAAW,EAAE,KAAA,EAAO,MAAA,EAAO,EAAoB;AAC7D,EAAA,uBAAO,IAAA,CAAC,QAAA,EAAA,EAAO,KAAA,EAAM,iBAAA,EAAkB,kBAAe,aAAA,EAAc,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,QAAI,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,IAAM,MAAA,oBAAU,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,2BAA2B,QAAA,EAAA,MAAA,EAAO;AAAA,GAAA,EAAO,CAAA;AACrJ","file":"chunk-2PES33HS.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nexport interface PageHeaderProps {\n title: string | SafeHtml;\n action?: SafeHtml;\n}\n\nexport function PageHeader({ title, action }: PageHeaderProps) {\n return <header class=\"kui-page-header\" data-component=\"page-header\"><h1>{title}</h1>{action && <div class=\"kui-page-header__action\">{action}</div>}</header>;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/toolbar-text.tsx"],"names":[],"mappings":";;;AAQO,SAAS,YAAY,EAAE,IAAA,EAAM,OAAO,SAAA,EAAW,SAAA,GAAY,IAAG,EAAqB;AACxF,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,EAAO,QAAA,EAAA,IAAA,EAAK,CAAA;AACnH","file":"chunk-GY5WH7TO.js","sourcesContent":["export type ToolbarTextSize = 'large' | 'default' | 'small';\n\nexport interface ToolbarTextProps {\n text: string;\n size?: ToolbarTextSize;\n className?: string;\n}\n\nexport function ToolbarText({ text, size = 'default', className = '' }: ToolbarTextProps) {\n return <span class={`kui-toolbar-text ${className}`.trim()} data-component=\"toolbar-text\" data-size={size}>{text}</span>;\n}\n"]}
@@ -1,75 +0,0 @@
1
- import { placeTokenSearchCaret, readTokenSearchField } from './chunk-7LDCTU7D.js';
2
- import { delegate } from 'kerfjs';
3
-
4
- function editorFromEvent(root, event) {
5
- const target = event.target;
6
- if (!(target instanceof Element)) return;
7
- const editor = target.closest("[data-token-search-editor]");
8
- return editor && root.contains(editor) ? editor : void 0;
9
- }
10
- function caretQueryOffset(editor) {
11
- const selection = editor.ownerDocument.getSelection();
12
- if (!selection || selection.rangeCount === 0) return;
13
- const selectionRange = selection.getRangeAt(0);
14
- if (!editor.contains(selectionRange.startContainer)) return;
15
- const prefixRange = editor.ownerDocument.createRange();
16
- prefixRange.selectNodeContents(editor);
17
- prefixRange.setEnd(selectionRange.startContainer, selectionRange.startOffset);
18
- const prefix = editor.ownerDocument.createElement("div");
19
- prefix.append(prefixRange.cloneContents());
20
- return readTokenSearchField(prefix).query.length;
21
- }
22
- function replacementEditor(root, id) {
23
- return [...root.querySelectorAll("[data-token-search-editor]")].find((editor) => editor.dataset.tokenSearchEditor === id);
24
- }
25
- function wireTokenSearchFields(root, { onSubmit }) {
26
- const pending = /* @__PURE__ */ new WeakMap();
27
- const onBeforeInput = (event) => {
28
- const inputEvent = event;
29
- const editor = editorFromEvent(root, event);
30
- if (!editor || !inputEvent.inputType.startsWith("delete") || editor.ownerDocument.activeElement !== editor) return;
31
- const field = editor.closest('[data-component="token-search-field"]');
32
- const id = field?.dataset.tokenSearchId;
33
- const offset = caretQueryOffset(editor);
34
- if (!id || offset === void 0 || field?.dataset.disabled === "true") return;
35
- pending.set(editor, {
36
- id,
37
- offset,
38
- tokenCount: editor.querySelectorAll('[data-component="token-search-token"]').length
39
- });
40
- };
41
- const onInput = (event) => {
42
- const editor = editorFromEvent(root, event);
43
- if (!editor) return;
44
- const deletion = pending.get(editor);
45
- pending.delete(editor);
46
- if (!deletion || editor.querySelectorAll('[data-component="token-search-token"]').length >= deletion.tokenCount) return;
47
- editor.ownerDocument.defaultView.requestAnimationFrame(() => {
48
- const replacement = replacementEditor(root, deletion.id);
49
- if (!replacement) return;
50
- const active = replacement.ownerDocument.activeElement;
51
- if (active !== editor && active !== replacement && active !== replacement.ownerDocument.body) return;
52
- placeTokenSearchCaret(replacement, deletion.offset);
53
- });
54
- };
55
- root.addEventListener("beforeinput", onBeforeInput, true);
56
- root.addEventListener("input", onInput, true);
57
- const stopSubmit = delegate(root, "keydown", "[data-token-search-editor]", (event, element) => {
58
- const keyboardEvent = event;
59
- const editor = element;
60
- const field = editor.closest('[data-component="token-search-field"]');
61
- const id = field?.dataset.tokenSearchId;
62
- if (keyboardEvent.key !== "Enter" || keyboardEvent.isComposing || !id || field?.dataset.disabled === "true") return;
63
- keyboardEvent.preventDefault();
64
- onSubmit({ id, editor });
65
- });
66
- return () => {
67
- root.removeEventListener("beforeinput", onBeforeInput, true);
68
- root.removeEventListener("input", onInput, true);
69
- stopSubmit();
70
- };
71
- }
72
-
73
- export { wireTokenSearchFields };
74
-
75
- //# sourceMappingURL=chunk-H5AGGVU5.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/wire-token-search-fields.ts"],"names":[],"mappings":"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","file":"chunk-H5AGGVU5.js","sourcesContent":["import { delegate } from 'kerfjs';\n\nimport { placeTokenSearchCaret, readTokenSearchField } from './token-search-field.js';\n\nexport interface TokenSearchSubmit {\n id: string;\n editor: HTMLElement;\n}\n\nexport interface WireTokenSearchFieldsOptions {\n onSubmit: (submission: TokenSearchSubmit) => void;\n}\n\ninterface PendingTokenDeletion {\n id: string;\n offset: number;\n tokenCount: number;\n}\n\nfunction editorFromEvent(root: HTMLElement, event: Event): HTMLElement | undefined {\n const target = event.target;\n if (!(target instanceof Element)) return;\n const editor = target.closest<HTMLElement>('[data-token-search-editor]');\n return editor && root.contains(editor) ? editor : undefined;\n}\n\nfunction caretQueryOffset(editor: HTMLElement): number | undefined {\n const selection = editor.ownerDocument.getSelection();\n if (!selection || selection.rangeCount === 0) return;\n const selectionRange = selection.getRangeAt(0);\n if (!editor.contains(selectionRange.startContainer)) return;\n const prefixRange = editor.ownerDocument.createRange();\n prefixRange.selectNodeContents(editor);\n prefixRange.setEnd(selectionRange.startContainer, selectionRange.startOffset);\n const prefix = editor.ownerDocument.createElement('div');\n prefix.append(prefixRange.cloneContents());\n return readTokenSearchField(prefix).query.length;\n}\n\nfunction replacementEditor(root: HTMLElement, id: string): HTMLElement | undefined {\n return [...root.querySelectorAll<HTMLElement>('[data-token-search-editor]')]\n .find((editor) => editor.dataset.tokenSearchEditor === id);\n}\n\n/** Keep TokenSearchField wrapping, submit Enter, and preserve its caret across controlled token deletion. */\nexport function wireTokenSearchFields(root: HTMLElement, { onSubmit }: WireTokenSearchFieldsOptions) {\n const pending = new WeakMap<HTMLElement, PendingTokenDeletion>();\n const onBeforeInput = (event: Event) => {\n const inputEvent = event as InputEvent;\n const editor = editorFromEvent(root, event);\n if (!editor || !inputEvent.inputType.startsWith('delete') || editor.ownerDocument.activeElement !== editor) return;\n const field = editor.closest<HTMLElement>('[data-component=\"token-search-field\"]');\n const id = field?.dataset.tokenSearchId;\n const offset = caretQueryOffset(editor);\n if (!id || offset === undefined || field?.dataset.disabled === 'true') return;\n pending.set(editor, {\n id,\n offset,\n tokenCount: editor.querySelectorAll('[data-component=\"token-search-token\"]').length,\n });\n };\n const onInput = (event: Event) => {\n const editor = editorFromEvent(root, event);\n if (!editor) return;\n const deletion = pending.get(editor);\n pending.delete(editor);\n if (!deletion || editor.querySelectorAll('[data-component=\"token-search-token\"]').length >= deletion.tokenCount) return;\n editor.ownerDocument.defaultView!.requestAnimationFrame(() => {\n const replacement = replacementEditor(root, deletion.id);\n if (!replacement) return;\n const active = replacement.ownerDocument.activeElement;\n if (active !== editor && active !== replacement && active !== replacement.ownerDocument.body) return;\n placeTokenSearchCaret(replacement, deletion.offset);\n });\n };\n root.addEventListener('beforeinput', onBeforeInput, true);\n root.addEventListener('input', onInput, true);\n\n const stopSubmit = delegate(root, 'keydown', '[data-token-search-editor]', (event, element) => {\n const keyboardEvent = event as KeyboardEvent;\n const editor = element as HTMLElement;\n const field = editor.closest<HTMLElement>('[data-component=\"token-search-field\"]');\n const id = field?.dataset.tokenSearchId;\n if (keyboardEvent.key !== 'Enter' || keyboardEvent.isComposing || !id || field?.dataset.disabled === 'true') return;\n keyboardEvent.preventDefault();\n onSubmit({ id, editor });\n });\n return () => {\n root.removeEventListener('beforeinput', onBeforeInput, true);\n root.removeEventListener('input', onInput, true);\n stopSubmit();\n };\n}\n"]}
@@ -1,24 +0,0 @@
1
- import { ToolbarControlGroup } from './chunk-MFKMHK5W.js';
2
- import { Toolbar } from './chunk-DAFFDO33.js';
3
- import { jsxs, jsx } from 'kerfjs/jsx-runtime';
4
-
5
- function DialogHeader({ title, titleId, summary, summaryId, icon, iconClassName = "", actions, actionsLabel }) {
6
- const titleContent = /* @__PURE__ */ jsx("div", { class: "kui-dialog-header__copy", children: /* @__PURE__ */ jsx("h2", { id: titleId, children: title }) });
7
- const identity = /* @__PURE__ */ jsx(
8
- ToolbarControlGroup,
9
- {
10
- appearance: "borderless",
11
- className: "kui-dialog-header__identity",
12
- children: icon ? [/* @__PURE__ */ jsx("span", { class: `kui-dialog-header__icon ${iconClassName}`.trim(), children: icon }), titleContent] : titleContent
13
- }
14
- );
15
- const actionGroup = actions && /* @__PURE__ */ jsx(ToolbarControlGroup, { className: "kui-dialog-header__actions", label: actionsLabel, children: actions });
16
- return /* @__PURE__ */ jsxs("div", { class: "kui-dialog-header", "data-component": "dialog-header", "data-has-icon": String(Boolean(icon)), "data-has-actions": String(Boolean(actions)), "data-has-summary": String(Boolean(summary)), children: [
17
- /* @__PURE__ */ jsx(Toolbar, { leading: identity, trailing: actionGroup, divider: false, className: "kui-dialog-header__toolbar" }),
18
- summary && /* @__PURE__ */ jsx("p", { class: "kui-dialog-header__summary", id: summaryId, children: summary })
19
- ] });
20
- }
21
-
22
- export { DialogHeader };
23
-
24
- //# sourceMappingURL=chunk-K3G72I6D.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/dialog-header.tsx"],"names":[],"mappings":";;;;AAgBO,SAAS,YAAA,CAAa,EAAE,KAAA,EAAO,OAAA,EAAS,OAAA,EAAS,SAAA,EAAW,IAAA,EAAM,aAAA,GAAgB,EAAA,EAAI,OAAA,EAAS,YAAA,EAAa,EAAsB;AACvI,EAAA,MAAM,YAAA,mBAAe,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,yBAAA,EAA0B,8BAAC,IAAA,EAAA,EAAG,EAAA,EAAI,OAAA,EAAU,QAAA,EAAA,KAAA,EAAM,CAAA,EAAK,CAAA;AACvF,EAAA,MAAM,QAAA,mBAAW,GAAA;AAAA,IAAC,mBAAA;AAAA,IAAA;AAAA,MAChB,UAAA,EAAW,YAAA;AAAA,MACX,SAAA,EAAU,6BAAA;AAAA,MACV,QAAA,EAAU,IAAA,GAAO,iBAAC,GAAA,CAAC,UAAK,KAAA,EAAO,CAAA,wBAAA,EAA2B,aAAa,CAAA,CAAA,CAAG,IAAA,EAAK,EAAI,QAAA,EAAA,IAAA,EAAK,CAAA,EAAS,YAAY,CAAA,GAAI;AAAA;AAAA,GACnH;AACA,EAAA,MAAM,WAAA,GAAc,2BAAW,GAAA,CAAC,mBAAA,EAAA,EAAoB,WAAU,4BAAA,EAA6B,KAAA,EAAO,cAAe,QAAA,EAAA,OAAA,EAAQ,CAAA;AAEzH,EAAA,uBAAO,IAAA,CAAC,SAAI,KAAA,EAAM,mBAAA,EAAoB,kBAAe,eAAA,EAAgB,eAAA,EAAe,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAC,GAAG,kBAAA,EAAkB,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAC,CAAA,EAAG,oBAAkB,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAC,CAAA,EAC9L,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,OAAA,EAAA,EAAQ,SAAS,QAAA,EAAU,QAAA,EAAU,aAAa,OAAA,EAAS,KAAA,EAAO,WAAU,4BAAA,EAA6B,CAAA;AAAA,IACzG,2BAAW,GAAA,CAAC,GAAA,EAAA,EAAE,OAAM,4BAAA,EAA6B,EAAA,EAAI,WAAY,QAAA,EAAA,OAAA,EAAQ;AAAA,GAAA,EAC5E,CAAA;AACF","file":"chunk-K3G72I6D.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport { Toolbar } from './toolbar.js';\nimport { ToolbarControlGroup } from './toolbar-control-group.js';\n\nexport interface DialogHeaderProps {\n title: string;\n titleId: string;\n summary?: string;\n summaryId?: string;\n icon?: SafeHtml;\n iconClassName?: string;\n actions?: SafeHtml;\n actionsLabel?: string;\n}\n\nexport function DialogHeader({ title, titleId, summary, summaryId, icon, iconClassName = '', actions, actionsLabel }: DialogHeaderProps) {\n const titleContent = <div class=\"kui-dialog-header__copy\"><h2 id={titleId}>{title}</h2></div>;\n const identity = <ToolbarControlGroup\n appearance=\"borderless\"\n className=\"kui-dialog-header__identity\"\n children={icon ? [<span class={`kui-dialog-header__icon ${iconClassName}`.trim()}>{icon}</span>, titleContent] : titleContent}\n />;\n const actionGroup = actions && <ToolbarControlGroup className=\"kui-dialog-header__actions\" label={actionsLabel}>{actions}</ToolbarControlGroup>;\n\n return <div class=\"kui-dialog-header\" data-component=\"dialog-header\" data-has-icon={String(Boolean(icon))} data-has-actions={String(Boolean(actions))} data-has-summary={String(Boolean(summary))}>\n <Toolbar leading={identity} trailing={actionGroup} divider={false} className=\"kui-dialog-header__toolbar\" />\n {summary && <p class=\"kui-dialog-header__summary\" id={summaryId}>{summary}</p>}\n </div>;\n}\n"]}
@@ -1,15 +0,0 @@
1
- import { SafeHtml } from 'kerfjs';
2
-
3
- interface DialogHeaderProps {
4
- title: string;
5
- titleId: string;
6
- summary?: string;
7
- summaryId?: string;
8
- icon?: SafeHtml;
9
- iconClassName?: string;
10
- actions?: SafeHtml;
11
- actionsLabel?: string;
12
- }
13
- declare function DialogHeader({ title, titleId, summary, summaryId, icon, iconClassName, actions, actionsLabel }: DialogHeaderProps): SafeHtml;
14
-
15
- export { DialogHeader, type DialogHeaderProps };
@@ -1,5 +0,0 @@
1
- export { DialogHeader } from './chunk-K3G72I6D.js';
2
-
3
-
4
-
5
- //# sourceMappingURL=dialog-header.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"dialog-header.js"}
@@ -1,9 +0,0 @@
1
- import { SafeHtml } from 'kerfjs';
2
-
3
- interface PageHeaderProps {
4
- title: string | SafeHtml;
5
- action?: SafeHtml;
6
- }
7
- declare function PageHeader({ title, action }: PageHeaderProps): SafeHtml;
8
-
9
- export { PageHeader, type PageHeaderProps };
@@ -1,3 +0,0 @@
1
- export { PageHeader } from './chunk-2PES33HS.js';
2
-
3
- //# sourceMappingURL=page-header.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"page-header.js"}
@@ -1,87 +0,0 @@
1
- .kui-dialog-header {
2
- --kui-dialog-header-border: transparent;
3
- --kui-dialog-header-icon-background: var(--kui-color-brand-fill-quiet);
4
- --kui-dialog-header-icon-foreground: var(--kui-color-brand-on-quiet);
5
- --kui-dialog-header-title-inset: 2px;
6
- display: grid;
7
- min-height: 2.75rem;
8
- margin-inline: var(--kui-layout-inline-margin, 0.5rem);
9
- padding: var(--kui-layout-item-padding, 0.5rem);
10
- box-sizing: border-box;
11
- border: 1px solid var(--kui-dialog-header-border);
12
- border-radius: var(--kui-layout-rounded-radius, calc(1px + 0.6875rem));
13
- gap: 0;
14
- }
15
-
16
- .kui-dialog-header[data-has-icon="true"] {
17
- --kui-dialog-header-title-inset: calc(
18
- 2px + 2.125rem + var(--kui-layout-item-gap, 0.5rem)
19
- );
20
- }
21
-
22
- .kui-dialog-header__toolbar {
23
- min-height: var(--kui-toolbar-group-size, calc(2px + 2.625rem));
24
- padding: 0;
25
- }
26
-
27
- .kui-dialog-header__identity {
28
- max-width: 100%;
29
- border-color: transparent;
30
- background: transparent;
31
- gap: var(--kui-layout-item-gap, 0.5rem);
32
- }
33
-
34
- .kui-dialog-header__icon {
35
- display: grid;
36
- width: 2.125rem;
37
- height: 2.125rem;
38
- border-radius: var(--kui-radius-circle);
39
- color: var(--kui-dialog-header-icon-foreground);
40
- background: var(--kui-dialog-header-icon-background);
41
- flex: none;
42
- place-items: center;
43
- }
44
-
45
- .kui-dialog-header__icon svg {
46
- width: 1.5rem;
47
- height: 1.5rem;
48
- }
49
-
50
- .kui-dialog-header__copy {
51
- min-width: 0;
52
- overflow: hidden;
53
- }
54
-
55
- .kui-dialog-header h2,
56
- .kui-dialog-header__summary {
57
- margin: 0;
58
- }
59
-
60
- .kui-dialog-header h2 {
61
- overflow: hidden;
62
- color: var(--kui-color-text);
63
- font-size: var(--kui-font-l);
64
- line-height: 1.2;
65
- text-overflow: ellipsis;
66
- white-space: nowrap;
67
- }
68
-
69
- .kui-dialog-header__summary {
70
- min-width: 0;
71
- margin-block-start: calc(-1 * var(--kui-layout-item-padding, 0.5rem));
72
- padding-inline: var(--kui-layout-item-padding, 0.5rem);
73
- padding-inline-start: var(--kui-dialog-header-title-inset);
74
- color: var(--kui-color-text-quiet);
75
- }
76
-
77
- .kui-dialog-header__actions {
78
- gap: 0;
79
- }
80
-
81
- .kui-dialog-header__actions:has(> .kui-toolbar-control-group) {
82
- height: var(--kui-toolbar-group-size, calc(2px + 2.625rem));
83
- padding: 0;
84
- border-color: transparent;
85
- background: transparent;
86
- gap: var(--kui-layout-item-gap, 0.5rem);
87
- }
@@ -1,26 +0,0 @@
1
- .kui-page-header {
2
- --kui-page-header-background: transparent;
3
- --kui-page-header-border: transparent;
4
- --kui-page-header-foreground: var(--kui-color-text);
5
- display: flex;
6
- min-height: 2.75rem;
7
- margin-inline: var(--kui-layout-inline-margin, 0.5rem);
8
- padding: var(--kui-layout-item-padding, 0.5rem);
9
- box-sizing: border-box;
10
- border: 1px solid var(--kui-page-header-border);
11
- border-radius: var(--kui-layout-rounded-radius, calc(1px + 0.6875rem));
12
- color: var(--kui-page-header-foreground);
13
- background: var(--kui-page-header-background);
14
- align-items: center;
15
- justify-content: space-between;
16
- gap: var(--kui-layout-item-gap, 0.5rem);
17
- }
18
- .kui-page-header h1 {
19
- margin: 0;
20
- color: inherit;
21
- font-size: clamp(var(--kui-font-l), 2.3vw, var(--kui-font-2xl));
22
- letter-spacing: -0.025em;
23
- }
24
- .kui-page-header__action {
25
- flex: none;
26
- }