@kerfjs/ui 5.0.0-beta.54 → 5.0.0-beta.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/ai/component-catalog-v2.json +58 -1
- package/ai/component-catalog.json +105 -8
- package/ai/public-api-signatures-v1.md +265 -28
- package/ai/skill.md +6 -4
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/dist/browser/popup-menu.js +3 -0
- package/dist/catalog-resources.d.ts +1 -1
- package/dist/catalog.d.ts +10 -4
- package/dist/catalog.js +243 -300
- package/dist/catalog.js.map +1 -1
- package/dist/{chunk-7IUSV4XG.js → chunk-24PHKUR3.js} +2 -2
- package/dist/chunk-24PHKUR3.js.map +1 -0
- package/dist/chunk-4BIMLITI.js +92 -0
- package/dist/chunk-4BIMLITI.js.map +1 -0
- package/dist/{chunk-ZK5EGVFP.js → chunk-5OLVUEND.js} +12 -2
- package/dist/chunk-5OLVUEND.js.map +1 -0
- package/dist/{chunk-CMUIXJZM.js → chunk-BSKEH3UC.js} +2 -2
- package/dist/{chunk-CMUIXJZM.js.map → chunk-BSKEH3UC.js.map} +1 -1
- package/dist/chunk-EAX2GSS4.js +384 -0
- package/dist/chunk-EAX2GSS4.js.map +1 -0
- package/dist/chunk-KH6VUGHU.js +399 -0
- package/dist/chunk-KH6VUGHU.js.map +1 -0
- package/dist/{chunk-BJJKFVWW.js → chunk-LZXQVUGN.js} +2 -2
- package/dist/chunk-LZXQVUGN.js.map +1 -0
- package/dist/chunk-N7FHFNT6.js +55 -0
- package/dist/chunk-N7FHFNT6.js.map +1 -0
- package/dist/{chunk-KPNTVB7A.js → chunk-R754MHXX.js} +3 -3
- package/dist/{chunk-KPNTVB7A.js.map → chunk-R754MHXX.js.map} +1 -1
- package/dist/{chunk-HJKRCKDR.js → chunk-RNRUVPJ3.js} +4 -2
- package/dist/chunk-RNRUVPJ3.js.map +1 -0
- package/dist/collapsible-panel.d.ts +40 -13
- package/dist/collapsible-panel.js +41 -10
- package/dist/collapsible-panel.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +17 -16
- package/dist/list-header.js +1 -1
- package/dist/list-inset-text.d.ts +7 -1
- package/dist/list-inset-text.js +2 -1
- package/dist/panel-toolbar-BFQxFITu.d.ts +52 -0
- package/dist/popup-menu-register.d.ts +9 -0
- package/dist/popup-menu-register.js +30 -0
- package/dist/popup-menu-register.js.map +1 -0
- package/dist/popup-menu.d.ts +71 -0
- package/dist/popup-menu.js +3 -0
- package/dist/popup-menu.js.map +1 -0
- package/dist/state-banner.js +1 -1
- package/dist/styles/catalog/components/catalog-example.css +0 -16
- package/dist/styles/catalog/components/catalog-stage.css +8 -13
- package/dist/styles/catalog/components/catalog.css +8 -18
- package/dist/styles/catalog.css +0 -5
- package/dist/styles/popup-menu.css +12 -0
- package/dist/styles/state-banner.css +13 -4
- package/dist/styles/styles.css +1 -0
- package/dist/styles/tab-bar.css +31 -3
- package/dist/styles/toolbar-control-group.css +13 -0
- package/dist/styles/toolbar.css +43 -2
- package/dist/styles/workbench.css +31 -0
- package/dist/text.js +1 -1
- package/dist/token-search-field.d.ts +10 -1
- package/dist/token-search-field.js +1 -1
- package/dist/{types-CEsieBZi.d.ts → types-D6vzj-VT.d.ts} +15 -0
- package/dist/wire-catalog.d.ts +13 -1
- package/dist/wire-catalog.js +18 -3
- package/dist/wire-catalog.js.map +1 -1
- package/dist/wire-sidebar.js +6 -3
- package/dist/wire-sidebar.js.map +1 -1
- package/dist/wire-token-search-fields.js +1 -1
- package/dist/wire-workbench.js +1 -350
- package/dist/wire-workbench.js.map +1 -1
- package/dist/workbench.d.ts +107 -6
- package/dist/workbench.js +11 -208
- package/dist/workbench.js.map +1 -1
- package/docs/accessibility.md +12 -1
- package/docs/catalog.md +27 -9
- package/docs/collapsible-panel.md +55 -0
- package/docs/component-contract.md +2 -2
- package/docs/component-selection.md +25 -17
- package/docs/design/templates/state-banner/danger-dark.svg +1 -1
- package/docs/design/templates/state-banner/danger.svg +1 -1
- package/docs/design/templates/state-banner/info-dark.svg +1 -1
- package/docs/design/templates/state-banner/info.svg +1 -1
- package/docs/design/templates/state-banner/success-dark.svg +1 -1
- package/docs/design/templates/state-banner/success.svg +1 -1
- package/docs/design/templates/state-banner/warning-dark.svg +1 -1
- package/docs/design/templates/state-banner/warning.svg +1 -1
- package/docs/design/templates/state-banner-dark.svg +1 -1
- package/docs/design/templates/state-banner.svg +1 -1
- package/docs/layout.md +5 -0
- package/docs/recipes.md +44 -37
- package/docs/surface-scaffold.md +1 -1
- package/docs/ux-demo.md +6 -2
- package/docs/workbench.md +92 -7
- package/llms.txt +6 -5
- package/package.json +13 -2
- package/ux-demo/recipes/app-shell.tsx +141 -223
- package/ux-demo/recipes/collapsible-sidebar.tsx +44 -75
- package/ux-demo/recipes/list-detail-dialog.tsx +150 -54
- package/ux-demo/recipes/mount-recipe.ts +0 -5
- package/ux-demo/recipes/types.ts +0 -1
- package/dist/chunk-7IUSV4XG.js.map +0 -1
- package/dist/chunk-BJJKFVWW.js.map +0 -1
- package/dist/chunk-HJKRCKDR.js.map +0 -1
- package/dist/chunk-ZK5EGVFP.js.map +0 -1
- package/dist/styles/catalog/components/catalog-detail.css +0 -35
- package/dist/styles/catalog/components/catalog-resource-footer.css +0 -37
- package/dist/styles/catalog/components/catalog-secondary-sections.css +0 -38
- package/dist/styles/catalog/components/catalog-section-list.css +0 -22
- package/dist/styles/catalog/components/catalog-sidebar.css +0 -82
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import '@awesome.me/webawesome/dist/components/button/button.js';
|
|
2
|
+
import '@awesome.me/webawesome/dist/components/divider/divider.js';
|
|
3
|
+
import '@awesome.me/webawesome/dist/components/dropdown-item/dropdown-item.js';
|
|
4
|
+
import WaDropdown from '@awesome.me/webawesome/dist/components/dropdown/dropdown.js';
|
|
5
|
+
|
|
6
|
+
// src/popup-menu-register.ts
|
|
7
|
+
|
|
8
|
+
// src/install-popup-menu-keyboard.ts
|
|
9
|
+
var installed = /* @__PURE__ */ new WeakSet();
|
|
10
|
+
function installPopupMenuKeyboard(prototype) {
|
|
11
|
+
if (installed.has(prototype)) return;
|
|
12
|
+
installed.add(prototype);
|
|
13
|
+
const target = prototype;
|
|
14
|
+
const makeSelection = target.makeSelection;
|
|
15
|
+
target.makeSelection = function(item, event) {
|
|
16
|
+
if (event instanceof KeyboardEvent && this.classList.contains("kui-popup-menu") && !item.disabled) {
|
|
17
|
+
item.click();
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
makeSelection.call(this, item, event);
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// src/popup-menu-register.ts
|
|
25
|
+
installPopupMenuKeyboard(WaDropdown.prototype);
|
|
26
|
+
var popupMenuElementsRegistered = true;
|
|
27
|
+
|
|
28
|
+
export { popupMenuElementsRegistered };
|
|
29
|
+
|
|
30
|
+
//# sourceMappingURL=popup-menu-register.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/install-popup-menu-keyboard.ts","../src/popup-menu-register.ts"],"names":[],"mappings":";;;;;;;;AAOA,IAAM,SAAA,uBAAgB,OAAA,EAAgB;AAW/B,SAAS,yBAAyB,SAAA,EAAyB;AAChE,EAAA,IAAI,SAAA,CAAU,GAAA,CAAI,SAAS,CAAA,EAAG;AAC9B,EAAA,SAAA,CAAU,IAAI,SAAS,CAAA;AACvB,EAAA,MAAM,MAAA,GAAS,SAAA;AACf,EAAA,MAAM,gBAAgB,MAAA,CAAO,aAAA;AAC7B,EAAA,MAAA,CAAO,aAAA,GAAgB,SAAmC,IAAA,EAAM,KAAA,EAAa;AAC3E,IAAA,IACE,KAAA,YAAiB,iBACjB,IAAA,CAAK,SAAA,CAAU,SAAS,gBAAgB,CAAA,IACxC,CAAC,IAAA,CAAK,QAAA,EACN;AACA,MAAA,IAAA,CAAK,KAAA,EAAM;AACX,MAAA;AAAA,IACF;AACA,IAAA,aAAA,CAAc,IAAA,CAAK,IAAA,EAAM,IAAA,EAAM,KAAK,CAAA;AAAA,EACtC,CAAA;AACF;;;AC1BA,wBAAA,CAAyB,WAAW,SAAS,CAAA;AAQtC,IAAM,2BAAA,GAA8B","file":"popup-menu-register.js","sourcesContent":["interface PopupMenuDropdown extends HTMLElement {\n makeSelection(\n item: HTMLElement & { disabled?: boolean },\n event?: Event,\n ): void;\n}\n\nconst installed = new WeakSet<object>();\n\n/**\n * Route a keyboard choice in a `PopupMenu` through the item's click. Web Awesome\n * selects a pointer choice from the item's click event but a keyboard choice\n * (Enter or Space) directly, so delegated `data-action` click handlers would\n * never run for keyboard users. Clicking the item makes Web Awesome select it\n * exactly as it does for a pointer — one `wa-select`, then close and focus\n * return — while the click reaches the application's delegation. Raw\n * `wa-dropdown`s outside `PopupMenu` are unaffected.\n */\nexport function installPopupMenuKeyboard(prototype: object): void {\n if (installed.has(prototype)) return;\n installed.add(prototype);\n const target = prototype as PopupMenuDropdown;\n const makeSelection = target.makeSelection;\n target.makeSelection = function (this: PopupMenuDropdown, item, event): void {\n if (\n event instanceof KeyboardEvent &&\n this.classList.contains('kui-popup-menu') &&\n !item.disabled\n ) {\n item.click();\n return;\n }\n makeSelection.call(this, item, event);\n };\n}\n","import '@awesome.me/webawesome/dist/components/button/button.js';\nimport '@awesome.me/webawesome/dist/components/divider/divider.js';\nimport '@awesome.me/webawesome/dist/components/dropdown-item/dropdown-item.js';\n\nimport WaDropdown from '@awesome.me/webawesome/dist/components/dropdown/dropdown.js';\n\nimport { installPopupMenuKeyboard } from './install-popup-menu-keyboard.js';\n\ninstallPopupMenuKeyboard(WaDropdown.prototype);\n\n/**\n * Marker export for tests and tooling; importing this module registers the\n * Web Awesome elements a `PopupMenu` renders (`wa-dropdown`,\n * `wa-dropdown-item`, `wa-button`, and `wa-divider`) and routes a keyboard\n * choice through the item's click so delegated `data-action`s run.\n */\nexport const popupMenuElementsRegistered = true;\n"]}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { SafeHtml } from 'kerfjs';
|
|
2
|
+
import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
|
|
3
|
+
|
|
4
|
+
type PopupMenuPlacement = 'bottom-start' | 'bottom' | 'bottom-end' | 'top-start' | 'top' | 'top-end';
|
|
5
|
+
type PopupMenuDataAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
|
|
6
|
+
'data-action'?: never;
|
|
7
|
+
'data-component'?: never;
|
|
8
|
+
'data-key'?: never;
|
|
9
|
+
'data-morph-skip-children'?: never;
|
|
10
|
+
}>;
|
|
11
|
+
/** One command in the menu. */
|
|
12
|
+
interface PopupMenuItem {
|
|
13
|
+
kind?: 'item';
|
|
14
|
+
label: string;
|
|
15
|
+
/** Delegated `data-action` the app handles when the item is chosen. */
|
|
16
|
+
action?: string;
|
|
17
|
+
/** Native `wa-dropdown-item` value, reported by its `wa-select` event. */
|
|
18
|
+
value?: string;
|
|
19
|
+
/** Leading icon, typically a `LucideIcon`; it is placed in the item's icon slot. */
|
|
20
|
+
icon?: SafeHtml;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
/** Application `data-*` metadata such as a record id. */
|
|
23
|
+
attributes?: PopupMenuDataAttributes;
|
|
24
|
+
}
|
|
25
|
+
/** A labeled group heading; items that follow it belong to the group. */
|
|
26
|
+
interface PopupMenuHeading {
|
|
27
|
+
kind: 'heading';
|
|
28
|
+
label: string;
|
|
29
|
+
}
|
|
30
|
+
/** A separator between groups of items. */
|
|
31
|
+
interface PopupMenuDivider {
|
|
32
|
+
kind: 'divider';
|
|
33
|
+
}
|
|
34
|
+
type PopupMenuEntry = PopupMenuItem | PopupMenuHeading | PopupMenuDivider;
|
|
35
|
+
type PopupMenuTriggerName = {
|
|
36
|
+
/** Visible trigger text, which is also its accessible name. */
|
|
37
|
+
text: string;
|
|
38
|
+
label?: never;
|
|
39
|
+
} | {
|
|
40
|
+
text?: never;
|
|
41
|
+
/**
|
|
42
|
+
* Accessible name of an icon-only trigger, rendered as visually hidden
|
|
43
|
+
* slotted text (a Web Awesome button takes its name from its content).
|
|
44
|
+
*/
|
|
45
|
+
label: string;
|
|
46
|
+
};
|
|
47
|
+
type PopupMenuProps = PopupMenuTriggerName & {
|
|
48
|
+
/** Trigger icon, typically a `LucideIcon`, before any visible text. */
|
|
49
|
+
icon?: KerfUiContent;
|
|
50
|
+
items: readonly PopupMenuEntry[];
|
|
51
|
+
/** Where the menu opens relative to its trigger. Defaults to `bottom-start`. */
|
|
52
|
+
placement?: PopupMenuPlacement;
|
|
53
|
+
/** Show the disclosure caret after the trigger content. Defaults to true. */
|
|
54
|
+
caret?: boolean;
|
|
55
|
+
disabled?: boolean;
|
|
56
|
+
/** Application `data-*` metadata on the menu root. */
|
|
57
|
+
rootAttributes?: PopupMenuDataAttributes;
|
|
58
|
+
/** Native named-slot assignment when composed inside a web component. */
|
|
59
|
+
slot?: string;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* An action menu: a trigger button that opens a list of commands. Renders the
|
|
63
|
+
* `wa-dropdown` root directly, so a `single` `ToolbarControlGroup` (with
|
|
64
|
+
* `nestedDropdown`) or a `PopupSurface` sizes and insets it as usual. Items
|
|
65
|
+
* dispatch through delegated `data-action`s; the app owns the commands and any
|
|
66
|
+
* open-state reaction. Import `@kerfjs/ui/popup-menu/register` once to register
|
|
67
|
+
* the Web Awesome elements.
|
|
68
|
+
*/
|
|
69
|
+
declare function PopupMenu({ text, label, icon, items, placement, caret, disabled, rootAttributes, slot, }: PopupMenuProps): SafeHtml;
|
|
70
|
+
|
|
71
|
+
export { PopupMenu, type PopupMenuDivider, type PopupMenuEntry, type PopupMenuHeading, type PopupMenuItem, type PopupMenuPlacement, type PopupMenuProps };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"popup-menu.js"}
|
package/dist/state-banner.js
CHANGED
|
@@ -8,19 +8,6 @@
|
|
|
8
8
|
gap: 0.5rem;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
.kui-catalog-example__note {
|
|
12
|
-
margin: 0;
|
|
13
|
-
padding-block: var(--kui-layout-item-padding, 0.5rem);
|
|
14
|
-
padding-inline: calc(
|
|
15
|
-
var(--kui-layout-inline-margin, 0.5rem) +
|
|
16
|
-
var(--kui-layout-item-padding, 0.5rem)
|
|
17
|
-
);
|
|
18
|
-
box-sizing: border-box;
|
|
19
|
-
border: 1px solid transparent;
|
|
20
|
-
color: var(--kui-color-text-quiet);
|
|
21
|
-
font-size: var(--kui-font-xs);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
11
|
.kui-catalog-example__viewport {
|
|
25
12
|
position: relative;
|
|
26
13
|
max-width: 100%;
|
|
@@ -139,9 +126,6 @@
|
|
|
139
126
|
|
|
140
127
|
.kui-catalog-example__compact-fallback {
|
|
141
128
|
display: none;
|
|
142
|
-
margin: 0;
|
|
143
|
-
color: var(--kui-color-text-quiet);
|
|
144
|
-
font-size: var(--kui-font-s);
|
|
145
129
|
}
|
|
146
130
|
|
|
147
131
|
@media ((max-width: 52rem)) {
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
+
/* The preview stage fills the work area's scroller — and grows with a taller
|
|
2
|
+
specimen, never shrinking under it — behind a transparency checkerboard,
|
|
3
|
+
so a specimen's own surface (or lack of one) stays visible. */
|
|
1
4
|
.kui-catalog__stage {
|
|
2
|
-
width: 100%;
|
|
3
|
-
min-height: 0;
|
|
4
5
|
flex: 1 0 auto;
|
|
6
|
+
background-color: var(--kui-color-surface-lowered);
|
|
7
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%238e8e93' fill-opacity='.12' d='M0 0h12v12H0zM12 12h12v12H12z'/%3E%3C/svg%3E");
|
|
8
|
+
background-size: 1.5rem 1.5rem;
|
|
5
9
|
}
|
|
6
10
|
|
|
11
|
+
/* The centered specimen canvas, at the catalog's reading measure. */
|
|
7
12
|
.kui-catalog__canvas {
|
|
8
13
|
position: relative;
|
|
9
14
|
display: grid;
|
|
10
|
-
width: min(100%,
|
|
15
|
+
width: min(100%, 70rem);
|
|
11
16
|
min-width: 0;
|
|
12
17
|
min-height: 100%;
|
|
13
18
|
margin-inline: auto;
|
|
@@ -48,13 +53,3 @@
|
|
|
48
53
|
.kui-catalog__geometry-margin {
|
|
49
54
|
background: color-mix(in srgb, #f6a94c 55%, transparent);
|
|
50
55
|
}
|
|
51
|
-
|
|
52
|
-
@media (max-width: 52rem) {
|
|
53
|
-
.kui-catalog__stage {
|
|
54
|
-
min-height: 24rem;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.kui-catalog__canvas {
|
|
58
|
-
min-height: 16rem;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
@@ -1,22 +1,12 @@
|
|
|
1
|
+
/* The catalog fills its container, which must have a definite height (the
|
|
2
|
+
`document.css` baseline's `.kui-app-root`, as for any Workbench). */
|
|
1
3
|
.kui-catalog {
|
|
2
|
-
|
|
3
|
-
--kui-catalog-content-measure: 70rem;
|
|
4
|
-
|
|
5
|
-
display: grid;
|
|
6
|
-
height: 100vh;
|
|
7
|
-
grid-template-columns: var(--kui-catalog-sidebar-width) minmax(0, 1fr);
|
|
8
|
-
overflow: hidden;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.kui-catalog[data-sidebar-collapsed="true"] {
|
|
12
|
-
grid-template-columns: 0 minmax(0, 1fr);
|
|
4
|
+
height: 100%;
|
|
13
5
|
}
|
|
14
6
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
grid-template-columns: 1fr;
|
|
21
|
-
}
|
|
7
|
+
/* The brand mark, sized to sit inside a toolbar group. */
|
|
8
|
+
.kui-catalog__mark {
|
|
9
|
+
display: block;
|
|
10
|
+
width: 2.125rem;
|
|
11
|
+
height: 2.125rem;
|
|
22
12
|
}
|
package/dist/styles/catalog.css
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
/* Public compatibility entrypoint. Each catalog component owns its styles. */
|
|
2
2
|
@import "./catalog/components/catalog.css";
|
|
3
|
-
@import "./catalog/components/catalog-sidebar.css";
|
|
4
|
-
@import "./catalog/components/catalog-section-list.css";
|
|
5
|
-
@import "./catalog/components/catalog-secondary-sections.css";
|
|
6
|
-
@import "./catalog/components/catalog-detail.css";
|
|
7
3
|
@import "./catalog/components/catalog-stage.css";
|
|
8
|
-
@import "./catalog/components/catalog-resource-footer.css";
|
|
9
4
|
@import "./catalog/components/catalog-example.css";
|
|
10
5
|
@import "./catalog/components/catalog-example-stack.css";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/* An icon-only trigger's accessible name: Web Awesome names its button from the
|
|
2
|
+
slotted content, so the label is present but visually hidden. */
|
|
3
|
+
.kui-popup-menu__label {
|
|
4
|
+
position: absolute;
|
|
5
|
+
width: 1px;
|
|
6
|
+
height: 1px;
|
|
7
|
+
padding: 0;
|
|
8
|
+
overflow: hidden;
|
|
9
|
+
clip: rect(0, 0, 0, 0);
|
|
10
|
+
white-space: nowrap;
|
|
11
|
+
clip-path: inset(50%);
|
|
12
|
+
}
|
|
@@ -179,16 +179,25 @@
|
|
|
179
179
|
> *::before {
|
|
180
180
|
content: "\200b";
|
|
181
181
|
}
|
|
182
|
+
/* The clip lives on an inner span, not on the detail itself. WebKit still
|
|
183
|
+
applies the CSS 2.1 rule that an inline-block whose overflow is not
|
|
184
|
+
`visible` takes its baseline from its bottom margin edge, so a clipped
|
|
185
|
+
inline-block detail rose off the title's baseline there and pushed the
|
|
186
|
+
title and badge down. An inline flex container's baseline is its first
|
|
187
|
+
item's text baseline in every engine, whatever that item's overflow. */
|
|
182
188
|
.kui-state-banner__detail {
|
|
183
|
-
display: inline-
|
|
189
|
+
display: inline-flex;
|
|
184
190
|
max-width: 100%;
|
|
185
|
-
overflow: clip;
|
|
186
191
|
color: var(--_kui-state-banner-detail);
|
|
187
192
|
font-size: var(--kui-font-2xs);
|
|
188
|
-
text-overflow: ellipsis;
|
|
189
193
|
vertical-align: baseline;
|
|
190
194
|
white-space: nowrap;
|
|
191
195
|
}
|
|
196
|
+
.kui-state-banner__detail > span {
|
|
197
|
+
min-width: 0;
|
|
198
|
+
overflow: clip;
|
|
199
|
+
text-overflow: ellipsis;
|
|
200
|
+
}
|
|
192
201
|
.kui-state-banner__action {
|
|
193
202
|
justify-self: end;
|
|
194
203
|
}
|
|
@@ -216,6 +225,6 @@
|
|
|
216
225
|
relationship: a content-sized badge one item gap after the title, on the
|
|
217
226
|
title's baseline. */
|
|
218
227
|
.kui-state-banner__detail {
|
|
219
|
-
display:
|
|
228
|
+
display: flex;
|
|
220
229
|
}
|
|
221
230
|
}
|
package/dist/styles/styles.css
CHANGED
package/dist/styles/tab-bar.css
CHANGED
|
@@ -18,9 +18,11 @@
|
|
|
18
18
|
.kui-tab-bar__tabs {
|
|
19
19
|
display: flex;
|
|
20
20
|
min-width: 0;
|
|
21
|
-
height: var(--kui-toolbar-group-size, calc(2px + 2.625rem));
|
|
21
|
+
min-height: var(--kui-toolbar-group-size, calc(2px + 2.625rem));
|
|
22
22
|
padding: 1px;
|
|
23
|
-
overflow-x
|
|
23
|
+
/* Scroll along the strip only: overflow-x alone computes overflow-y to auto,
|
|
24
|
+
so any vertical excess would let the strip scroll vertically on touch. */
|
|
25
|
+
overflow: auto hidden;
|
|
24
26
|
box-sizing: border-box;
|
|
25
27
|
border: 1px solid var(--kui-tab-bar-border);
|
|
26
28
|
border-radius: var(--kui-layout-pill-radius, calc(1px + 1.3125rem));
|
|
@@ -36,12 +38,38 @@
|
|
|
36
38
|
--kui-tab-bar-background: var(--kui-color-neutral-fill-quiet);
|
|
37
39
|
--kui-tab-bar-border: var(--kui-color-neutral-border-quiet);
|
|
38
40
|
}
|
|
41
|
+
/* A segmented strip's outer ends follow the pill track. The first tab's
|
|
42
|
+
leading corners, and a filled strip's last tab's trailing corners, are
|
|
43
|
+
pill-rounded, and a compact tab is inset from the track's ends by the same
|
|
44
|
+
distance as from its top and bottom, so each end is concentric with the
|
|
45
|
+
track. Only fill allocation carries the last tab to the track's trailing
|
|
46
|
+
end; an intrinsic strip's last tab stops short of it and keeps the segment
|
|
47
|
+
radius, as do the corners between tabs. */
|
|
48
|
+
.kui-tab-bar[data-presentation="segmented"]
|
|
49
|
+
.kui-tab-bar__tabs:has(> [data-component="app-tab"][data-size="compact"]) {
|
|
50
|
+
padding-inline: calc(
|
|
51
|
+
(var(--kui-toolbar-group-size, calc(2px + 2.625rem)) - 2rem) /
|
|
52
|
+
2 - 1px
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
.kui-tab-bar[data-presentation="segmented"]
|
|
56
|
+
.kui-tab-bar__tabs
|
|
57
|
+
> [data-component="app-tab"]:first-child {
|
|
58
|
+
border-start-start-radius: var(--kui-radius-pill);
|
|
59
|
+
border-end-start-radius: var(--kui-radius-pill);
|
|
60
|
+
}
|
|
61
|
+
.kui-tab-bar[data-presentation="segmented"][data-allocation="fill"]
|
|
62
|
+
.kui-tab-bar__tabs
|
|
63
|
+
> [data-component="app-tab"]:last-child {
|
|
64
|
+
border-start-end-radius: var(--kui-radius-pill);
|
|
65
|
+
border-end-end-radius: var(--kui-radius-pill);
|
|
66
|
+
}
|
|
39
67
|
.kui-tab-bar[data-presentation="inspector"] {
|
|
40
68
|
min-height: 2.125rem;
|
|
41
69
|
padding: 0;
|
|
42
70
|
}
|
|
43
71
|
.kui-tab-bar[data-presentation="inspector"] .kui-tab-bar__tabs {
|
|
44
|
-
height: 2.125rem;
|
|
72
|
+
min-height: 2.125rem;
|
|
45
73
|
border-radius: var(--kui-radius-s);
|
|
46
74
|
}
|
|
47
75
|
.kui-tab-bar[data-allocation="fill"] [data-component="app-tab"] {
|
|
@@ -254,6 +254,19 @@
|
|
|
254
254
|
white-space: nowrap;
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
+
/* An icon tile: a non-interactive icon placed directly in a group (a panel
|
|
258
|
+
heading's identity glyph) takes the same 40px slot and 16px visual as an
|
|
259
|
+
icon button, so it centers in the group and lines up with button icons,
|
|
260
|
+
without a hover surface or a focusable control that does nothing. */
|
|
261
|
+
.kui-toolbar-control-group > svg {
|
|
262
|
+
display: block;
|
|
263
|
+
width: 1rem;
|
|
264
|
+
height: 1rem;
|
|
265
|
+
padding: 0.75rem;
|
|
266
|
+
box-sizing: content-box;
|
|
267
|
+
flex: 0 0 auto;
|
|
268
|
+
}
|
|
269
|
+
|
|
257
270
|
.kui-toolbar-control-group > button svg,
|
|
258
271
|
.kui-toolbar-control-group wa-button > svg,
|
|
259
272
|
.kui-toolbar-control-group > .kui-toolbar-action-link svg {
|
package/dist/styles/toolbar.css
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
color: var(--kui-color-text);
|
|
7
7
|
background: transparent;
|
|
8
8
|
grid-template-columns: auto minmax(0, 1fr) auto;
|
|
9
|
-
align-items:
|
|
9
|
+
align-items: start;
|
|
10
10
|
gap: var(--kui-toolbar-gap, 0.5rem);
|
|
11
11
|
container: kui-toolbar / inline-size;
|
|
12
12
|
font-family: var(--kui-font-sans);
|
|
@@ -128,15 +128,56 @@
|
|
|
128
128
|
);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
/* The control band. Every zone reserves one group-height row at the top of
|
|
132
|
+
the toolbar, and each item is centered in that band by its own size, not by
|
|
133
|
+
its siblings: a group or title shorter than the band takes half the
|
|
134
|
+
difference as a top margin, and anything taller (a wrapped title, a
|
|
135
|
+
multi-line search, a second trailing row) starts at the band's top and grows
|
|
136
|
+
down. A growing item therefore never moves the other items or its own top.
|
|
137
|
+
Centering the zones in the toolbar row instead dropped every control to the
|
|
138
|
+
middle of a two-line title. The band is resolved here, on the toolbar, so a
|
|
139
|
+
compact group's own smaller group size never redefines it. */
|
|
140
|
+
.kui-toolbar {
|
|
141
|
+
--_kui-toolbar-band: var(--kui-toolbar-group-size, calc(2px + 2.625rem));
|
|
142
|
+
}
|
|
143
|
+
|
|
131
144
|
.kui-toolbar__leading,
|
|
132
145
|
.kui-toolbar__center,
|
|
133
146
|
.kui-toolbar__trailing {
|
|
134
147
|
display: flex;
|
|
135
148
|
min-width: 0;
|
|
136
|
-
|
|
149
|
+
min-height: var(--_kui-toolbar-band);
|
|
150
|
+
align-items: flex-start;
|
|
137
151
|
gap: var(--kui-toolbar-gap, 0.5rem);
|
|
138
152
|
}
|
|
139
153
|
|
|
154
|
+
:is(.kui-toolbar__leading, .kui-toolbar__center, .kui-toolbar__trailing)
|
|
155
|
+
> [data-component="toolbar-control-group"] {
|
|
156
|
+
margin-block-start: max(
|
|
157
|
+
0px,
|
|
158
|
+
calc(
|
|
159
|
+
(
|
|
160
|
+
var(--_kui-toolbar-band) -
|
|
161
|
+
var(--kui-toolbar-group-size, calc(2px + 2.625rem))
|
|
162
|
+
) /
|
|
163
|
+
2
|
|
164
|
+
)
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* A title fills the band and centers its first line in it; further lines of a
|
|
169
|
+
wrapped title continue below the band. */
|
|
170
|
+
:is(.kui-toolbar__leading, .kui-toolbar__center, .kui-toolbar__trailing)
|
|
171
|
+
> [data-component="toolbar-text"] {
|
|
172
|
+
height: auto;
|
|
173
|
+
min-height: var(--_kui-toolbar-band);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
:is(.kui-toolbar__leading, .kui-toolbar__center, .kui-toolbar__trailing)
|
|
177
|
+
> [data-component="toolbar-text"][data-wrap="true"] {
|
|
178
|
+
padding-block: max(0px, calc((var(--_kui-toolbar-band) - 1.25em) / 2));
|
|
179
|
+
}
|
|
180
|
+
|
|
140
181
|
/* Pin each zone to its column so a display:none (empty) leading or center zone
|
|
141
182
|
doesn't let the trailing zone auto-place into the first column — which left an
|
|
142
183
|
extra gap + empty track to the trailing zone's right (KF-5BEF2M). The trailing
|
|
@@ -187,6 +187,20 @@
|
|
|
187
187
|
--kui-edge-inset-inline-end: 0px;
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
+
/* A region whose only child is a Pane or layout lets it fill the region, so a
|
|
191
|
+
composed toolbar's footer (or the app's own) sits at the region's bottom
|
|
192
|
+
edge rather than under short content. */
|
|
193
|
+
:is(.kui-workbench__main, .kui-workbench__panel-content)
|
|
194
|
+
> :is(
|
|
195
|
+
[data-component="pane"],
|
|
196
|
+
[data-component="nav-stack"],
|
|
197
|
+
[data-component="split-view"],
|
|
198
|
+
[data-component="workbench"],
|
|
199
|
+
[data-component="tab-scaffold"]
|
|
200
|
+
):only-child {
|
|
201
|
+
height: 100%;
|
|
202
|
+
}
|
|
203
|
+
|
|
190
204
|
/* Bottom drawer — the vertical analogue of a rail. */
|
|
191
205
|
.kui-workbench__drawer {
|
|
192
206
|
--kui-edge-inset-block-start: 0px;
|
|
@@ -779,3 +793,20 @@
|
|
|
779
793
|
transition: none;
|
|
780
794
|
}
|
|
781
795
|
}
|
|
796
|
+
|
|
797
|
+
/* On a compact (phone-sized) Workbench an overlay rail fills the Workbench
|
|
798
|
+
less a dismiss margin on the side away from its edge, so a press beside it
|
|
799
|
+
closes it (the wiring's outside press); `compactOverlay: "full"` fills the
|
|
800
|
+
Workbench. The rail's resize and configured size stop applying there. */
|
|
801
|
+
@container kui-workbench (max-width: 28rem) {
|
|
802
|
+
.kui-workbench__rail[data-responsive-overlay-at] {
|
|
803
|
+
width: calc(
|
|
804
|
+
100% - var(--kui-workbench-overlay-dismiss-margin, 2.75rem)
|
|
805
|
+
);
|
|
806
|
+
max-width: none;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
.kui-workbench__rail[data-responsive-overlay-at][data-compact-overlay="full"] {
|
|
810
|
+
width: 100%;
|
|
811
|
+
}
|
|
812
|
+
}
|
package/dist/text.js
CHANGED
|
@@ -20,6 +20,15 @@ interface TokenSearchFieldBaseProps {
|
|
|
20
20
|
label: string;
|
|
21
21
|
query?: string;
|
|
22
22
|
tokens?: readonly TokenSearchToken[];
|
|
23
|
+
/**
|
|
24
|
+
* Editor identity for a programmatic text replacement. The editor's text is
|
|
25
|
+
* DOM-owned between token changes, so a new `query` with the same tokens
|
|
26
|
+
* does not re-render it (that would reset the caret on every keystroke).
|
|
27
|
+
* Change `revision` when the app replaces the text itself — reseeding a
|
|
28
|
+
* persistent dialog's field on reopen, applying a saved search — and the
|
|
29
|
+
* editor is rebuilt from `query` and `tokens`.
|
|
30
|
+
*/
|
|
31
|
+
revision?: string | number;
|
|
23
32
|
placeholder?: string;
|
|
24
33
|
tokenPlaceholder?: string;
|
|
25
34
|
disabled?: boolean;
|
|
@@ -55,7 +64,7 @@ interface TokenSearchFieldValue {
|
|
|
55
64
|
query: string;
|
|
56
65
|
tokens: TokenSearchToken[];
|
|
57
66
|
}
|
|
58
|
-
declare function TokenSearchField({ id, label, query, tokens, placeholder, tokenPlaceholder, disabled, autofocus, collapsible, expanded, expandAction, expandLabel, leading, trailing, presentation, editAction, removeAction, clearAction, clearLabel, className, editorAttributes, slot, }: TokenSearchFieldProps): kerfjs.SafeHtml;
|
|
67
|
+
declare function TokenSearchField({ id, label, query, tokens, revision, placeholder, tokenPlaceholder, disabled, autofocus, collapsible, expanded, expandAction, expandLabel, leading, trailing, presentation, editAction, removeAction, clearAction, clearLabel, className, editorAttributes, slot, }: TokenSearchFieldProps): kerfjs.SafeHtml;
|
|
59
68
|
/** Read editable text and ordered token offsets from a rendered TokenSearchField editor. */
|
|
60
69
|
declare function readTokenSearchField(editor: HTMLElement, knownTokens?: readonly TokenSearchToken[]): TokenSearchFieldValue;
|
|
61
70
|
/** Focus an editor and place its caret at a text offset, skipping atomic token chips. */
|
|
@@ -44,6 +44,11 @@ type CatalogStageRootAttributes = Readonly<Record<`data-${string}`, string | und
|
|
|
44
44
|
'data-catalog-stage'?: never;
|
|
45
45
|
}>;
|
|
46
46
|
interface CatalogProps {
|
|
47
|
+
/**
|
|
48
|
+
* The catalog's `id` (default `kui-catalog`). Its Workbench derives the
|
|
49
|
+
* sidebar's id from it (`<id>-left-rail`), which `wireCatalog` wires.
|
|
50
|
+
*/
|
|
51
|
+
id?: string;
|
|
47
52
|
brand: CatalogBrand;
|
|
48
53
|
sections: readonly CatalogSection[];
|
|
49
54
|
active: string;
|
|
@@ -61,6 +66,16 @@ interface CatalogProps {
|
|
|
61
66
|
toggleSidebarAction?: string;
|
|
62
67
|
toggleThemeAction?: string;
|
|
63
68
|
toggleSecondaryAction?: string;
|
|
69
|
+
/**
|
|
70
|
+
* Whether the entry toolbar stays pinned above the preview (`fixed`,
|
|
71
|
+
* default) or scrolls away with it (`scroll`).
|
|
72
|
+
*/
|
|
73
|
+
headerPlacement?: 'fixed' | 'scroll';
|
|
74
|
+
/**
|
|
75
|
+
* Whether the status and resource footer stays pinned below the preview
|
|
76
|
+
* (`fixed`, default) or scrolls with it (`scroll`).
|
|
77
|
+
*/
|
|
78
|
+
footerPlacement?: 'fixed' | 'scroll';
|
|
64
79
|
className?: string;
|
|
65
80
|
/** Native named-slot assignment when composed inside a web component. */
|
|
66
81
|
slot?: string;
|
package/dist/wire-catalog.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Signal } from 'kerfjs';
|
|
2
|
+
|
|
1
3
|
interface WireCatalogOptions {
|
|
2
4
|
/** Invoked with the entry id when a sidebar item or a related-entry option is chosen. */
|
|
3
5
|
onSelect: (id: string) => void;
|
|
@@ -18,6 +20,16 @@ interface WireCatalogOptions {
|
|
|
18
20
|
toggleSidebarAction?: string;
|
|
19
21
|
toggleThemeAction?: string;
|
|
20
22
|
toggleSecondaryAction?: string;
|
|
23
|
+
/**
|
|
24
|
+
* The sidebar's app-owned collapsed flag. With it, the catalog's Workbench
|
|
25
|
+
* sidebar is wired like any Workbench rail: it becomes a transient overlay
|
|
26
|
+
* on a small screen (collapsed as the breakpoint applies, closed on Escape
|
|
27
|
+
* or a press outside, focus handed back), and choosing an entry from the
|
|
28
|
+
* open overlay closes it.
|
|
29
|
+
*/
|
|
30
|
+
collapsed?: Signal<boolean>;
|
|
31
|
+
/** The Catalog's `id`, when it is not the default `kui-catalog`. */
|
|
32
|
+
id?: string;
|
|
21
33
|
}
|
|
22
34
|
interface CatalogRevealOptions {
|
|
23
35
|
/** Scroll alignment within the sidebar. Default `'nearest'`. */
|
|
@@ -52,6 +64,6 @@ declare function wireCatalogGeometryOverlay(root: HTMLElement): () => void;
|
|
|
52
64
|
* them in the callbacks; optionally mirror the active id into the URL via `urlParam`.
|
|
53
65
|
* Returns a disposer.
|
|
54
66
|
*/
|
|
55
|
-
declare function wireCatalog(root: HTMLElement, { onSelect, onToggleSidebar, onToggleTheme, onToggleSecondary, urlParam, revealSelection, selectAction, toggleSidebarAction, toggleThemeAction, toggleSecondaryAction, }: WireCatalogOptions): () => void;
|
|
67
|
+
declare function wireCatalog(root: HTMLElement, { onSelect, onToggleSidebar, onToggleTheme, onToggleSecondary, urlParam, revealSelection, selectAction, toggleSidebarAction, toggleThemeAction, toggleSecondaryAction, collapsed, id: catalogId, }: WireCatalogOptions): () => void;
|
|
56
68
|
|
|
57
69
|
export { type CatalogRevealOptions, type WireCatalogOptions, revealCatalogEntry, wireCatalog, wireCatalogGeometryOverlay };
|
package/dist/wire-catalog.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { wireWorkbench } from './chunk-KH6VUGHU.js';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
1
5
|
import { delegate } from 'kerfjs';
|
|
2
6
|
|
|
3
|
-
|
|
4
|
-
var catalogDesktopMedia = "(min-width: 52.01rem)";
|
|
7
|
+
var catalogDesktopMedia = "(min-width: 44.01rem)";
|
|
5
8
|
function revealCatalogEntry(root, id, {
|
|
6
9
|
block = "nearest",
|
|
7
10
|
inline = "nearest",
|
|
@@ -228,7 +231,9 @@ function wireCatalog(root, {
|
|
|
228
231
|
selectAction = "catalog-select",
|
|
229
232
|
toggleSidebarAction = "catalog-toggle-sidebar",
|
|
230
233
|
toggleThemeAction = "catalog-toggle-theme",
|
|
231
|
-
toggleSecondaryAction = "catalog-toggle-secondary"
|
|
234
|
+
toggleSecondaryAction = "catalog-toggle-secondary",
|
|
235
|
+
collapsed,
|
|
236
|
+
id: catalogId = "kui-catalog"
|
|
232
237
|
}) {
|
|
233
238
|
let cancelReveal;
|
|
234
239
|
const select = (id) => {
|
|
@@ -239,6 +244,9 @@ function wireCatalog(root, {
|
|
|
239
244
|
url.searchParams.set(urlParam, id);
|
|
240
245
|
view.history.replaceState(null, "", url);
|
|
241
246
|
}
|
|
247
|
+
const rail = root.ownerDocument.getElementById(`${catalogId}-left-rail`);
|
|
248
|
+
if (collapsed && !collapsed.peek() && rail && root.ownerDocument.defaultView?.getComputedStyle(rail).position === "absolute")
|
|
249
|
+
collapsed.value = true;
|
|
242
250
|
if (revealSelection) {
|
|
243
251
|
cancelReveal?.();
|
|
244
252
|
cancelReveal = revealCatalogEntry(
|
|
@@ -291,6 +299,13 @@ function wireCatalog(root, {
|
|
|
291
299
|
)
|
|
292
300
|
);
|
|
293
301
|
}
|
|
302
|
+
if (collapsed)
|
|
303
|
+
disposers.push(
|
|
304
|
+
wireWorkbench(root, {
|
|
305
|
+
id: catalogId,
|
|
306
|
+
panels: { leftRail: { collapsed } }
|
|
307
|
+
})
|
|
308
|
+
);
|
|
294
309
|
return () => {
|
|
295
310
|
cancelReveal?.();
|
|
296
311
|
for (const dispose of disposers.splice(0)) dispose();
|