@unofficialbox/box-open-elements 0.5.0 → 0.6.0
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 -3
- package/dist/components/collections/table.d.ts +57 -3
- package/dist/components/collections/table.js +339 -20
- package/dist/components/feedback/due-badge.d.ts +38 -0
- package/dist/components/feedback/due-badge.js +168 -0
- package/dist/components/feedback/due-types.d.ts +32 -0
- package/dist/components/feedback/due-types.js +91 -0
- package/dist/components/feedback/progress-steps.d.ts +51 -5
- package/dist/components/feedback/progress-steps.js +200 -22
- package/dist/components/feedback/stage-path.d.ts +44 -0
- package/dist/components/feedback/stage-path.js +235 -0
- package/dist/components/forms/select.d.ts +21 -0
- package/dist/components/forms/select.js +100 -3
- package/dist/components/forms/text-field.d.ts +21 -0
- package/dist/components/forms/text-field.js +100 -1
- package/dist/components/layout/nav-sidebar.d.ts +14 -0
- package/dist/components/layout/nav-sidebar.js +49 -0
- package/dist/components/layout/split-view.d.ts +14 -0
- package/dist/components/layout/split-view.js +80 -1
- package/dist/components/overlays/command-palette.d.ts +62 -0
- package/dist/components/overlays/command-palette.js +537 -0
- package/dist/components/overlays/command-types.d.ts +90 -0
- package/dist/components/overlays/command-types.js +259 -0
- package/dist/components/overlays/drawer.d.ts +18 -0
- package/dist/components/overlays/drawer.js +135 -9
- package/dist/components/overlays/shortcuts-overlay.d.ts +48 -0
- package/dist/components/overlays/shortcuts-overlay.js +385 -0
- package/dist/components/overlays/tooltip.js +1 -1
- package/dist/element-maps.d.ts +292 -0
- package/dist/element-maps.js +1 -0
- package/dist/entries/activity-density.d.ts +1 -0
- package/dist/entries/activity-density.js +1 -0
- package/dist/entries/agent-chat.d.ts +1 -0
- package/dist/entries/agent-chat.js +1 -0
- package/dist/entries/audit-log.d.ts +1 -0
- package/dist/entries/audit-log.js +1 -0
- package/dist/entries/command-palette.d.ts +1 -0
- package/dist/entries/command-palette.js +1 -0
- package/dist/entries/compare-view.d.ts +1 -0
- package/dist/entries/compare-view.js +1 -0
- package/dist/entries/diff-viewer.d.ts +1 -0
- package/dist/entries/diff-viewer.js +1 -0
- package/dist/entries/due-badge.d.ts +1 -0
- package/dist/entries/due-badge.js +1 -0
- package/dist/entries/form-wizard.d.ts +1 -0
- package/dist/entries/form-wizard.js +1 -0
- package/dist/entries/lineage-graph.d.ts +1 -0
- package/dist/entries/lineage-graph.js +1 -0
- package/dist/entries/notification-bell.d.ts +1 -0
- package/dist/entries/notification-bell.js +1 -0
- package/dist/entries/notification-inbox.d.ts +1 -0
- package/dist/entries/notification-inbox.js +1 -0
- package/dist/entries/provenance-strip.d.ts +1 -0
- package/dist/entries/provenance-strip.js +1 -0
- package/dist/entries/run-trace.d.ts +1 -0
- package/dist/entries/run-trace.js +1 -0
- package/dist/entries/shortcuts-overlay.d.ts +1 -0
- package/dist/entries/shortcuts-overlay.js +1 -0
- package/dist/entries/signature-ceremony.d.ts +1 -0
- package/dist/entries/signature-ceremony.js +1 -0
- package/dist/entries/stage-path.d.ts +1 -0
- package/dist/entries/stage-path.js +1 -0
- package/dist/entries/timeline.d.ts +1 -0
- package/dist/entries/timeline.js +1 -0
- package/dist/entries/version-graph.d.ts +1 -0
- package/dist/entries/version-graph.js +1 -0
- package/dist/entries/version-list.d.ts +1 -0
- package/dist/entries/version-list.js +1 -0
- package/dist/entries/wizard-summary.d.ts +1 -0
- package/dist/entries/wizard-summary.js +1 -0
- package/dist/entries/work-queue.d.ts +1 -0
- package/dist/entries/work-queue.js +1 -0
- package/dist/entries/workload-board.d.ts +1 -0
- package/dist/entries/workload-board.js +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +21 -0
- package/dist/patterns/agent-chat/agent-chat.d.ts +75 -0
- package/dist/patterns/agent-chat/agent-chat.js +820 -0
- package/dist/patterns/agent-chat/controller.d.ts +27 -0
- package/dist/patterns/agent-chat/controller.js +182 -0
- package/dist/patterns/agent-chat/index.d.ts +3 -0
- package/dist/patterns/agent-chat/index.js +6 -0
- package/dist/patterns/agent-chat/types.d.ts +109 -0
- package/dist/patterns/agent-chat/types.js +1 -0
- package/dist/patterns/audit/activity-density.d.ts +68 -0
- package/dist/patterns/audit/activity-density.js +428 -0
- package/dist/patterns/audit/audit-log.d.ts +81 -0
- package/dist/patterns/audit/audit-log.js +794 -0
- package/dist/patterns/audit/index.d.ts +3 -0
- package/dist/patterns/audit/index.js +7 -0
- package/dist/patterns/audit/shared.d.ts +10 -0
- package/dist/patterns/audit/shared.js +50 -0
- package/dist/patterns/audit/types.d.ts +143 -0
- package/dist/patterns/audit/types.js +327 -0
- package/dist/patterns/content-explorer/actions/controller.js +12 -2
- package/dist/patterns/content-explorer/box-transport.js +117 -25
- package/dist/patterns/content-explorer/content-explorer.d.ts +13 -1
- package/dist/patterns/content-explorer/content-explorer.js +36 -3
- package/dist/patterns/content-explorer/contracts.d.ts +24 -1
- package/dist/patterns/content-explorer/contracts.js +68 -11
- package/dist/patterns/content-explorer/controller.d.ts +16 -1
- package/dist/patterns/content-explorer/controller.js +130 -4
- package/dist/patterns/content-explorer/navigation/controller.js +11 -9
- package/dist/patterns/content-explorer/types.d.ts +58 -1
- package/dist/patterns/content-picker/content-picker.d.ts +71 -0
- package/dist/patterns/content-picker/content-picker.js +747 -0
- package/dist/patterns/content-picker/controller.d.ts +38 -0
- package/dist/patterns/content-picker/controller.js +141 -0
- package/dist/patterns/content-picker/index.d.ts +3 -0
- package/dist/patterns/content-picker/index.js +6 -0
- package/dist/patterns/content-picker/types.d.ts +52 -0
- package/dist/patterns/content-picker/types.js +26 -0
- package/dist/patterns/content-sidebar/content-sidebar.d.ts +43 -0
- package/dist/patterns/content-sidebar/content-sidebar.js +293 -0
- package/dist/patterns/content-sidebar/index.d.ts +2 -0
- package/dist/patterns/content-sidebar/index.js +4 -0
- package/dist/patterns/content-sidebar/types.d.ts +18 -0
- package/dist/patterns/content-sidebar/types.js +20 -0
- package/dist/patterns/content-uploader/box-transport.d.ts +14 -0
- package/dist/patterns/content-uploader/box-transport.js +54 -0
- package/dist/patterns/content-uploader/content-uploader.d.ts +62 -0
- package/dist/patterns/content-uploader/content-uploader.js +559 -0
- package/dist/patterns/content-uploader/controller.d.ts +39 -0
- package/dist/patterns/content-uploader/controller.js +227 -0
- package/dist/patterns/content-uploader/index.d.ts +4 -0
- package/dist/patterns/content-uploader/index.js +8 -0
- package/dist/patterns/content-uploader/types.d.ts +120 -0
- package/dist/patterns/content-uploader/types.js +38 -0
- package/dist/patterns/diff/compare-view.d.ts +47 -0
- package/dist/patterns/diff/compare-view.js +276 -0
- package/dist/patterns/diff/diff-viewer.d.ts +42 -0
- package/dist/patterns/diff/diff-viewer.js +434 -0
- package/dist/patterns/diff/engine.d.ts +22 -0
- package/dist/patterns/diff/engine.js +276 -0
- package/dist/patterns/diff/index.d.ts +4 -0
- package/dist/patterns/diff/index.js +8 -0
- package/dist/patterns/diff/types.d.ts +69 -0
- package/dist/patterns/diff/types.js +24 -0
- package/dist/patterns/form-wizard/controller.d.ts +39 -0
- package/dist/patterns/form-wizard/controller.js +157 -0
- package/dist/patterns/form-wizard/form-wizard.d.ts +63 -0
- package/dist/patterns/form-wizard/form-wizard.js +468 -0
- package/dist/patterns/form-wizard/index.d.ts +4 -0
- package/dist/patterns/form-wizard/index.js +8 -0
- package/dist/patterns/form-wizard/types.d.ts +109 -0
- package/dist/patterns/form-wizard/types.js +83 -0
- package/dist/patterns/form-wizard/wizard-summary.d.ts +62 -0
- package/dist/patterns/form-wizard/wizard-summary.js +324 -0
- package/dist/patterns/internal/safe-href.d.ts +17 -0
- package/dist/patterns/internal/safe-href.js +17 -0
- package/dist/patterns/lineage/index.d.ts +3 -0
- package/dist/patterns/lineage/index.js +6 -0
- package/dist/patterns/lineage/lineage-graph.d.ts +30 -0
- package/dist/patterns/lineage/lineage-graph.js +434 -0
- package/dist/patterns/lineage/provenance-strip.d.ts +22 -0
- package/dist/patterns/lineage/provenance-strip.js +194 -0
- package/dist/patterns/lineage/types.d.ts +53 -0
- package/dist/patterns/lineage/types.js +49 -0
- package/dist/patterns/notifications/index.d.ts +3 -0
- package/dist/patterns/notifications/index.js +6 -0
- package/dist/patterns/notifications/notification-bell.d.ts +38 -0
- package/dist/patterns/notifications/notification-bell.js +198 -0
- package/dist/patterns/notifications/notification-inbox.d.ts +46 -0
- package/dist/patterns/notifications/notification-inbox.js +537 -0
- package/dist/patterns/notifications/types.d.ts +61 -0
- package/dist/patterns/notifications/types.js +108 -0
- package/dist/patterns/preview/annotation-inspector.d.ts +25 -6
- package/dist/patterns/preview/annotation-inspector.js +239 -94
- package/dist/patterns/preview/annotation-thread.d.ts +25 -5
- package/dist/patterns/preview/annotation-thread.js +233 -82
- package/dist/patterns/preview/annotation-toolbar.d.ts +20 -6
- package/dist/patterns/preview/annotation-toolbar.js +162 -96
- package/dist/patterns/preview/content-preview-adapter.d.ts +10 -1
- package/dist/patterns/preview/content-preview-adapter.js +26 -1
- package/dist/patterns/preview/preview-element.d.ts +15 -2
- package/dist/patterns/preview/preview-element.js +223 -52
- package/dist/patterns/preview/provider-adapter.d.ts +47 -0
- package/dist/patterns/preview/provider-adapter.js +17 -0
- package/dist/patterns/run/index.d.ts +2 -0
- package/dist/patterns/run/index.js +4 -0
- package/dist/patterns/run/run-trace.d.ts +40 -0
- package/dist/patterns/run/run-trace.js +441 -0
- package/dist/patterns/run/types.d.ts +66 -0
- package/dist/patterns/run/types.js +152 -0
- package/dist/patterns/signature/index.d.ts +2 -0
- package/dist/patterns/signature/index.js +4 -0
- package/dist/patterns/signature/signature-ceremony.d.ts +33 -0
- package/dist/patterns/signature/signature-ceremony.js +317 -0
- package/dist/patterns/signature/types.d.ts +68 -0
- package/dist/patterns/signature/types.js +89 -0
- package/dist/patterns/timeline/index.d.ts +2 -0
- package/dist/patterns/timeline/index.js +4 -0
- package/dist/patterns/timeline/timeline.d.ts +27 -0
- package/dist/patterns/timeline/timeline.js +430 -0
- package/dist/patterns/timeline/types.d.ts +36 -0
- package/dist/patterns/timeline/types.js +27 -0
- package/dist/patterns/versions/graph-layout.d.ts +43 -0
- package/dist/patterns/versions/graph-layout.js +159 -0
- package/dist/patterns/versions/index.d.ts +4 -0
- package/dist/patterns/versions/index.js +8 -0
- package/dist/patterns/versions/shared.d.ts +4 -0
- package/dist/patterns/versions/shared.js +13 -0
- package/dist/patterns/versions/types.d.ts +37 -0
- package/dist/patterns/versions/types.js +39 -0
- package/dist/patterns/versions/version-graph.d.ts +36 -0
- package/dist/patterns/versions/version-graph.js +438 -0
- package/dist/patterns/versions/version-list.d.ts +39 -0
- package/dist/patterns/versions/version-list.js +407 -0
- package/dist/patterns/work-queue/controller.d.ts +26 -0
- package/dist/patterns/work-queue/controller.js +150 -0
- package/dist/patterns/work-queue/index.d.ts +4 -0
- package/dist/patterns/work-queue/index.js +7 -0
- package/dist/patterns/work-queue/types.d.ts +128 -0
- package/dist/patterns/work-queue/types.js +45 -0
- package/dist/patterns/work-queue/work-queue.d.ts +48 -0
- package/dist/patterns/work-queue/work-queue.js +534 -0
- package/dist/patterns/work-queue/workload-board.d.ts +53 -0
- package/dist/patterns/work-queue/workload-board.js +608 -0
- package/package.json +89 -5
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { FormAssociatedElement, boeFormFieldErrorStyles, boeFormFieldSupportStyles, formDataFromNamedValues, formDescriptionMarkup, formErrorMessageMarkup, stringValuesFromFormValue, } from "../../core/index.js";
|
|
2
2
|
import { boeControl, boeRadius, boeSpace } from "../../foundations/geometry/index.js";
|
|
3
|
+
import { boeMotionDuration, boeMotionEasing, boeReducedMotionStyles, } from "../../foundations/motion/index.js";
|
|
3
4
|
const DEFAULT_TAG_NAME = "box-select";
|
|
5
|
+
/** Attribute payloads are author input — validate every record. */
|
|
6
|
+
const isSelectOptionRecord = (value) => {
|
|
7
|
+
if (typeof value !== "object" || value === null) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
const option = value;
|
|
11
|
+
return typeof option.value === "string" && typeof option.label === "string";
|
|
12
|
+
};
|
|
4
13
|
const escapeHtml = (value) => value
|
|
5
14
|
.replaceAll("&", "&")
|
|
6
15
|
.replaceAll("<", "<")
|
|
@@ -77,16 +86,56 @@ const selectStyles = `
|
|
|
77
86
|
border-radius: ${boeRadius.size};
|
|
78
87
|
}
|
|
79
88
|
|
|
89
|
+
/* Control wrapper exists for the trailing status; with no status it is
|
|
90
|
+
layout-neutral. */
|
|
91
|
+
[part="control"] {
|
|
92
|
+
position: relative;
|
|
93
|
+
display: block;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
[part="status"] {
|
|
97
|
+
position: absolute;
|
|
98
|
+
inset-block-start: 50%;
|
|
99
|
+
/* Left of the chevron. */
|
|
100
|
+
inset-inline-end: 2rem;
|
|
101
|
+
transform: translateY(-50%);
|
|
102
|
+
display: none;
|
|
103
|
+
align-items: center;
|
|
104
|
+
pointer-events: none;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
[part="control"][data-status="loading"] [part="status"] {
|
|
108
|
+
display: inline-flex;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
[part="spinner"] {
|
|
112
|
+
inline-size: 1rem;
|
|
113
|
+
block-size: 1rem;
|
|
114
|
+
border-radius: 999px;
|
|
115
|
+
border: 2px solid color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 20%, transparent);
|
|
116
|
+
border-top-color: var(--boe-token-surface-surface-brand, #0061d5);
|
|
117
|
+
animation: boe-select-spin ${boeMotionDuration.spin} ${boeMotionEasing.linear} infinite;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@keyframes boe-select-spin {
|
|
121
|
+
to { transform: rotate(360deg); }
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
${boeReducedMotionStyles('[part="spinner"]', "animation-duration: 1.6s;")}
|
|
125
|
+
|
|
80
126
|
${boeFormFieldErrorStyles}
|
|
81
127
|
${boeFormFieldSupportStyles}
|
|
82
128
|
`;
|
|
129
|
+
const spinnerMarkup = '<span part="spinner" aria-hidden="true"></span>';
|
|
83
130
|
export class Select extends FormAssociatedElement {
|
|
84
131
|
static tagName = DEFAULT_TAG_NAME;
|
|
85
132
|
static get observedAttributes() {
|
|
86
133
|
return [
|
|
87
134
|
...FormAssociatedElement.fieldObservedAttributes,
|
|
88
135
|
"disabled",
|
|
136
|
+
"empty-text",
|
|
89
137
|
"label",
|
|
138
|
+
"loading",
|
|
90
139
|
"multiple",
|
|
91
140
|
"options",
|
|
92
141
|
"value",
|
|
@@ -98,6 +147,8 @@ export class Select extends FormAssociatedElement {
|
|
|
98
147
|
labelEl;
|
|
99
148
|
descriptionEl;
|
|
100
149
|
errorEl;
|
|
150
|
+
controlEl;
|
|
151
|
+
statusEl;
|
|
101
152
|
/** Allow selecting several options (native multi-select list box). */
|
|
102
153
|
get multiple() {
|
|
103
154
|
return this.hasAttribute("multiple");
|
|
@@ -146,6 +197,28 @@ export class Select extends FormAssociatedElement {
|
|
|
146
197
|
set label(value) {
|
|
147
198
|
this.setAttribute("label", value);
|
|
148
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* True while options are being fetched: shows a trailing spinner (matching
|
|
202
|
+
* `box-text-field`'s status vocabulary) and states "Loading options…" in
|
|
203
|
+
* the control instead of leaving it blank.
|
|
204
|
+
*/
|
|
205
|
+
get loading() {
|
|
206
|
+
return this.hasAttribute("loading");
|
|
207
|
+
}
|
|
208
|
+
set loading(value) {
|
|
209
|
+
this.toggleAttribute("loading", Boolean(value));
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* What the control says when it has no options and is not loading. An
|
|
213
|
+
* async-loaded select with an empty result must say so — a silently blank
|
|
214
|
+
* control reads as broken.
|
|
215
|
+
*/
|
|
216
|
+
get emptyText() {
|
|
217
|
+
return this.getAttribute("empty-text") ?? "No options available";
|
|
218
|
+
}
|
|
219
|
+
set emptyText(value) {
|
|
220
|
+
this.setAttribute("empty-text", value);
|
|
221
|
+
}
|
|
149
222
|
get options() {
|
|
150
223
|
const raw = this.getAttribute("options");
|
|
151
224
|
if (!raw) {
|
|
@@ -153,7 +226,9 @@ export class Select extends FormAssociatedElement {
|
|
|
153
226
|
}
|
|
154
227
|
try {
|
|
155
228
|
const parsed = JSON.parse(raw);
|
|
156
|
-
return Array.isArray(parsed)
|
|
229
|
+
return Array.isArray(parsed) && parsed.every(isSelectOptionRecord)
|
|
230
|
+
? parsed
|
|
231
|
+
: [];
|
|
157
232
|
}
|
|
158
233
|
catch {
|
|
159
234
|
return [];
|
|
@@ -202,7 +277,10 @@ export class Select extends FormAssociatedElement {
|
|
|
202
277
|
<label part="field">
|
|
203
278
|
<span part="label"></span>
|
|
204
279
|
${formDescriptionMarkup()}
|
|
205
|
-
<
|
|
280
|
+
<span part="control">
|
|
281
|
+
<select part="select"></select>
|
|
282
|
+
<span part="status" aria-hidden="true"></span>
|
|
283
|
+
</span>
|
|
206
284
|
${formErrorMessageMarkup()}
|
|
207
285
|
</label>
|
|
208
286
|
`;
|
|
@@ -210,6 +288,8 @@ export class Select extends FormAssociatedElement {
|
|
|
210
288
|
this.descriptionEl = this.shadowRoot.querySelector('[part="description"]');
|
|
211
289
|
this.selectEl = this.shadowRoot.querySelector('[part="select"]');
|
|
212
290
|
this.errorEl = this.shadowRoot.querySelector('[part="error-message"]');
|
|
291
|
+
this.controlEl = this.shadowRoot.querySelector('[part="control"]');
|
|
292
|
+
this.statusEl = this.shadowRoot.querySelector('[part="status"]');
|
|
213
293
|
}
|
|
214
294
|
setupListeners() {
|
|
215
295
|
this.selectEl.addEventListener("change", event => {
|
|
@@ -262,8 +342,25 @@ export class Select extends FormAssociatedElement {
|
|
|
262
342
|
}
|
|
263
343
|
this.labelEl.textContent = this.label;
|
|
264
344
|
// Rebuild options (the list itself may change), grouping by `group`.
|
|
345
|
+
// While loading — and when an async load came back empty — the control
|
|
346
|
+
// says so in words instead of presenting a silently blank select.
|
|
265
347
|
this.selectEl.multiple = this.multiple;
|
|
266
|
-
|
|
348
|
+
const options = this.options;
|
|
349
|
+
if (this.loading) {
|
|
350
|
+
this.controlEl.dataset.status = "loading";
|
|
351
|
+
this.statusEl.innerHTML = spinnerMarkup;
|
|
352
|
+
this.selectEl.innerHTML = `<option value="" disabled selected>Loading options…</option>`;
|
|
353
|
+
}
|
|
354
|
+
else if (options.length === 0) {
|
|
355
|
+
this.controlEl.removeAttribute("data-status");
|
|
356
|
+
this.statusEl.innerHTML = "";
|
|
357
|
+
this.selectEl.innerHTML = `<option value="" disabled selected>${escapeHtml(this.emptyText)}</option>`;
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
this.controlEl.removeAttribute("data-status");
|
|
361
|
+
this.statusEl.innerHTML = "";
|
|
362
|
+
this.selectEl.innerHTML = this.optionsMarkup();
|
|
363
|
+
}
|
|
267
364
|
// Patch selected value(s) and disabled after rebuilding options.
|
|
268
365
|
if (this.multiple) {
|
|
269
366
|
const selected = new Set(this.valuesInternal);
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { FormAssociatedElement } from "../../core/index.js";
|
|
2
2
|
import type { FormValue } from "../../core/index.js";
|
|
3
|
+
/** Detail of this element's `value-changed` event, for typed listeners. */
|
|
4
|
+
export interface TextFieldValueChangedDetail {
|
|
5
|
+
value: string;
|
|
6
|
+
}
|
|
3
7
|
export declare class TextField extends FormAssociatedElement {
|
|
4
8
|
static readonly tagName: string;
|
|
5
9
|
static get observedAttributes(): string[];
|
|
6
10
|
private valueInternal;
|
|
11
|
+
private revealed;
|
|
7
12
|
private inputEl;
|
|
8
13
|
private labelEl;
|
|
9
14
|
private descriptionEl;
|
|
@@ -11,9 +16,25 @@ export declare class TextField extends FormAssociatedElement {
|
|
|
11
16
|
private controlEl;
|
|
12
17
|
private iconSlot;
|
|
13
18
|
private statusEl;
|
|
19
|
+
private revealEl;
|
|
14
20
|
/** Input type passthrough (text/email/tel/url/password/search/number). */
|
|
15
21
|
get type(): string;
|
|
16
22
|
set type(value: string);
|
|
23
|
+
/**
|
|
24
|
+
* `autocomplete` passthrough to the inner input ("email",
|
|
25
|
+
* "current-password", "off", …). Without it password managers and
|
|
26
|
+
* autofill cannot classify the field — the shadow boundary hides any
|
|
27
|
+
* autocomplete the host writes on the custom element itself.
|
|
28
|
+
*/
|
|
29
|
+
get autocomplete(): string;
|
|
30
|
+
set autocomplete(value: string);
|
|
31
|
+
/**
|
|
32
|
+
* Opt-in visibility toggle for `type="password"`: renders a Show/Hide
|
|
33
|
+
* control that swaps the inner input between password and text without
|
|
34
|
+
* changing the field's declared `type`.
|
|
35
|
+
*/
|
|
36
|
+
get reveal(): boolean;
|
|
37
|
+
set reveal(value: boolean);
|
|
17
38
|
/** Shows a trailing spinner (e.g. while validating/looking up asynchronously). */
|
|
18
39
|
get loading(): boolean;
|
|
19
40
|
set loading(value: boolean);
|
|
@@ -109,6 +109,47 @@ const textFieldStyles = `
|
|
|
109
109
|
color: var(--boe-token-surface-status-surface-success, #26c281);
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
/* Password visibility toggle: a word, not an eye glyph, so the state is
|
|
113
|
+
stated. Hidden entirely unless reveal is opted in on a password. */
|
|
114
|
+
[part="reveal"] {
|
|
115
|
+
position: absolute;
|
|
116
|
+
inset-block-start: 50%;
|
|
117
|
+
inset-inline-end: 0.35rem;
|
|
118
|
+
transform: translateY(-50%);
|
|
119
|
+
appearance: none;
|
|
120
|
+
border: 0;
|
|
121
|
+
padding: 0.15rem 0.4rem;
|
|
122
|
+
border-radius: 4px;
|
|
123
|
+
background: transparent;
|
|
124
|
+
font: inherit;
|
|
125
|
+
font-size: 0.78rem;
|
|
126
|
+
font-weight: 700;
|
|
127
|
+
color: var(--boe-token-surface-surface-brand, #0061d5);
|
|
128
|
+
cursor: pointer;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
[part="reveal"]:hover {
|
|
132
|
+
background: color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 8%, transparent);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
[part="reveal"]:focus-visible {
|
|
136
|
+
outline: 2px solid color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 34%, transparent);
|
|
137
|
+
outline-offset: 1px;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
[part="control"][data-reveal="true"] [part="input"] {
|
|
141
|
+
padding-inline-end: 3.4rem;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/* Reveal and a trailing status can coexist: the status shifts inward. */
|
|
145
|
+
[part="control"][data-reveal="true"] [part="status"] {
|
|
146
|
+
inset-inline-end: 3.4rem;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
[part="control"][data-reveal="true"][data-status] [part="input"] {
|
|
150
|
+
padding-inline-end: 5rem;
|
|
151
|
+
}
|
|
152
|
+
|
|
112
153
|
${boeFormFieldErrorStyles}
|
|
113
154
|
${boeFormFieldSupportStyles}
|
|
114
155
|
`;
|
|
@@ -117,9 +158,11 @@ export class TextField extends FormAssociatedElement {
|
|
|
117
158
|
static get observedAttributes() {
|
|
118
159
|
return [
|
|
119
160
|
...FormAssociatedElement.fieldObservedAttributes,
|
|
161
|
+
"autocomplete",
|
|
120
162
|
"disabled",
|
|
121
163
|
"label",
|
|
122
164
|
"placeholder",
|
|
165
|
+
"reveal",
|
|
123
166
|
"type",
|
|
124
167
|
"loading",
|
|
125
168
|
"valid",
|
|
@@ -127,6 +170,7 @@ export class TextField extends FormAssociatedElement {
|
|
|
127
170
|
];
|
|
128
171
|
}
|
|
129
172
|
valueInternal = "";
|
|
173
|
+
revealed = false;
|
|
130
174
|
inputEl;
|
|
131
175
|
labelEl;
|
|
132
176
|
descriptionEl;
|
|
@@ -134,6 +178,7 @@ export class TextField extends FormAssociatedElement {
|
|
|
134
178
|
controlEl;
|
|
135
179
|
iconSlot;
|
|
136
180
|
statusEl;
|
|
181
|
+
revealEl;
|
|
137
182
|
/** Input type passthrough (text/email/tel/url/password/search/number). */
|
|
138
183
|
get type() {
|
|
139
184
|
const value = this.getAttribute("type");
|
|
@@ -142,6 +187,34 @@ export class TextField extends FormAssociatedElement {
|
|
|
142
187
|
set type(value) {
|
|
143
188
|
this.setAttribute("type", value);
|
|
144
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* `autocomplete` passthrough to the inner input ("email",
|
|
192
|
+
* "current-password", "off", …). Without it password managers and
|
|
193
|
+
* autofill cannot classify the field — the shadow boundary hides any
|
|
194
|
+
* autocomplete the host writes on the custom element itself.
|
|
195
|
+
*/
|
|
196
|
+
get autocomplete() {
|
|
197
|
+
return this.getAttribute("autocomplete") ?? "";
|
|
198
|
+
}
|
|
199
|
+
set autocomplete(value) {
|
|
200
|
+
if (value) {
|
|
201
|
+
this.setAttribute("autocomplete", value);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
this.removeAttribute("autocomplete");
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Opt-in visibility toggle for `type="password"`: renders a Show/Hide
|
|
209
|
+
* control that swaps the inner input between password and text without
|
|
210
|
+
* changing the field's declared `type`.
|
|
211
|
+
*/
|
|
212
|
+
get reveal() {
|
|
213
|
+
return this.hasAttribute("reveal");
|
|
214
|
+
}
|
|
215
|
+
set reveal(value) {
|
|
216
|
+
this.toggleAttribute("reveal", Boolean(value));
|
|
217
|
+
}
|
|
145
218
|
/** Shows a trailing spinner (e.g. while validating/looking up asynchronously). */
|
|
146
219
|
get loading() {
|
|
147
220
|
return this.hasAttribute("loading");
|
|
@@ -214,6 +287,7 @@ export class TextField extends FormAssociatedElement {
|
|
|
214
287
|
<slot name="icon" part="icon"></slot>
|
|
215
288
|
<input type="text" part="input" />
|
|
216
289
|
<span part="status" aria-hidden="true"></span>
|
|
290
|
+
<button type="button" part="reveal" aria-pressed="false" hidden></button>
|
|
217
291
|
</span>
|
|
218
292
|
${formErrorMessageMarkup()}
|
|
219
293
|
</label>
|
|
@@ -225,9 +299,14 @@ export class TextField extends FormAssociatedElement {
|
|
|
225
299
|
this.controlEl = this.shadowRoot.querySelector('[part="control"]');
|
|
226
300
|
this.iconSlot = this.shadowRoot.querySelector('slot[name="icon"]');
|
|
227
301
|
this.statusEl = this.shadowRoot.querySelector('[part="status"]');
|
|
302
|
+
this.revealEl = this.shadowRoot.querySelector('[part="reveal"]');
|
|
228
303
|
}
|
|
229
304
|
setupListeners() {
|
|
230
305
|
this.iconSlot.addEventListener("slotchange", () => this.syncIconSlot());
|
|
306
|
+
this.revealEl.addEventListener("click", () => {
|
|
307
|
+
this.revealed = !this.revealed;
|
|
308
|
+
this.update();
|
|
309
|
+
});
|
|
231
310
|
this.inputEl.addEventListener("input", event => {
|
|
232
311
|
const nextValue = event.currentTarget.value;
|
|
233
312
|
this.valueInternal = nextValue;
|
|
@@ -253,9 +332,29 @@ export class TextField extends FormAssociatedElement {
|
|
|
253
332
|
return;
|
|
254
333
|
}
|
|
255
334
|
this.labelEl.textContent = this.label;
|
|
256
|
-
this.
|
|
335
|
+
const revealActive = this.reveal && this.type === "password";
|
|
336
|
+
this.inputEl.type = revealActive && this.revealed ? "text" : this.type;
|
|
257
337
|
this.inputEl.placeholder = this.placeholder;
|
|
338
|
+
if (this.autocomplete) {
|
|
339
|
+
this.inputEl.setAttribute("autocomplete", this.autocomplete);
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
this.inputEl.removeAttribute("autocomplete");
|
|
343
|
+
}
|
|
258
344
|
this.syncIconSlot();
|
|
345
|
+
// The reveal control only exists for a password with reveal opted in.
|
|
346
|
+
this.revealEl.hidden = !revealActive;
|
|
347
|
+
this.controlEl.dataset.reveal = revealActive ? "true" : "false";
|
|
348
|
+
if (revealActive) {
|
|
349
|
+
// The visible word and the accessible name agree; aria-pressed makes
|
|
350
|
+
// the toggle state machine explicit to AT.
|
|
351
|
+
this.revealEl.textContent = this.revealed ? "Hide" : "Show";
|
|
352
|
+
this.revealEl.setAttribute("aria-label", this.revealed ? "Hide password" : "Show password");
|
|
353
|
+
this.revealEl.setAttribute("aria-pressed", String(this.revealed));
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
this.revealed = false;
|
|
357
|
+
}
|
|
259
358
|
// Trailing status: loading spinner takes precedence over the valid check.
|
|
260
359
|
if (this.loading) {
|
|
261
360
|
this.controlEl.dataset.status = "loading";
|
|
@@ -9,6 +9,12 @@ import { BaseElement } from "../../core/index.js";
|
|
|
9
9
|
* Collapsed icon contract: slot `a`/`button` rows with an icon and a
|
|
10
10
|
* `[data-nav-label]` span. Host exposes `--boe-nav-label-display` (`none` when
|
|
11
11
|
* collapsed) so light-DOM CSS can hide labels without piercing the shadow tree.
|
|
12
|
+
*
|
|
13
|
+
* Hiding the label span removes the row's only accessible name, so while
|
|
14
|
+
* collapsed this element mirrors each row's label text onto `aria-label` (and
|
|
15
|
+
* `title`, for the hover tooltip) — but only on rows the host has not named
|
|
16
|
+
* itself, and it removes exactly what it added on expand. The host stays the
|
|
17
|
+
* authority: an author-set `aria-label` or `title` is never overwritten.
|
|
12
18
|
*/
|
|
13
19
|
export declare class NavSidebar extends BaseElement {
|
|
14
20
|
static readonly tagName: string;
|
|
@@ -19,5 +25,13 @@ export declare class NavSidebar extends BaseElement {
|
|
|
19
25
|
get label(): string;
|
|
20
26
|
set label(value: string);
|
|
21
27
|
protected renderTemplate(): void;
|
|
28
|
+
protected setupListeners(): void;
|
|
29
|
+
/**
|
|
30
|
+
* Collapsing hides `[data-nav-label]`, which is a row's only accessible
|
|
31
|
+
* name. Mirror the label text onto `aria-label`/`title` while collapsed —
|
|
32
|
+
* marked, so expand removes only what collapse added and a host-authored
|
|
33
|
+
* name is never touched.
|
|
34
|
+
*/
|
|
35
|
+
private syncCollapsedRowNames;
|
|
22
36
|
protected update(): void;
|
|
23
37
|
}
|
|
@@ -134,6 +134,12 @@ const navSidebarStyles = `
|
|
|
134
134
|
* Collapsed icon contract: slot `a`/`button` rows with an icon and a
|
|
135
135
|
* `[data-nav-label]` span. Host exposes `--boe-nav-label-display` (`none` when
|
|
136
136
|
* collapsed) so light-DOM CSS can hide labels without piercing the shadow tree.
|
|
137
|
+
*
|
|
138
|
+
* Hiding the label span removes the row's only accessible name, so while
|
|
139
|
+
* collapsed this element mirrors each row's label text onto `aria-label` (and
|
|
140
|
+
* `title`, for the hover tooltip) — but only on rows the host has not named
|
|
141
|
+
* itself, and it removes exactly what it added on expand. The host stays the
|
|
142
|
+
* authority: an author-set `aria-label` or `title` is never overwritten.
|
|
137
143
|
*/
|
|
138
144
|
export class NavSidebar extends BaseElement {
|
|
139
145
|
static tagName = DEFAULT_TAG_NAME;
|
|
@@ -173,12 +179,55 @@ export class NavSidebar extends BaseElement {
|
|
|
173
179
|
`;
|
|
174
180
|
this.sidebarEl = this.shadowRoot.querySelector('[part="sidebar"]');
|
|
175
181
|
}
|
|
182
|
+
setupListeners() {
|
|
183
|
+
// Rows slotted in while already collapsed still need their names mirrored.
|
|
184
|
+
this.shadowRoot
|
|
185
|
+
?.querySelector('[part="body"] slot')
|
|
186
|
+
?.addEventListener("slotchange", () => {
|
|
187
|
+
this.update();
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Collapsing hides `[data-nav-label]`, which is a row's only accessible
|
|
192
|
+
* name. Mirror the label text onto `aria-label`/`title` while collapsed —
|
|
193
|
+
* marked, so expand removes only what collapse added and a host-authored
|
|
194
|
+
* name is never touched.
|
|
195
|
+
*/
|
|
196
|
+
syncCollapsedRowNames() {
|
|
197
|
+
for (const row of Array.from(this.querySelectorAll("a, button"))) {
|
|
198
|
+
if (this.collapsed) {
|
|
199
|
+
const label = row.querySelector("[data-nav-label]")?.textContent?.trim();
|
|
200
|
+
if (!label) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (!row.hasAttribute("aria-label")) {
|
|
204
|
+
row.setAttribute("aria-label", label);
|
|
205
|
+
row.setAttribute("data-boe-managed-name", "");
|
|
206
|
+
}
|
|
207
|
+
if (!row.hasAttribute("title")) {
|
|
208
|
+
row.setAttribute("title", label);
|
|
209
|
+
row.setAttribute("data-boe-managed-title", "");
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
if (row.hasAttribute("data-boe-managed-name")) {
|
|
214
|
+
row.removeAttribute("aria-label");
|
|
215
|
+
row.removeAttribute("data-boe-managed-name");
|
|
216
|
+
}
|
|
217
|
+
if (row.hasAttribute("data-boe-managed-title")) {
|
|
218
|
+
row.removeAttribute("title");
|
|
219
|
+
row.removeAttribute("data-boe-managed-title");
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
176
224
|
update() {
|
|
177
225
|
if (!this.sidebarEl) {
|
|
178
226
|
return;
|
|
179
227
|
}
|
|
180
228
|
this.sidebarEl.dataset.collapsed = this.collapsed ? "true" : "false";
|
|
181
229
|
this.sidebarEl.setAttribute("aria-label", this.label);
|
|
230
|
+
this.syncCollapsedRowNames();
|
|
182
231
|
}
|
|
183
232
|
}
|
|
184
233
|
NavSidebar.register();
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { BaseElement } from "../../core/index.js";
|
|
2
|
+
/** Detail of `detail-dismissed`: what asked the slide-over to close. */
|
|
3
|
+
export interface SplitViewDetailDismissedDetail {
|
|
4
|
+
source: "escape";
|
|
5
|
+
}
|
|
2
6
|
export declare class SplitView extends BaseElement {
|
|
3
7
|
static readonly tagName: string;
|
|
4
8
|
static get observedAttributes(): string[];
|
|
@@ -11,6 +15,16 @@ export declare class SplitView extends BaseElement {
|
|
|
11
15
|
set ratio(value: number);
|
|
12
16
|
get resizable(): boolean;
|
|
13
17
|
set resizable(value: boolean);
|
|
18
|
+
/** "auto" collapses to master-detail when the container narrows. */
|
|
19
|
+
get collapse(): string;
|
|
20
|
+
set collapse(value: string);
|
|
21
|
+
/**
|
|
22
|
+
* Host-controlled: whether the secondary pane shows as a slide-over while
|
|
23
|
+
* collapsed. The host sets it on selection and clears it on
|
|
24
|
+
* `detail-dismissed` — selection state stays where it lives, in the list.
|
|
25
|
+
*/
|
|
26
|
+
get detailOpen(): boolean;
|
|
27
|
+
set detailOpen(value: boolean);
|
|
14
28
|
private setRatioFromResize;
|
|
15
29
|
private stopResize;
|
|
16
30
|
protected renderTemplate(): void;
|
|
@@ -33,11 +33,47 @@ const splitViewStyles = `
|
|
|
33
33
|
height: 100%;
|
|
34
34
|
background: color-mix(in srgb, var(--boe-token-stroke-stroke, #e8e8e8) 82%, transparent);
|
|
35
35
|
}
|
|
36
|
+
|
|
37
|
+
:host {
|
|
38
|
+
container-type: inline-size;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* Master-detail collapse (opt-in via collapse="auto"): when the container
|
|
42
|
+
narrows, the primary pane takes the full width and the secondary pane
|
|
43
|
+
becomes a slide-over that the host opens with detail-open — typically on
|
|
44
|
+
selection — and closes by clearing it (Escape asks via detail-dismissed).
|
|
45
|
+
The slotted content never moves; only the shadow wrapper changes shape. */
|
|
46
|
+
@container (max-width: 640px) {
|
|
47
|
+
:host([collapse="auto"]) [part="split-view"] {
|
|
48
|
+
grid-template-columns: minmax(0, 1fr) !important;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
:host([collapse="auto"]) [part="separator"] {
|
|
52
|
+
display: none;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
:host([collapse="auto"]) [part="secondary"] {
|
|
56
|
+
display: none;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
:host([collapse="auto"][detail-open]) [part="secondary"] {
|
|
60
|
+
display: block;
|
|
61
|
+
position: fixed;
|
|
62
|
+
inset-block: 0;
|
|
63
|
+
inset-inline-end: 0;
|
|
64
|
+
z-index: 1100;
|
|
65
|
+
width: min(90vw, 26rem);
|
|
66
|
+
overflow: auto;
|
|
67
|
+
background: var(--boe-token-surface-surface, #ffffff);
|
|
68
|
+
border-inline-start: 1px solid var(--boe-token-stroke-stroke, #e8e8e8);
|
|
69
|
+
box-shadow: -12px 0 32px rgb(0 0 0 / 18%);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
36
72
|
`;
|
|
37
73
|
export class SplitView extends BaseElement {
|
|
38
74
|
static tagName = DEFAULT_TAG_NAME;
|
|
39
75
|
static get observedAttributes() {
|
|
40
|
-
return ["label", "ratio", "resizable"];
|
|
76
|
+
return ["collapse", "detail-open", "label", "ratio", "resizable"];
|
|
41
77
|
}
|
|
42
78
|
isResizing = false;
|
|
43
79
|
splitViewEl;
|
|
@@ -64,6 +100,29 @@ export class SplitView extends BaseElement {
|
|
|
64
100
|
set resizable(value) {
|
|
65
101
|
this.toggleAttribute("resizable", value);
|
|
66
102
|
}
|
|
103
|
+
/** "auto" collapses to master-detail when the container narrows. */
|
|
104
|
+
get collapse() {
|
|
105
|
+
return this.getAttribute("collapse") ?? "";
|
|
106
|
+
}
|
|
107
|
+
set collapse(value) {
|
|
108
|
+
if (value) {
|
|
109
|
+
this.setAttribute("collapse", value);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
this.removeAttribute("collapse");
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Host-controlled: whether the secondary pane shows as a slide-over while
|
|
117
|
+
* collapsed. The host sets it on selection and clears it on
|
|
118
|
+
* `detail-dismissed` — selection state stays where it lives, in the list.
|
|
119
|
+
*/
|
|
120
|
+
get detailOpen() {
|
|
121
|
+
return this.hasAttribute("detail-open");
|
|
122
|
+
}
|
|
123
|
+
set detailOpen(value) {
|
|
124
|
+
this.toggleAttribute("detail-open", Boolean(value));
|
|
125
|
+
}
|
|
67
126
|
setRatioFromResize(nextRatio) {
|
|
68
127
|
const clamped = Math.max(0.2, Math.min(0.8, nextRatio));
|
|
69
128
|
const previous = this.ratio;
|
|
@@ -108,6 +167,26 @@ export class SplitView extends BaseElement {
|
|
|
108
167
|
this.separatorEl = this.shadowRoot.querySelector('[part="separator"]');
|
|
109
168
|
}
|
|
110
169
|
setupListeners() {
|
|
170
|
+
// Escape inside the collapsed slide-over asks the host to close it; the
|
|
171
|
+
// host owns detail-open, so this only asks.
|
|
172
|
+
this.addEventListener("keydown", event => {
|
|
173
|
+
const keyboardEvent = event;
|
|
174
|
+
if (keyboardEvent.key !== "Escape" || !this.detailOpen || this.collapse !== "auto") {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
// The slide-over only exists under the 640px container query; on a wide
|
|
178
|
+
// container the secondary pane is an ordinary pane and Escape means
|
|
179
|
+
// nothing. Mirror the CSS condition rather than emitting a phantom ask.
|
|
180
|
+
if (this.offsetWidth > 640) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
keyboardEvent.preventDefault();
|
|
184
|
+
this.dispatchEvent(new CustomEvent("detail-dismissed", {
|
|
185
|
+
bubbles: true,
|
|
186
|
+
composed: true,
|
|
187
|
+
detail: { source: "escape" },
|
|
188
|
+
}));
|
|
189
|
+
});
|
|
111
190
|
this.separatorEl.addEventListener("pointerdown", event => {
|
|
112
191
|
const pointerEvent = event;
|
|
113
192
|
this.isResizing = true;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { CommandDescriptor } from "./command-types.js";
|
|
2
|
+
import { BaseElement } from "../../core/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Keyboard-first action launcher (CLM gap 4) over the existing overlay and
|
|
5
|
+
* listbox machinery.
|
|
6
|
+
*
|
|
7
|
+
* Follows the ARIA combobox-with-listbox pattern: focus never leaves the
|
|
8
|
+
* search input, so typing and navigating are the same gesture. The active
|
|
9
|
+
* option is communicated with `aria-activedescendant` rather than by moving
|
|
10
|
+
* focus, which is what lets Up/Down browse results while the query stays
|
|
11
|
+
* editable.
|
|
12
|
+
*
|
|
13
|
+
* The host owns what commands mean — the palette only reports the choice.
|
|
14
|
+
*/
|
|
15
|
+
export declare class CommandPalette extends BaseElement {
|
|
16
|
+
static readonly tagName: string;
|
|
17
|
+
static get observedAttributes(): string[];
|
|
18
|
+
private hostEl;
|
|
19
|
+
private readonly focusRestore;
|
|
20
|
+
private openValue;
|
|
21
|
+
private wasOpen;
|
|
22
|
+
private query;
|
|
23
|
+
private activeIndex;
|
|
24
|
+
/** Flattened, ranked matches — the index space the keyboard walks. */
|
|
25
|
+
private rankedMatches;
|
|
26
|
+
private commandsRaw;
|
|
27
|
+
private commandsCache;
|
|
28
|
+
private recentIdsValue;
|
|
29
|
+
private readonly onDocumentKeydown;
|
|
30
|
+
get open(): boolean;
|
|
31
|
+
set open(value: boolean);
|
|
32
|
+
get placeholder(): string;
|
|
33
|
+
set placeholder(value: string);
|
|
34
|
+
/**
|
|
35
|
+
* Global shortcut that opens the palette, e.g. `mod+k`. `mod` resolves to
|
|
36
|
+
* Cmd or Ctrl per platform. Omit to let the host own the trigger.
|
|
37
|
+
*/
|
|
38
|
+
get hotkey(): string;
|
|
39
|
+
set hotkey(value: string);
|
|
40
|
+
get hideDisabled(): boolean;
|
|
41
|
+
set hideDisabled(value: boolean);
|
|
42
|
+
/** Command catalogue; JSON payloads are validated per record. */
|
|
43
|
+
get commands(): CommandDescriptor[];
|
|
44
|
+
set commands(value: CommandDescriptor[]);
|
|
45
|
+
/** Most recently run command ids, most recent first; boosts ranking. */
|
|
46
|
+
get recentIds(): string[];
|
|
47
|
+
set recentIds(value: string[]);
|
|
48
|
+
/** The ranked matches currently on screen. */
|
|
49
|
+
get visibleCommands(): CommandDescriptor[];
|
|
50
|
+
show(): void;
|
|
51
|
+
hide(): void;
|
|
52
|
+
connectedCallback(): void;
|
|
53
|
+
disconnectedCallback(): void;
|
|
54
|
+
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
|
|
55
|
+
private runActive;
|
|
56
|
+
private moveActive;
|
|
57
|
+
private scrollActiveIntoView;
|
|
58
|
+
private optionHtml;
|
|
59
|
+
protected renderTemplate(): void;
|
|
60
|
+
protected setupListeners(): void;
|
|
61
|
+
protected update(): void;
|
|
62
|
+
}
|