@spectrum-web-components/picker 1.2.0-beta.17 → 1.2.0-beta.19
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/custom-elements.json +176 -30
- package/package.json +16 -16
- package/src/InteractionController.dev.js +7 -1
- package/src/InteractionController.dev.js.map +2 -2
- package/src/InteractionController.js +1 -1
- package/src/InteractionController.js.map +2 -2
- package/src/MobileController.dev.js +4 -1
- package/src/MobileController.dev.js.map +2 -2
- package/src/MobileController.js +1 -1
- package/src/MobileController.js.map +2 -2
- package/src/Picker.d.ts +35 -5
- package/src/Picker.dev.js +142 -65
- package/src/Picker.dev.js.map +2 -2
- package/src/Picker.js +17 -21
- package/src/Picker.js.map +3 -3
- package/test/index.js +318 -298
- package/test/index.js.map +3 -3
- package/test/picker-reparenting.test.js +12 -3
- package/test/picker-reparenting.test.js.map +2 -2
package/src/Picker.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { CSSResultArray, PropertyValues, TemplateResult } from '@spectrum-web-components/base';
|
|
1
|
+
import { CSSResultArray, PropertyValues, SpectrumElement, TemplateResult } from '@spectrum-web-components/base';
|
|
2
2
|
import { StyleInfo } from '@spectrum-web-components/base/src/directives.js';
|
|
3
|
-
import { Focusable } from '@spectrum-web-components/shared/src/focusable.js';
|
|
4
3
|
import type { Tooltip } from '@spectrum-web-components/tooltip';
|
|
5
4
|
import '@spectrum-web-components/icons-ui/icons/sp-icon-chevron100.js';
|
|
6
5
|
import '@spectrum-web-components/icons-workflow/icons/sp-icon-alert.js';
|
|
7
6
|
import '@spectrum-web-components/menu/sp-menu.js';
|
|
8
7
|
import type { Menu, MenuItem, MenuItemChildren } from '@spectrum-web-components/menu';
|
|
8
|
+
import type { MenuItemKeydownEvent } from '@spectrum-web-components/menu';
|
|
9
9
|
import { Placement } from '@spectrum-web-components/overlay';
|
|
10
10
|
import { MatchMediaController } from '@spectrum-web-components/reactive-controllers/src/MatchMedia.js';
|
|
11
11
|
import { DependencyManagerController } from '@spectrum-web-components/reactive-controllers/src/DependencyManger.js';
|
|
@@ -16,11 +16,16 @@ import type { FieldLabel } from '@spectrum-web-components/field-label';
|
|
|
16
16
|
import { DesktopController } from './DesktopController.js';
|
|
17
17
|
import { MobileController } from './MobileController.js';
|
|
18
18
|
export declare const DESCRIPTION_ID = "option-picker";
|
|
19
|
-
declare const PickerBase_base: typeof
|
|
19
|
+
declare const PickerBase_base: typeof SpectrumElement & {
|
|
20
20
|
new (...args: any[]): import("@spectrum-web-components/base").SizedElementInterface;
|
|
21
21
|
prototype: import("@spectrum-web-components/base").SizedElementInterface;
|
|
22
22
|
};
|
|
23
23
|
export declare class PickerBase extends PickerBase_base {
|
|
24
|
+
static shadowRootOptions: {
|
|
25
|
+
delegatesFocus: boolean;
|
|
26
|
+
mode: ShadowRootMode;
|
|
27
|
+
slotAssignment?: SlotAssignmentMode | undefined;
|
|
28
|
+
};
|
|
24
29
|
isMobile: MatchMediaController;
|
|
25
30
|
strategy: DesktopController | MobileController;
|
|
26
31
|
appliedLabel?: string;
|
|
@@ -48,7 +53,9 @@ export declare class PickerBase extends PickerBase_base {
|
|
|
48
53
|
labelAlignment?: 'inline';
|
|
49
54
|
protected get menuItems(): MenuItem[];
|
|
50
55
|
optionsMenu: Menu;
|
|
51
|
-
|
|
56
|
+
/**
|
|
57
|
+
* @deprecated
|
|
58
|
+
* */
|
|
52
59
|
get selfManageFocusElement(): boolean;
|
|
53
60
|
overlayElement: Overlay;
|
|
54
61
|
protected tooltipEl?: Tooltip;
|
|
@@ -73,12 +80,19 @@ export declare class PickerBase extends PickerBase_base {
|
|
|
73
80
|
get focusElement(): HTMLElement;
|
|
74
81
|
forceFocusVisible(): void;
|
|
75
82
|
click(): void;
|
|
83
|
+
handleButtonClick(): void;
|
|
76
84
|
handleButtonBlur(): void;
|
|
77
85
|
focus(options?: FocusOptions): void;
|
|
86
|
+
/**
|
|
87
|
+
* @deprecated - Use `focus` instead.
|
|
88
|
+
*/
|
|
78
89
|
handleHelperFocus(): void;
|
|
90
|
+
handleFocus(): void;
|
|
79
91
|
handleChange(event: Event): void;
|
|
80
92
|
handleButtonFocus(event: FocusEvent): void;
|
|
93
|
+
protected handleEscape: (event: MenuItemKeydownEvent | KeyboardEvent) => void;
|
|
81
94
|
protected handleKeydown: (event: KeyboardEvent) => void;
|
|
95
|
+
protected keyboardOpen(): Promise<void>;
|
|
82
96
|
protected setValueFromItem(item: MenuItem, menuChangeEvent?: Event): Promise<void>;
|
|
83
97
|
protected setMenuItemSelected(item: MenuItem, value: boolean): void;
|
|
84
98
|
toggle(target?: boolean): void;
|
|
@@ -94,9 +108,12 @@ export declare class PickerBase extends PickerBase_base {
|
|
|
94
108
|
protected renderLabelContent(content: Node[]): TemplateResult | Node[];
|
|
95
109
|
protected get buttonContent(): TemplateResult[];
|
|
96
110
|
applyFocusElementLabel: (value: string, labelElement: FieldLabel) => void;
|
|
111
|
+
protected hasAccessibleLabel(): boolean;
|
|
112
|
+
protected warnNoLabel(): void;
|
|
97
113
|
protected renderOverlay(menu: TemplateResult): TemplateResult;
|
|
98
114
|
protected get renderDescriptionSlot(): TemplateResult;
|
|
99
115
|
protected render(): TemplateResult;
|
|
116
|
+
protected willUpdate(changes: PropertyValues<this>): void;
|
|
100
117
|
protected update(changes: PropertyValues<this>): void;
|
|
101
118
|
protected bindButtonKeydownListener(): void;
|
|
102
119
|
protected updated(changes: PropertyValues<this>): void;
|
|
@@ -106,9 +123,22 @@ export declare class PickerBase extends PickerBase_base {
|
|
|
106
123
|
protected hasRenderedOverlay: boolean;
|
|
107
124
|
private onScroll;
|
|
108
125
|
protected get renderMenu(): TemplateResult;
|
|
109
|
-
|
|
126
|
+
/**
|
|
127
|
+
* whether a selection change is already scheduled
|
|
128
|
+
*/
|
|
129
|
+
willManageSelection: boolean;
|
|
130
|
+
/**
|
|
131
|
+
* when the value changes or the menu slot changes, manage the selection on the next frame, if not already scheduled
|
|
132
|
+
* @param event
|
|
133
|
+
*/
|
|
110
134
|
protected shouldScheduleManageSelection(event?: Event): void;
|
|
135
|
+
/**
|
|
136
|
+
* when an item is added or updated, manage the selection, if it's not already scheduled
|
|
137
|
+
*/
|
|
111
138
|
protected shouldManageSelection(): void;
|
|
139
|
+
/**
|
|
140
|
+
* updates menu selection based on value
|
|
141
|
+
*/
|
|
112
142
|
protected manageSelection(): Promise<void>;
|
|
113
143
|
private selectionPromise;
|
|
114
144
|
private selectionResolver;
|
package/src/Picker.dev.js
CHANGED
|
@@ -13,7 +13,8 @@ import {
|
|
|
13
13
|
html,
|
|
14
14
|
nothing,
|
|
15
15
|
render,
|
|
16
|
-
SizedMixin
|
|
16
|
+
SizedMixin,
|
|
17
|
+
SpectrumElement
|
|
17
18
|
} from "@spectrum-web-components/base";
|
|
18
19
|
import {
|
|
19
20
|
classMap,
|
|
@@ -27,7 +28,6 @@ import {
|
|
|
27
28
|
} from "@spectrum-web-components/base/src/decorators.js";
|
|
28
29
|
import pickerStyles from "./picker.css.js";
|
|
29
30
|
import chevronStyles from "@spectrum-web-components/icon/src/spectrum-icon-chevron.css.js";
|
|
30
|
-
import { Focusable } from "@spectrum-web-components/shared/src/focusable.js";
|
|
31
31
|
import "@spectrum-web-components/icons-ui/icons/sp-icon-chevron100.js";
|
|
32
32
|
import "@spectrum-web-components/icons-workflow/icons/sp-icon-alert.js";
|
|
33
33
|
import "@spectrum-web-components/menu/sp-menu.js";
|
|
@@ -45,7 +45,9 @@ const chevronClass = {
|
|
|
45
45
|
xl: "spectrum-UIIcon-ChevronDown300"
|
|
46
46
|
};
|
|
47
47
|
export const DESCRIPTION_ID = "option-picker";
|
|
48
|
-
export class PickerBase extends SizedMixin(
|
|
48
|
+
export class PickerBase extends SizedMixin(SpectrumElement, {
|
|
49
|
+
noDefaultSize: true
|
|
50
|
+
}) {
|
|
49
51
|
/**
|
|
50
52
|
* Initializes the `PendingStateController` for the Picker component.
|
|
51
53
|
* The `PendingStateController` manages the pending state of the Picker.
|
|
@@ -64,20 +66,32 @@ export class PickerBase extends SizedMixin(Focusable, { noDefaultSize: true }) {
|
|
|
64
66
|
this.open = false;
|
|
65
67
|
this.readonly = false;
|
|
66
68
|
this.selects = "single";
|
|
67
|
-
this._selfManageFocusElement = false;
|
|
68
69
|
this.placement = "bottom-start";
|
|
69
70
|
this.quiet = false;
|
|
70
71
|
this.value = "";
|
|
71
72
|
this.listRole = "listbox";
|
|
72
73
|
this.itemRole = "option";
|
|
74
|
+
this.handleEscape = (event) => {
|
|
75
|
+
if (event.key === "Escape") {
|
|
76
|
+
event.stopPropagation();
|
|
77
|
+
event.preventDefault();
|
|
78
|
+
this.toggle(false);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
73
81
|
this.handleKeydown = (event) => {
|
|
74
82
|
this.focused = true;
|
|
75
|
-
if (
|
|
83
|
+
if (!["ArrowUp", "ArrowDown", "Enter", " ", "Escape"].includes(
|
|
84
|
+
event.key
|
|
85
|
+
)) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (event.key === "Escape") {
|
|
89
|
+
this.handleEscape(event);
|
|
76
90
|
return;
|
|
77
91
|
}
|
|
78
92
|
event.stopPropagation();
|
|
79
93
|
event.preventDefault();
|
|
80
|
-
this.
|
|
94
|
+
this.keyboardOpen();
|
|
81
95
|
};
|
|
82
96
|
this.handleSlottableRequest = (_event) => {
|
|
83
97
|
};
|
|
@@ -86,12 +100,20 @@ export class PickerBase extends SizedMixin(Focusable, { noDefaultSize: true }) {
|
|
|
86
100
|
this.labelAlignment = labelElement.sideAligned ? "inline" : void 0;
|
|
87
101
|
};
|
|
88
102
|
this.hasRenderedOverlay = false;
|
|
103
|
+
/**
|
|
104
|
+
* whether a selection change is already scheduled
|
|
105
|
+
*/
|
|
89
106
|
this.willManageSelection = false;
|
|
90
107
|
this.selectionPromise = Promise.resolve();
|
|
91
108
|
this.recentlyConnected = false;
|
|
92
109
|
this.enterKeydownOn = null;
|
|
93
110
|
this.handleEnterKeydown = (event) => {
|
|
94
|
-
if (event.
|
|
111
|
+
if (event.key !== "Enter") {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const target = event == null ? void 0 : event.target;
|
|
115
|
+
if (!target.open && target.hasSubmenu) {
|
|
116
|
+
event.preventDefault();
|
|
95
117
|
return;
|
|
96
118
|
}
|
|
97
119
|
if (this.enterKeydownOn) {
|
|
@@ -102,7 +124,7 @@ export class PickerBase extends SizedMixin(Focusable, { noDefaultSize: true }) {
|
|
|
102
124
|
this.addEventListener(
|
|
103
125
|
"keyup",
|
|
104
126
|
async (keyupEvent) => {
|
|
105
|
-
if (keyupEvent.
|
|
127
|
+
if (keyupEvent.key !== "Enter") {
|
|
106
128
|
return;
|
|
107
129
|
}
|
|
108
130
|
this.enterKeydownOn = null;
|
|
@@ -115,8 +137,11 @@ export class PickerBase extends SizedMixin(Focusable, { noDefaultSize: true }) {
|
|
|
115
137
|
get menuItems() {
|
|
116
138
|
return this.optionsMenu.childItems;
|
|
117
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* @deprecated
|
|
142
|
+
* */
|
|
118
143
|
get selfManageFocusElement() {
|
|
119
|
-
return
|
|
144
|
+
return true;
|
|
120
145
|
}
|
|
121
146
|
get selectedItem() {
|
|
122
147
|
return this._selectedItem;
|
|
@@ -140,7 +165,12 @@ export class PickerBase extends SizedMixin(Focusable, { noDefaultSize: true }) {
|
|
|
140
165
|
}
|
|
141
166
|
this.focused = true;
|
|
142
167
|
}
|
|
168
|
+
// handled by interaction controller, desktop or mobile; this is only called with a programmatic this.click()
|
|
143
169
|
click() {
|
|
170
|
+
this.toggle();
|
|
171
|
+
}
|
|
172
|
+
// pointer events handled by interaction controller, desktop or mobile; this is only called with a programmatic this.button.click()
|
|
173
|
+
handleButtonClick() {
|
|
144
174
|
if (this.disabled) {
|
|
145
175
|
return;
|
|
146
176
|
}
|
|
@@ -150,15 +180,21 @@ export class PickerBase extends SizedMixin(Focusable, { noDefaultSize: true }) {
|
|
|
150
180
|
this.focused = false;
|
|
151
181
|
}
|
|
152
182
|
focus(options) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
this.focused = this.hasVisibleFocusInTree();
|
|
156
|
-
}
|
|
183
|
+
var _a;
|
|
184
|
+
(_a = this.focusElement) == null ? void 0 : _a.focus(options);
|
|
157
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* @deprecated - Use `focus` instead.
|
|
188
|
+
*/
|
|
158
189
|
handleHelperFocus() {
|
|
159
190
|
this.focused = true;
|
|
160
191
|
this.button.focus();
|
|
161
192
|
}
|
|
193
|
+
handleFocus() {
|
|
194
|
+
if (!this.disabled && this.focusElement) {
|
|
195
|
+
this.focused = this.hasVisibleFocusInTree();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
162
198
|
handleChange(event) {
|
|
163
199
|
if (this.strategy) {
|
|
164
200
|
this.strategy.preventNextToggle = "no";
|
|
@@ -179,6 +215,9 @@ export class PickerBase extends SizedMixin(Focusable, { noDefaultSize: true }) {
|
|
|
179
215
|
var _a;
|
|
180
216
|
(_a = this.strategy) == null ? void 0 : _a.handleButtonFocus(event);
|
|
181
217
|
}
|
|
218
|
+
async keyboardOpen() {
|
|
219
|
+
this.toggle(true);
|
|
220
|
+
}
|
|
182
221
|
async setValueFromItem(item, menuChangeEvent) {
|
|
183
222
|
var _a;
|
|
184
223
|
this.open = false;
|
|
@@ -228,18 +267,25 @@ export class PickerBase extends SizedMixin(Focusable, { noDefaultSize: true }) {
|
|
|
228
267
|
item.selected = value;
|
|
229
268
|
}
|
|
230
269
|
toggle(target) {
|
|
231
|
-
if (this.readonly || this.pending) {
|
|
270
|
+
if (this.readonly || this.pending || this.disabled) {
|
|
232
271
|
return;
|
|
233
272
|
}
|
|
234
|
-
|
|
273
|
+
const open = typeof target !== "undefined" ? target : !this.open;
|
|
274
|
+
if (open && !this.open)
|
|
275
|
+
this.addEventListener(
|
|
276
|
+
"sp-opened",
|
|
277
|
+
() => {
|
|
278
|
+
var _a;
|
|
279
|
+
return (_a = this.optionsMenu) == null ? void 0 : _a.focusOnFirstSelectedItem();
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
once: true
|
|
283
|
+
}
|
|
284
|
+
);
|
|
285
|
+
this.open = open;
|
|
235
286
|
if (this.strategy) {
|
|
236
287
|
this.strategy.open = this.open;
|
|
237
288
|
}
|
|
238
|
-
if (this.open) {
|
|
239
|
-
this._selfManageFocusElement = true;
|
|
240
|
-
} else {
|
|
241
|
-
this._selfManageFocusElement = false;
|
|
242
|
-
}
|
|
243
289
|
}
|
|
244
290
|
close() {
|
|
245
291
|
if (this.readonly) {
|
|
@@ -331,11 +377,33 @@ export class PickerBase extends SizedMixin(Focusable, { noDefaultSize: true }) {
|
|
|
331
377
|
aria-hidden="true"
|
|
332
378
|
name="tooltip"
|
|
333
379
|
id="tooltip"
|
|
380
|
+
@keydown=${this.handleKeydown}
|
|
334
381
|
@slotchange=${this.handleTooltipSlotchange}
|
|
335
382
|
></slot>
|
|
336
383
|
`
|
|
337
384
|
];
|
|
338
385
|
}
|
|
386
|
+
hasAccessibleLabel() {
|
|
387
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
388
|
+
const slotContent = ((_a = this.querySelector('[slot="label"]')) == null ? void 0 : _a.textContent) && ((_c = (_b = this.querySelector('[slot="label"]')) == null ? void 0 : _b.textContent) == null ? void 0 : _c.trim()) !== "";
|
|
389
|
+
const slotAlt = ((_e = (_d = this.querySelector('[slot="label"]')) == null ? void 0 : _d.getAttribute("alt")) == null ? void 0 : _e.trim()) && ((_g = (_f = this.querySelector('[slot="label"]')) == null ? void 0 : _f.getAttribute("alt")) == null ? void 0 : _g.trim()) !== "";
|
|
390
|
+
return !!this.label || !!this.getAttribute("aria-label") || !!this.getAttribute("aria-labelledby") || !!this.appliedLabel || !!slotContent || !!slotAlt;
|
|
391
|
+
}
|
|
392
|
+
warnNoLabel() {
|
|
393
|
+
window.__swc.warn(
|
|
394
|
+
this,
|
|
395
|
+
`<${this.localName}> needs one of the following to be accessible:`,
|
|
396
|
+
"https://opensource.adobe.com/spectrum-web-components/components/picker/#accessibility",
|
|
397
|
+
{
|
|
398
|
+
type: "accessibility",
|
|
399
|
+
issues: [
|
|
400
|
+
`an <sp-field-label> element with a \`for\` attribute referencing the \`id\` of the \`<${this.localName}>\`, or`,
|
|
401
|
+
'value supplied to the "label" attribute, which will be displayed visually as placeholder text, or',
|
|
402
|
+
'text content supplied in a <span> with slot="label", which will also be displayed visually as placeholder text.'
|
|
403
|
+
]
|
|
404
|
+
}
|
|
405
|
+
);
|
|
406
|
+
}
|
|
339
407
|
renderOverlay(menu) {
|
|
340
408
|
var _a, _b, _c;
|
|
341
409
|
if (((_a = this.strategy) == null ? void 0 : _a.overlay) === void 0) {
|
|
@@ -361,15 +429,9 @@ export class PickerBase extends SizedMixin(Focusable, { noDefaultSize: true }) {
|
|
|
361
429
|
this.tooltipEl.disabled = this.open;
|
|
362
430
|
}
|
|
363
431
|
return html`
|
|
364
|
-
<span
|
|
365
|
-
id="focus-helper"
|
|
366
|
-
tabindex="${this.focused || this.open ? "-1" : "0"}"
|
|
367
|
-
@focus=${this.handleHelperFocus}
|
|
368
|
-
aria-describedby=${DESCRIPTION_ID}
|
|
369
|
-
></span>
|
|
370
432
|
<button
|
|
371
433
|
aria-controls=${ifDefined(this.open ? "menu" : void 0)}
|
|
372
|
-
aria-describedby="tooltip"
|
|
434
|
+
aria-describedby="tooltip ${DESCRIPTION_ID}"
|
|
373
435
|
aria-expanded=${this.open ? "true" : "false"}
|
|
374
436
|
aria-haspopup="true"
|
|
375
437
|
aria-labelledby="loader icon label applied-label"
|
|
@@ -377,35 +439,36 @@ export class PickerBase extends SizedMixin(Focusable, { noDefaultSize: true }) {
|
|
|
377
439
|
class=${ifDefined(
|
|
378
440
|
this.labelAlignment ? `label-${this.labelAlignment}` : void 0
|
|
379
441
|
)}
|
|
442
|
+
@focus=${this.handleButtonFocus}
|
|
380
443
|
@blur=${this.handleButtonBlur}
|
|
381
444
|
@keydown=${{
|
|
382
445
|
handleEvent: this.handleEnterKeydown,
|
|
383
446
|
capture: true
|
|
384
447
|
}}
|
|
385
448
|
?disabled=${this.disabled}
|
|
386
|
-
tabindex="-1"
|
|
387
449
|
>
|
|
388
450
|
${this.buttonContent}
|
|
389
451
|
</button>
|
|
390
452
|
${this.renderMenu} ${this.renderDescriptionSlot}
|
|
391
453
|
`;
|
|
392
454
|
}
|
|
455
|
+
willUpdate(changes) {
|
|
456
|
+
super.willUpdate(changes);
|
|
457
|
+
if (changes.has("tabIndex") && !!this.tabIndex) {
|
|
458
|
+
this.button.tabIndex = this.tabIndex;
|
|
459
|
+
this.removeAttribute("tabindex");
|
|
460
|
+
}
|
|
461
|
+
}
|
|
393
462
|
update(changes) {
|
|
394
463
|
var _a, _b;
|
|
395
464
|
if (this.selects) {
|
|
396
465
|
this.selects = "single";
|
|
397
466
|
}
|
|
398
467
|
if (changes.has("disabled") && this.disabled) {
|
|
399
|
-
|
|
400
|
-
this.open = false;
|
|
401
|
-
this.strategy.open = false;
|
|
402
|
-
}
|
|
468
|
+
this.close();
|
|
403
469
|
}
|
|
404
470
|
if (changes.has("pending") && this.pending) {
|
|
405
|
-
|
|
406
|
-
this.open = false;
|
|
407
|
-
this.strategy.open = false;
|
|
408
|
-
}
|
|
471
|
+
this.close();
|
|
409
472
|
}
|
|
410
473
|
if (changes.has("value")) {
|
|
411
474
|
this.shouldScheduleManageSelection();
|
|
@@ -428,20 +491,8 @@ export class PickerBase extends SizedMixin(Focusable, { noDefaultSize: true }) {
|
|
|
428
491
|
this.updateComplete.then(async () => {
|
|
429
492
|
await new Promise((res) => requestAnimationFrame(res));
|
|
430
493
|
await new Promise((res) => requestAnimationFrame(res));
|
|
431
|
-
if (!this.
|
|
432
|
-
|
|
433
|
-
this,
|
|
434
|
-
`<${this.localName}> needs one of the following to be accessible:`,
|
|
435
|
-
"https://opensource.adobe.com/spectrum-web-components/components/picker/#accessibility",
|
|
436
|
-
{
|
|
437
|
-
type: "accessibility",
|
|
438
|
-
issues: [
|
|
439
|
-
`an <sp-field-label> element with a \`for\` attribute referencing the \`id\` of the \`<${this.localName}>\`, or`,
|
|
440
|
-
'value supplied to the "label" attribute, which will be displayed visually as placeholder text, or',
|
|
441
|
-
'text content supplied in a <span> with slot="label", which will also be displayed visually as placeholder text.'
|
|
442
|
-
]
|
|
443
|
-
}
|
|
444
|
-
);
|
|
494
|
+
if (!this.hasAccessibleLabel()) {
|
|
495
|
+
this.warnNoLabel();
|
|
445
496
|
}
|
|
446
497
|
});
|
|
447
498
|
}
|
|
@@ -525,6 +576,7 @@ export class PickerBase extends SizedMixin(Focusable, { noDefaultSize: true }) {
|
|
|
525
576
|
.selects=${this.selects}
|
|
526
577
|
.selected=${this.value ? [this.value] : []}
|
|
527
578
|
size=${this.size}
|
|
579
|
+
@sp-menu-item-keydown=${this.handleEscape}
|
|
528
580
|
@sp-menu-item-added-or-updated=${this.shouldManageSelection}
|
|
529
581
|
>
|
|
530
582
|
<slot @slotchange=${this.shouldScheduleManageSelection}></slot>
|
|
@@ -539,6 +591,10 @@ export class PickerBase extends SizedMixin(Focusable, { noDefaultSize: true }) {
|
|
|
539
591
|
}
|
|
540
592
|
return menu;
|
|
541
593
|
}
|
|
594
|
+
/**
|
|
595
|
+
* when the value changes or the menu slot changes, manage the selection on the next frame, if not already scheduled
|
|
596
|
+
* @param event
|
|
597
|
+
*/
|
|
542
598
|
shouldScheduleManageSelection(event) {
|
|
543
599
|
if (!this.willManageSelection && (!event || event.target.getRootNode().host === this)) {
|
|
544
600
|
this.willManageSelection = true;
|
|
@@ -549,6 +605,9 @@ export class PickerBase extends SizedMixin(Focusable, { noDefaultSize: true }) {
|
|
|
549
605
|
});
|
|
550
606
|
}
|
|
551
607
|
}
|
|
608
|
+
/**
|
|
609
|
+
* when an item is added or updated, manage the selection, if it's not already scheduled
|
|
610
|
+
*/
|
|
552
611
|
shouldManageSelection() {
|
|
553
612
|
if (this.willManageSelection) {
|
|
554
613
|
return;
|
|
@@ -556,6 +615,9 @@ export class PickerBase extends SizedMixin(Focusable, { noDefaultSize: true }) {
|
|
|
556
615
|
this.willManageSelection = true;
|
|
557
616
|
this.manageSelection();
|
|
558
617
|
}
|
|
618
|
+
/**
|
|
619
|
+
* updates menu selection based on value
|
|
620
|
+
*/
|
|
559
621
|
async manageSelection() {
|
|
560
622
|
if (this.selects == null) return;
|
|
561
623
|
this.selectionPromise = new Promise(
|
|
@@ -605,6 +667,7 @@ export class PickerBase extends SizedMixin(Focusable, { noDefaultSize: true }) {
|
|
|
605
667
|
connectedCallback() {
|
|
606
668
|
super.connectedCallback();
|
|
607
669
|
this.recentlyConnected = this.hasUpdated;
|
|
670
|
+
this.addEventListener("focus", this.handleFocus);
|
|
608
671
|
}
|
|
609
672
|
disconnectedCallback() {
|
|
610
673
|
var _a;
|
|
@@ -613,6 +676,10 @@ export class PickerBase extends SizedMixin(Focusable, { noDefaultSize: true }) {
|
|
|
613
676
|
super.disconnectedCallback();
|
|
614
677
|
}
|
|
615
678
|
}
|
|
679
|
+
PickerBase.shadowRootOptions = {
|
|
680
|
+
...SpectrumElement.shadowRootOptions,
|
|
681
|
+
delegatesFocus: true
|
|
682
|
+
};
|
|
616
683
|
__decorateClass([
|
|
617
684
|
state()
|
|
618
685
|
], PickerBase.prototype, "appliedLabel", 2);
|
|
@@ -677,28 +744,38 @@ export class Picker extends PickerBase {
|
|
|
677
744
|
constructor() {
|
|
678
745
|
super(...arguments);
|
|
679
746
|
this.handleKeydown = (event) => {
|
|
680
|
-
|
|
747
|
+
var _a;
|
|
748
|
+
const { key } = event;
|
|
749
|
+
const handledKeys = [
|
|
750
|
+
"ArrowUp",
|
|
751
|
+
"ArrowDown",
|
|
752
|
+
"ArrowLeft",
|
|
753
|
+
"ArrowRight",
|
|
754
|
+
"Enter",
|
|
755
|
+
" ",
|
|
756
|
+
"Escape"
|
|
757
|
+
].includes(key);
|
|
758
|
+
const openKeys = ["ArrowUp", "ArrowDown", "Enter", " "].includes(key);
|
|
681
759
|
this.focused = true;
|
|
682
|
-
if (
|
|
760
|
+
if ("Escape" === key) {
|
|
761
|
+
this.handleEscape(event);
|
|
683
762
|
return;
|
|
684
763
|
}
|
|
685
|
-
if (
|
|
686
|
-
this.toggle(true);
|
|
687
|
-
event.preventDefault();
|
|
764
|
+
if (!handledKeys || this.readonly || this.pending) {
|
|
688
765
|
return;
|
|
689
766
|
}
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
let nextIndex = selectedIndex + nextOffset;
|
|
694
|
-
while (this.menuItems[nextIndex] && this.menuItems[nextIndex].disabled) {
|
|
695
|
-
nextIndex += nextOffset;
|
|
696
|
-
}
|
|
697
|
-
if (!this.menuItems[nextIndex] || this.menuItems[nextIndex].disabled) {
|
|
767
|
+
if (openKeys) {
|
|
768
|
+
this.keyboardOpen();
|
|
769
|
+
event.preventDefault();
|
|
698
770
|
return;
|
|
699
771
|
}
|
|
700
|
-
|
|
701
|
-
|
|
772
|
+
event.preventDefault();
|
|
773
|
+
const nextItem = (_a = this.optionsMenu) == null ? void 0 : _a.getNeighboringFocusableElement(
|
|
774
|
+
this.selectedItem,
|
|
775
|
+
key === "ArrowLeft"
|
|
776
|
+
);
|
|
777
|
+
if (!this.value || nextItem !== this.selectedItem) {
|
|
778
|
+
if (!!nextItem) this.setValueFromItem(nextItem);
|
|
702
779
|
}
|
|
703
780
|
};
|
|
704
781
|
}
|