@unofficialbox/box-open-elements 0.5.0 → 0.7.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 +27 -73
- package/dist/components/collections/table.d.ts +113 -3
- package/dist/components/collections/table.js +540 -37
- 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/core/index.d.ts +4 -0
- package/dist/core/index.js +2 -0
- package/dist/core/offset-window.d.ts +70 -0
- package/dist/core/offset-window.js +134 -0
- package/dist/core/virtualize.d.ts +71 -0
- package/dist/core/virtualize.js +67 -0
- 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 +182 -0
- package/dist/patterns/audit/audit-log.js +1082 -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/audit/window.d.ts +116 -0
- package/dist/patterns/audit/window.js +132 -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
|
@@ -8,6 +8,50 @@ const escapeHtml = (value) => value
|
|
|
8
8
|
.replaceAll(">", ">")
|
|
9
9
|
.replaceAll('"', """)
|
|
10
10
|
.replaceAll("'", "'");
|
|
11
|
+
const STEP_STATUSES = new Set(["complete", "blocked", "failed", "disabled"]);
|
|
12
|
+
/** Attribute payloads are author input — validate every record. */
|
|
13
|
+
export const isProgressStepRecord = (value) => {
|
|
14
|
+
if (typeof value !== "object" || value === null) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
const step = value;
|
|
18
|
+
return (typeof step.value === "string" &&
|
|
19
|
+
step.value.length > 0 &&
|
|
20
|
+
typeof step.label === "string" &&
|
|
21
|
+
step.label.length > 0 &&
|
|
22
|
+
(step.status === undefined || STEP_STATUSES.has(step.status)) &&
|
|
23
|
+
// Non-string text fields would reach escapeHtml and throw mid-render.
|
|
24
|
+
(step.description === undefined || typeof step.description === "string") &&
|
|
25
|
+
(step.statusNote === undefined || typeof step.statusNote === "string"));
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* The state rules, pure and DOM-free, so a host can drive its own surface
|
|
29
|
+
* (or decide whether "Continue" is enabled) from the same function the
|
|
30
|
+
* component renders from. An unknown `value` falls back to the first step,
|
|
31
|
+
* matching the component's long-standing behaviour.
|
|
32
|
+
*/
|
|
33
|
+
export const resolveStepStates = (items, value) => {
|
|
34
|
+
const currentIndex = Math.max(0, items.findIndex(item => item.value === value));
|
|
35
|
+
return items.map((item, index) => {
|
|
36
|
+
const positional = index < currentIndex ? "complete" : index === currentIndex ? "current" : "upcoming";
|
|
37
|
+
const state = item.status ?? positional;
|
|
38
|
+
return {
|
|
39
|
+
item,
|
|
40
|
+
state,
|
|
41
|
+
isCurrent: index === currentIndex,
|
|
42
|
+
interactive: state !== "blocked" && state !== "disabled",
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
/** Every state in words — colour never carries the meaning alone. */
|
|
47
|
+
export const STEP_STATE_LABEL = {
|
|
48
|
+
complete: "Complete",
|
|
49
|
+
current: "Current step",
|
|
50
|
+
upcoming: "Not started",
|
|
51
|
+
blocked: "Blocked",
|
|
52
|
+
failed: "Failed",
|
|
53
|
+
disabled: "Unavailable",
|
|
54
|
+
};
|
|
11
55
|
const progressStepsStyles = `
|
|
12
56
|
:host {
|
|
13
57
|
display: block;
|
|
@@ -100,6 +144,66 @@ const progressStepsStyles = `
|
|
|
100
144
|
color: var(--boe-token-text-text-secondary, #6f6f6f);
|
|
101
145
|
line-height: 1.45;
|
|
102
146
|
}
|
|
147
|
+
|
|
148
|
+
[part="step"]:disabled {
|
|
149
|
+
cursor: not-allowed;
|
|
150
|
+
background: var(--boe-token-surface-surface, #ffffff);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
[part="step"][data-state="blocked"] [part="step-label"],
|
|
154
|
+
[part="step"][data-state="disabled"] [part="step-label"] {
|
|
155
|
+
color: var(--boe-token-text-text-secondary, #6f6f6f);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
[part="step"][data-state="blocked"] [part="marker"] {
|
|
159
|
+
background: color-mix(in srgb, var(--boe-token-surface-status-surface-warning, #f5b31b) 18%, var(--boe-token-surface-surface, #ffffff) 82%);
|
|
160
|
+
color: color-mix(in srgb, var(--boe-token-surface-status-surface-warning, #f5b31b) 52%, var(--boe-token-text-text, #222222));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
[part="step"][data-state="failed"] {
|
|
164
|
+
border-color: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 34%, transparent);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
[part="step"][data-state="failed"] [part="marker"] {
|
|
168
|
+
border-color: transparent;
|
|
169
|
+
background: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 16%, var(--boe-token-surface-surface, #ffffff) 84%);
|
|
170
|
+
color: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 72%, black 28%);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
[part="step"][data-state="disabled"] {
|
|
174
|
+
opacity: 0.62;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/* The status, in words: visible for the conditions a user must not miss. */
|
|
178
|
+
[part="step-status"] {
|
|
179
|
+
font-size: 0.8rem;
|
|
180
|
+
font-weight: 700;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
[part="step"][data-state="blocked"] [part="step-status"] {
|
|
184
|
+
color: color-mix(in srgb, var(--boe-token-surface-status-surface-warning, #f5b31b) 48%, var(--boe-token-text-text, #222222));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
[part="step"][data-state="failed"] [part="step-status"] {
|
|
188
|
+
color: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 76%, black 24%);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
[part="step-status-note"] {
|
|
192
|
+
font-size: 0.82rem;
|
|
193
|
+
color: var(--boe-token-text-text-secondary, #6f6f6f);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.boe-sr-only {
|
|
197
|
+
position: absolute;
|
|
198
|
+
width: 1px;
|
|
199
|
+
height: 1px;
|
|
200
|
+
margin: -1px;
|
|
201
|
+
padding: 0;
|
|
202
|
+
border: 0;
|
|
203
|
+
clip: rect(0, 0, 0, 0);
|
|
204
|
+
overflow: hidden;
|
|
205
|
+
white-space: nowrap;
|
|
206
|
+
}
|
|
103
207
|
`;
|
|
104
208
|
export class ProgressSteps extends BaseElement {
|
|
105
209
|
static tagName = DEFAULT_TAG_NAME;
|
|
@@ -108,6 +212,7 @@ export class ProgressSteps extends BaseElement {
|
|
|
108
212
|
}
|
|
109
213
|
valueInternal = "";
|
|
110
214
|
stepsEl;
|
|
215
|
+
liveEl;
|
|
111
216
|
itemsSignature = "";
|
|
112
217
|
get label() {
|
|
113
218
|
return this.getAttribute("label") ?? "Progress Steps";
|
|
@@ -122,7 +227,9 @@ export class ProgressSteps extends BaseElement {
|
|
|
122
227
|
}
|
|
123
228
|
try {
|
|
124
229
|
const parsed = JSON.parse(raw);
|
|
125
|
-
return Array.isArray(parsed)
|
|
230
|
+
return Array.isArray(parsed) && parsed.every(isProgressStepRecord)
|
|
231
|
+
? parsed
|
|
232
|
+
: [];
|
|
126
233
|
}
|
|
127
234
|
catch {
|
|
128
235
|
return [];
|
|
@@ -131,6 +238,10 @@ export class ProgressSteps extends BaseElement {
|
|
|
131
238
|
set items(value) {
|
|
132
239
|
this.setAttribute("items", JSON.stringify(value));
|
|
133
240
|
}
|
|
241
|
+
/** The resolved states — same objects the render uses. */
|
|
242
|
+
get resolvedSteps() {
|
|
243
|
+
return resolveStepStates(this.items, this.valueInternal);
|
|
244
|
+
}
|
|
134
245
|
get value() {
|
|
135
246
|
return this.valueInternal;
|
|
136
247
|
}
|
|
@@ -154,8 +265,10 @@ export class ProgressSteps extends BaseElement {
|
|
|
154
265
|
this.shadowRoot.innerHTML = `
|
|
155
266
|
<style>${progressStepsStyles}</style>
|
|
156
267
|
<div part="steps" role="group"></div>
|
|
268
|
+
<div part="live" class="boe-sr-only" aria-live="polite"></div>
|
|
157
269
|
`;
|
|
158
270
|
this.stepsEl = this.shadowRoot.querySelector('[part="steps"]');
|
|
271
|
+
this.liveEl = this.shadowRoot.querySelector('[part="live"]');
|
|
159
272
|
}
|
|
160
273
|
setupListeners() {
|
|
161
274
|
this.stepsEl.addEventListener("click", event => {
|
|
@@ -175,34 +288,51 @@ export class ProgressSteps extends BaseElement {
|
|
|
175
288
|
if (!step || !this.stepsEl.contains(step)) {
|
|
176
289
|
return;
|
|
177
290
|
}
|
|
178
|
-
const
|
|
291
|
+
const resolved = this.resolvedSteps;
|
|
179
292
|
const index = Array.from(this.stepsEl.querySelectorAll('[part="step"]')).indexOf(step);
|
|
180
|
-
if (index < 0) {
|
|
293
|
+
if (index < 0 || resolved.length === 0) {
|
|
181
294
|
return;
|
|
182
295
|
}
|
|
183
|
-
|
|
184
|
-
|
|
296
|
+
// Arrows walk to the next *interactive* step — blocked and disabled
|
|
297
|
+
// steps are skipped, not landed on and bounced off.
|
|
298
|
+
const isInteractive = (candidate) => resolved[candidate]?.interactive ?? false;
|
|
299
|
+
const walk = (direction) => {
|
|
300
|
+
for (let offset = 1; offset <= resolved.length; offset += 1) {
|
|
301
|
+
const candidate = (((index + direction * offset) % resolved.length) + resolved.length) % resolved.length;
|
|
302
|
+
if (isInteractive(candidate)) {
|
|
303
|
+
return candidate;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return -1;
|
|
307
|
+
};
|
|
308
|
+
let nextIndex;
|
|
185
309
|
if (keyboardEvent.key === "ArrowRight" || keyboardEvent.key === "ArrowDown") {
|
|
186
|
-
nextIndex =
|
|
310
|
+
nextIndex = walk(1);
|
|
187
311
|
}
|
|
188
312
|
else if (keyboardEvent.key === "ArrowLeft" || keyboardEvent.key === "ArrowUp") {
|
|
189
|
-
nextIndex =
|
|
313
|
+
nextIndex = walk(-1);
|
|
190
314
|
}
|
|
191
315
|
else if (keyboardEvent.key === "Home") {
|
|
192
|
-
nextIndex =
|
|
316
|
+
nextIndex = resolved.findIndex(entry => entry.interactive);
|
|
193
317
|
}
|
|
194
318
|
else if (keyboardEvent.key === "End") {
|
|
195
|
-
nextIndex =
|
|
319
|
+
nextIndex = -1;
|
|
320
|
+
for (let candidate = resolved.length - 1; candidate >= 0; candidate -= 1) {
|
|
321
|
+
if (isInteractive(candidate)) {
|
|
322
|
+
nextIndex = candidate;
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
196
326
|
}
|
|
197
327
|
else {
|
|
198
328
|
return;
|
|
199
329
|
}
|
|
200
330
|
keyboardEvent.preventDefault();
|
|
201
|
-
const nextStep =
|
|
202
|
-
if (!nextStep) {
|
|
331
|
+
const nextStep = resolved[nextIndex];
|
|
332
|
+
if (nextIndex < 0 || !nextStep) {
|
|
203
333
|
return;
|
|
204
334
|
}
|
|
205
|
-
this.selectValue(nextStep.value);
|
|
335
|
+
this.selectValue(nextStep.item.value);
|
|
206
336
|
queueMicrotask(() => {
|
|
207
337
|
const nextButton = this.stepsEl.querySelectorAll('[part="step"]')[nextIndex];
|
|
208
338
|
nextButton?.focus();
|
|
@@ -210,6 +340,13 @@ export class ProgressSteps extends BaseElement {
|
|
|
210
340
|
});
|
|
211
341
|
}
|
|
212
342
|
selectValue(nextValue) {
|
|
343
|
+
// Disabled buttons never emit clicks and the keyboard path skips them,
|
|
344
|
+
// but the invariant should not depend on every caller knowing that.
|
|
345
|
+
const resolved = resolveStepStates(this.items, this.valueInternal);
|
|
346
|
+
const target = resolved.find(entry => entry.item.value === nextValue);
|
|
347
|
+
if (!target || !target.interactive) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
213
350
|
this.valueInternal = nextValue;
|
|
214
351
|
this.setAttribute("value", nextValue);
|
|
215
352
|
this.dispatchEvent(new CustomEvent("value-changed", {
|
|
@@ -218,6 +355,28 @@ export class ProgressSteps extends BaseElement {
|
|
|
218
355
|
detail: { value: nextValue },
|
|
219
356
|
}));
|
|
220
357
|
this.update();
|
|
358
|
+
this.announceStep(target);
|
|
359
|
+
}
|
|
360
|
+
/** A polite announcement on user-driven step changes, never on render. */
|
|
361
|
+
announceStep(target) {
|
|
362
|
+
if (!this.liveEl) {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
const items = this.items;
|
|
366
|
+
const position = items.findIndex(item => item.value === target.item.value) + 1;
|
|
367
|
+
this.liveEl.textContent = `${target.item.label}, step ${String(position)} of ${String(items.length)}`;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* The tab stop lives on the current step — unless that step is blocked or
|
|
371
|
+
* disabled (a host can point `value` anywhere), in which case the first
|
|
372
|
+
* interactive step takes it so the group stays reachable.
|
|
373
|
+
*/
|
|
374
|
+
tabbableIndex(resolved) {
|
|
375
|
+
const currentIndex = resolved.findIndex(entry => entry.isCurrent);
|
|
376
|
+
if (resolved[currentIndex]?.interactive) {
|
|
377
|
+
return currentIndex;
|
|
378
|
+
}
|
|
379
|
+
return resolved.findIndex(entry => entry.interactive);
|
|
221
380
|
}
|
|
222
381
|
update() {
|
|
223
382
|
if (!this.stepsEl) {
|
|
@@ -231,24 +390,35 @@ export class ProgressSteps extends BaseElement {
|
|
|
231
390
|
this.setAttribute("value", selectedValue);
|
|
232
391
|
}
|
|
233
392
|
this.stepsEl.setAttribute("aria-label", this.label);
|
|
393
|
+
const resolved = resolveStepStates(items, this.valueInternal);
|
|
394
|
+
const tabbable = this.tabbableIndex(resolved);
|
|
234
395
|
const signature = JSON.stringify(items);
|
|
235
396
|
if (signature !== this.itemsSignature) {
|
|
236
397
|
this.itemsSignature = signature;
|
|
237
|
-
this.stepsEl.innerHTML =
|
|
238
|
-
.map((
|
|
239
|
-
const
|
|
398
|
+
this.stepsEl.innerHTML = resolved
|
|
399
|
+
.map((entry, index) => {
|
|
400
|
+
const { item, state, isCurrent, interactive } = entry;
|
|
401
|
+
// Blocked / failed / disabled are said out loud on the surface; the
|
|
402
|
+
// positional states get a screen-reader word so colour and a number
|
|
403
|
+
// are never the only carriers of the state.
|
|
404
|
+
const explicitStatus = item.status
|
|
405
|
+
? `<span part="step-status">${STEP_STATE_LABEL[state]}</span>
|
|
406
|
+
${item.statusNote ? `<span part="step-status-note">${escapeHtml(item.statusNote)}</span>` : ""}`
|
|
407
|
+
: `<span part="step-state" class="boe-sr-only">${STEP_STATE_LABEL[state]}</span>`;
|
|
240
408
|
return `
|
|
241
409
|
<button
|
|
242
410
|
type="button"
|
|
243
411
|
part="step"
|
|
244
412
|
data-state="${state}"
|
|
245
413
|
data-value="${escapeHtml(item.value)}"
|
|
246
|
-
aria-current="${
|
|
247
|
-
tabindex="${index ===
|
|
414
|
+
aria-current="${isCurrent ? "step" : "false"}"
|
|
415
|
+
tabindex="${index === tabbable ? "0" : "-1"}"
|
|
416
|
+
${interactive ? "" : "disabled"}
|
|
248
417
|
>
|
|
249
418
|
<span part="marker">${index + 1}</span>
|
|
250
419
|
<span part="content">
|
|
251
420
|
<strong part="step-label">${escapeHtml(item.label)}</strong>
|
|
421
|
+
${explicitStatus}
|
|
252
422
|
${item.description ? `<span part="step-description">${escapeHtml(item.description)}</span>` : ""}
|
|
253
423
|
</span>
|
|
254
424
|
</button>
|
|
@@ -258,12 +428,20 @@ export class ProgressSteps extends BaseElement {
|
|
|
258
428
|
return;
|
|
259
429
|
}
|
|
260
430
|
this.stepsEl.querySelectorAll('[part="step"]').forEach((step, index) => {
|
|
261
|
-
const
|
|
431
|
+
const entry = resolved[index];
|
|
432
|
+
if (!entry) {
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
262
435
|
const button = step;
|
|
263
|
-
button.dataset.state = state;
|
|
264
|
-
button.setAttribute("aria-current",
|
|
265
|
-
button.
|
|
266
|
-
button.
|
|
436
|
+
button.dataset.state = entry.state;
|
|
437
|
+
button.setAttribute("aria-current", entry.isCurrent ? "step" : "false");
|
|
438
|
+
button.tabIndex = index === tabbable ? 0 : -1;
|
|
439
|
+
button.disabled = !entry.interactive;
|
|
440
|
+
// Positional states move with `value`; keep the spoken word in step.
|
|
441
|
+
const stateWord = button.querySelector('[part="step-state"]');
|
|
442
|
+
if (stateWord) {
|
|
443
|
+
stateWord.textContent = STEP_STATE_LABEL[entry.state];
|
|
444
|
+
}
|
|
267
445
|
});
|
|
268
446
|
}
|
|
269
447
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { BaseElement } from "../../core/index.js";
|
|
2
|
+
/** One point in a record's lifecycle. */
|
|
3
|
+
export interface StagePathStage {
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
/** Optional detail shown under the label on the current stage. */
|
|
7
|
+
description?: string;
|
|
8
|
+
}
|
|
9
|
+
export type StageState = "complete" | "current" | "upcoming";
|
|
10
|
+
/** Attribute payloads are author input — validate every record. */
|
|
11
|
+
export declare const isStagePathStageRecord: (value: unknown) => value is StagePathStage;
|
|
12
|
+
/** State of each stage relative to the current one. */
|
|
13
|
+
export declare const resolveStageStates: (stages: readonly StagePathStage[], currentId: string) => StageState[];
|
|
14
|
+
/**
|
|
15
|
+
* Horizontal chevron lifecycle tracker for record headers — Draft → In
|
|
16
|
+
* Review → Approved → Executed.
|
|
17
|
+
*
|
|
18
|
+
* Distinct from `box-progress-steps`, which is a vertical setup rail for a
|
|
19
|
+
* task the reader is working through: this states where a *record* sits in
|
|
20
|
+
* its lifecycle, is read-only, and belongs in a header rather than a form.
|
|
21
|
+
*
|
|
22
|
+
* Rendered as an ordered list with the current stage marked `aria-current`,
|
|
23
|
+
* so the sequence and the position are both available without relying on the
|
|
24
|
+
* chevron geometry — which is decoration, and collapses on narrow viewports.
|
|
25
|
+
*/
|
|
26
|
+
export declare class StagePath extends BaseElement {
|
|
27
|
+
static readonly tagName: string;
|
|
28
|
+
static get observedAttributes(): string[];
|
|
29
|
+
private pathEl;
|
|
30
|
+
private stagesRaw;
|
|
31
|
+
private stagesCache;
|
|
32
|
+
get label(): string;
|
|
33
|
+
set label(value: string);
|
|
34
|
+
/** Id of the stage the record is at. An unknown id leaves every stage upcoming. */
|
|
35
|
+
get current(): string;
|
|
36
|
+
set current(value: string);
|
|
37
|
+
get stages(): StagePathStage[];
|
|
38
|
+
set stages(value: StagePathStage[]);
|
|
39
|
+
/** State of each stage, in order. */
|
|
40
|
+
get states(): StageState[];
|
|
41
|
+
protected renderTemplate(): void;
|
|
42
|
+
protected setupListeners(): void;
|
|
43
|
+
protected update(): void;
|
|
44
|
+
}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { BaseElement } from "../../core/index.js";
|
|
2
|
+
import { boeMotionDuration, boeMotionEasing } from "../../foundations/motion/index.js";
|
|
3
|
+
const DEFAULT_TAG_NAME = "box-stage-path";
|
|
4
|
+
const escapeHtml = (value) => value
|
|
5
|
+
.replaceAll("&", "&")
|
|
6
|
+
.replaceAll("<", "<")
|
|
7
|
+
.replaceAll(">", ">")
|
|
8
|
+
.replaceAll('"', """)
|
|
9
|
+
.replaceAll("'", "'");
|
|
10
|
+
/** Attribute payloads are author input — validate every record. */
|
|
11
|
+
export const isStagePathStageRecord = (value) => {
|
|
12
|
+
if (typeof value !== "object" || value === null) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
const stage = value;
|
|
16
|
+
return (typeof stage.id === "string" &&
|
|
17
|
+
stage.id.length > 0 &&
|
|
18
|
+
typeof stage.label === "string" &&
|
|
19
|
+
stage.label.length > 0);
|
|
20
|
+
};
|
|
21
|
+
/** State of each stage relative to the current one. */
|
|
22
|
+
export const resolveStageStates = (stages, currentId) => {
|
|
23
|
+
const index = stages.findIndex(stage => stage.id === currentId);
|
|
24
|
+
// An unknown current id means nothing is complete — better than silently
|
|
25
|
+
// marking the whole path done because the host sent a stale value.
|
|
26
|
+
return stages.map((_, position) => index === -1
|
|
27
|
+
? "upcoming"
|
|
28
|
+
: position < index
|
|
29
|
+
? "complete"
|
|
30
|
+
: position === index
|
|
31
|
+
? "current"
|
|
32
|
+
: "upcoming");
|
|
33
|
+
};
|
|
34
|
+
const elementStyles = `
|
|
35
|
+
:host {
|
|
36
|
+
display: block;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
[part="path"] {
|
|
40
|
+
display: flex;
|
|
41
|
+
flex-wrap: wrap;
|
|
42
|
+
margin: 0;
|
|
43
|
+
padding: 0;
|
|
44
|
+
list-style: none;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
[part="stage"] {
|
|
48
|
+
position: relative;
|
|
49
|
+
flex: 1 1 0;
|
|
50
|
+
min-inline-size: 6rem;
|
|
51
|
+
padding: 0.45rem 0.7rem 0.45rem 1.35rem;
|
|
52
|
+
background: var(--boe-token-surface-surface-hover, #f4f4f4);
|
|
53
|
+
color: var(--boe-token-text-text-secondary, #6f6f6f);
|
|
54
|
+
font-size: 0.82rem;
|
|
55
|
+
transition: background ${boeMotionDuration.interactive} ${boeMotionEasing.standard};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
[part="stage"]:first-child {
|
|
59
|
+
padding-inline-start: 0.8rem;
|
|
60
|
+
border-start-start-radius: 999px;
|
|
61
|
+
border-end-start-radius: 999px;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
[part="stage"]:last-child {
|
|
65
|
+
border-start-end-radius: 999px;
|
|
66
|
+
border-end-end-radius: 999px;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* The chevron: a notch cut from the following stage plus an arrow on
|
|
70
|
+
this one, so the path reads as a directed sequence rather than a row
|
|
71
|
+
of pills. Drawn with clip-path so no extra elements are needed. */
|
|
72
|
+
[part="stage"]:not(:last-child) {
|
|
73
|
+
clip-path: polygon(0 0, calc(100% - 0.7rem) 0, 100% 50%, calc(100% - 0.7rem) 100%, 0 100%, 0.7rem 50%);
|
|
74
|
+
margin-inline-end: -0.55rem;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
[part="stage"]:first-child:not(:last-child) {
|
|
78
|
+
clip-path: polygon(0 0, calc(100% - 0.7rem) 0, 100% 50%, calc(100% - 0.7rem) 100%, 0 100%);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
[part="stage"]:last-child:not(:first-child) {
|
|
82
|
+
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, 0.7rem 50%);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
[part="stage"][data-state="complete"] {
|
|
86
|
+
background: color-mix(in srgb, var(--boe-token-surface-status-surface-success, #26a27b) 18%, transparent);
|
|
87
|
+
color: color-mix(in srgb, var(--boe-token-surface-status-surface-success, #26a27b) 72%, black 28%);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
[part="stage"][data-state="current"] {
|
|
91
|
+
background: var(--boe-token-surface-surface-brand, #0061d5);
|
|
92
|
+
color: var(--boe-token-text-text-on-brand, #ffffff);
|
|
93
|
+
font-weight: 700;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
[part="stage-label"] {
|
|
97
|
+
display: block;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
[part="stage-description"] {
|
|
101
|
+
display: block;
|
|
102
|
+
margin-block-start: 0.1rem;
|
|
103
|
+
font-size: 0.72rem;
|
|
104
|
+
font-weight: 400;
|
|
105
|
+
opacity: 0.85;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
[part="stage-marker"] {
|
|
109
|
+
margin-inline-end: 0.3rem;
|
|
110
|
+
font-weight: 700;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@media (prefers-reduced-motion: reduce) {
|
|
114
|
+
[part="stage"] {
|
|
115
|
+
transition: none;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@media (max-width: 34rem) {
|
|
120
|
+
/* Chevrons collapse below the width where they stop being legible;
|
|
121
|
+
the states still read from tone and the completed marker. */
|
|
122
|
+
[part="stage"],
|
|
123
|
+
[part="stage"]:first-child:not(:last-child),
|
|
124
|
+
[part="stage"]:last-child:not(:first-child) {
|
|
125
|
+
clip-path: none;
|
|
126
|
+
margin-inline-end: 0;
|
|
127
|
+
padding-inline-start: 0.8rem;
|
|
128
|
+
border-radius: 0;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
`;
|
|
132
|
+
/**
|
|
133
|
+
* Horizontal chevron lifecycle tracker for record headers — Draft → In
|
|
134
|
+
* Review → Approved → Executed.
|
|
135
|
+
*
|
|
136
|
+
* Distinct from `box-progress-steps`, which is a vertical setup rail for a
|
|
137
|
+
* task the reader is working through: this states where a *record* sits in
|
|
138
|
+
* its lifecycle, is read-only, and belongs in a header rather than a form.
|
|
139
|
+
*
|
|
140
|
+
* Rendered as an ordered list with the current stage marked `aria-current`,
|
|
141
|
+
* so the sequence and the position are both available without relying on the
|
|
142
|
+
* chevron geometry — which is decoration, and collapses on narrow viewports.
|
|
143
|
+
*/
|
|
144
|
+
export class StagePath extends BaseElement {
|
|
145
|
+
static tagName = DEFAULT_TAG_NAME;
|
|
146
|
+
static get observedAttributes() {
|
|
147
|
+
return ["current", "label", "stages"];
|
|
148
|
+
}
|
|
149
|
+
pathEl;
|
|
150
|
+
stagesRaw = null;
|
|
151
|
+
stagesCache = [];
|
|
152
|
+
get label() {
|
|
153
|
+
return this.getAttribute("label") ?? "Lifecycle";
|
|
154
|
+
}
|
|
155
|
+
set label(value) {
|
|
156
|
+
this.setAttribute("label", value);
|
|
157
|
+
}
|
|
158
|
+
/** Id of the stage the record is at. An unknown id leaves every stage upcoming. */
|
|
159
|
+
get current() {
|
|
160
|
+
return this.getAttribute("current") ?? "";
|
|
161
|
+
}
|
|
162
|
+
set current(value) {
|
|
163
|
+
this.setAttribute("current", value);
|
|
164
|
+
}
|
|
165
|
+
get stages() {
|
|
166
|
+
const raw = this.getAttribute("stages");
|
|
167
|
+
if (!raw) {
|
|
168
|
+
return [];
|
|
169
|
+
}
|
|
170
|
+
if (raw !== this.stagesRaw) {
|
|
171
|
+
this.stagesRaw = raw;
|
|
172
|
+
try {
|
|
173
|
+
const parsed = JSON.parse(raw);
|
|
174
|
+
this.stagesCache =
|
|
175
|
+
Array.isArray(parsed) && parsed.every(isStagePathStageRecord)
|
|
176
|
+
? parsed
|
|
177
|
+
: [];
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
this.stagesCache = [];
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return [...this.stagesCache];
|
|
184
|
+
}
|
|
185
|
+
set stages(value) {
|
|
186
|
+
if (value.length) {
|
|
187
|
+
this.setAttribute("stages", JSON.stringify(value));
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
this.removeAttribute("stages");
|
|
191
|
+
}
|
|
192
|
+
/** State of each stage, in order. */
|
|
193
|
+
get states() {
|
|
194
|
+
return resolveStageStates(this.stages, this.current);
|
|
195
|
+
}
|
|
196
|
+
renderTemplate() {
|
|
197
|
+
if (!this.shadowRoot) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
this.shadowRoot.innerHTML = `<style>${elementStyles}</style><ol part="path"></ol>`;
|
|
201
|
+
this.pathEl = this.shadowRoot.querySelector('[part="path"]');
|
|
202
|
+
}
|
|
203
|
+
setupListeners() {
|
|
204
|
+
// Read-only: a record's lifecycle position is not something a header edits.
|
|
205
|
+
}
|
|
206
|
+
update() {
|
|
207
|
+
if (!this.pathEl) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const stages = this.stages;
|
|
211
|
+
const states = resolveStageStates(stages, this.current);
|
|
212
|
+
this.pathEl.setAttribute("aria-label", this.label);
|
|
213
|
+
this.pathEl.innerHTML = stages
|
|
214
|
+
.map((stage, index) => {
|
|
215
|
+
const state = states[index];
|
|
216
|
+
// The completed marker is a second, non-colour signal for "done".
|
|
217
|
+
const marker = state === "complete" ? `<span part="stage-marker" aria-hidden="true">✓</span>` : "";
|
|
218
|
+
return `
|
|
219
|
+
<li
|
|
220
|
+
part="stage"
|
|
221
|
+
data-stage-id="${escapeHtml(stage.id)}"
|
|
222
|
+
data-state="${state}"
|
|
223
|
+
${state === "current" ? 'aria-current="step"' : ""}
|
|
224
|
+
>
|
|
225
|
+
<span part="stage-label">${marker}${escapeHtml(stage.label)}</span>
|
|
226
|
+
${state === "current" && stage.description
|
|
227
|
+
? `<span part="stage-description">${escapeHtml(stage.description)}</span>`
|
|
228
|
+
: ""}
|
|
229
|
+
</li>
|
|
230
|
+
`;
|
|
231
|
+
})
|
|
232
|
+
.join("");
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
StagePath.register();
|
|
@@ -6,6 +6,11 @@ type SelectOption = {
|
|
|
6
6
|
disabled?: boolean;
|
|
7
7
|
group?: string;
|
|
8
8
|
};
|
|
9
|
+
/** Detail of this element's `value-changed` event; `values` only when `multiple`. */
|
|
10
|
+
export interface SelectValueChangedDetail {
|
|
11
|
+
value: string;
|
|
12
|
+
values?: string[];
|
|
13
|
+
}
|
|
9
14
|
export declare class Select extends FormAssociatedElement {
|
|
10
15
|
static readonly tagName: string;
|
|
11
16
|
static get observedAttributes(): string[];
|
|
@@ -15,6 +20,8 @@ export declare class Select extends FormAssociatedElement {
|
|
|
15
20
|
private labelEl;
|
|
16
21
|
private descriptionEl;
|
|
17
22
|
private errorEl;
|
|
23
|
+
private controlEl;
|
|
24
|
+
private statusEl;
|
|
18
25
|
/** Allow selecting several options (native multi-select list box). */
|
|
19
26
|
get multiple(): boolean;
|
|
20
27
|
set multiple(value: boolean);
|
|
@@ -27,6 +34,20 @@ export declare class Select extends FormAssociatedElement {
|
|
|
27
34
|
set disabled(value: boolean);
|
|
28
35
|
get label(): string;
|
|
29
36
|
set label(value: string);
|
|
37
|
+
/**
|
|
38
|
+
* True while options are being fetched: shows a trailing spinner (matching
|
|
39
|
+
* `box-text-field`'s status vocabulary) and states "Loading options…" in
|
|
40
|
+
* the control instead of leaving it blank.
|
|
41
|
+
*/
|
|
42
|
+
get loading(): boolean;
|
|
43
|
+
set loading(value: boolean);
|
|
44
|
+
/**
|
|
45
|
+
* What the control says when it has no options and is not loading. An
|
|
46
|
+
* async-loaded select with an empty result must say so — a silently blank
|
|
47
|
+
* control reads as broken.
|
|
48
|
+
*/
|
|
49
|
+
get emptyText(): string;
|
|
50
|
+
set emptyText(value: string);
|
|
30
51
|
get options(): SelectOption[];
|
|
31
52
|
set options(value: SelectOption[]);
|
|
32
53
|
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
|