@kerfjs/ui 5.0.0-beta.58 → 5.0.0-beta.59

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 (53) hide show
  1. package/README.md +11 -1
  2. package/ai/component-catalog.json +48 -15
  3. package/ai/component-catalog.schema.json +16 -0
  4. package/ai/component-composition.json +16 -2
  5. package/ai/components/README.md +2 -2
  6. package/ai/components/popup-menu.md +96 -7
  7. package/ai/components/text.md +3 -3
  8. package/ai/components/token-search-field.md +6 -4
  9. package/ai/public-api-signatures-v1.md +49 -81
  10. package/ai/skill.md +5 -1
  11. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  12. package/dist/catalog.js +3 -3
  13. package/dist/chunk-F7F7KRO2.js +187 -0
  14. package/dist/chunk-F7F7KRO2.js.map +1 -0
  15. package/dist/{chunk-63ZWBGE3.js → chunk-RRB26JRJ.js} +25 -3
  16. package/dist/chunk-RRB26JRJ.js.map +1 -0
  17. package/dist/{chunk-NBYTIVHS.js → chunk-UFYZHYWU.js} +118 -12
  18. package/dist/chunk-UFYZHYWU.js.map +1 -0
  19. package/dist/{chunk-WLG6SSNT.js → chunk-UWONG4QE.js} +41 -8
  20. package/dist/chunk-UWONG4QE.js.map +1 -0
  21. package/dist/{chunk-553ASUK6.js → chunk-UX2VVXZ3.js} +2 -2
  22. package/dist/{chunk-553ASUK6.js.map → chunk-UX2VVXZ3.js.map} +1 -1
  23. package/dist/{chunk-24PHKUR3.js → chunk-UXT7TE6B.js} +1 -1
  24. package/dist/chunk-UXT7TE6B.js.map +1 -0
  25. package/dist/index.d.ts +2 -2
  26. package/dist/index.js +6 -5
  27. package/dist/list-header.js +1 -1
  28. package/dist/popup-menu.d.ts +31 -3
  29. package/dist/popup-menu.js +1 -1
  30. package/dist/styles/popup-menu.css +33 -4
  31. package/dist/styles/text.css +8 -0
  32. package/dist/styles/token-search-field.css +29 -0
  33. package/dist/text.d.ts +1 -1
  34. package/dist/text.js +1 -1
  35. package/dist/token-search-field-CCke1yvQ.d.ts +126 -0
  36. package/dist/token-search-field.d.ts +3 -75
  37. package/dist/token-search-field.js +1 -1
  38. package/dist/token-search-model.d.ts +3 -0
  39. package/dist/token-search-model.js +3 -0
  40. package/dist/token-search-model.js.map +1 -0
  41. package/dist/wire-token-search-fields.d.ts +5 -1
  42. package/dist/wire-token-search-fields.js +1 -1
  43. package/docs/accessibility.md +14 -0
  44. package/docs/component-contract.md +2 -1
  45. package/docs/component-integration.md +8 -1
  46. package/docs/component-selection.md +40 -0
  47. package/docs/layout.md +4 -1
  48. package/llms.txt +6 -3
  49. package/package.json +5 -1
  50. package/dist/chunk-24PHKUR3.js.map +0 -1
  51. package/dist/chunk-63ZWBGE3.js.map +0 -1
  52. package/dist/chunk-NBYTIVHS.js.map +0 -1
  53. package/dist/chunk-WLG6SSNT.js.map +0 -1
@@ -18,9 +18,19 @@ interface PopupMenuItem {
18
18
  value?: string;
19
19
  /** Leading icon, typically a `LucideIcon`; it is placed in the item's icon slot. */
20
20
  icon?: SafeHtml;
21
+ /** A checked menu choice, including nested choices. */
22
+ checked?: boolean;
23
+ /** Trailing safe content, such as a selected-choice tick. */
24
+ details?: SafeHtml;
25
+ /** Destructive command styling. */
26
+ tone?: 'default' | 'danger';
21
27
  disabled?: boolean;
28
+ /** Native tooltip text for a disabled command. */
29
+ disabledReason?: string;
22
30
  /** Application `data-*` metadata such as a record id. */
23
31
  attributes?: PopupMenuDataAttributes;
32
+ /** Child commands opened by hover or keyboard navigation. */
33
+ submenu?: readonly PopupMenuItem[];
24
34
  }
25
35
  /** A labeled group heading; items that follow it belong to the group. */
