@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.
- package/README.md +11 -1
- package/ai/component-catalog.json +48 -15
- package/ai/component-catalog.schema.json +16 -0
- package/ai/component-composition.json +16 -2
- package/ai/components/README.md +2 -2
- package/ai/components/popup-menu.md +96 -7
- package/ai/components/text.md +3 -3
- package/ai/components/token-search-field.md +6 -4
- package/ai/public-api-signatures-v1.md +49 -81
- package/ai/skill.md +5 -1
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/dist/catalog.js +3 -3
- package/dist/chunk-F7F7KRO2.js +187 -0
- package/dist/chunk-F7F7KRO2.js.map +1 -0
- package/dist/{chunk-63ZWBGE3.js → chunk-RRB26JRJ.js} +25 -3
- package/dist/chunk-RRB26JRJ.js.map +1 -0
- package/dist/{chunk-NBYTIVHS.js → chunk-UFYZHYWU.js} +118 -12
- package/dist/chunk-UFYZHYWU.js.map +1 -0
- package/dist/{chunk-WLG6SSNT.js → chunk-UWONG4QE.js} +41 -8
- package/dist/chunk-UWONG4QE.js.map +1 -0
- package/dist/{chunk-553ASUK6.js → chunk-UX2VVXZ3.js} +2 -2
- package/dist/{chunk-553ASUK6.js.map → chunk-UX2VVXZ3.js.map} +1 -1
- package/dist/{chunk-24PHKUR3.js → chunk-UXT7TE6B.js} +1 -1
- package/dist/chunk-UXT7TE6B.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +6 -5
- package/dist/list-header.js +1 -1
- package/dist/popup-menu.d.ts +31 -3
- package/dist/popup-menu.js +1 -1
- package/dist/styles/popup-menu.css +33 -4
- package/dist/styles/text.css +8 -0
- package/dist/styles/token-search-field.css +29 -0
- package/dist/text.d.ts +1 -1
- package/dist/text.js +1 -1
- package/dist/token-search-field-CCke1yvQ.d.ts +126 -0
- package/dist/token-search-field.d.ts +3 -75
- package/dist/token-search-field.js +1 -1
- package/dist/token-search-model.d.ts +3 -0
- package/dist/token-search-model.js +3 -0
- package/dist/token-search-model.js.map +1 -0
- package/dist/wire-token-search-fields.d.ts +5 -1
- package/dist/wire-token-search-fields.js +1 -1
- package/docs/accessibility.md +14 -0
- package/docs/component-contract.md +2 -1
- package/docs/component-integration.md +8 -1
- package/docs/component-selection.md +40 -0
- package/docs/layout.md +4 -1
- package/llms.txt +6 -3
- package/package.json +5 -1
- package/dist/chunk-24PHKUR3.js.map +0 -1
- package/dist/chunk-63ZWBGE3.js.map +0 -1
- package/dist/chunk-NBYTIVHS.js.map +0 -1
- package/dist/chunk-WLG6SSNT.js.map +0 -1
package/dist/popup-menu.d.ts
CHANGED
|
@@ -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
|
|
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 };
|
package/dist/popup-menu.js
CHANGED
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
scale: none !important;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
.kui-popup-menu
|
|
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
|
|
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
|
|
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
|
|
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 {
|
package/dist/styles/text.css
CHANGED
|
@@ -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' | '
|
|
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
|
@@ -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
|
|
2
|
-
import
|
|
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';
|
|
@@ -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 @@
|
|
|
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 };
|
package/docs/accessibility.md
CHANGED
|
@@ -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,
|
|
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
|
|
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,
|
|
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.
|
|
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"]}
|