@patternfly/pfe-core 2.4.1 → 3.0.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 +0 -1
- package/controllers/cascade-controller.d.ts +6 -0
- package/controllers/cascade-controller.js +5 -3
- package/controllers/cascade-controller.js.map +1 -1
- package/controllers/floating-dom-controller.d.ts +2 -2
- package/controllers/floating-dom-controller.js +84 -81
- package/controllers/floating-dom-controller.js.map +1 -1
- package/controllers/internals-controller.d.ts +86 -41
- package/controllers/internals-controller.js +322 -36
- package/controllers/internals-controller.js.map +1 -1
- package/controllers/light-dom-controller.js.map +1 -1
- package/controllers/listbox-controller.d.ts +58 -0
- package/controllers/listbox-controller.js +250 -0
- package/controllers/listbox-controller.js.map +1 -0
- package/controllers/logger.d.ts +27 -3
- package/controllers/logger.js +50 -9
- package/controllers/logger.js.map +1 -1
- package/controllers/overflow-controller.d.ts +10 -3
- package/controllers/overflow-controller.js +75 -44
- package/controllers/overflow-controller.js.map +1 -1
- package/controllers/perf-controller.js.map +1 -1
- package/controllers/property-observer-controller.js +2 -3
- package/controllers/property-observer-controller.js.map +1 -1
- package/controllers/roving-tabindex-controller.d.ts +42 -24
- package/controllers/roving-tabindex-controller.js +167 -140
- package/controllers/roving-tabindex-controller.js.map +1 -1
- package/controllers/scroll-spy-controller.js +91 -93
- package/controllers/scroll-spy-controller.js.map +1 -1
- package/controllers/slot-controller.d.ts +18 -7
- package/controllers/slot-controller.js +85 -71
- package/controllers/slot-controller.js.map +1 -1
- package/controllers/style-controller.js.map +1 -1
- package/controllers/tabs-aria-controller.d.ts +29 -0
- package/controllers/tabs-aria-controller.js +95 -0
- package/controllers/tabs-aria-controller.js.map +1 -0
- package/controllers/timestamp-controller.js +68 -70
- package/controllers/timestamp-controller.js.map +1 -1
- package/core.d.ts +3 -0
- package/core.js.map +1 -1
- package/custom-elements.json +3120 -1110
- package/decorators/bound.js.map +1 -1
- package/decorators/cascades.d.ts +1 -0
- package/decorators/cascades.js +1 -0
- package/decorators/cascades.js.map +1 -1
- package/decorators/deprecation.js.map +1 -1
- package/decorators/initializer.js.map +1 -1
- package/decorators/observed.js.map +1 -1
- package/decorators/time.js.map +1 -1
- package/decorators/trace.js.map +1 -1
- package/functions/containsDeep.d.ts +6 -0
- package/functions/containsDeep.js +21 -0
- package/functions/containsDeep.js.map +1 -0
- package/functions/context.d.ts +9 -0
- package/functions/context.js +17 -0
- package/functions/context.js.map +1 -0
- package/functions/debounce.js.map +1 -1
- package/functions/isElementInView.js.map +1 -1
- package/package.json +7 -4
- package/functions/deprecatedCustomEvent.d.ts +0 -5
- package/functions/deprecatedCustomEvent.js +0 -12
- package/functions/deprecatedCustomEvent.js.map +0 -1
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
var _ListboxController_instances, _ListboxController_shiftStartingItem, _ListboxController_items, _ListboxController_listening, _ListboxController_getEnabledOptions, _ListboxController_getEventOption, _ListboxController_onFocus, _ListboxController_onClick, _ListboxController_onKeyup, _ListboxController_onKeydown, _ListboxController_optionsChanged, _ListboxController_updateSingleselect, _ListboxController_updateMultiselect;
|
|
2
|
+
import { __classPrivateFieldGet, __classPrivateFieldSet } from "tslib";
|
|
3
|
+
let constructingAllowed = false;
|
|
4
|
+
/**
|
|
5
|
+
* Implements listbox semantics and accesibility. As there are two recognized
|
|
6
|
+
* patterns for implementing keyboard interactions with listbox patterns,
|
|
7
|
+
* provide a secondary controller (either RovingTabindexController or
|
|
8
|
+
* ActiveDescendantController) to complete the implementation.
|
|
9
|
+
*/
|
|
10
|
+
export class ListboxController {
|
|
11
|
+
static of(host, options) {
|
|
12
|
+
constructingAllowed = true;
|
|
13
|
+
const instance = ListboxController.instances.get(host) ?? new ListboxController(host, options);
|
|
14
|
+
constructingAllowed = false;
|
|
15
|
+
return instance;
|
|
16
|
+
}
|
|
17
|
+
constructor(host,
|
|
18
|
+
// this should ideally be ecma #private, but tsc/esbuild tooling isn't up to scratch yet
|
|
19
|
+
// so for now we rely on the underscore convention to avoid compile-time errors
|
|
20
|
+
// try refactoring after updating tooling dependencies
|
|
21
|
+
_options) {
|
|
22
|
+
_ListboxController_instances.add(this);
|
|
23
|
+
this.host = host;
|
|
24
|
+
this._options = _options;
|
|
25
|
+
/** Current active descendant when shift key is pressed */
|
|
26
|
+
_ListboxController_shiftStartingItem.set(this, null);
|
|
27
|
+
/** All options that will not be hidden by a filter */
|
|
28
|
+
_ListboxController_items.set(this, []);
|
|
29
|
+
_ListboxController_listening.set(this, false);
|
|
30
|
+
/** Whether listbox is disabled */
|
|
31
|
+
this.disabled = false;
|
|
32
|
+
/**
|
|
33
|
+
* handles focusing on an option:
|
|
34
|
+
* updates roving tabindex and active descendant
|
|
35
|
+
*/
|
|
36
|
+
_ListboxController_onFocus.set(this, (event) => {
|
|
37
|
+
const target = __classPrivateFieldGet(this, _ListboxController_instances, "m", _ListboxController_getEventOption).call(this, event);
|
|
38
|
+
if (target && target !== this._options.a11yController.activeItem) {
|
|
39
|
+
this._options.a11yController.setActiveItem(target);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* handles clicking on a listbox option:
|
|
44
|
+
* which selects an item by default
|
|
45
|
+
* or toggles selection if multiselectable
|
|
46
|
+
*/
|
|
47
|
+
_ListboxController_onClick.set(this, (event) => {
|
|
48
|
+
const target = __classPrivateFieldGet(this, _ListboxController_instances, "m", _ListboxController_getEventOption).call(this, event);
|
|
49
|
+
if (target) {
|
|
50
|
+
const oldValue = this.value;
|
|
51
|
+
if (this._options.multi) {
|
|
52
|
+
if (!event.shiftKey) {
|
|
53
|
+
this._options.requestSelect(target, !this._options.isSelected(target));
|
|
54
|
+
}
|
|
55
|
+
else if (__classPrivateFieldGet(this, _ListboxController_shiftStartingItem, "f") && target) {
|
|
56
|
+
__classPrivateFieldGet(this, _ListboxController_instances, "m", _ListboxController_updateMultiselect).call(this, target, __classPrivateFieldGet(this, _ListboxController_shiftStartingItem, "f"));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
// select target and deselect all other options
|
|
61
|
+
this.options.forEach(option => this._options.requestSelect(option, option === target));
|
|
62
|
+
}
|
|
63
|
+
if (target !== this._options.a11yController.activeItem) {
|
|
64
|
+
this._options.a11yController.setActiveItem(target);
|
|
65
|
+
}
|
|
66
|
+
if (oldValue !== this.value) {
|
|
67
|
+
this.host.requestUpdate();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
/**
|
|
72
|
+
* handles keyup:
|
|
73
|
+
* track whether shift key is being used for multiselectable listbox
|
|
74
|
+
*/
|
|
75
|
+
_ListboxController_onKeyup.set(this, (event) => {
|
|
76
|
+
const target = __classPrivateFieldGet(this, _ListboxController_instances, "m", _ListboxController_getEventOption).call(this, event);
|
|
77
|
+
if (target && event.shiftKey && this._options.multi) {
|
|
78
|
+
if (__classPrivateFieldGet(this, _ListboxController_shiftStartingItem, "f") && target) {
|
|
79
|
+
__classPrivateFieldGet(this, _ListboxController_instances, "m", _ListboxController_updateMultiselect).call(this, target, __classPrivateFieldGet(this, _ListboxController_shiftStartingItem, "f"));
|
|
80
|
+
}
|
|
81
|
+
if (event.key === 'Shift') {
|
|
82
|
+
__classPrivateFieldSet(this, _ListboxController_shiftStartingItem, null, "f");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
/**
|
|
87
|
+
* handles keydown:
|
|
88
|
+
* filters listbox by keyboard event when slotted option has focus,
|
|
89
|
+
* or by external element such as a text field
|
|
90
|
+
*/
|
|
91
|
+
_ListboxController_onKeydown.set(this, (event) => {
|
|
92
|
+
const target = __classPrivateFieldGet(this, _ListboxController_instances, "m", _ListboxController_getEventOption).call(this, event);
|
|
93
|
+
if (!target || event.altKey || event.metaKey || !this.options.includes(target)) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const first = this._options.a11yController.firstItem;
|
|
97
|
+
const last = this._options.a11yController.lastItem;
|
|
98
|
+
// need to set for keyboard support of multiselect
|
|
99
|
+
if (event.key === 'Shift' && this._options.multi) {
|
|
100
|
+
__classPrivateFieldSet(this, _ListboxController_shiftStartingItem, this.activeItem ?? null, "f");
|
|
101
|
+
}
|
|
102
|
+
switch (event.key) {
|
|
103
|
+
case 'a':
|
|
104
|
+
case 'A':
|
|
105
|
+
if (event.ctrlKey) {
|
|
106
|
+
// ctrl+A selects all options
|
|
107
|
+
__classPrivateFieldGet(this, _ListboxController_instances, "m", _ListboxController_updateMultiselect).call(this, first, last, true);
|
|
108
|
+
event.preventDefault();
|
|
109
|
+
}
|
|
110
|
+
break;
|
|
111
|
+
case 'Enter':
|
|
112
|
+
case ' ':
|
|
113
|
+
// enter and space are only applicable if a listbox option is clicked
|
|
114
|
+
// an external text input should not trigger multiselect
|
|
115
|
+
if (this._options.multi) {
|
|
116
|
+
if (event.shiftKey) {
|
|
117
|
+
__classPrivateFieldGet(this, _ListboxController_instances, "m", _ListboxController_updateMultiselect).call(this, target);
|
|
118
|
+
}
|
|
119
|
+
else if (!this.disabled) {
|
|
120
|
+
this._options.requestSelect(target, !this._options.isSelected(target));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
__classPrivateFieldGet(this, _ListboxController_instances, "m", _ListboxController_updateSingleselect).call(this);
|
|
125
|
+
}
|
|
126
|
+
event.preventDefault();
|
|
127
|
+
break;
|
|
128
|
+
default:
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
if (!constructingAllowed) {
|
|
133
|
+
throw new Error('ListboxController must be constructed with `ListboxController.of()`');
|
|
134
|
+
}
|
|
135
|
+
if (!(host instanceof HTMLElement) && typeof _options.getHTMLElement !== 'function') {
|
|
136
|
+
throw new Error('ListboxController requires the host to be an HTMLElement, or for the initializer to include a `getHTMLElement()` function');
|
|
137
|
+
}
|
|
138
|
+
if (!_options.a11yController) {
|
|
139
|
+
throw new Error('ListboxController requires an additional keyboard accessibility controller. Provide either a RovingTabindexController or an ActiveDescendantController');
|
|
140
|
+
}
|
|
141
|
+
ListboxController.instances.set(host, this);
|
|
142
|
+
this.host.addController(this);
|
|
143
|
+
if (this.element?.isConnected) {
|
|
144
|
+
this.hostConnected();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/** Current active descendant in listbox */
|
|
148
|
+
get activeItem() {
|
|
149
|
+
return this.options.find(option => option === this._options.a11yController.activeItem) || this._options.a11yController.firstItem;
|
|
150
|
+
}
|
|
151
|
+
get nextItem() {
|
|
152
|
+
return this._options.a11yController.nextItem;
|
|
153
|
+
}
|
|
154
|
+
get options() {
|
|
155
|
+
return __classPrivateFieldGet(this, _ListboxController_items, "f");
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* array of options which are selected
|
|
159
|
+
*/
|
|
160
|
+
get selectedOptions() {
|
|
161
|
+
return this.options.filter(option => this._options.isSelected(option));
|
|
162
|
+
}
|
|
163
|
+
get value() {
|
|
164
|
+
const [firstItem] = this.selectedOptions;
|
|
165
|
+
return this._options.multi ? this.selectedOptions : firstItem;
|
|
166
|
+
}
|
|
167
|
+
get element() {
|
|
168
|
+
return this._options.getHTMLElement();
|
|
169
|
+
}
|
|
170
|
+
async hostConnected() {
|
|
171
|
+
if (!__classPrivateFieldGet(this, _ListboxController_listening, "f")) {
|
|
172
|
+
await this.host.updateComplete;
|
|
173
|
+
this.element?.addEventListener('click', __classPrivateFieldGet(this, _ListboxController_onClick, "f"));
|
|
174
|
+
this.element?.addEventListener('focus', __classPrivateFieldGet(this, _ListboxController_onFocus, "f"));
|
|
175
|
+
this.element?.addEventListener('keydown', __classPrivateFieldGet(this, _ListboxController_onKeydown, "f"));
|
|
176
|
+
this.element?.addEventListener('keyup', __classPrivateFieldGet(this, _ListboxController_onKeyup, "f"));
|
|
177
|
+
__classPrivateFieldSet(this, _ListboxController_listening, true, "f");
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
hostUpdated() {
|
|
181
|
+
this.element?.setAttribute('role', 'listbox');
|
|
182
|
+
this.element?.setAttribute('aria-disabled', String(!!this.disabled));
|
|
183
|
+
this.element?.setAttribute('aria-multi-selectable', String(!!this._options.multi));
|
|
184
|
+
for (const option of this._options.a11yController.items) {
|
|
185
|
+
if (this._options.a11yController.activeItem === option) {
|
|
186
|
+
option.setAttribute('aria-selected', 'true');
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
option.removeAttribute('aria-selected');
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
hostDisconnected() {
|
|
194
|
+
this.element?.removeEventListener('click', __classPrivateFieldGet(this, _ListboxController_onClick, "f"));
|
|
195
|
+
this.element?.removeEventListener('focus', __classPrivateFieldGet(this, _ListboxController_onFocus, "f"));
|
|
196
|
+
this.element?.removeEventListener('keydown', __classPrivateFieldGet(this, _ListboxController_onKeydown, "f"));
|
|
197
|
+
this.element?.removeEventListener('keyup', __classPrivateFieldGet(this, _ListboxController_onKeyup, "f"));
|
|
198
|
+
__classPrivateFieldSet(this, _ListboxController_listening, false, "f");
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* sets the listbox value based on selected options
|
|
202
|
+
*/
|
|
203
|
+
setValue(value) {
|
|
204
|
+
const selected = Array.isArray(value) ? value : [value];
|
|
205
|
+
const [firstItem = null] = selected;
|
|
206
|
+
for (const option of this.options) {
|
|
207
|
+
this._options.requestSelect(option, (!!this._options.multi && Array.isArray(value) ? value?.includes(option)
|
|
208
|
+
: firstItem === option));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* register's the host's Item elements as listbox controller items
|
|
213
|
+
*/
|
|
214
|
+
setOptions(options) {
|
|
215
|
+
const oldOptions = [...__classPrivateFieldGet(this, _ListboxController_items, "f")];
|
|
216
|
+
__classPrivateFieldSet(this, _ListboxController_items, options, "f");
|
|
217
|
+
__classPrivateFieldGet(this, _ListboxController_instances, "m", _ListboxController_optionsChanged).call(this, oldOptions);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
_ListboxController_shiftStartingItem = new WeakMap(), _ListboxController_items = new WeakMap(), _ListboxController_listening = new WeakMap(), _ListboxController_onFocus = new WeakMap(), _ListboxController_onClick = new WeakMap(), _ListboxController_onKeyup = new WeakMap(), _ListboxController_onKeydown = new WeakMap(), _ListboxController_instances = new WeakSet(), _ListboxController_getEnabledOptions = function _ListboxController_getEnabledOptions(options = this.options) {
|
|
221
|
+
return options.filter(option => !option.ariaDisabled && !option.closest('[disabled]'));
|
|
222
|
+
}, _ListboxController_getEventOption = function _ListboxController_getEventOption(event) {
|
|
223
|
+
return event.composedPath().find(node => __classPrivateFieldGet(this, _ListboxController_items, "f").includes(node));
|
|
224
|
+
}, _ListboxController_optionsChanged = function _ListboxController_optionsChanged(oldOptions) {
|
|
225
|
+
const setSize = __classPrivateFieldGet(this, _ListboxController_items, "f").length;
|
|
226
|
+
if (setSize !== oldOptions.length || !oldOptions.every((element, index) => element === __classPrivateFieldGet(this, _ListboxController_items, "f")[index])) {
|
|
227
|
+
this._options.a11yController.updateItems(this.options);
|
|
228
|
+
}
|
|
229
|
+
}, _ListboxController_updateSingleselect = function _ListboxController_updateSingleselect() {
|
|
230
|
+
if (!this._options.multi && !this.disabled) {
|
|
231
|
+
__classPrivateFieldGet(this, _ListboxController_instances, "m", _ListboxController_getEnabledOptions).call(this)
|
|
232
|
+
.forEach(option => this._options.requestSelect(option, option === this._options.a11yController.activeItem));
|
|
233
|
+
}
|
|
234
|
+
}, _ListboxController_updateMultiselect = function _ListboxController_updateMultiselect(currentItem, referenceItem = this.activeItem, ctrlA = false) {
|
|
235
|
+
if (referenceItem && this._options.multi && !this.disabled && currentItem) {
|
|
236
|
+
// select all options between active descendant and target
|
|
237
|
+
const [start, end] = [this.options.indexOf(referenceItem), this.options.indexOf(currentItem)].sort();
|
|
238
|
+
const options = [...this.options].slice(start, end + 1);
|
|
239
|
+
// by default CTRL+A will select all options
|
|
240
|
+
// if all options are selected, CTRL+A will deselect all options
|
|
241
|
+
const allSelected = __classPrivateFieldGet(this, _ListboxController_instances, "m", _ListboxController_getEnabledOptions).call(this, options).filter(option => !this._options.isSelected(option))?.length === 0;
|
|
242
|
+
// whether options will be selected (true) or deselected (false)
|
|
243
|
+
const selected = ctrlA ? !allSelected : this._options.isSelected(referenceItem);
|
|
244
|
+
__classPrivateFieldGet(this, _ListboxController_instances, "m", _ListboxController_getEnabledOptions).call(this, options).forEach(option => this._options.requestSelect(option, selected));
|
|
245
|
+
// update starting item for other multiselect
|
|
246
|
+
__classPrivateFieldSet(this, _ListboxController_shiftStartingItem, currentItem, "f");
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
ListboxController.instances = new WeakMap();
|
|
250
|
+
//# sourceMappingURL=listbox-controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listbox-controller.js","sourceRoot":"","sources":["listbox-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from 'lit';\n\nexport interface ListboxAccessibilityController<Item extends HTMLElement> extends ReactiveController {\n items: Item[];\n activeItem?: Item;\n nextItem?: Item;\n prevItem?: Item;\n firstItem?: Item;\n lastItem?: Item;\n updateItems(items: Item[]): void;\n setActiveItem(item: Item): void;\n}\n\n/**\n * Filtering, multiselect, and orientation options for listbox\n */\nexport interface ListboxConfigOptions<T extends HTMLElement> {\n multi?: boolean;\n a11yController: ListboxAccessibilityController<T>;\n getHTMLElement(): HTMLElement | null;\n requestSelect(option: T, force?: boolean): boolean;\n isSelected(option: T): boolean;\n}\n\nlet constructingAllowed = false;\n\n/**\n * Implements listbox semantics and accesibility. As there are two recognized\n * patterns for implementing keyboard interactions with listbox patterns,\n * provide a secondary controller (either RovingTabindexController or\n * ActiveDescendantController) to complete the implementation.\n */\nexport class ListboxController<Item extends HTMLElement> implements ReactiveController {\n private static instances = new WeakMap<ReactiveControllerHost, ListboxController<any>>();\n\n public static of<Item extends HTMLElement>(\n host: ReactiveControllerHost,\n options: ListboxConfigOptions<Item>,\n ): ListboxController<Item> {\n constructingAllowed = true;\n const instance: ListboxController<Item> =\n ListboxController.instances.get(host) ?? new ListboxController<Item>(host, options);\n constructingAllowed = false;\n return instance;\n }\n\n private constructor(\n public host: ReactiveControllerHost,\n // this should ideally be ecma #private, but tsc/esbuild tooling isn't up to scratch yet\n // so for now we rely on the underscore convention to avoid compile-time errors\n // try refactoring after updating tooling dependencies\n private _options: ListboxConfigOptions<Item>,\n ) {\n if (!constructingAllowed) {\n throw new Error('ListboxController must be constructed with `ListboxController.of()`');\n }\n if (!(host instanceof HTMLElement) && typeof _options.getHTMLElement !== 'function') {\n throw new Error('ListboxController requires the host to be an HTMLElement, or for the initializer to include a `getHTMLElement()` function');\n }\n if (!_options.a11yController) {\n throw new Error('ListboxController requires an additional keyboard accessibility controller. Provide either a RovingTabindexController or an ActiveDescendantController');\n }\n ListboxController.instances.set(host, this);\n this.host.addController(this);\n if (this.element?.isConnected) {\n this.hostConnected();\n }\n }\n\n /** Current active descendant when shift key is pressed */\n #shiftStartingItem: Item | null = null;\n\n /** All options that will not be hidden by a filter */\n #items: Item[] = [];\n\n #listening = false;\n\n /** Whether listbox is disabled */\n disabled = false;\n\n /** Current active descendant in listbox */\n get activeItem() {\n return this.options.find(option =>\n option === this._options.a11yController.activeItem) || this._options.a11yController.firstItem;\n }\n\n get nextItem() {\n return this._options.a11yController.nextItem;\n }\n\n get options() {\n return this.#items;\n }\n\n /**\n * array of options which are selected\n */\n get selectedOptions() {\n return this.options.filter(option => this._options.isSelected(option));\n }\n\n get value() {\n const [firstItem] = this.selectedOptions;\n return this._options.multi ? this.selectedOptions : firstItem;\n }\n\n private get element() {\n return this._options.getHTMLElement();\n }\n\n async hostConnected() {\n if (!this.#listening) {\n await this.host.updateComplete;\n this.element?.addEventListener('click', this.#onClick);\n this.element?.addEventListener('focus', this.#onFocus);\n this.element?.addEventListener('keydown', this.#onKeydown);\n this.element?.addEventListener('keyup', this.#onKeyup);\n this.#listening = true;\n }\n }\n\n hostUpdated() {\n this.element?.setAttribute('role', 'listbox');\n this.element?.setAttribute('aria-disabled', String(!!this.disabled));\n this.element?.setAttribute('aria-multi-selectable', String(!!this._options.multi));\n for (const option of this._options.a11yController.items) {\n if (this._options.a11yController.activeItem === option) {\n option.setAttribute('aria-selected', 'true');\n } else {\n option.removeAttribute('aria-selected');\n }\n }\n }\n\n hostDisconnected() {\n this.element?.removeEventListener('click', this.#onClick);\n this.element?.removeEventListener('focus', this.#onFocus);\n this.element?.removeEventListener('keydown', this.#onKeydown);\n this.element?.removeEventListener('keyup', this.#onKeyup);\n this.#listening = false;\n }\n\n #getEnabledOptions(options = this.options) {\n return options.filter(option => !option.ariaDisabled && !option.closest('[disabled]'));\n }\n\n #getEventOption(event: Event): Item | undefined {\n return event.composedPath().find(node => this.#items.includes(node as Item)) as Item | undefined;\n }\n\n\n /**\n * handles focusing on an option:\n * updates roving tabindex and active descendant\n */\n #onFocus = (event: FocusEvent) => {\n const target = this.#getEventOption(event);\n if (target && target !== this._options.a11yController.activeItem) {\n this._options.a11yController.setActiveItem(target);\n }\n };\n\n /**\n * handles clicking on a listbox option:\n * which selects an item by default\n * or toggles selection if multiselectable\n */\n #onClick = (event: MouseEvent) => {\n const target = this.#getEventOption(event);\n if (target) {\n const oldValue = this.value;\n if (this._options.multi) {\n if (!event.shiftKey) {\n this._options.requestSelect(target, !this._options.isSelected(target));\n } else if (this.#shiftStartingItem && target) {\n this.#updateMultiselect(target, this.#shiftStartingItem);\n }\n } else {\n // select target and deselect all other options\n this.options.forEach(option => this._options.requestSelect(option, option === target));\n }\n if (target !== this._options.a11yController.activeItem) {\n this._options.a11yController.setActiveItem(target);\n }\n if (oldValue !== this.value) {\n this.host.requestUpdate();\n }\n }\n };\n\n /**\n * handles keyup:\n * track whether shift key is being used for multiselectable listbox\n */\n #onKeyup = (event: KeyboardEvent) => {\n const target = this.#getEventOption(event);\n if (target && event.shiftKey && this._options.multi) {\n if (this.#shiftStartingItem && target) {\n this.#updateMultiselect(target, this.#shiftStartingItem);\n }\n if (event.key === 'Shift') {\n this.#shiftStartingItem = null;\n }\n }\n };\n\n /**\n * handles keydown:\n * filters listbox by keyboard event when slotted option has focus,\n * or by external element such as a text field\n */\n #onKeydown = (event: KeyboardEvent) => {\n const target = this.#getEventOption(event);\n\n if (!target || event.altKey || event.metaKey || !this.options.includes(target)) {\n return;\n }\n\n const first = this._options.a11yController.firstItem;\n const last = this._options.a11yController.lastItem;\n\n // need to set for keyboard support of multiselect\n if (event.key === 'Shift' && this._options.multi) {\n this.#shiftStartingItem = this.activeItem ?? null;\n }\n\n switch (event.key) {\n case 'a':\n case 'A':\n if (event.ctrlKey) {\n // ctrl+A selects all options\n this.#updateMultiselect(first, last, true);\n event.preventDefault();\n }\n break;\n case 'Enter':\n case ' ':\n // enter and space are only applicable if a listbox option is clicked\n // an external text input should not trigger multiselect\n if (this._options.multi) {\n if (event.shiftKey) {\n this.#updateMultiselect(target);\n } else if (!this.disabled) {\n this._options.requestSelect(target, !this._options.isSelected(target));\n }\n } else {\n this.#updateSingleselect();\n }\n event.preventDefault();\n break;\n default:\n break;\n }\n };\n\n /**\n * handles change to options given previous options array\n */\n #optionsChanged(oldOptions: Item[]) {\n const setSize = this.#items.length;\n if (setSize !== oldOptions.length || !oldOptions.every((element, index) => element === this.#items[index])) {\n this._options.a11yController.updateItems(this.options);\n }\n }\n\n /**\n * updates option selections for single select listbox\n */\n #updateSingleselect() {\n if (!this._options.multi && !this.disabled) {\n this.#getEnabledOptions()\n .forEach(option => this._options.requestSelect(option, option === this._options.a11yController.activeItem));\n }\n }\n\n /**\n * updates option selections for multiselectable listbox:\n * toggles all options between active descendant and target\n */\n #updateMultiselect(\n currentItem?: Item,\n referenceItem = this.activeItem,\n ctrlA = false,\n ) {\n if (referenceItem && this._options.multi && !this.disabled && currentItem) {\n // select all options between active descendant and target\n const [start, end] = [this.options.indexOf(referenceItem), this.options.indexOf(currentItem)].sort();\n const options = [...this.options].slice(start, end + 1);\n\n // by default CTRL+A will select all options\n // if all options are selected, CTRL+A will deselect all options\n const allSelected = this.#getEnabledOptions(options).filter(option => !this._options.isSelected(option))?.length === 0;\n\n // whether options will be selected (true) or deselected (false)\n const selected = ctrlA ? !allSelected : this._options.isSelected(referenceItem);\n this.#getEnabledOptions(options).forEach(option =>\n this._options.requestSelect(option, selected));\n\n // update starting item for other multiselect\n this.#shiftStartingItem = currentItem;\n }\n }\n\n /**\n * sets the listbox value based on selected options\n */\n setValue(value: Item | Item[]) {\n const selected = Array.isArray(value) ? value : [value];\n const [firstItem = null] = selected;\n for (const option of this.options) {\n this._options.requestSelect(option, (\n !!this._options.multi && Array.isArray(value) ? value?.includes(option)\n : firstItem === option\n ));\n }\n }\n\n /**\n * register's the host's Item elements as listbox controller items\n */\n setOptions(options: Item[]) {\n const oldOptions = [...this.#items];\n this.#items = options;\n this.#optionsChanged(oldOptions);\n }\n}\n"]}
|
package/controllers/logger.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ReactiveController,
|
|
1
|
+
import type { ReactiveController, ReactiveControllerHost } from 'lit';
|
|
2
2
|
export declare class Logger implements ReactiveController {
|
|
3
3
|
private host;
|
|
4
4
|
private static logDebug;
|
|
@@ -14,7 +14,19 @@ export declare class Logger implements ReactiveController {
|
|
|
14
14
|
/**
|
|
15
15
|
* A logging wrapper which checks the debugLog boolean and prints to the console if true.
|
|
16
16
|
*
|
|
17
|
-
* @example Logger.
|
|
17
|
+
* @example Logger.debug("Hello");
|
|
18
|
+
*/
|
|
19
|
+
static debug(...msgs: unknown[]): void;
|
|
20
|
+
/**
|
|
21
|
+
* A logging wrapper which checks the debugLog boolean and prints to the console if true.
|
|
22
|
+
*
|
|
23
|
+
* @example Logger.info("Hello");
|
|
24
|
+
*/
|
|
25
|
+
static info(...msgs: unknown[]): void;
|
|
26
|
+
/**
|
|
27
|
+
* A logging wrapper which checks the debugLog boolean and prints to the console if true.
|
|
28
|
+
*
|
|
29
|
+
* @example Logger.log("Hello");
|
|
18
30
|
*/
|
|
19
31
|
static log(...msgs: unknown[]): void;
|
|
20
32
|
/**
|
|
@@ -29,6 +41,18 @@ export declare class Logger implements ReactiveController {
|
|
|
29
41
|
* @example Logger.error("Hello");
|
|
30
42
|
*/
|
|
31
43
|
static error(...msgs: unknown[]): void;
|
|
44
|
+
/**
|
|
45
|
+
* Debug logging that outputs the tag name as a prefix automatically
|
|
46
|
+
*
|
|
47
|
+
* @example this.logger.log("Hello");
|
|
48
|
+
*/
|
|
49
|
+
debug(...msgs: unknown[]): void;
|
|
50
|
+
/**
|
|
51
|
+
* Info logging that outputs the tag name as a prefix automatically
|
|
52
|
+
*
|
|
53
|
+
* @example this.logger.log("Hello");
|
|
54
|
+
*/
|
|
55
|
+
info(...msgs: unknown[]): void;
|
|
32
56
|
/**
|
|
33
57
|
* Local logging that outputs the tag name as a prefix automatically
|
|
34
58
|
*
|
|
@@ -47,6 +71,6 @@ export declare class Logger implements ReactiveController {
|
|
|
47
71
|
* @example this.logger.error("Hello");
|
|
48
72
|
*/
|
|
49
73
|
error(...msgs: unknown[]): void;
|
|
50
|
-
constructor(host:
|
|
74
|
+
constructor(host: ReactiveControllerHost);
|
|
51
75
|
hostConnected(): void;
|
|
52
76
|
}
|
package/controllers/logger.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
class Logger {
|
|
2
|
-
static { this.instances = new WeakMap(); }
|
|
1
|
+
export class Logger {
|
|
3
2
|
get prefix() {
|
|
4
|
-
|
|
3
|
+
if (this.host instanceof HTMLElement) {
|
|
4
|
+
return `[${this.host.localName}${this.host.id ? `#${this.host.id}` : ''}]`;
|
|
5
|
+
}
|
|
6
|
+
else {
|
|
7
|
+
return `[${this.host.constructor.name}]`;
|
|
8
|
+
}
|
|
5
9
|
}
|
|
6
10
|
/**
|
|
7
11
|
* A boolean value that indicates if the logging should be printed to the console; used for debugging.
|
|
@@ -23,14 +27,34 @@ class Logger {
|
|
|
23
27
|
return Logger.logDebug;
|
|
24
28
|
}
|
|
25
29
|
}
|
|
30
|
+
/* eslint-disable no-console */
|
|
31
|
+
/**
|
|
32
|
+
* A logging wrapper which checks the debugLog boolean and prints to the console if true.
|
|
33
|
+
*
|
|
34
|
+
* @example Logger.debug("Hello");
|
|
35
|
+
*/
|
|
36
|
+
static debug(...msgs) {
|
|
37
|
+
if (Logger.debugLog()) {
|
|
38
|
+
console.debug(...msgs);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A logging wrapper which checks the debugLog boolean and prints to the console if true.
|
|
43
|
+
*
|
|
44
|
+
* @example Logger.info("Hello");
|
|
45
|
+
*/
|
|
46
|
+
static info(...msgs) {
|
|
47
|
+
if (Logger.debugLog()) {
|
|
48
|
+
console.info(...msgs);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
26
51
|
/**
|
|
27
52
|
* A logging wrapper which checks the debugLog boolean and prints to the console if true.
|
|
28
53
|
*
|
|
29
|
-
|
|
54
|
+
* @example Logger.log("Hello");
|
|
30
55
|
*/
|
|
31
56
|
static log(...msgs) {
|
|
32
57
|
if (Logger.debugLog()) {
|
|
33
|
-
// eslint-disable-next-line no-console
|
|
34
58
|
console.log(...msgs);
|
|
35
59
|
}
|
|
36
60
|
}
|
|
@@ -40,7 +64,7 @@ class Logger {
|
|
|
40
64
|
* @example Logger.warn("Hello");
|
|
41
65
|
*/
|
|
42
66
|
static warn(...msgs) {
|
|
43
|
-
console.warn(...msgs);
|
|
67
|
+
console.warn(...msgs);
|
|
44
68
|
}
|
|
45
69
|
/**
|
|
46
70
|
* A console error wrapper which formats your output with useful debugging information.
|
|
@@ -48,7 +72,24 @@ class Logger {
|
|
|
48
72
|
* @example Logger.error("Hello");
|
|
49
73
|
*/
|
|
50
74
|
static error(...msgs) {
|
|
51
|
-
console.error([...msgs].join(' '));
|
|
75
|
+
console.error([...msgs].join(' '));
|
|
76
|
+
}
|
|
77
|
+
/* eslint-enable no-console */
|
|
78
|
+
/**
|
|
79
|
+
* Debug logging that outputs the tag name as a prefix automatically
|
|
80
|
+
*
|
|
81
|
+
* @example this.logger.log("Hello");
|
|
82
|
+
*/
|
|
83
|
+
debug(...msgs) {
|
|
84
|
+
Logger.debug(this.prefix, ...msgs);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Info logging that outputs the tag name as a prefix automatically
|
|
88
|
+
*
|
|
89
|
+
* @example this.logger.log("Hello");
|
|
90
|
+
*/
|
|
91
|
+
info(...msgs) {
|
|
92
|
+
Logger.info(this.prefix, ...msgs);
|
|
52
93
|
}
|
|
53
94
|
/**
|
|
54
95
|
* Local logging that outputs the tag name as a prefix automatically
|
|
@@ -84,8 +125,8 @@ class Logger {
|
|
|
84
125
|
Logger.instances.set(host, this);
|
|
85
126
|
}
|
|
86
127
|
hostConnected() {
|
|
87
|
-
this.
|
|
128
|
+
this.debug('connected');
|
|
88
129
|
}
|
|
89
130
|
}
|
|
90
|
-
|
|
131
|
+
Logger.instances = new WeakMap();
|
|
91
132
|
//# sourceMappingURL=logger.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["logger.ts"],"names":[],"mappings":"AAEA,
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["logger.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from 'lit';\n\nexport class Logger implements ReactiveController {\n private static logDebug: boolean;\n\n private static instances: WeakMap<ReactiveControllerHost, Logger> = new WeakMap();\n\n private get prefix() {\n if (this.host instanceof HTMLElement) {\n return `[${this.host.localName}${this.host.id ? `#${this.host.id}` : ''}]`;\n } else {\n return `[${this.host.constructor.name}]`;\n }\n }\n\n /**\n * A boolean value that indicates if the logging should be printed to the console; used for debugging.\n * For use in a JS file or script tag; can also be added in the constructor of a component during development.\n * @example Logger.debugLog(true);\n * @tags debug\n */\n static debugLog(preference = null) {\n // wrap localStorage references in a try/catch; merely referencing it can\n // throw errors in some locked down environments\n try {\n if (preference !== null) {\n Logger.logDebug = !!preference;\n localStorage.pfeLog = !!preference;\n }\n return localStorage.pfeLog === 'true';\n } catch (e) {\n return Logger.logDebug;\n }\n }\n\n /* eslint-disable no-console */\n\n /**\n * A logging wrapper which checks the debugLog boolean and prints to the console if true.\n *\n * @example Logger.debug(\"Hello\");\n */\n static debug(...msgs: unknown[]) {\n if (Logger.debugLog()) {\n console.debug(...msgs);\n }\n }\n\n /**\n * A logging wrapper which checks the debugLog boolean and prints to the console if true.\n *\n * @example Logger.info(\"Hello\");\n */\n static info(...msgs: unknown[]) {\n if (Logger.debugLog()) {\n console.info(...msgs);\n }\n }\n\n /**\n * A logging wrapper which checks the debugLog boolean and prints to the console if true.\n *\n * @example Logger.log(\"Hello\");\n */\n static log(...msgs: unknown[]) {\n if (Logger.debugLog()) {\n console.log(...msgs);\n }\n }\n\n /**\n * A console warning wrapper which formats your output with useful debugging information.\n *\n * @example Logger.warn(\"Hello\");\n */\n static warn(...msgs: unknown[]) {\n console.warn(...msgs);\n }\n\n /**\n * A console error wrapper which formats your output with useful debugging information.\n * For use inside a component's function.\n * @example Logger.error(\"Hello\");\n */\n static error(...msgs: unknown[]) {\n console.error([...msgs].join(' '));\n }\n\n /* eslint-enable no-console */\n\n /**\n * Debug logging that outputs the tag name as a prefix automatically\n *\n * @example this.logger.log(\"Hello\");\n */\n debug(...msgs: unknown[]) {\n Logger.debug(this.prefix, ...msgs);\n }\n\n /**\n * Info logging that outputs the tag name as a prefix automatically\n *\n * @example this.logger.log(\"Hello\");\n */\n info(...msgs: unknown[]) {\n Logger.info(this.prefix, ...msgs);\n }\n\n /**\n * Local logging that outputs the tag name as a prefix automatically\n *\n * @example this.logger.log(\"Hello\");\n */\n log(...msgs: unknown[]) {\n Logger.log(this.prefix, ...msgs);\n }\n\n /**\n * Local warning wrapper that outputs the tag name as a prefix automatically.\n * For use inside a component's function.\n * @example this.logger.warn(\"Hello\");\n */\n warn(...msgs: unknown[]) {\n Logger.warn(this.prefix, ...msgs);\n }\n\n /**\n * Local error wrapper that outputs the tag name as a prefix automatically.\n * For use inside a component's function.\n * @example this.logger.error(\"Hello\");\n */\n error(...msgs: unknown[]) {\n Logger.error(this.prefix, ...msgs);\n }\n\n constructor(private host: ReactiveControllerHost) {\n // We only need one logger instance per host\n if (Logger.instances.get(host)) {\n return Logger.instances.get(host) as Logger;\n }\n host.addController(this);\n Logger.instances.set(host, this);\n }\n\n hostConnected() {\n this.debug('connected');\n }\n}\n"]}
|
|
@@ -1,17 +1,24 @@
|
|
|
1
|
-
import type { ReactiveController,
|
|
1
|
+
import type { ReactiveController, ReactiveElement } from 'lit';
|
|
2
2
|
export interface Options {
|
|
3
|
+
/**
|
|
4
|
+
* Force hide the scroll buttons regardless of overflow
|
|
5
|
+
*/
|
|
3
6
|
hideOverflowButtons?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Delay in ms to wait before checking for overflow
|
|
9
|
+
*/
|
|
10
|
+
scrollTimeoutDelay?: number;
|
|
4
11
|
}
|
|
5
12
|
export declare class OverflowController implements ReactiveController {
|
|
6
13
|
#private;
|
|
7
|
-
host:
|
|
14
|
+
host: ReactiveElement;
|
|
8
15
|
private options?;
|
|
9
16
|
showScrollButtons: boolean;
|
|
10
17
|
overflowLeft: boolean;
|
|
11
18
|
overflowRight: boolean;
|
|
12
19
|
get firstItem(): HTMLElement | undefined;
|
|
13
20
|
get lastItem(): HTMLElement | undefined;
|
|
14
|
-
constructor(host:
|
|
21
|
+
constructor(host: ReactiveElement, options?: Options | undefined);
|
|
15
22
|
init(container: HTMLElement, items: HTMLElement[]): void;
|
|
16
23
|
onScroll: () => void;
|
|
17
24
|
scrollLeft(): void;
|