26
36
  interface PopupMenuHeading {
@@ -44,7 +54,17 @@ type PopupMenuTriggerName = {
44
54
  */
45
55
  label: string;
46
56
  };
47
- type PopupMenuProps = PopupMenuTriggerName & {
57
+ type PopupMenuTrigger = (PopupMenuTriggerName & {
58
+ context?: false;
59
+ }) | {
60
+ context: true;
61
+ label: string;
62
+ text?: never;
63
+ icon?: never;
64
+ caret?: never;
65
+ disabled?: never;
66
+ };
67
+ type PopupMenuProps = PopupMenuTrigger & {
48
68
  /** Trigger icon, typically a `LucideIcon`, before any visible text. */
49
69
  icon?: KerfUiContent;
50
70
  items: readonly PopupMenuEntry[];
@@ -58,6 +78,14 @@ type PopupMenuProps = PopupMenuTriggerName & {
58
78
  /** Native named-slot assignment when composed inside a web component. */
59
79
  slot?: string;
60
80
  };
81
+ /** A rendered context PopupMenu with Web Awesome's controlled open state. */
82
+ type PopupMenuElement = HTMLElement & {
83
+ open: boolean;
84
+ };
85
+ /** Open a context PopupMenu at viewport pointer coordinates. */
86
+ declare function openPopupMenuAt(menu: PopupMenuElement, x: number, y: number): void;
87
+ /** Close a programmatically opened PopupMenu. */
88
+ declare function closePopupMenu(menu: PopupMenuElement): void;
61
89
  /**
62
90
  * An action menu: a trigger button that opens a list of commands. Renders the
63
91
  * `wa-dropdown` root directly, so a `single` `ToolbarControlGroup` (with
@@ -66,6 +94,6 @@ type PopupMenuProps = PopupMenuTriggerName & {
66
94
  * open-state reaction. Import `@kerfjs/ui/popup-menu/register` once to register
67
95
  * the Web Awesome elements.
68
96
  */
69
- declare function PopupMenu({ text, label, icon, items, placement, caret, disabled, rootAttributes, slot, }: PopupMenuProps): SafeHtml;
97
+ declare function PopupMenu({ text, label, icon, items, placement, caret, disabled, rootAttributes, slot, context, }: PopupMenuProps): SafeHtml;
70
98
 
71
- export { PopupMenu, type PopupMenuDivider, type PopupMenuEntry, type PopupMenuHeading, type PopupMenuItem, type PopupMenuPlacement, type PopupMenuProps };
99
+ export { PopupMenu, type PopupMenuDivider, type PopupMenuElement, type PopupMenuEntry, type PopupMenuHeading, type PopupMenuItem, type PopupMenuPlacement, type PopupMenuProps, closePopupMenu, openPopupMenuAt };
@@ -1,3 +1,3 @@
1
- export { PopupMenu } from './chunk-WLG6SSNT.js';
1
+ export { PopupMenu, closePopupMenu, openPopupMenuAt } from './chunk-UWONG4QE.js';
2
2
 
3
3
  //# sourceMappingURL=popup-menu.js.map
@@ -33,7 +33,7 @@
33
33
  scale: none !important;
34
34
  }
35
35
 
36
- .kui-popup-menu > wa-dropdown-item {
36
+ .kui-popup-menu wa-dropdown-item {
37
37
  /* Leading inset plus the Select's check column, so item icons and labels
38
38
  start where a Select option's do. */
39
39
  padding: var(--_kui-popup-row-padding-block)
@@ -43,13 +43,13 @@
43
43
  var(--_kui-popup-row-check-width)
44
44
  );
45
45
  }
46
- .kui-popup-menu > wa-dropdown-item::part(label) {
46
+ .kui-popup-menu wa-dropdown-item::part(label) {
47
47
  padding-block: var(--_kui-popup-row-label-padding-block);
48
48
  line-height: var(--_kui-popup-row-label-line-height);
49
49
  }
50
50
  /* A keyboard-focused item is the menu's current row: the Select's brand fill,
51
51
  with no second focus ring inside the open popup. */
52
- .kui-popup-menu > wa-dropdown-item:focus-visible {
52
+ .kui-popup-menu wa-dropdown-item:focus-visible {
53
53
  outline: none;
54
54
  color: var(--_kui-popup-row-current-color);
55
55
  background-color: var(--_kui-popup-row-current-background);
@@ -59,7 +59,7 @@
59
59
  }
60
60
 
61
61
  /* Center the icon on the label's line, like the Select's start slot. */
62
- .kui-popup-menu > wa-dropdown-item::part(icon) {
62
+ .kui-popup-menu wa-dropdown-item::part(icon) {
63
63
  display: flex;
64
64
  align-self: center;
65
65
  }
@@ -78,6 +78,35 @@
78
78
  height: 100%;
79
79
  }
80
80
 
81
+ .kui-popup-menu__details {
82
+ display: inline-flex;
83
+ align-items: center;
84
+ }
85
+
86
+ .kui-popup-menu__details svg {
87
+ display: block;
88
+ width: var(--_kui-popup-row-icon-size);
89
+ height: var(--_kui-popup-row-icon-size);
90
+ }
91
+
92
+ .kui-popup-menu[data-trigger="context"] {
93
+ display: inline-block;
94
+ width: 0;
95
+ height: 0;
96
+ }
97
+
98
+ .kui-popup-menu__context-anchor {
99
+ position: fixed;
100
+ top: var(--kui-popup-menu-context-y, 0px);
101
+ left: var(--kui-popup-menu-context-x, 0px);
102
+ width: 1px;
103
+ height: 1px;
104
+ padding: 0;
105
+ border: 0;
106
+ opacity: 0;
107
+ pointer-events: none;
108
+ }
109
+
81
110
  /* A group title matches the Select's group title. It is a styled element
82
111
  rather than a slotted heading, whose Web Awesome metrics are !important. */
83
112
  .kui-popup-menu__heading {
@@ -17,6 +17,14 @@
17
17
  font-size: var(--kui-font-xs);
18
18
  }
19
19
 
20
+ .kui-text[data-size="large"] {
21
+ font-size: var(--kui-font-l);
22
+ }
23
+
24
+ .kui-text[data-size="xlarge"] {
25
+ font-size: var(--kui-font-2xl);
26
+ }
27
+
20
28
  .kui-text[data-font="monospace"] {
21
29
  font-family: var(--kui-font-mono);
22
30
  }
@@ -145,6 +145,35 @@
145
145
  grid-column: 4;
146
146
  }
147
147
 
148
+ .kui-token-search__suggestions {
149
+ display: grid;
150
+ grid-column: 2 / -1;
151
+ min-width: 0;
152
+ padding: 0.25rem;
153
+ border: 1px solid var(--kui-token-search-border);
154
+ border-radius: var(--kui-radius-pill);
155
+ background: var(--kui-token-search-background);
156
+ gap: 0.125rem;
157
+ }
158
+
159
+ .kui-token-search__suggestion {
160
+ width: 100%;
161
+ padding: 0.375rem 0.5rem;
162
+ border: 0;
163
+ border-radius: var(--kui-radius-pill);
164
+ color: var(--kui-color-text);
165
+ background: transparent;
166
+ font: inherit;
167
+ text-align: start;
168
+ cursor: pointer;
169
+ }
170
+
171
+ .kui-token-search__suggestion:hover,
172
+ .kui-token-search__suggestion:focus-visible {
173
+ background: var(--kui-color-surface-lowered);
174
+ outline: var(--kui-focus-ring);
175
+ }
176
+
148
177
  .kui-token-search[data-has-trailing="false"] .kui-token-search__clear {
149
178
  grid-column: 4;
150
179
  }
package/dist/text.d.ts CHANGED
@@ -4,7 +4,7 @@ import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
4
4
 
5
5
  type TextVariant = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span';
6
6
  type TextTone = 'default' | 'quiet' | 'danger';
7
- type TextSize = 'default' | 'compact';
7
+ type TextSize = 'compact' | 'default' | 'large' | 'xlarge';
8
8
  type TextFont = 'default' | 'monospace';
9
9
  type TextBorder = 'transparent' | 'none';
10
10
  type TextContent = KerfUiContent | string | number | readonly TextContent[];
package/dist/text.js CHANGED
@@ -1,3 +1,3 @@
1
- export { Text } from './chunk-24PHKUR3.js';
1
+ export { Text } from './chunk-UXT7TE6B.js';
2
2
 
3
3
  //# sourceMappingURL=text.js.map
@@ -0,0 +1,126 @@
1
+ import { Signal, SafeHtml } from 'kerfjs';
2
+ import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
3
+
4
+ interface TokenSearchRule {
5
+ /** The word before `:` (for example `tag` or `status`). */
6
+ name: string;
7
+ /** Return a canonical value, or undefined to leave invalid input as text. */
8
+ parse?: (input: string) => string | undefined;
9
+ /** Label for a committed chip. Defaults to `name:input`. */
10
+ label?: (value: string, input: string) => string;
11
+ /** Suggestions for the unfinished value after `name:`. */
12
+ suggest?: (input: string) => readonly (string | {
13
+ value: string;
14
+ label: string;
15
+ })[];
16
+ }
17
+ interface TokenSearchResolvedToken extends TokenSearchToken {
18
+ kind: string;
19
+ parsedValue: string;
20
+ }
21
+ interface TokenSearchState {
22
+ query: string;
23
+ tokens: TokenSearchResolvedToken[];
24
+ }
25
+ interface TokenSearchSuggestion {
26
+ value: string;
27
+ label: string;
28
+ }
29
+ interface TokenSearchModel<Result = unknown> {
30
+ state: Signal<TokenSearchState>;
31
+ /** Changes when a model action must replace DOM-owned editor text. */
32
+ editorRevision: Signal<number>;
33
+ suggestions: Signal<readonly TokenSearchSuggestion[]>;
34
+ result: Signal<Result | undefined>;
35
+ edit(value: TokenSearchFieldValue, commit?: boolean): void;
36
+ submit(value: TokenSearchFieldValue): void;
37
+ choose(value: string): void;
38
+ expandToken(value: string): void;
39
+ remove(value: string): void;
40
+ clear(): void;
41
+ dismiss(): void;
42
+ }
43
+ interface TokenSearchModelOptions<Result> {
44
+ rules?: readonly TokenSearchRule[];
45
+ initial?: TokenSearchFieldValue;
46
+ /** Runs after every state change, including initial state. */
47
+ evaluate?: (state: TokenSearchState) => Result;
48
+ onSubmit?: (state: TokenSearchState, result: Result | undefined) => void;
49
+ }
50
+ /** Opt-in state, token parsing, suggestions, and evaluation for TokenSearchField. */
51
+ declare function createTokenSearchModel<Result = unknown>({ rules, initial, evaluate, onSubmit, }?: TokenSearchModelOptions<Result>): TokenSearchModel<Result>;
52
+
53
+ interface TokenSearchToken {
54
+ value: string;
55
+ label: string;
56
+ offset?: number;
57
+ accessibleLabel?: string;
58
+ }
59
+ type TokenSearchEditorAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
60
+ 'data-component'?: never;
61
+ 'data-key'?: never;
62
+ 'data-morph-skip'?: never;
63
+ 'data-token-search-editor'?: never;
64
+ 'data-token-count'?: never;
65
+ 'data-placeholder'?: never;
66
+ }>;
67
+ interface TokenSearchFieldBaseProps {
68
+ id: string;
69
+ label: string;
70
+ query?: string;
71
+ tokens?: readonly TokenSearchToken[];
72
+ /** Opt-in grammar, suggestion, and evaluation state. Overrides `query` and `tokens`. */
73
+ model?: TokenSearchModel;
74
+ /**
75
+ * Editor identity for a programmatic text replacement. The editor's text is
76
+ * DOM-owned between token changes, so a new `query` with the same tokens
77
+ * does not re-render it (that would reset the caret on every keystroke).
78
+ * Change `revision` when the app replaces the text itself — reseeding a
79
+ * persistent dialog's field on reopen, applying a saved search — and the
80
+ * editor is rebuilt from `query` and `tokens`.
81
+ */
82
+ revision?: string | number;
83
+ placeholder?: string;
84
+ tokenPlaceholder?: string;
85
+ disabled?: boolean;
86
+ autofocus?: boolean;
87
+ leading?: KerfUiContent;
88
+ trailing?: KerfUiContent;
89
+ /** Standalone field chrome or the inset visual layer of a configured toolbar group. */
90
+ presentation?: 'standalone' | 'toolbar-group';
91
+ editAction?: string;
92
+ removeAction?: string;
93
+ clearAction?: string;
94
+ clearLabel?: string;
95
+ /** Icon for the clear button. Default: the Lucide `x` glyph token chips also use. */
96
+ clearIcon?: SafeHtml;
97
+ className?: string;
98
+ editorAttributes?: TokenSearchEditorAttributes;
99
+ /** Native named-slot assignment when composed inside a web component. */
100
+ slot?: string;
101
+ }
102
+ type TokenSearchCollapsibleProps = {
103
+ /** Allow an empty field to render as one iconic action. */
104
+ collapsible: true;
105
+ /** Keep an empty collapsible field open while the application owns focus. */
106
+ expanded?: boolean;
107
+ expandAction?: string;
108
+ expandLabel?: string;
109
+ } | {
110
+ collapsible?: false;
111
+ expanded?: never;
112
+ expandAction?: never;
113
+ expandLabel?: never;
114
+ };
115
+ type TokenSearchFieldProps = TokenSearchFieldBaseProps & TokenSearchCollapsibleProps;
116
+ interface TokenSearchFieldValue {
117
+ query: string;
118
+ tokens: TokenSearchToken[];
119
+ }
120
+ declare function TokenSearchField({ id, label, query, tokens, model, revision, placeholder, tokenPlaceholder, disabled, autofocus, collapsible, expanded, expandAction, expandLabel, leading, trailing, presentation, editAction, removeAction, clearAction, clearLabel, clearIcon, className, editorAttributes, slot, }: TokenSearchFieldProps): SafeHtml;
121
+ /** Read editable text and ordered token offsets from a rendered TokenSearchField editor. */
122
+ declare function readTokenSearchField(editor: HTMLElement, knownTokens?: readonly TokenSearchToken[]): TokenSearchFieldValue;
123
+ /** Focus an editor and place its caret at a text offset, skipping atomic token chips. */
124
+ declare function placeTokenSearchCaret(editor: HTMLElement, offset?: number): void;
125
+
126
+ export { type TokenSearchEditorAttributes as T, TokenSearchField as a, type TokenSearchFieldProps as b, type TokenSearchFieldValue as c, type TokenSearchModel as d, type TokenSearchModelOptions as e, type TokenSearchResolvedToken as f, type TokenSearchRule as g, type TokenSearchState as h, type TokenSearchSuggestion as i, type TokenSearchToken as j, createTokenSearchModel as k, placeTokenSearchCaret as p, readTokenSearchField as r };
@@ -1,75 +1,3 @@
1
- import { SafeHtml } from 'kerfjs';
2
- import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
3
-
4
- interface TokenSearchToken {
5
- value: string;
6
- label: string;
7
- offset?: number;
8
- accessibleLabel?: string;
9
- }
10
- type TokenSearchEditorAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
11
- 'data-component'?: never;
12
- 'data-key'?: never;
13
- 'data-morph-skip'?: never;
14
- 'data-token-search-editor'?: never;
15
- 'data-token-count'?: never;
16
- 'data-placeholder'?: never;
17
- }>;
18
- interface TokenSearchFieldBaseProps {
19
- id: string;
20
- label: string;
21
- query?: string;
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;
32
- placeholder?: string;
33
- tokenPlaceholder?: string;
34
- disabled?: boolean;
35
- autofocus?: boolean;
36
- leading?: KerfUiContent;
37
- trailing?: KerfUiContent;
38
- /** Standalone field chrome or the inset visual layer of a configured toolbar group. */
39
- presentation?: 'standalone' | 'toolbar-group';
40
- editAction?: string;
41
- removeAction?: string;
42
- clearAction?: string;
43
- clearLabel?: string;
44
- /** Icon for the clear button. Default: the Lucide `x` glyph token chips also use. */
45
- clearIcon?: SafeHtml;
46
- className?: string;
47
- editorAttributes?: TokenSearchEditorAttributes;
48
- /** Native named-slot assignment when composed inside a web component. */
49
- slot?: string;
50
- }
51
- type TokenSearchCollapsibleProps = {
52
- /** Allow an empty field to render as one iconic action. */
53
- collapsible: true;
54
- /** Keep an empty collapsible field open while the application owns focus. */
55
- expanded?: boolean;
56
- expandAction?: string;
57
- expandLabel?: string;
58
- } | {
59
- collapsible?: false;
60
- expanded?: never;
61
- expandAction?: never;
62
- expandLabel?: never;
63
- };
64
- type TokenSearchFieldProps = TokenSearchFieldBaseProps & TokenSearchCollapsibleProps;
65
- interface TokenSearchFieldValue {
66
- query: string;
67
- tokens: TokenSearchToken[];
68
- }
69
- declare function TokenSearchField({ id, label, query, tokens, revision, placeholder, tokenPlaceholder, disabled, autofocus, collapsible, expanded, expandAction, expandLabel, leading, trailing, presentation, editAction, removeAction, clearAction, clearLabel, clearIcon, className, editorAttributes, slot, }: TokenSearchFieldProps): SafeHtml;
70
- /** Read editable text and ordered token offsets from a rendered TokenSearchField editor. */
71
- declare function readTokenSearchField(editor: HTMLElement, knownTokens?: readonly TokenSearchToken[]): TokenSearchFieldValue;
72
- /** Focus an editor and place its caret at a text offset, skipping atomic token chips. */
73
- declare function placeTokenSearchCaret(editor: HTMLElement, offset?: number): void;
74
-
75
- export { type TokenSearchEditorAttributes, TokenSearchField, type TokenSearchFieldProps, type TokenSearchFieldValue, type TokenSearchToken, placeTokenSearchCaret, readTokenSearchField };
1
+ import 'kerfjs';
2
+ import './semantic-content-BbzjvSu9.js';
3
+ export { T as TokenSearchEditorAttributes, a as TokenSearchField, b as TokenSearchFieldProps, c as TokenSearchFieldValue, j as TokenSearchToken, p as placeTokenSearchCaret, r as readTokenSearchField } from './token-search-field-CCke1yvQ.js';
@@ -1,4 +1,4 @@
1
- export { TokenSearchField, placeTokenSearchCaret, readTokenSearchField } from './chunk-63ZWBGE3.js';
1
+ export { TokenSearchField, placeTokenSearchCaret, readTokenSearchField } from './chunk-RRB26JRJ.js';
2
2
 
3
3
 
4
4
  //# sourceMappingURL=token-search-field.js.map
@@ -0,0 +1,3 @@
1
+ import 'kerfjs';
2
+ export { d as TokenSearchModel, e as TokenSearchModelOptions, f as TokenSearchResolvedToken, g as TokenSearchRule, h as TokenSearchState, i as TokenSearchSuggestion, k as createTokenSearchModel } from './token-search-field-CCke1yvQ.js';
3
+ import './semantic-content-BbzjvSu9.js';
@@ -0,0 +1,3 @@
1
+ export { createTokenSearchModel } from './chunk-F7F7KRO2.js';
2
+
3
+ //# sourceMappingURL=token-search-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"token-search-model.js"}
@@ -1,4 +1,6 @@
1
1
  import { Signal } from 'kerfjs';
2
+ import { d as TokenSearchModel } from './token-search-field-CCke1yvQ.js';
3
+ import './semantic-content-BbzjvSu9.js';
2
4
 
3
5
  interface TokenSearchSubmit {
4
6
  id: string;
@@ -76,6 +78,8 @@ interface TokenSearchCollapsibleOptions {
76
78
  signals?: Readonly<Record<string, Signal<boolean>>>;
77
79
  }
78
80
  interface WireTokenSearchFieldsOptions {
81
+ /** Optional automatic grammar/suggestion models, keyed by TokenSearchField id. */
82
+ models?: Readonly<Record<string, TokenSearchModel>>;
79
83
  onSubmit?: (submission: TokenSearchSubmit) => void;
80
84
  /** Fired on every editor `input`, after the browser mutates it, so a caller can drop its own `input` listener. */
81
85
  onEdit?: (edit: TokenSearchEdit) => void;
@@ -106,6 +110,6 @@ interface TokenSearchFieldsHandle {
106
110
  * expand/collapse/focus. Returns a {@link TokenSearchFieldsHandle} — a disposer that also
107
111
  * exposes the managed `expanded` state per field id.
108
112
  */
109
- declare function wireTokenSearchFields(root: HTMLElement, { onSubmit, onEdit, collapsible, keyboard, }?: WireTokenSearchFieldsOptions): TokenSearchFieldsHandle;
113
+ declare function wireTokenSearchFields(root: HTMLElement, { models, onSubmit, onEdit, collapsible, keyboard, }?: WireTokenSearchFieldsOptions): TokenSearchFieldsHandle;
110
114
 
111
115
  export { type TokenSearchCollapsibleOptions, type TokenSearchEdit, type TokenSearchFieldsHandle, type TokenSearchKeyboardOptions, type TokenSearchSubmit, type TokenSearchTokenRemoval, type WireTokenSearchFieldsOptions, wireTokenSearchFields };
@@ -1,4 +1,4 @@
1
- export { wireTokenSearchFields } from './chunk-NBYTIVHS.js';
1
+ export { wireTokenSearchFields } from './chunk-UFYZHYWU.js';
2
2
 
3
3
 
4
4
 
@@ -195,6 +195,12 @@ are presentational. A keyboard-focused item is the menu's current row, painted
195
195
  with the Select's current-option fill rather than a second focus ring inside the
196
196
  open popup. A disabled item stays in the menu but cannot be
197
197
  chosen; disable the whole trigger only when every command is unavailable.
198
+ Nested items use Web Awesome's submenu pointer and Left/Right arrow routing;
199
+ checked items expose checkbox menu semantics. `details` supplies optional
200
+ trailing visual content without changing a command's accessible label. A
201
+ `context` menu's invisible anchor is outside the accessibility tree and normal
202
+ Tab order; opening the menu moves focus into its commands and Escape dismisses
203
+ it. Keep a separate visible row action named even when it is disabled.
198
204
 
199
205
  ## ListActionRow
200
206
 
@@ -405,6 +411,14 @@ originating `InputEvent` so a caller can gate on `inputType`/`data` — fires on
405
411
  `input`, letting a caller drop its own `input` listener; the application still
406
412
  owns query parsing and result-count/loading announcements.
407
413
 
414
+ With a `createTokenSearchModel` passed to the field and registered in
415
+ `wireTokenSearchFields(root, { models })`, grammar parsing, chips, clear/edit/
416
+ remove actions, and suggestions are managed. Arrow Down moves from the editor
417
+ to suggestions, arrow keys move between suggestions, Enter selects one, and
418
+ Escape returns focus to the editor. The application still announces results
419
+ when needed and can supply an `evaluate` callback to compute them. Omitting the
420
+ model leaves the manual behavior above intact.
421
+
408
422
  Managed clear captures the action before application handlers run, keeps the adopted
409
423
  expanded signal open during editor replacement, and restores focus at the actual
410
424
  mutation checkpoint before the next input task. It also returns keyboard activation
@@ -50,7 +50,8 @@ responsive ownership, layout and geometry, accessibility obligations, public
50
50
  CSS boundaries, diagnostics, and provenance. A wrapper entry may add
51
51
  `rendersAs`: the cataloged roots it renders (any one of them, or nothing), so
52
52
  composition checks treat its elements as each root rather than as an unknown
53
- child.
53
+ child. A placement with listed parent constraints produces one `KUI-L201`
54
+ diagnostic even when both the wrapper and a rendered root reject that parent.
54
55
 
55
56
  `boundaries.placeableClasses` names the subset of `publicClasses` an
56
57
  application may write onto its own elements (layout utilities, the document
@@ -33,7 +33,14 @@ For each catalog component, the validator checks:
33
33
  The existing catalog sync and compatibility gates remain responsible for the
34
34
  typed catalog projections, catalog count/order, and artifact digests. Public
35
35
  API signatures derive component subpaths from the catalog, so a newly cataloged
36
- component can no longer be silently omitted from that corpus.
36
+ component can no longer be silently omitted from that corpus. Overrides in
37
+ `publicExportImports` also add their subpaths to the signature reference.
38
+
39
+ Generated component pages group `publicExports` by import subpath. Exports use
40
+ the component `delivery.browserImport` or `delivery.moduleImport` by default;
41
+ set `publicExportImports` for helpers shipped from a different subpath. The
42
+ catalog check verifies each override names a public export and a package
43
+ subpath, and the generated Props section links each relevant signature.
37
44
 
38
45
  Non-component helpers, wiring modules, compositions, recipes, and development
39
46
  tools remain explicit package surfaces. They do not masquerade as visual
@@ -210,6 +210,8 @@ an upstream component or recipe request.
210
210
  hidden compact replacement and keeps compact overlays exclusive by default.
211
211
  - `TokenSearchField` is a structured editor. A native input or `wa-input` is the right answer for ordinary text.
212
212
 
213
+ For common structured search, use `createTokenSearchModel` from `@kerfjs/ui/token-search-model`, pass the model to `TokenSearchField`, and register it under the field id in `wireTokenSearchFields(root, { models })`. Rules parse `name:value` expressions and provide suggestions; the model owns chips, selection, removal, clear, and an optional evaluation result. Omit `model` and `models` for full manual control.
214
+
213
215
  ## Toolbar composition
214
216
 
215
217
  A `Toolbar` has three zones — `leading`, `center`, and `trailing`. In almost
@@ -250,6 +252,8 @@ Common toolbar patterns:
250
252
  | A command menu | `<ToolbarControlGroup single nestedDropdown><PopupMenu … /></ToolbarControlGroup>` | Register `@kerfjs/ui/popup-menu/register` once; set `menuInset` on the group |
251
253
  | A collapsible search box | `<ToolbarControlGroup single><TokenSearchField collapsible … /></ToolbarControlGroup>` | The group animates the iconic ↔ expanded states; `wireTokenSearchFields` manages expand/collapse/focus by default |
252
254
 
255
+ ### Popup menu migration
256
+
253
257
  A **popup menu in a toolbar** is a `PopupMenu` (`@kerfjs/ui/popup-menu`) in a
254
258
  `single` `ToolbarControlGroup` with `nestedDropdown`; the group sizes the trigger
255
259
  as a toolbar button and `menuInset` sets the menu's inset. `PopupMenu` renders the
@@ -271,6 +275,42 @@ menu.
271
275
  </ToolbarControlGroup>
272
276
  ```
273
277
 
278
+ Nested decisions use an item with `submenu`. Children keep their own actions,
279
+ `attributes` metadata, icons, `checked` state, disabled state and
280
+ `disabledReason` tooltip. `tone: 'danger'` maps to the Web Awesome destructive
281
+ variant. A parent can sit among ordinary commands and dividers, so the same
282
+ items shape covers single-line and batch actions; compute each batch child's
283
+ `disabled` state from the current selection.
284
+
285
+ ```tsx
286
+ <PopupMenu
287
+ label="Line actions"
288
+ items={[
289
+ { label: 'Copy reference', action: 'copy-reference', attributes: { 'data-item-id': lineId } },
290
+ { label: 'Decide', submenu: [
291
+ { label: 'Approve', action: 'decide', checked: current === 'approve', attributes: { 'data-item-id': lineId, 'data-decision': 'approve' } },
292
+ { label: 'Reject', action: 'decide', tone: 'danger', disabled: needsPrice, disabledReason: needsPrice ? 'Add a price first' : undefined, attributes: { 'data-item-id': lineId, 'data-decision': 'reject' } },
293
+ ] },
294
+ { kind: 'divider' },
295
+ { label: 'Remove', action: 'remove', tone: 'danger' },
296
+ ]}
297
+ />
298
+ ```
299
+
300
+ For a flat command menu with persistent sort choices, group commands under
301
+ `heading` entries and set `details` to a safe trailing tick for the chosen
302
+ item. Set `checked` when checkbox menu semantics fit. Commands still dispatch
303
+ their own `data-action` once on pointer and keyboard selection.
304
+
305
+ For a row opened by right-click, render `PopupMenu` with `context`, `label`,
306
+ and a stable root `data-*` marker. Its trigger is an invisible anchor removed
307
+ from the accessibility tree; a separate visible button may stay disabled. In
308
+ the app's `contextmenu` handler, find that root, call `openPopupMenuAt` with
309
+ the menu and `event.clientX` / `event.clientY`, and prevent the browser
310
+ menu. Call `closePopupMenu` for programmatic dismissal. The pointer anchor
311
+ retains Web Awesome's collision placement, focus management, submenu keyboard
312
+ navigation, and outside/Escape dismissal.
313
+
274
314
  ## Configuring recurring list rows
275
315
 
276
316
  Configure the List family instead of selecting its descendant classes. Use
package/docs/layout.md CHANGED
@@ -285,7 +285,8 @@ rail) and pane identity should stay quiet.
285
285
 
286
286
  Presentation is independent of the native element: use `tone="quiet"` for
287
287
  supporting copy, `tone="danger"` for error or validation copy, `size="compact"`
288
- for compact metadata, and `font="monospace"` for code or identifiers (the
288
+ for compact metadata, `size="large"` for prominent copy, `size="xlarge"` for
289
+ display copy, and `font="monospace"` for code or identifiers (the
289
290
  `--kui-font-mono` stack, which Kerf owns even with Web Awesome loaded). These
290
291
  finite props compose with each other and with every semantic `variant`; omit
291
292
  them to inherit the surrounding color, size, and font.
@@ -297,6 +298,8 @@ import { Text } from "@kerfjs/ui/text";
297
298
  <Text variant="h3">Notifications</Text>; // normal-color subsection title
298
299
  <Text aria-describedby="details-title">Supporting copy</Text>;
299
300
  <Text tone="quiet" size="compact">Updated yesterday</Text>;
301
+ <Text size="large">A prominent summary</Text>;
302
+ <Text variant="h2" size="xlarge">A display-sized section title</Text>;
300
303
  <strong>Inbox<Text variant="span" tone="quiet" size="compact"> · 3 msg</Text></strong>;
301
304
  <Text tone="danger" font="monospace">ERR_INVALID_ID</Text>;
302
305
  ```
package/llms.txt CHANGED
@@ -242,7 +242,10 @@ headingLevel`, `TokenSearchField clearIcon`, `ContentItem frame="framed"` for a
242
242
  (`@kerfjs/ui/popup-menu`, registered once via `@kerfjs/ui/popup-menu/register`)
243
243
  in a `single` `ToolbarControlGroup` with `nestedDropdown`; never hand-write
244
244
  `wa-dropdown` markup for a menu. Let the group size the trigger from its icon,
245
- localized text, and caret; do not force a dropdown or button width. Nothing
245
+ localized text, and caret. `PopupMenu` items also support nested `submenu`
246
+ actions, checked or trailing choice marks, danger tone, and disabled reasons;
247
+ use `context` with `openPopupMenuAt`/`closePopupMenu` for pointer-anchored row
248
+ menus. Do not force a dropdown or button width. Nothing
246
249
  wraps inside a group: an icon sits beside its label on one row, and a
247
250
  `ToolbarText` is one ellipsized line unless you opt into `wrap`/`maxLines`. A
248
251
  Select or PopupMenu trigger drops its focus ring while its popup is open and
@@ -265,8 +268,8 @@ headingLevel`, `TokenSearchField clearIcon`, `ContentItem frame="framed"` for a
265
268
  text outside toolbar title zones.** Omit `variant` for the default `p`, pass
266
269
  `h1`–`h6` based on the document outline, or use `variant="span"` inside a row,
267
270
  label, or table cell without adding box geometry. Independently compose `tone="quiet|danger"`,
268
- `size="compact"`, and `font="monospace"` for supporting, error, compact, and
269
- code roles instead of global utility classes. It passes native attributes
271
+ `size="compact|large|xlarge"`, and `font="monospace"` for supporting, error,
272
+ compact, prominent, display, and code roles instead of global utility classes. It passes native attributes
270
273
  through; block variants own the standard transparent border plus item padding, while `span` owns none. Keep
271
274
  toolbar titles on `ToolbarText` and list-aligned bare prose on `ListInsetText`.
272
275
  - **Space by the five-step scale, by relationship not by eye.** `0`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kerfjs/ui",
3
- "version": "5.0.0-beta.58",
3
+ "version": "5.0.0-beta.59",
4
4
  "description": "Accessible, composable UI primitives for kerf applications.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -281,6 +281,10 @@
281
281
  "browser": "./dist/browser/token-search-field.js",
282
282
  "import": "./dist/token-search-field.js"
283
283
  },
284
+ "./token-search-model": {
285
+ "types": "./dist/token-search-model.d.ts",
286
+ "import": "./dist/token-search-model.js"
287
+ },
284
288
  "./wire-token-search-fields": {
285
289
  "types": "./dist/wire-token-search-fields.d.ts",
286
290
  "import": "./dist/wire-token-search-fields.js"
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/text.tsx"],"names":[],"mappings":";;;AAsCO,SAAS,IAAA,CAAK;AAAA,EACnB,SAAS,OAAA,GAAU,GAAA;AAAA,EACnB,IAAA,GAAO,SAAA;AAAA,EACP,IAAA,GAAO,SAAA;AAAA,EACP,IAAA,GAAO,SAAA;AAAA,EACP,MAAA,GAAS,aAAA;AAAA,EACT,QAAA;AAAA,EACA,OAAO,UAAA,GAAa,EAAA;AAAA,EACpB,SAAA,GAAY,EAAA;AAAA,EACZ,GAAG;AACL,CAAA,EAAc;AACZ,EAAA,MAAM,OAAA,GAAU,CAAC,UAAA,EAAY,UAAA,EAAY,SAAS,EAAE,MAAA,CAAO,OAAO,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AAC5E,EAAA,uBACE,GAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACE,GAAG,UAAA;AAAA,MACJ,KAAA,EAAO,OAAA;AAAA,MACP,gBAAA,EAAe,MAAA;AAAA,MACf,WAAA,EAAW,IAAA;AAAA,MACX,WAAA,EAAW,IAAA;AAAA,MACX,WAAA,EAAW,IAAA;AAAA,MACX,aAAA,EAAa,MAAA;AAAA,MAEZ;AAAA;AAAA,GACH;AAEJ","file":"chunk-24PHKUR3.js","sourcesContent":["import type { KerfBaseAttrs } from 'kerfjs/jsx-runtime';\n\nimport type { KerfUiContent } from './semantic-content.js';\n\nexport type TextVariant =\n 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span';\nexport type TextTone = 'default' | 'quiet' | 'danger';\nexport type TextSize = 'default' | 'compact';\nexport type TextFont = 'default' | 'monospace';\nexport type TextBorder = 'transparent' | 'none';\n\nexport type TextContent =\n KerfUiContent | string | number | readonly TextContent[];\n\nexport type TextProps = Omit<\n KerfBaseAttrs,\n 'children' | 'class' | 'className'\n> & {\n /** Native heading, paragraph, or inline span element to render. Defaults to `p`. */\n variant?: TextVariant;\n /** Semantic foreground treatment. Defaults to the inherited foreground. */\n tone?: TextTone;\n /** Text sizing independent of the native semantic element. */\n size?: TextSize;\n /** Font family independent of the native semantic element. */\n font?: TextFont;\n /** Transparent alignment border or no border when embedded in owner chrome. */\n border?: TextBorder;\n children: TextContent;\n class?: string;\n className?: string;\n};\n\n/**\n * Semantic heading, paragraph, or inline text. Block variants use the standard\n * content-item padding; `span` adds no box geometry.\n * All ordinary native heading/paragraph attributes pass through to the element.\n */\nexport function Text({\n variant: Variant = 'p',\n tone = 'default',\n size = 'default',\n font = 'default',\n border = 'transparent',\n children,\n class: classValue = '',\n className = '',\n ...attributes\n}: TextProps) {\n const classes = ['kui-text', classValue, className].filter(Boolean).join(' ');\n return (\n <Variant\n {...attributes}\n class={classes}\n data-component=\"text\"\n data-tone={tone}\n data-size={size}\n data-font={font}\n data-border={border}\n >\n {children}\n </Variant>\n );\n}\n"]}