@spectrum-web-components/picker 0.10.3 → 0.10.4-express.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/package.json +5 -5
- package/sp-picker.d.ts +6 -0
- package/sp-picker.js +14 -0
- package/sp-picker.js.map +1 -0
- package/src/Picker.d.ts +102 -0
- package/src/Picker.js +529 -0
- package/src/Picker.js.map +1 -0
- package/src/index.d.ts +1 -0
- package/src/index.js +13 -0
- package/src/index.js.map +1 -0
- package/src/picker.css.d.ts +2 -0
- package/src/picker.css.js +299 -0
- package/src/picker.css.js.map +1 -0
- package/src/spectrum-picker.css.d.ts +2 -0
- package/src/spectrum-picker.css.js +295 -0
- package/src/spectrum-picker.css.js.map +1 -0
- package/stories/picker-sizes.stories.js +51 -0
- package/stories/picker-sizes.stories.js.map +1 -0
- package/stories/picker.stories.js +381 -0
- package/stories/picker.stories.js.map +1 -0
- package/stories/states.js +238 -0
- package/stories/states.js.map +1 -0
- package/sync/index.d.ts +1 -0
- package/sync/index.js +17 -0
- package/sync/index.js.map +1 -0
- package/sync/sp-picker.d.ts +2 -0
- package/sync/sp-picker.js +14 -0
- package/sync/sp-picker.js.map +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spectrum-web-components/picker",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.4-express.0+7a2be85d7",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -53,9 +53,9 @@
|
|
|
53
53
|
"@spectrum-web-components/icon": "^0.11.4",
|
|
54
54
|
"@spectrum-web-components/icons-ui": "^0.8.4",
|
|
55
55
|
"@spectrum-web-components/icons-workflow": "^0.8.4",
|
|
56
|
-
"@spectrum-web-components/menu": "^0.12.
|
|
57
|
-
"@spectrum-web-components/overlay": "^0.15.0",
|
|
58
|
-
"@spectrum-web-components/popover": "^0.11.
|
|
56
|
+
"@spectrum-web-components/menu": "^0.12.3-express.0+7a2be85d7",
|
|
57
|
+
"@spectrum-web-components/overlay": "^0.15.1-express.0+7a2be85d7",
|
|
58
|
+
"@spectrum-web-components/popover": "^0.11.8-express.0+7a2be85d7",
|
|
59
59
|
"@spectrum-web-components/reactive-controllers": "^0.2.1",
|
|
60
60
|
"@spectrum-web-components/shared": "^0.13.5",
|
|
61
61
|
"@spectrum-web-components/tray": "^0.3.3",
|
|
@@ -71,5 +71,5 @@
|
|
|
71
71
|
"./sync/index.js",
|
|
72
72
|
"./sync/sp-*.js"
|
|
73
73
|
],
|
|
74
|
-
"gitHead": "
|
|
74
|
+
"gitHead": "7a2be85d7e231dcf4141a86b7056f6c139a43851"
|
|
75
75
|
}
|
package/sp-picker.d.ts
ADDED
package/sp-picker.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
import { Picker } from './src/Picker.js';
|
|
13
|
+
customElements.define('sp-picker', Picker);
|
|
14
|
+
//# sourceMappingURL=sp-picker.js.map
|
package/sp-picker.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sp-picker.js","sourceRoot":"","sources":["sp-picker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;EAUE;AAEF,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,cAAc,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC","sourcesContent":["/*\nCopyright 2020 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\nimport { Picker } from './src/Picker.js';\n\ncustomElements.define('sp-picker', Picker);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sp-picker': Picker;\n }\n}\n"]}
|
package/src/Picker.d.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { CSSResultArray, PropertyValues, TemplateResult } from '@spectrum-web-components/base';
|
|
2
|
+
import { Focusable } from '@spectrum-web-components/shared/src/focusable.js';
|
|
3
|
+
import '@spectrum-web-components/icons-ui/icons/sp-icon-chevron100.js';
|
|
4
|
+
import '@spectrum-web-components/icons-workflow/icons/sp-icon-alert.js';
|
|
5
|
+
import '@spectrum-web-components/menu/sp-menu.js';
|
|
6
|
+
import type { Menu, MenuItem, MenuItemAddedOrUpdatedEvent, MenuItemChildren, MenuItemRemovedEvent } from '@spectrum-web-components/menu';
|
|
7
|
+
import '@spectrum-web-components/tray/sp-tray.js';
|
|
8
|
+
import '@spectrum-web-components/popover/sp-popover.js';
|
|
9
|
+
import { OverlayOptions, Placement, TriggerInteractions } from '@spectrum-web-components/overlay';
|
|
10
|
+
import { MatchMediaController } from '@spectrum-web-components/reactive-controllers/src/MatchMedia.js';
|
|
11
|
+
declare const PickerBase_base: typeof Focusable & {
|
|
12
|
+
new (...args: any[]): import("@spectrum-web-components/base").SizedElementInterface;
|
|
13
|
+
prototype: import("@spectrum-web-components/base").SizedElementInterface;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* @element sp-picker
|
|
17
|
+
*
|
|
18
|
+
* @slot label - The placeholder content for the Picker
|
|
19
|
+
* @slot - menu items to be listed in the Picker
|
|
20
|
+
* @fires change - Announces that the `value` of the element has changed
|
|
21
|
+
* @fires sp-opened - Announces that the overlay has been opened
|
|
22
|
+
* @fires sp-closed - Announces that the overlay has been closed
|
|
23
|
+
*/
|
|
24
|
+
export declare class PickerBase extends PickerBase_base {
|
|
25
|
+
/**
|
|
26
|
+
* @private
|
|
27
|
+
*/
|
|
28
|
+
static openOverlay: (target: HTMLElement, interaction: TriggerInteractions, content: HTMLElement, options: OverlayOptions) => Promise<() => void>;
|
|
29
|
+
protected isMobile: MatchMediaController;
|
|
30
|
+
button: HTMLButtonElement;
|
|
31
|
+
get target(): HTMLButtonElement | this;
|
|
32
|
+
disabled: boolean;
|
|
33
|
+
focused: boolean;
|
|
34
|
+
icons?: 'only' | 'none';
|
|
35
|
+
invalid: boolean;
|
|
36
|
+
label?: string;
|
|
37
|
+
open: boolean;
|
|
38
|
+
readonly: boolean;
|
|
39
|
+
selects: undefined | 'single';
|
|
40
|
+
menuItems: MenuItem[];
|
|
41
|
+
private restoreChildren?;
|
|
42
|
+
optionsMenu: Menu;
|
|
43
|
+
/**
|
|
44
|
+
* @type {"auto" | "auto-start" | "auto-end" | "top" | "bottom" | "right" | "left" | "top-start" | "top-end" | "bottom-start" | "bottom-end" | "right-start" | "right-end" | "left-start" | "left-end" | "none"}
|
|
45
|
+
* @attr
|
|
46
|
+
*/
|
|
47
|
+
placement: Placement;
|
|
48
|
+
quiet: boolean;
|
|
49
|
+
value: string;
|
|
50
|
+
selectedItem?: MenuItem;
|
|
51
|
+
private closeOverlay?;
|
|
52
|
+
private popover;
|
|
53
|
+
protected listRole: 'listbox' | 'menu';
|
|
54
|
+
protected itemRole: string;
|
|
55
|
+
constructor();
|
|
56
|
+
get focusElement(): HTMLElement;
|
|
57
|
+
forceFocusVisible(): void;
|
|
58
|
+
onButtonBlur(): void;
|
|
59
|
+
protected onButtonClick(): void;
|
|
60
|
+
focus(options?: FocusOptions): void;
|
|
61
|
+
onHelperFocus(): void;
|
|
62
|
+
onButtonFocus(): void;
|
|
63
|
+
handleChange(event: Event): void;
|
|
64
|
+
protected onKeydown: (event: KeyboardEvent) => void;
|
|
65
|
+
setValueFromItem(item: MenuItem, menuChangeEvent?: Event): Promise<void>;
|
|
66
|
+
toggle(target?: boolean): void;
|
|
67
|
+
close(): void;
|
|
68
|
+
overlayCloseCallback: () => void;
|
|
69
|
+
protected onOverlayClosed(): void;
|
|
70
|
+
private popoverFragment;
|
|
71
|
+
private generatePopover;
|
|
72
|
+
private openMenu;
|
|
73
|
+
protected sizePopover(popover: HTMLElement): void;
|
|
74
|
+
private closeMenu;
|
|
75
|
+
protected get selectedItemContent(): MenuItemChildren;
|
|
76
|
+
protected renderLabelContent(content: Node[]): TemplateResult | Node[];
|
|
77
|
+
protected get buttonContent(): TemplateResult[];
|
|
78
|
+
protected render(): TemplateResult;
|
|
79
|
+
protected update(changes: PropertyValues<this>): void;
|
|
80
|
+
protected get dismissHelper(): TemplateResult;
|
|
81
|
+
protected get renderPopover(): TemplateResult;
|
|
82
|
+
private _willUpdateItems;
|
|
83
|
+
protected itemsUpdated: Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Acquire the available MenuItems in the Picker by
|
|
86
|
+
* direct element query or by assuming the list managed
|
|
87
|
+
* by the Menu within the open options overlay.
|
|
88
|
+
*/
|
|
89
|
+
protected updateMenuItems(event?: MenuItemAddedOrUpdatedEvent | MenuItemRemovedEvent): void;
|
|
90
|
+
protected updated(changedProperties: PropertyValues): void;
|
|
91
|
+
protected manageSelection(): void;
|
|
92
|
+
private menuStatePromise;
|
|
93
|
+
private menuStateResolver;
|
|
94
|
+
protected getUpdateComplete(): Promise<boolean>;
|
|
95
|
+
connectedCallback(): void;
|
|
96
|
+
disconnectedCallback(): void;
|
|
97
|
+
}
|
|
98
|
+
export declare class Picker extends PickerBase {
|
|
99
|
+
static get styles(): CSSResultArray;
|
|
100
|
+
protected onKeydown: (event: KeyboardEvent) => void;
|
|
101
|
+
}
|
|
102
|
+
export {};
|
package/src/Picker.js
ADDED
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
var _a;
|
|
13
|
+
import { __decorate } from "tslib";
|
|
14
|
+
import { html, nothing, render, SizedMixin, } from '@spectrum-web-components/base';
|
|
15
|
+
import { classMap } from '@spectrum-web-components/base/src/directives.js';
|
|
16
|
+
import { property, query, } from '@spectrum-web-components/base/src/decorators.js';
|
|
17
|
+
import pickerStyles from './picker.css.js';
|
|
18
|
+
import chevronStyles from '@spectrum-web-components/icon/src/spectrum-icon-chevron.css.js';
|
|
19
|
+
import { Focusable } from '@spectrum-web-components/shared/src/focusable.js';
|
|
20
|
+
import { reparentChildren } from '@spectrum-web-components/shared/src/reparent-children.js';
|
|
21
|
+
import '@spectrum-web-components/icons-ui/icons/sp-icon-chevron100.js';
|
|
22
|
+
import '@spectrum-web-components/icons-workflow/icons/sp-icon-alert.js';
|
|
23
|
+
import '@spectrum-web-components/menu/sp-menu.js';
|
|
24
|
+
import '@spectrum-web-components/tray/sp-tray.js';
|
|
25
|
+
import '@spectrum-web-components/popover/sp-popover.js';
|
|
26
|
+
import { openOverlay, } from '@spectrum-web-components/overlay';
|
|
27
|
+
import { IS_MOBILE, MatchMediaController, } from '@spectrum-web-components/reactive-controllers/src/MatchMedia.js';
|
|
28
|
+
const chevronClass = {
|
|
29
|
+
s: 'spectrum-UIIcon-ChevronDown75',
|
|
30
|
+
m: 'spectrum-UIIcon-ChevronDown100',
|
|
31
|
+
l: 'spectrum-UIIcon-ChevronDown200',
|
|
32
|
+
xl: 'spectrum-UIIcon-ChevronDown300',
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* @element sp-picker
|
|
36
|
+
*
|
|
37
|
+
* @slot label - The placeholder content for the Picker
|
|
38
|
+
* @slot - menu items to be listed in the Picker
|
|
39
|
+
* @fires change - Announces that the `value` of the element has changed
|
|
40
|
+
* @fires sp-opened - Announces that the overlay has been opened
|
|
41
|
+
* @fires sp-closed - Announces that the overlay has been closed
|
|
42
|
+
*/
|
|
43
|
+
export class PickerBase extends SizedMixin(Focusable) {
|
|
44
|
+
constructor() {
|
|
45
|
+
super();
|
|
46
|
+
this.isMobile = new MatchMediaController(this, IS_MOBILE);
|
|
47
|
+
this.disabled = false;
|
|
48
|
+
this.focused = false;
|
|
49
|
+
this.invalid = false;
|
|
50
|
+
this.open = false;
|
|
51
|
+
this.readonly = false;
|
|
52
|
+
this.selects = 'single';
|
|
53
|
+
this.menuItems = [];
|
|
54
|
+
/**
|
|
55
|
+
* @type {"auto" | "auto-start" | "auto-end" | "top" | "bottom" | "right" | "left" | "top-start" | "top-end" | "bottom-start" | "bottom-end" | "right-start" | "right-end" | "left-start" | "left-end" | "none"}
|
|
56
|
+
* @attr
|
|
57
|
+
*/
|
|
58
|
+
this.placement = 'bottom-start';
|
|
59
|
+
this.quiet = false;
|
|
60
|
+
this.value = '';
|
|
61
|
+
this.listRole = 'listbox';
|
|
62
|
+
this.itemRole = 'option';
|
|
63
|
+
this.onKeydown = (event) => {
|
|
64
|
+
this.focused = true;
|
|
65
|
+
if (event.code !== 'ArrowDown' && event.code !== 'ArrowUp') {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
event.preventDefault();
|
|
69
|
+
this.toggle(true);
|
|
70
|
+
};
|
|
71
|
+
this.overlayCloseCallback = () => {
|
|
72
|
+
this.open = false;
|
|
73
|
+
};
|
|
74
|
+
this._willUpdateItems = false;
|
|
75
|
+
this.itemsUpdated = Promise.resolve();
|
|
76
|
+
this.menuStatePromise = Promise.resolve();
|
|
77
|
+
this.onKeydown = this.onKeydown.bind(this);
|
|
78
|
+
}
|
|
79
|
+
get target() {
|
|
80
|
+
return this.button;
|
|
81
|
+
}
|
|
82
|
+
get focusElement() {
|
|
83
|
+
if (this.open) {
|
|
84
|
+
return this.optionsMenu;
|
|
85
|
+
}
|
|
86
|
+
return this.button;
|
|
87
|
+
}
|
|
88
|
+
forceFocusVisible() {
|
|
89
|
+
this.focused = true;
|
|
90
|
+
}
|
|
91
|
+
onButtonBlur() {
|
|
92
|
+
this.focused = false;
|
|
93
|
+
this.target.removeEventListener('keydown', this.onKeydown);
|
|
94
|
+
}
|
|
95
|
+
onButtonClick() {
|
|
96
|
+
this.toggle();
|
|
97
|
+
}
|
|
98
|
+
focus(options) {
|
|
99
|
+
super.focus(options);
|
|
100
|
+
if (!this.disabled && this.focusElement) {
|
|
101
|
+
this.focused = this.hasVisibleFocusInTree();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
onHelperFocus() {
|
|
105
|
+
// set focused to true here instead of onButtonFocus so clicks don't flash a focus outline
|
|
106
|
+
this.focused = true;
|
|
107
|
+
this.button.focus();
|
|
108
|
+
}
|
|
109
|
+
onButtonFocus() {
|
|
110
|
+
this.target.addEventListener('keydown', this.onKeydown);
|
|
111
|
+
}
|
|
112
|
+
handleChange(event) {
|
|
113
|
+
event.stopPropagation();
|
|
114
|
+
const target = event.target;
|
|
115
|
+
const [selected] = target.selectedItems;
|
|
116
|
+
this.setValueFromItem(selected, event);
|
|
117
|
+
}
|
|
118
|
+
async setValueFromItem(item, menuChangeEvent) {
|
|
119
|
+
const oldSelectedItem = this.selectedItem;
|
|
120
|
+
const oldValue = this.value;
|
|
121
|
+
this.selectedItem = item;
|
|
122
|
+
this.value = item.value;
|
|
123
|
+
this.open = false;
|
|
124
|
+
await this.updateComplete;
|
|
125
|
+
const applyDefault = this.dispatchEvent(new Event('change', {
|
|
126
|
+
bubbles: true,
|
|
127
|
+
cancelable: true,
|
|
128
|
+
composed: true,
|
|
129
|
+
}));
|
|
130
|
+
if (!applyDefault) {
|
|
131
|
+
if (menuChangeEvent) {
|
|
132
|
+
menuChangeEvent.preventDefault();
|
|
133
|
+
}
|
|
134
|
+
this.selectedItem.selected = false;
|
|
135
|
+
if (oldSelectedItem) {
|
|
136
|
+
oldSelectedItem.selected = true;
|
|
137
|
+
}
|
|
138
|
+
this.selectedItem = oldSelectedItem;
|
|
139
|
+
this.value = oldValue;
|
|
140
|
+
this.open = true;
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (oldSelectedItem) {
|
|
144
|
+
oldSelectedItem.selected = false;
|
|
145
|
+
}
|
|
146
|
+
item.selected = !!this.selects;
|
|
147
|
+
}
|
|
148
|
+
toggle(target) {
|
|
149
|
+
if (this.readonly) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
this.open = typeof target !== 'undefined' ? target : !this.open;
|
|
153
|
+
}
|
|
154
|
+
close() {
|
|
155
|
+
if (this.readonly) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
this.open = false;
|
|
159
|
+
}
|
|
160
|
+
onOverlayClosed() {
|
|
161
|
+
this.close();
|
|
162
|
+
if (this.restoreChildren) {
|
|
163
|
+
this.restoreChildren();
|
|
164
|
+
this.restoreChildren = undefined;
|
|
165
|
+
}
|
|
166
|
+
this.menuStateResolver();
|
|
167
|
+
}
|
|
168
|
+
async generatePopover(deprecatedMenu) {
|
|
169
|
+
if (!this.popoverFragment) {
|
|
170
|
+
this.popoverFragment = document.createDocumentFragment();
|
|
171
|
+
}
|
|
172
|
+
render(this.renderPopover, this.popoverFragment, { host: this });
|
|
173
|
+
this.popover = this.popoverFragment.children[0];
|
|
174
|
+
this.optionsMenu = this.popover.children[1];
|
|
175
|
+
if (deprecatedMenu) {
|
|
176
|
+
console.warn(`Deprecation Notice: You no longer need to provide an sp-menu child to ${this.tagName.toLowerCase()}. Any styling or attributes on the sp-menu will be ignored.`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
async openMenu() {
|
|
180
|
+
/* c8 ignore next 9 */
|
|
181
|
+
let reparentableChildren = [];
|
|
182
|
+
const deprecatedMenu = this.querySelector(':scope > sp-menu');
|
|
183
|
+
await this.generatePopover(deprecatedMenu);
|
|
184
|
+
if (deprecatedMenu) {
|
|
185
|
+
reparentableChildren = Array.from(deprecatedMenu.children);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
reparentableChildren = Array.from(this.children).filter((element) => {
|
|
189
|
+
return !element.hasAttribute('slot');
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
if (reparentableChildren.length === 0) {
|
|
193
|
+
this.menuStateResolver();
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
this.restoreChildren = reparentChildren(reparentableChildren, this.optionsMenu, () => {
|
|
197
|
+
return (el) => {
|
|
198
|
+
if (typeof el.focused !== 'undefined') {
|
|
199
|
+
el.focused = false;
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
});
|
|
203
|
+
this.sizePopover(this.popover);
|
|
204
|
+
this.addEventListener('sp-opened', async () => {
|
|
205
|
+
this.updateMenuItems();
|
|
206
|
+
await Promise.all([
|
|
207
|
+
this.itemsUpdated,
|
|
208
|
+
this.optionsMenu.updateComplete,
|
|
209
|
+
]);
|
|
210
|
+
this.menuStateResolver();
|
|
211
|
+
}, { once: true });
|
|
212
|
+
this.closeOverlay = Picker.openOverlay(this, 'modal', this.popover, {
|
|
213
|
+
placement: this.isMobile.matches ? 'none' : this.placement,
|
|
214
|
+
receivesFocus: 'auto',
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
sizePopover(popover) {
|
|
218
|
+
if (this.isMobile.matches) {
|
|
219
|
+
popover.style.setProperty('--swc-menu-width', `100%`);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (this.quiet)
|
|
223
|
+
return;
|
|
224
|
+
// only use `this.offsetWidth` when Standard variant
|
|
225
|
+
popover.style.setProperty('min-width', `${this.offsetWidth}px`);
|
|
226
|
+
}
|
|
227
|
+
async closeMenu() {
|
|
228
|
+
if (this.closeOverlay) {
|
|
229
|
+
const closeOverlay = this.closeOverlay;
|
|
230
|
+
delete this.closeOverlay;
|
|
231
|
+
(await closeOverlay)();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
get selectedItemContent() {
|
|
235
|
+
if (this.selectedItem) {
|
|
236
|
+
return this.selectedItem.itemChildren;
|
|
237
|
+
}
|
|
238
|
+
return { icon: [], content: [] };
|
|
239
|
+
}
|
|
240
|
+
renderLabelContent(content) {
|
|
241
|
+
if (this.value && this.selectedItem) {
|
|
242
|
+
return content;
|
|
243
|
+
}
|
|
244
|
+
return html `
|
|
245
|
+
<slot name="label">${this.label}</slot>
|
|
246
|
+
`;
|
|
247
|
+
}
|
|
248
|
+
get buttonContent() {
|
|
249
|
+
const labelClasses = {
|
|
250
|
+
'visually-hidden': this.icons === 'only' && !!this.value,
|
|
251
|
+
placeholder: !this.value,
|
|
252
|
+
};
|
|
253
|
+
return [
|
|
254
|
+
html `
|
|
255
|
+
<span id="icon" ?hidden=${this.icons === 'none'}>
|
|
256
|
+
${this.selectedItemContent.icon}
|
|
257
|
+
</span>
|
|
258
|
+
<span id="label" class=${classMap(labelClasses)}>
|
|
259
|
+
${this.renderLabelContent(this.selectedItemContent.content)}
|
|
260
|
+
</span>
|
|
261
|
+
${this.invalid
|
|
262
|
+
? html `
|
|
263
|
+
<sp-icon-alert
|
|
264
|
+
class="validation-icon"
|
|
265
|
+
></sp-icon-alert>
|
|
266
|
+
`
|
|
267
|
+
: nothing}
|
|
268
|
+
<sp-icon-chevron100
|
|
269
|
+
class="picker ${chevronClass[this.size]}"
|
|
270
|
+
></sp-icon-chevron100>
|
|
271
|
+
`,
|
|
272
|
+
];
|
|
273
|
+
}
|
|
274
|
+
// a helper to throw focus to the button is needed because Safari
|
|
275
|
+
// won't include buttons in the tab order even with tabindex="0"
|
|
276
|
+
render() {
|
|
277
|
+
return html `
|
|
278
|
+
<span
|
|
279
|
+
id="focus-helper"
|
|
280
|
+
tabindex="${this.focused ? '-1' : '0'}"
|
|
281
|
+
@focus=${this.onHelperFocus}
|
|
282
|
+
></span>
|
|
283
|
+
<button
|
|
284
|
+
aria-haspopup="true"
|
|
285
|
+
aria-expanded=${this.open ? 'true' : 'false'}
|
|
286
|
+
aria-labelledby="button icon label"
|
|
287
|
+
id="button"
|
|
288
|
+
class="button"
|
|
289
|
+
@blur=${this.onButtonBlur}
|
|
290
|
+
@click=${this.onButtonClick}
|
|
291
|
+
@focus=${this.onButtonFocus}
|
|
292
|
+
?disabled=${this.disabled}
|
|
293
|
+
tabindex="-1"
|
|
294
|
+
>
|
|
295
|
+
${this.buttonContent}
|
|
296
|
+
</button>
|
|
297
|
+
`;
|
|
298
|
+
}
|
|
299
|
+
update(changes) {
|
|
300
|
+
if (this.selects) {
|
|
301
|
+
// Always force `selects` to "single" when set.
|
|
302
|
+
// TODO: Add support functionally and visually for "multiple"
|
|
303
|
+
this.selects = 'single';
|
|
304
|
+
}
|
|
305
|
+
super.update(changes);
|
|
306
|
+
}
|
|
307
|
+
get dismissHelper() {
|
|
308
|
+
return html `
|
|
309
|
+
<div class="visually-hidden">
|
|
310
|
+
<button
|
|
311
|
+
tabindex="-1"
|
|
312
|
+
arial-label="Dismiss"
|
|
313
|
+
@click=${this.close}
|
|
314
|
+
></button>
|
|
315
|
+
</div>
|
|
316
|
+
`;
|
|
317
|
+
}
|
|
318
|
+
get renderPopover() {
|
|
319
|
+
const content = html `
|
|
320
|
+
${this.dismissHelper}
|
|
321
|
+
<sp-menu
|
|
322
|
+
id="menu"
|
|
323
|
+
role="${this.listRole}"
|
|
324
|
+
@change=${this.handleChange}
|
|
325
|
+
.selects=${this.selects}
|
|
326
|
+
></sp-menu>
|
|
327
|
+
${this.dismissHelper}
|
|
328
|
+
`;
|
|
329
|
+
if (this.isMobile.matches) {
|
|
330
|
+
return html `
|
|
331
|
+
<sp-tray
|
|
332
|
+
id="popover"
|
|
333
|
+
role="dialog"
|
|
334
|
+
@sp-menu-item-added-or-updated=${this.updateMenuItems}
|
|
335
|
+
@sp-overlay-closed=${this.onOverlayClosed}
|
|
336
|
+
.overlayCloseCallback=${this.overlayCloseCallback}
|
|
337
|
+
>
|
|
338
|
+
${content}
|
|
339
|
+
</sp-tray>
|
|
340
|
+
`;
|
|
341
|
+
}
|
|
342
|
+
return html `
|
|
343
|
+
<sp-popover
|
|
344
|
+
id="popover"
|
|
345
|
+
role="dialog"
|
|
346
|
+
@sp-menu-item-added-or-updated=${this.updateMenuItems}
|
|
347
|
+
@sp-overlay-closed=${this.onOverlayClosed}
|
|
348
|
+
.overlayCloseCallback=${this.overlayCloseCallback}
|
|
349
|
+
>
|
|
350
|
+
${content}
|
|
351
|
+
</sp-popover>
|
|
352
|
+
`;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Acquire the available MenuItems in the Picker by
|
|
356
|
+
* direct element query or by assuming the list managed
|
|
357
|
+
* by the Menu within the open options overlay.
|
|
358
|
+
*/
|
|
359
|
+
updateMenuItems(event) {
|
|
360
|
+
if (this.open && (event === null || event === void 0 ? void 0 : event.type) === 'sp-menu-item-removed')
|
|
361
|
+
return;
|
|
362
|
+
if (this._willUpdateItems)
|
|
363
|
+
return;
|
|
364
|
+
this._willUpdateItems = true;
|
|
365
|
+
if ((event === null || event === void 0 ? void 0 : event.item) === this.selectedItem) {
|
|
366
|
+
this.requestUpdate();
|
|
367
|
+
}
|
|
368
|
+
let resolve = () => {
|
|
369
|
+
return;
|
|
370
|
+
};
|
|
371
|
+
this.itemsUpdated = new Promise((res) => (resolve = res));
|
|
372
|
+
// Debounce the update so we only update once
|
|
373
|
+
// if multiple items have changed
|
|
374
|
+
window.requestAnimationFrame(async () => {
|
|
375
|
+
if (this.open) {
|
|
376
|
+
await this.optionsMenu.updateComplete;
|
|
377
|
+
this.menuItems = this.optionsMenu.childItems;
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
this.menuItems = [
|
|
381
|
+
...this.querySelectorAll('sp-menu-item'),
|
|
382
|
+
];
|
|
383
|
+
}
|
|
384
|
+
this.manageSelection();
|
|
385
|
+
resolve();
|
|
386
|
+
this._willUpdateItems = false;
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
updated(changedProperties) {
|
|
390
|
+
super.updated(changedProperties);
|
|
391
|
+
if (changedProperties.has('value') &&
|
|
392
|
+
!changedProperties.has('selectedItem')) {
|
|
393
|
+
this.updateMenuItems();
|
|
394
|
+
}
|
|
395
|
+
if (changedProperties.has('disabled') && this.disabled) {
|
|
396
|
+
this.open = false;
|
|
397
|
+
}
|
|
398
|
+
if (changedProperties.has('open') &&
|
|
399
|
+
(this.open || typeof changedProperties.get('open') !== 'undefined')) {
|
|
400
|
+
this.menuStatePromise = new Promise((res) => (this.menuStateResolver = res));
|
|
401
|
+
if (this.open) {
|
|
402
|
+
this.openMenu();
|
|
403
|
+
}
|
|
404
|
+
else {
|
|
405
|
+
this.closeMenu();
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
manageSelection() {
|
|
410
|
+
let selectedItem;
|
|
411
|
+
this.menuItems.forEach((item) => {
|
|
412
|
+
if (this.value === item.value && !item.disabled) {
|
|
413
|
+
selectedItem = item;
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
item.selected = false;
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
if (selectedItem) {
|
|
420
|
+
selectedItem.selected = !!this.selects;
|
|
421
|
+
this.selectedItem = selectedItem;
|
|
422
|
+
}
|
|
423
|
+
else {
|
|
424
|
+
this.value = '';
|
|
425
|
+
this.selectedItem = undefined;
|
|
426
|
+
}
|
|
427
|
+
if (this.open) {
|
|
428
|
+
this.optionsMenu.updateComplete.then(() => {
|
|
429
|
+
this.optionsMenu.updateSelectedItemIndex();
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
async getUpdateComplete() {
|
|
434
|
+
const complete = (await super.getUpdateComplete());
|
|
435
|
+
await this.menuStatePromise;
|
|
436
|
+
await this.itemsUpdated;
|
|
437
|
+
return complete;
|
|
438
|
+
}
|
|
439
|
+
connectedCallback() {
|
|
440
|
+
this.updateMenuItems();
|
|
441
|
+
this.addEventListener('sp-menu-item-added-or-updated', this.updateMenuItems);
|
|
442
|
+
this.addEventListener('sp-menu-item-removed', this.updateMenuItems);
|
|
443
|
+
super.connectedCallback();
|
|
444
|
+
}
|
|
445
|
+
disconnectedCallback() {
|
|
446
|
+
this.open = false;
|
|
447
|
+
super.disconnectedCallback();
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
_a = PickerBase;
|
|
451
|
+
/**
|
|
452
|
+
* @private
|
|
453
|
+
*/
|
|
454
|
+
PickerBase.openOverlay = async (target, interaction, content, options) => {
|
|
455
|
+
return await openOverlay(target, interaction, content, options);
|
|
456
|
+
};
|
|
457
|
+
__decorate([
|
|
458
|
+
query('#button')
|
|
459
|
+
], PickerBase.prototype, "button", void 0);
|
|
460
|
+
__decorate([
|
|
461
|
+
property({ type: Boolean, reflect: true })
|
|
462
|
+
], PickerBase.prototype, "disabled", void 0);
|
|
463
|
+
__decorate([
|
|
464
|
+
property({ type: Boolean, reflect: true })
|
|
465
|
+
], PickerBase.prototype, "focused", void 0);
|
|
466
|
+
__decorate([
|
|
467
|
+
property({ type: String, reflect: true })
|
|
468
|
+
], PickerBase.prototype, "icons", void 0);
|
|
469
|
+
__decorate([
|
|
470
|
+
property({ type: Boolean, reflect: true })
|
|
471
|
+
], PickerBase.prototype, "invalid", void 0);
|
|
472
|
+
__decorate([
|
|
473
|
+
property()
|
|
474
|
+
], PickerBase.prototype, "label", void 0);
|
|
475
|
+
__decorate([
|
|
476
|
+
property({ type: Boolean, reflect: true })
|
|
477
|
+
], PickerBase.prototype, "open", void 0);
|
|
478
|
+
__decorate([
|
|
479
|
+
property({ type: Boolean, reflect: true })
|
|
480
|
+
], PickerBase.prototype, "readonly", void 0);
|
|
481
|
+
__decorate([
|
|
482
|
+
property()
|
|
483
|
+
], PickerBase.prototype, "placement", void 0);
|
|
484
|
+
__decorate([
|
|
485
|
+
property({ type: Boolean, reflect: true })
|
|
486
|
+
], PickerBase.prototype, "quiet", void 0);
|
|
487
|
+
__decorate([
|
|
488
|
+
property({ type: String })
|
|
489
|
+
], PickerBase.prototype, "value", void 0);
|
|
490
|
+
__decorate([
|
|
491
|
+
property({ attribute: false })
|
|
492
|
+
], PickerBase.prototype, "selectedItem", void 0);
|
|
493
|
+
export class Picker extends PickerBase {
|
|
494
|
+
constructor() {
|
|
495
|
+
super(...arguments);
|
|
496
|
+
this.onKeydown = (event) => {
|
|
497
|
+
const { code } = event;
|
|
498
|
+
this.focused = true;
|
|
499
|
+
if (!code.startsWith('Arrow') || this.readonly) {
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
event.preventDefault();
|
|
503
|
+
if (code === 'ArrowUp' || code === 'ArrowDown') {
|
|
504
|
+
this.toggle(true);
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
const selectedIndex = this.selectedItem
|
|
508
|
+
? this.menuItems.indexOf(this.selectedItem)
|
|
509
|
+
: -1;
|
|
510
|
+
// use a positive offset to find the first non-disabled item when no selection is available.
|
|
511
|
+
const nextOffset = !this.value || code === 'ArrowRight' ? 1 : -1;
|
|
512
|
+
let nextIndex = selectedIndex + nextOffset;
|
|
513
|
+
while (this.menuItems[nextIndex] &&
|
|
514
|
+
this.menuItems[nextIndex].disabled) {
|
|
515
|
+
nextIndex += nextOffset;
|
|
516
|
+
}
|
|
517
|
+
if (!this.menuItems[nextIndex] || this.menuItems[nextIndex].disabled) {
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
if (!this.value || nextIndex !== selectedIndex) {
|
|
521
|
+
this.setValueFromItem(this.menuItems[nextIndex]);
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
static get styles() {
|
|
526
|
+
return [pickerStyles, chevronStyles];
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
//# sourceMappingURL=Picker.js.map
|