igniteui-webcomponents 7.1.1 → 7.1.2
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/CHANGELOG.md +20 -0
- package/README.md +13 -11
- package/animations/easings.d.ts +1 -1
- package/animations/easings.js +1 -1
- package/animations/easings.js.map +1 -1
- package/components/button-group/button-group.js +2 -2
- package/components/button-group/button-group.js.map +1 -1
- package/components/button-group/themes/dark/button-group.bootstrap.css.js +1 -1
- package/components/button-group/themes/dark/button-group.bootstrap.css.js.map +1 -1
- package/components/button-group/themes/dark/button-group.fluent.css.js +1 -1
- package/components/button-group/themes/dark/button-group.fluent.css.js.map +1 -1
- package/components/button-group/themes/dark/button-group.indigo.css.js +1 -1
- package/components/button-group/themes/dark/button-group.indigo.css.js.map +1 -1
- package/components/button-group/themes/dark/button-group.material.css.js +1 -1
- package/components/button-group/themes/dark/button-group.material.css.js.map +1 -1
- package/components/button-group/themes/dark/button-group.shared.css.js +1 -1
- package/components/button-group/themes/dark/button-group.shared.css.js.map +1 -1
- package/components/button-group/themes/light/button-group.bootstrap.css.js +1 -1
- package/components/button-group/themes/light/button-group.bootstrap.css.js.map +1 -1
- package/components/button-group/themes/light/button-group.fluent.css.js +1 -1
- package/components/button-group/themes/light/button-group.fluent.css.js.map +1 -1
- package/components/button-group/themes/light/button-group.indigo.css.js +1 -1
- package/components/button-group/themes/light/button-group.indigo.css.js.map +1 -1
- package/components/button-group/themes/light/button-group.material.css.js +1 -1
- package/components/button-group/themes/light/button-group.material.css.js.map +1 -1
- package/components/button-group/themes/light/button-group.shared.css.js +1 -1
- package/components/button-group/themes/light/button-group.shared.css.js.map +1 -1
- package/components/button-group/themes/shared/button/button.bootstrap.css.js +1 -1
- package/components/button-group/themes/shared/button/button.bootstrap.css.js.map +1 -1
- package/components/button-group/themes/shared/button/button.common.css.js +1 -1
- package/components/button-group/themes/shared/button/button.common.css.js.map +1 -1
- package/components/button-group/themes/shared/button/button.fluent.css.js +1 -1
- package/components/button-group/themes/shared/button/button.fluent.css.js.map +1 -1
- package/components/button-group/themes/shared/button/button.indigo.css.js +1 -1
- package/components/button-group/themes/shared/button/button.indigo.css.js.map +1 -1
- package/components/button-group/themes/shared/button/button.material.css.js +1 -1
- package/components/button-group/themes/shared/button/button.material.css.js.map +1 -1
- package/components/calendar/calendar.js +3 -3
- package/components/calendar/calendar.js.map +1 -1
- package/components/calendar/helpers.js +2 -2
- package/components/calendar/helpers.js.map +1 -1
- package/components/carousel/carousel.js +2 -2
- package/components/carousel/carousel.js.map +1 -1
- package/components/chat/chat-message.js +1 -0
- package/components/chat/chat-message.js.map +1 -1
- package/components/chat/themes/dark/chat.bootstrap.css.js +1 -1
- package/components/chat/themes/dark/chat.bootstrap.css.js.map +1 -1
- package/components/chat/themes/dark/chat.fluent.css.js +1 -1
- package/components/chat/themes/dark/chat.fluent.css.js.map +1 -1
- package/components/chat/themes/dark/chat.indigo.css.js +1 -1
- package/components/chat/themes/dark/chat.indigo.css.js.map +1 -1
- package/components/chat/themes/dark/chat.material.css.js +1 -1
- package/components/chat/themes/dark/chat.material.css.js.map +1 -1
- package/components/chat/themes/light/chat.bootstrap.css.js +1 -1
- package/components/chat/themes/light/chat.bootstrap.css.js.map +1 -1
- package/components/chat/themes/light/chat.fluent.css.js +1 -1
- package/components/chat/themes/light/chat.fluent.css.js.map +1 -1
- package/components/chat/themes/light/chat.indigo.css.js +1 -1
- package/components/chat/themes/light/chat.indigo.css.js.map +1 -1
- package/components/chat/themes/light/chat.material.css.js +1 -1
- package/components/chat/themes/light/chat.material.css.js.map +1 -1
- package/components/chat/themes/light/chat.shared.css.js +1 -1
- package/components/chat/themes/light/chat.shared.css.js.map +1 -1
- package/components/chat/themes/message.base.css.js +1 -1
- package/components/chat/themes/message.base.css.js.map +1 -1
- package/components/chat/themes/message.js +0 -14
- package/components/chat/themes/message.js.map +1 -1
- package/components/chat/themes/shared/chat-message/chat-message.common.css.js +1 -1
- package/components/chat/themes/shared/chat-message/chat-message.common.css.js.map +1 -1
- package/components/chat/themes/shared/chat-message/chat-message.indigo.css.js +1 -1
- package/components/chat/themes/shared/chat-message/chat-message.indigo.css.js.map +1 -1
- package/components/chip/chip.d.ts +1 -0
- package/components/chip/chip.js +3 -1
- package/components/chip/chip.js.map +1 -1
- package/components/chip/themes/chip.base.css.js +1 -1
- package/components/chip/themes/chip.base.css.js.map +1 -1
- package/components/chip/themes/shared/chip.common.css.js +1 -1
- package/components/chip/themes/shared/chip.common.css.js.map +1 -1
- package/components/combo/combo-header.js.map +1 -1
- package/components/combo/combo-item.d.ts +6 -2
- package/components/combo/combo-item.js +5 -4
- package/components/combo/combo-item.js.map +1 -1
- package/components/combo/combo-list.js.map +1 -1
- package/components/combo/combo.d.ts +92 -81
- package/components/combo/combo.js +327 -281
- package/components/combo/combo.js.map +1 -1
- package/components/combo/controllers/data.d.ts +50 -13
- package/components/combo/controllers/data.js +49 -28
- package/components/combo/controllers/data.js.map +1 -1
- package/components/combo/controllers/navigation.d.ts +19 -18
- package/components/combo/controllers/navigation.js +73 -90
- package/components/combo/controllers/navigation.js.map +1 -1
- package/components/combo/operations/filter.d.ts +2 -2
- package/components/combo/operations/filter.js.map +1 -1
- package/components/combo/operations/group.d.ts +2 -2
- package/components/combo/operations/group.js.map +1 -1
- package/components/common/context.d.ts +1 -1
- package/components/common/context.js +1 -1
- package/components/common/context.js.map +1 -1
- package/components/common/controllers/drag.js +2 -2
- package/components/common/controllers/drag.js.map +1 -1
- package/components/common/controllers/key-bindings.d.ts +100 -18
- package/components/common/controllers/key-bindings.js +54 -47
- package/components/common/controllers/key-bindings.js.map +1 -1
- package/components/common/controllers/root-click.js +3 -3
- package/components/common/controllers/root-click.js.map +1 -1
- package/components/common/controllers/slot.d.ts +1 -1
- package/components/common/controllers/slot.js.map +1 -1
- package/components/common/mixins/combo-box.d.ts +24 -19
- package/components/common/mixins/combo-box.js +26 -23
- package/components/common/mixins/combo-box.js.map +1 -1
- package/components/common/util.d.ts +40 -2
- package/components/common/util.js +5 -2
- package/components/common/util.js.map +1 -1
- package/components/date-picker/date-picker.d.ts +3 -3
- package/components/date-picker/date-picker.js +10 -10
- package/components/date-picker/date-picker.js.map +1 -1
- package/components/date-range-picker/date-range-picker.d.ts +3 -3
- package/components/date-range-picker/date-range-picker.js +9 -9
- package/components/date-range-picker/date-range-picker.js.map +1 -1
- package/components/date-time-input/date-time-input.js +1 -1
- package/components/date-time-input/date-time-input.js.map +1 -1
- package/components/date-time-input/datetime-mask-parser.d.ts +1 -2
- package/components/date-time-input/datetime-mask-parser.js +1 -2
- package/components/date-time-input/datetime-mask-parser.js.map +1 -1
- package/components/dropdown/dropdown.d.ts +2 -2
- package/components/dropdown/dropdown.js +6 -6
- package/components/dropdown/dropdown.js.map +1 -1
- package/components/dropdown/themes/shared/item/dropdown-item.common.css.js +1 -1
- package/components/dropdown/themes/shared/item/dropdown-item.common.css.js.map +1 -1
- package/components/dropdown/themes/shared/item/dropdown-item.indigo.css.js +1 -1
- package/components/dropdown/themes/shared/item/dropdown-item.indigo.css.js.map +1 -1
- package/components/progress/themes/circular/dark/circular.progress.indigo.css.js +1 -1
- package/components/progress/themes/circular/dark/circular.progress.indigo.css.js.map +1 -1
- package/components/progress/themes/circular/dark/circular.progress.shared.css.js +1 -1
- package/components/progress/themes/circular/dark/circular.progress.shared.css.js.map +1 -1
- package/components/progress/themes/circular/light/circular.progress.indigo.css.js +1 -1
- package/components/progress/themes/circular/light/circular.progress.indigo.css.js.map +1 -1
- package/components/progress/themes/circular/light/circular.progress.shared.css.js +1 -1
- package/components/progress/themes/circular/light/circular.progress.shared.css.js.map +1 -1
- package/components/progress/themes/circular/shared/circular.progress.common.css.js +1 -1
- package/components/progress/themes/circular/shared/circular.progress.common.css.js.map +1 -1
- package/components/progress/themes/linear/linear.progress.base.css.js +1 -1
- package/components/progress/themes/linear/linear.progress.base.css.js.map +1 -1
- package/components/radio/radio.js +1 -1
- package/components/radio/radio.js.map +1 -1
- package/components/rating/rating.d.ts +57 -28
- package/components/rating/rating.js +123 -120
- package/components/rating/rating.js.map +1 -1
- package/components/resize-container/resize-controller.js +2 -3
- package/components/resize-container/resize-controller.js.map +1 -1
- package/components/select/select.d.ts +3 -3
- package/components/select/select.js +10 -10
- package/components/select/select.js.map +1 -1
- package/components/splitter/types.d.ts +1 -1
- package/components/splitter/types.js.map +1 -1
- package/components/stepper/common/state.d.ts +1 -1
- package/components/stepper/common/state.js.map +1 -1
- package/components/stepper/stepper.js +3 -3
- package/components/stepper/stepper.js.map +1 -1
- package/components/tabs/tabs.js +3 -3
- package/components/tabs/tabs.js.map +1 -1
- package/components/tile-manager/tile.js +2 -2
- package/components/tile-manager/tile.js.map +1 -1
- package/components/tree/themes/shared/item.indigo.css.js +1 -1
- package/components/tree/themes/shared/item.indigo.css.js.map +1 -1
- package/components/tree/tree-item.js +2 -3
- package/components/tree/tree-item.js.map +1 -1
- package/custom-elements.json +1690 -966
- package/igniteui-webcomponents.css-data.json +1 -1
- package/igniteui-webcomponents.html-data.json +1 -1
- package/package.json +1 -1
- package/skills/README.md +3 -0
- package/skills/igniteui-wc-choose-components/SKILL.md +53 -0
- package/skills/igniteui-wc-generate-from-image-design/SKILL.md +228 -0
- package/skills/igniteui-wc-generate-from-image-design/references/component-mapping.md +130 -0
- package/skills/igniteui-wc-generate-from-image-design/references/gotchas.md +147 -0
- package/skills/igniteui-wc-integrate-with-framework/SKILL.md +22 -1
- package/skills/igniteui-wc-integrate-with-framework/references/angular.md +2 -0
- package/skills/igniteui-wc-integrate-with-framework/references/react.md +2 -0
- package/skills/igniteui-wc-integrate-with-framework/references/vanilla-js.md +2 -0
- package/skills/igniteui-wc-integrate-with-framework/references/vue.md +2 -0
- package/web-types.json +2 -2
- package/components/chat/themes/shared/chat-message/chat-message.bootstrap.css.d.ts +0 -1
- package/components/chat/themes/shared/chat-message/chat-message.bootstrap.css.js +0 -3
- package/components/chat/themes/shared/chat-message/chat-message.bootstrap.css.js.map +0 -1
- package/components/chat/themes/shared/chat-message/chat-message.fluent.css.d.ts +0 -1
- package/components/chat/themes/shared/chat-message/chat-message.fluent.css.js +0 -3
- package/components/chat/themes/shared/chat-message/chat-message.fluent.css.js.map +0 -1
- package/components/combo/controllers/selection.d.ts +0 -33
- package/components/combo/controllers/selection.js +0 -169
- package/components/combo/controllers/selection.js.map +0 -1
|
@@ -13,7 +13,7 @@ export declare const pageUpKey: "PageUp";
|
|
|
13
13
|
export declare const pageDownKey: "PageDown";
|
|
14
14
|
export declare const tabKey: "Tab";
|
|
15
15
|
export declare const altKey: "Alt";
|
|
16
|
-
export declare const ctrlKey: "
|
|
16
|
+
export declare const ctrlKey: "Control";
|
|
17
17
|
export declare const metaKey: "Meta";
|
|
18
18
|
export declare const shiftKey: "Shift";
|
|
19
19
|
type KeyBindingHandler = (event: KeyboardEvent) => void;
|
|
@@ -31,13 +31,8 @@ type KeyBindingObserverCleanup = {
|
|
|
31
31
|
type KeyBindingSkipCallback = (node: Element, event: KeyboardEvent) => boolean;
|
|
32
32
|
/**
|
|
33
33
|
* The event type which will trigger the bound handler.
|
|
34
|
-
*
|
|
35
|
-
* @remarks
|
|
36
|
-
* `keydownRepeat` is similar to `keydown` with the exception
|
|
37
|
-
* that after the handler is invoked the pressed state of the key is reset
|
|
38
|
-
* in the controller.
|
|
39
34
|
*/
|
|
40
|
-
type KeyBindingTrigger = 'keydown' | 'keyup'
|
|
35
|
+
type KeyBindingTrigger = 'keydown' | 'keyup';
|
|
41
36
|
/**
|
|
42
37
|
* Configuration object for the controller.
|
|
43
38
|
* @ignore
|
|
@@ -91,6 +86,12 @@ interface KeyBindingOptions {
|
|
|
91
86
|
* Defaults to `keydown` if not set.
|
|
92
87
|
*/
|
|
93
88
|
triggers?: KeyBindingTrigger[];
|
|
89
|
+
/**
|
|
90
|
+
* Whether the handler should fire on auto-repeated keydown events (i.e. when a key is held down).
|
|
91
|
+
*
|
|
92
|
+
* Defaults to `false`.
|
|
93
|
+
*/
|
|
94
|
+
repeat?: boolean;
|
|
94
95
|
/**
|
|
95
96
|
* Whether to call `preventDefault` on the target event before the handler is invoked.
|
|
96
97
|
*/
|
|
@@ -100,6 +101,19 @@ interface KeyBindingOptions {
|
|
|
100
101
|
*/
|
|
101
102
|
stopPropagation?: boolean;
|
|
102
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Maps internal modifier names to their corresponding `KeyboardEvent` boolean property names.
|
|
106
|
+
* Needed because `ctrlKey` in the DOM is the property for the `'control'` modifier (not `'controlKey'`).
|
|
107
|
+
*/
|
|
108
|
+
export declare const MODIFIER_EVENT_KEYS: Record<string, string>;
|
|
109
|
+
/**
|
|
110
|
+
* A controller for managing key bindings on a host element. It allows you to register handlers for specific key combinations,
|
|
111
|
+
* with support for modifier keys and event options such as `preventDefault` and `stopPropagation`.
|
|
112
|
+
*
|
|
113
|
+
* The controller listens for keyboard events on the host element (or an optionally specified element) and invokes the appropriate handlers
|
|
114
|
+
* when the registered key combinations are detected.
|
|
115
|
+
*
|
|
116
|
+
*/
|
|
103
117
|
declare class KeyBindingController implements ReactiveController {
|
|
104
118
|
private static readonly _defaultOptions;
|
|
105
119
|
private readonly _host;
|
|
@@ -114,26 +128,65 @@ declare class KeyBindingController implements ReactiveController {
|
|
|
114
128
|
private get _element();
|
|
115
129
|
constructor(host: ReactiveControllerHost & Element, options?: KeyBindingControllerOptions);
|
|
116
130
|
/**
|
|
117
|
-
*
|
|
131
|
+
* Applies the event modifiers specified in the binding options to the provided keyboard event.
|
|
132
|
+
* If `preventDefault` is set, it calls `event.preventDefault()`.
|
|
133
|
+
* If `stopPropagation` is set, it calls `event.stopPropagation()`.
|
|
118
134
|
*/
|
|
119
135
|
private _applyEventModifiers;
|
|
136
|
+
/**
|
|
137
|
+
* Determines whether the provided keyboard event matches the specified key binding,
|
|
138
|
+
* taking into account the event type and the binding's trigger options.
|
|
139
|
+
*/
|
|
120
140
|
private _bindingMatches;
|
|
141
|
+
/**
|
|
142
|
+
* Determines whether the provided event should be ignored based on the controller's configuration and the event's context.
|
|
143
|
+
* The method checks if the event's key is among the allowed keys, if the event originated from within the controller's scope,
|
|
144
|
+
* and if it matches any of the skip conditions defined in the controller's options.
|
|
145
|
+
*/
|
|
121
146
|
private _shouldSkip;
|
|
122
147
|
/** @internal */
|
|
123
148
|
hostConnected(): void;
|
|
124
149
|
/** @internal */
|
|
125
150
|
hostDisconnected(): void;
|
|
151
|
+
/**
|
|
152
|
+
* Handles the global blur event to clear the internal state of pressed keys.
|
|
153
|
+
*
|
|
154
|
+
* This is necessary to prevent "stuck" keys when the user switches to another application
|
|
155
|
+
* or tab while holding down a key.
|
|
156
|
+
*/
|
|
157
|
+
private _handleGlobalBlur;
|
|
158
|
+
/**
|
|
159
|
+
* Handles keyboard events on the observed element.
|
|
160
|
+
*
|
|
161
|
+
* It checks if the event should be skipped based on the controller's configuration,
|
|
162
|
+
* and if not, it determines if there is a registered handler for the combination of pressed keys and active modifiers.
|
|
163
|
+
*
|
|
164
|
+
* If a matching handler is found, it applies the specified event modifiers and invokes the handler.
|
|
165
|
+
* It also manages the internal state of currently pressed keys to accurately detect key combinations.
|
|
166
|
+
*
|
|
167
|
+
*/
|
|
168
|
+
private _handleKeyEvent;
|
|
126
169
|
/** @internal */
|
|
127
|
-
handleEvent(event: KeyboardEvent): void;
|
|
170
|
+
handleEvent(event: KeyboardEvent | FocusEvent): void;
|
|
128
171
|
/**
|
|
129
|
-
* Registers a
|
|
172
|
+
* Registers a key binding with the specified key(s), handler function, and optional configuration.
|
|
173
|
+
*
|
|
174
|
+
* The `key` parameter can be a single key or an array of keys, and can include modifier keys (e.g., 'ctrl+s', ['shift', 'a']).
|
|
175
|
+
* The `handler` is a function that will be called when the specified key combination is detected.
|
|
176
|
+
* The `bindingOptions` allow you to customize the behavior of the binding, such as which event types trigger the handler,
|
|
177
|
+
* whether it should fire on auto-repeated keydown events, and whether to call `preventDefault` or `stopPropagation`.
|
|
178
|
+
*
|
|
179
|
+
* The method returns the controller instance to allow for method chaining.
|
|
130
180
|
*/
|
|
131
181
|
set(key: string | string[], handler: KeyBindingHandler, bindingOptions?: KeyBindingOptions): this;
|
|
132
182
|
/**
|
|
133
|
-
*
|
|
134
|
-
*
|
|
183
|
+
* Registers the provided handler function to be called when either the Enter key or Space bar is pressed.
|
|
184
|
+
*
|
|
185
|
+
* This is a common pattern for activating buttons or interactive elements, and this method provides a convenient way to set up such bindings.
|
|
186
|
+
*
|
|
187
|
+
* The method accepts optional `KeyBindingOptions` which are applied to both the Enter key and Space bar bindings.
|
|
188
|
+
* It returns the controller instance to allow for method chaining.
|
|
135
189
|
*
|
|
136
|
-
* In the browser context this is usually either an Enter and Space bar keypress.
|
|
137
190
|
*/
|
|
138
191
|
setActivateHandler(handler: KeyBindingHandler, options?: KeyBindingOptions): this;
|
|
139
192
|
/**
|
|
@@ -145,14 +198,43 @@ declare class KeyBindingController implements ReactiveController {
|
|
|
145
198
|
*/
|
|
146
199
|
observeElement(element: Element): KeyBindingObserverCleanup;
|
|
147
200
|
}
|
|
148
|
-
/**
|
|
149
|
-
|
|
201
|
+
/**
|
|
202
|
+
* Parses the provided key(s) and separates them into modifiers and regular keys.
|
|
203
|
+
*
|
|
204
|
+
* Modifiers are keys like Alt, Ctrl, Meta and Shift which modify the behavior of other keys when pressed in combination.
|
|
205
|
+
* Regular keys are all other keys which trigger the bound handler when pressed.
|
|
206
|
+
*
|
|
207
|
+
* The returned `keys` and `modifiers` are normalized to lowercase for consistency.
|
|
208
|
+
*
|
|
209
|
+
* @internal
|
|
210
|
+
*
|
|
211
|
+
* @param inputKeys - The key or keys to parse, provided as a string or an array of strings.
|
|
212
|
+
* @returns An object containing the separated `keys` and `modifiers`.
|
|
213
|
+
*/
|
|
214
|
+
export declare function parseKeys(inputKeys: string | string[]): {
|
|
150
215
|
keys: string[];
|
|
151
216
|
modifiers: string[];
|
|
152
217
|
};
|
|
153
218
|
/**
|
|
154
|
-
*
|
|
155
|
-
*
|
|
219
|
+
* Controller factory function which creates a {@link KeyBindingController} instance and attaches it to the provided host.
|
|
220
|
+
*
|
|
221
|
+
* @param element - The host element to which the controller will be attached.
|
|
222
|
+
* @param options - Optional configuration for the controller.
|
|
223
|
+
* @returns The created {@link KeyBindingController} instance.
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* ```ts
|
|
227
|
+
* class MyComponent extends LitElement {
|
|
228
|
+
* private _keyBindings = addKeybindings(this, {
|
|
229
|
+
* skip: ['input', 'textarea'], // Optional: Skip key events originating from these elements
|
|
230
|
+
* bindingDefaults: { preventDefault: true }, // Optional: Default options for all bindings
|
|
231
|
+
* });
|
|
232
|
+
*
|
|
233
|
+
* constructor() {
|
|
234
|
+
* super();
|
|
235
|
+
* this._keyBindings.set('ctrl+s', this._handleSave); // Register a key binding
|
|
236
|
+
* }
|
|
237
|
+
* ```
|
|
156
238
|
*/
|
|
157
239
|
export declare function addKeybindings(element: ReactiveControllerHost & Element, options?: KeyBindingControllerOptions): KeyBindingController;
|
|
158
|
-
export type {
|
|
240
|
+
export type { KeyBindingController, KeyBindingControllerOptions, KeyBindingHandler, KeyBindingObserverCleanup, KeyBindingOptions, KeyBindingSkipCallback, KeyBindingTrigger, };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createAbortHandle } from '../abort-handler.js';
|
|
2
|
-
import { asArray,
|
|
2
|
+
import { asArray, getElementFromPath, isFunction, partition, toMerged, } from '../util.js';
|
|
3
3
|
export const arrowLeft = 'ArrowLeft';
|
|
4
4
|
export const arrowRight = 'ArrowRight';
|
|
5
5
|
export const arrowUp = 'ArrowUp';
|
|
@@ -13,16 +13,17 @@ export const pageUpKey = 'PageUp';
|
|
|
13
13
|
export const pageDownKey = 'PageDown';
|
|
14
14
|
export const tabKey = 'Tab';
|
|
15
15
|
export const altKey = 'Alt';
|
|
16
|
-
export const ctrlKey = '
|
|
16
|
+
export const ctrlKey = 'Control';
|
|
17
17
|
export const metaKey = 'Meta';
|
|
18
18
|
export const shiftKey = 'Shift';
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
const MODIFIERS = new Set(['alt', 'control', 'meta', 'shift']);
|
|
20
|
+
const ALL_MODIFIER_VALUES = Array.from(MODIFIERS).sort();
|
|
21
|
+
export const MODIFIER_EVENT_KEYS = {
|
|
22
|
+
alt: 'altKey',
|
|
23
|
+
control: 'ctrlKey',
|
|
24
|
+
meta: 'metaKey',
|
|
25
|
+
shift: 'shiftKey',
|
|
26
|
+
};
|
|
26
27
|
function normalizeKeys(keys) {
|
|
27
28
|
return asArray(keys).map((key) => key.toLowerCase());
|
|
28
29
|
}
|
|
@@ -32,17 +33,6 @@ function isKeydown(event) {
|
|
|
32
33
|
function isKeyup(event) {
|
|
33
34
|
return event.type === 'keyup';
|
|
34
35
|
}
|
|
35
|
-
function isKeydownTrigger(triggers) {
|
|
36
|
-
return triggers
|
|
37
|
-
? triggers.includes('keydown') || isKeydownRepeatTrigger(triggers)
|
|
38
|
-
: false;
|
|
39
|
-
}
|
|
40
|
-
function isKeyupTrigger(triggers) {
|
|
41
|
-
return triggers ? triggers.includes('keyup') : false;
|
|
42
|
-
}
|
|
43
|
-
function isKeydownRepeatTrigger(triggers) {
|
|
44
|
-
return triggers ? triggers.includes('keydownRepeat') : false;
|
|
45
|
-
}
|
|
46
36
|
function createCombinationKey(keys, modifiers) {
|
|
47
37
|
const sortedKeys = keys.toSorted();
|
|
48
38
|
const sortedModifiers = ALL_MODIFIER_VALUES.filter((mod) => modifiers.includes(mod)).sort();
|
|
@@ -82,63 +72,81 @@ class KeyBindingController {
|
|
|
82
72
|
}
|
|
83
73
|
_bindingMatches(binding, event) {
|
|
84
74
|
const triggers = binding.options?.triggers ?? ['keydown'];
|
|
85
|
-
if (isKeydown(event) &&
|
|
86
|
-
return
|
|
75
|
+
if (isKeydown(event) && triggers.includes('keydown')) {
|
|
76
|
+
return !event.repeat || Boolean(binding.options?.repeat);
|
|
87
77
|
}
|
|
88
|
-
if (isKeyup(event) &&
|
|
78
|
+
if (isKeyup(event) && triggers.includes('keyup')) {
|
|
89
79
|
return true;
|
|
90
80
|
}
|
|
91
81
|
return false;
|
|
92
82
|
}
|
|
93
83
|
_shouldSkip(event) {
|
|
94
|
-
const skip = this._options
|
|
84
|
+
const skip = this._options.skip;
|
|
95
85
|
if (!this._allowedKeys.has(event.key.toLowerCase())) {
|
|
96
86
|
return true;
|
|
97
87
|
}
|
|
98
|
-
if (!
|
|
88
|
+
if (!getElementFromPath((e) => e === this._element, event)) {
|
|
99
89
|
return true;
|
|
100
90
|
}
|
|
101
91
|
if (Array.isArray(skip)) {
|
|
102
92
|
if (!this._skipSelector) {
|
|
103
93
|
return false;
|
|
104
94
|
}
|
|
105
|
-
return Boolean(
|
|
95
|
+
return Boolean(getElementFromPath(this._skipSelector, event));
|
|
106
96
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return false;
|
|
97
|
+
return isFunction(skip)
|
|
98
|
+
? skip.call(this._host, event.target, event)
|
|
99
|
+
: false;
|
|
111
100
|
}
|
|
112
101
|
hostConnected() {
|
|
113
102
|
const { signal } = this._abortHandle;
|
|
114
103
|
this._host.addEventListener('keyup', this, { signal });
|
|
115
104
|
this._host.addEventListener('keydown', this, { signal });
|
|
105
|
+
globalThis.addEventListener('blur', this, { signal });
|
|
116
106
|
}
|
|
117
107
|
hostDisconnected() {
|
|
118
108
|
this._abortHandle.abort();
|
|
119
109
|
}
|
|
120
|
-
|
|
110
|
+
_handleGlobalBlur() {
|
|
111
|
+
this._pressedKeys.clear();
|
|
112
|
+
}
|
|
113
|
+
_handleKeyEvent(event) {
|
|
121
114
|
if (this._shouldSkip(event)) {
|
|
115
|
+
const key = event.key.toLowerCase();
|
|
116
|
+
if (!MODIFIERS.has(key) && isKeyup(event)) {
|
|
117
|
+
this._pressedKeys.delete(key);
|
|
118
|
+
}
|
|
122
119
|
return;
|
|
123
120
|
}
|
|
124
121
|
const key = event.key.toLowerCase();
|
|
125
|
-
if (!
|
|
122
|
+
if (!MODIFIERS.has(key)) {
|
|
126
123
|
this._pressedKeys.add(key);
|
|
127
124
|
}
|
|
128
|
-
const activeModifiers = ALL_MODIFIER_VALUES.filter((mod) => event[
|
|
125
|
+
const activeModifiers = ALL_MODIFIER_VALUES.filter((mod) => event[MODIFIER_EVENT_KEYS[mod]]);
|
|
129
126
|
const combination = createCombinationKey(Array.from(this._pressedKeys), activeModifiers);
|
|
130
|
-
|
|
127
|
+
let binding = this._bindings.get(combination);
|
|
128
|
+
if (!binding && this._pressedKeys.size > 1) {
|
|
129
|
+
binding = this._bindings.get(createCombinationKey([key], activeModifiers));
|
|
130
|
+
}
|
|
131
131
|
if (binding && this._bindingMatches(binding, event)) {
|
|
132
132
|
this._applyEventModifiers(binding, event);
|
|
133
133
|
binding.handler.call(this._host, event);
|
|
134
|
-
if (isKeydownRepeatTrigger(binding.options?.triggers)) {
|
|
135
|
-
this._pressedKeys.delete(key);
|
|
136
|
-
}
|
|
137
134
|
}
|
|
138
|
-
if (
|
|
135
|
+
if (!MODIFIERS.has(key) && isKeyup(event)) {
|
|
139
136
|
this._pressedKeys.delete(key);
|
|
140
137
|
}
|
|
141
138
|
}
|
|
139
|
+
handleEvent(event) {
|
|
140
|
+
switch (event.type) {
|
|
141
|
+
case 'keydown':
|
|
142
|
+
case 'keyup':
|
|
143
|
+
this._handleKeyEvent(event);
|
|
144
|
+
break;
|
|
145
|
+
case 'blur':
|
|
146
|
+
this._handleGlobalBlur();
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
142
150
|
set(key, handler, bindingOptions) {
|
|
143
151
|
const { keys, modifiers } = parseKeys(key);
|
|
144
152
|
const combination = createCombinationKey(keys, modifiers);
|
|
@@ -160,19 +168,18 @@ class KeyBindingController {
|
|
|
160
168
|
this._observedElement = element;
|
|
161
169
|
return {
|
|
162
170
|
unsubscribe: () => {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
this._observedElement
|
|
171
|
+
element.removeEventListener('keydown', this);
|
|
172
|
+
element.removeEventListener('keyup', this);
|
|
173
|
+
if (this._observedElement === element) {
|
|
174
|
+
this._observedElement = undefined;
|
|
175
|
+
}
|
|
166
176
|
},
|
|
167
177
|
};
|
|
168
178
|
}
|
|
169
179
|
}
|
|
170
|
-
export function parseKeys(
|
|
171
|
-
const
|
|
172
|
-
return {
|
|
173
|
-
keys: normalizedKeys.filter((key) => !Modifiers.has(key)),
|
|
174
|
-
modifiers: normalizedKeys.filter((key) => Modifiers.has(key)),
|
|
175
|
-
};
|
|
180
|
+
export function parseKeys(inputKeys) {
|
|
181
|
+
const [modifiers, keys] = partition(normalizeKeys(inputKeys), (key) => MODIFIERS.has(key));
|
|
182
|
+
return { keys, modifiers };
|
|
176
183
|
}
|
|
177
184
|
export function addKeybindings(element, options) {
|
|
178
185
|
return new KeyBindingController(element, options);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"key-bindings.js","sourceRoot":"","sources":["../../../../src/components/common/controllers/key-bindings.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from 'lit';\nimport type { Ref } from 'lit/directives/ref.js';\nimport { createAbortHandle } from '../abort-handler.js';\nimport {\n asArray,\n findElementFromEventPath,\n isFunction,\n toMerged,\n} from '../util.js';\n\n//#region Keys and modifiers\n\n/* Common keys */\nexport const arrowLeft = 'ArrowLeft' as const;\nexport const arrowRight = 'ArrowRight' as const;\nexport const arrowUp = 'ArrowUp' as const;\nexport const arrowDown = 'ArrowDown' as const;\nexport const enterKey = 'Enter' as const;\nexport const spaceBar = ' ' as const;\nexport const escapeKey = 'Escape' as const;\nexport const homeKey = 'Home' as const;\nexport const endKey = 'End' as const;\nexport const pageUpKey = 'PageUp' as const;\nexport const pageDownKey = 'PageDown' as const;\nexport const tabKey = 'Tab' as const;\n\n/* Modifiers */\nexport const altKey = 'Alt' as const;\nexport const ctrlKey = 'Ctrl' as const;\nexport const metaKey = 'Meta' as const;\nexport const shiftKey = 'Shift' as const;\n\n//#endregion\n\n//#region Types\n\n/* Types */\ntype KeyBindingHandler = (event: KeyboardEvent) => void;\ntype KeyBindingObserverCleanup = { unsubscribe: () => void };\n\n/**\n * Whether the current event should be ignored by the controller.\n *\n * @param node - The event target\n * @param event - The event object\n *\n * When `true` is returned, the current event is ignored.\n */\ntype KeyBindingSkipCallback = (node: Element, event: KeyboardEvent) => boolean;\n\n/**\n * The event type which will trigger the bound handler.\n *\n * @remarks\n * `keydownRepeat` is similar to `keydown` with the exception\n * that after the handler is invoked the pressed state of the key is reset\n * in the controller.\n */\ntype KeyBindingTrigger = 'keydown' | 'keyup' | 'keydownRepeat';\n\n/**\n * Configuration object for the controller.\n * @ignore\n */\ninterface KeyBindingControllerOptions {\n /**\n * By default, the controller listens for keypress events in the context of the host element.\n * If you pass a `ref`, you can limit the observation to a certain DOM part of the host scope.\n */\n ref?: Ref;\n /**\n * Option to ignore key press events.\n *\n * If passed an array of CSS selectors, it will ignore key presses originating from elements in the event composed path\n * that match one of the selectors.\n * Otherwise you can pass a {@link KeyBindingSkipCallback} function.\n *\n * Defaults to `['input', 'textarea', 'select']`.\n *\n * @example\n * ```ts\n * {\n * // Skip events originating from elements with `readonly` attribute\n * skip: ['[readonly]']\n * }\n * ...\n * {\n * // Same as above but with a callback\n * skip: (node: Element) => node.hasAttribute('readonly')\n * }\n * ```\n */\n skip?: string[] | KeyBindingSkipCallback;\n /**\n * A set of KeyBindingOptions configuration which is applied to every handler\n * that is added to the controller.\n *\n * Any additional KeyBindingOptions values passed when `set` is called\n * will be merged with `bindingDefaults`.\n */\n bindingDefaults?: KeyBindingOptions;\n}\n\n/**\n * Configuration object for customizing the behavior of\n * the registered handler.\n */\ninterface KeyBindingOptions {\n /**\n * The event type(s) on which the handler will be invoked.\n *\n * Defaults to `keydown` if not set.\n */\n triggers?: KeyBindingTrigger[];\n /**\n * Whether to call `preventDefault` on the target event before the handler is invoked.\n */\n preventDefault?: boolean;\n /**\n * Whether to call `stopPropagation` on the target event before the handler is invoked.\n */\n stopPropagation?: boolean;\n}\n\ninterface KeyBinding {\n keys: string[];\n handler: KeyBindingHandler;\n options?: KeyBindingOptions;\n modifiers: string[];\n}\n\n//#endregion\n\n//#region Internal functions and constants\n\nconst Modifiers: Map<string, string> = new Map([\n [altKey.toLowerCase(), altKey.toLowerCase()],\n [ctrlKey.toLowerCase(), ctrlKey.toLowerCase()],\n [metaKey.toLowerCase(), metaKey.toLowerCase()],\n [shiftKey.toLowerCase(), shiftKey.toLowerCase()],\n]);\n\nconst ALL_MODIFIER_VALUES = Array.from(Modifiers.values()).sort();\n\nfunction normalizeKeys(keys: string | string[]): string[] {\n return asArray(keys).map((key) => key.toLowerCase());\n}\n\nfunction isKeydown(event: Event): boolean {\n return event.type === 'keydown';\n}\n\nfunction isKeyup(event: Event): boolean {\n return event.type === 'keyup';\n}\n\nfunction isKeydownTrigger(triggers?: KeyBindingTrigger[]): boolean {\n return triggers\n ? triggers.includes('keydown') || isKeydownRepeatTrigger(triggers)\n : false;\n}\n\nfunction isKeyupTrigger(triggers?: KeyBindingTrigger[]): boolean {\n return triggers ? triggers.includes('keyup') : false;\n}\n\nfunction isKeydownRepeatTrigger(triggers?: KeyBindingTrigger[]): boolean {\n return triggers ? triggers.includes('keydownRepeat') : false;\n}\n\nfunction createCombinationKey(keys: string[], modifiers: string[]): string {\n const sortedKeys = keys.toSorted();\n const sortedModifiers = ALL_MODIFIER_VALUES.filter((mod) =>\n modifiers.includes(mod)\n ).sort();\n\n return sortedModifiers.concat(sortedKeys).join('+');\n}\n\n//#endregion\n\nclass KeyBindingController implements ReactiveController {\n //#region Private properties and state\n\n private static readonly _defaultOptions: KeyBindingControllerOptions = {\n skip: ['input', 'textarea', 'select'],\n bindingDefaults: { preventDefault: true },\n };\n\n private readonly _host: ReactiveControllerHost & Element;\n private readonly _ref?: Ref;\n private readonly _abortHandle = createAbortHandle();\n\n private readonly _bindings = new Map<string, KeyBinding>();\n private readonly _allowedKeys = new Set<string>();\n private readonly _pressedKeys = new Set<string>();\n\n private readonly _options: KeyBindingControllerOptions;\n private readonly _skipSelector: string | undefined;\n\n private _observedElement?: Element;\n\n private get _element(): Element {\n if (this._observedElement) {\n return this._observedElement;\n }\n return this._ref?.value || this._host;\n }\n\n //#endregion\n\n constructor(\n host: ReactiveControllerHost & Element,\n options?: KeyBindingControllerOptions\n ) {\n this._host = host;\n this._ref = options?.ref;\n this._options = toMerged(\n KeyBindingController._defaultOptions,\n options ?? {}\n );\n\n if (Array.isArray(this._options.skip)) {\n this._skipSelector = this._options.skip.join(',');\n }\n\n host.addController(this);\n }\n\n //#region Private API\n\n /**\n * Checks and executes any event modifiers that are present in the matched binding.\n */\n private _applyEventModifiers(\n binding: KeyBinding,\n event: KeyboardEvent\n ): void {\n if (binding.options?.preventDefault) {\n event.preventDefault();\n }\n\n if (binding.options?.stopPropagation) {\n event.stopPropagation();\n }\n }\n\n private _bindingMatches(binding: KeyBinding, event: KeyboardEvent): boolean {\n const triggers = binding.options?.triggers ?? ['keydown'];\n\n if (isKeydown(event) && isKeydownTrigger(triggers)) {\n return true;\n }\n\n if (isKeyup(event) && isKeyupTrigger(triggers)) {\n return true;\n }\n\n return false;\n }\n\n private _shouldSkip(event: KeyboardEvent): boolean {\n const skip = this._options?.skip;\n\n if (!this._allowedKeys.has(event.key.toLowerCase())) {\n return true;\n }\n\n if (!findElementFromEventPath((e) => e === this._element, event)) {\n return true;\n }\n\n if (Array.isArray(skip)) {\n if (!this._skipSelector) {\n return false;\n }\n\n return Boolean(findElementFromEventPath(this._skipSelector, event));\n }\n\n if (isFunction(skip)) {\n return skip.call(this._host, event.target as Element, event);\n }\n\n return false;\n }\n\n //#endregion\n\n //#region Controller specific handlers\n\n /** @internal */\n public hostConnected(): void {\n const { signal } = this._abortHandle;\n this._host.addEventListener('keyup', this, { signal });\n this._host.addEventListener('keydown', this, { signal });\n }\n\n /** @internal */\n public hostDisconnected(): void {\n this._abortHandle.abort();\n }\n\n /** @internal */\n public handleEvent(event: KeyboardEvent): void {\n if (this._shouldSkip(event)) {\n return;\n }\n\n const key = event.key.toLowerCase();\n\n if (!Modifiers.has(key)) {\n this._pressedKeys.add(key);\n }\n\n const activeModifiers = ALL_MODIFIER_VALUES.filter(\n (mod) => event[`${mod}Key` as keyof KeyboardEvent]\n );\n\n const combination = createCombinationKey(\n Array.from(this._pressedKeys),\n activeModifiers\n );\n\n const binding = this._bindings.get(combination);\n\n if (binding && this._bindingMatches(binding, event)) {\n this._applyEventModifiers(binding, event);\n binding.handler.call(this._host, event);\n\n if (isKeydownRepeatTrigger(binding.options?.triggers)) {\n this._pressedKeys.delete(key);\n }\n }\n\n if (isKeyup(event) && !Modifiers.has(key)) {\n this._pressedKeys.delete(key);\n }\n }\n\n //#endregion\n\n //#region Public API\n\n /**\n * Registers a keybinding handler.\n */\n public set(\n key: string | string[],\n handler: KeyBindingHandler,\n bindingOptions?: KeyBindingOptions\n ) {\n const { keys, modifiers } = parseKeys(key);\n const combination = createCombinationKey(keys, modifiers);\n const options = toMerged(\n this._options.bindingDefaults!,\n bindingOptions ?? {}\n );\n\n for (const each of [...keys, ...modifiers]) {\n this._allowedKeys.add(each);\n }\n\n this._bindings.set(combination, { keys, handler, options, modifiers });\n\n return this;\n }\n\n /**\n * Register a handler function which is called when the target receives a key\n * which \"activates\" it.\n *\n * In the browser context this is usually either an Enter and Space bar keypress.\n */\n public setActivateHandler(\n handler: KeyBindingHandler,\n options?: KeyBindingOptions\n ) {\n this.set(enterKey, handler, options);\n this.set(spaceBar, handler, options);\n\n return this;\n }\n\n /**\n * Sets the controller to listen for keyboard events on an arbitrary `element` in the page context.\n * All the configuration and event handlers are applied as well.\n *\n * Returns an object with an `unsubscribe` function which should be called when the observing of keyboard\n * events on the `element` should cease.\n */\n public observeElement(element: Element): KeyBindingObserverCleanup {\n element.addEventListener('keydown', this);\n element.addEventListener('keyup', this);\n this._observedElement = element;\n\n return {\n unsubscribe: () => {\n this._observedElement?.removeEventListener('keydown', this);\n this._observedElement?.removeEventListener('keyup', this);\n this._observedElement = undefined;\n },\n };\n }\n\n //#endregion\n}\n\n/** @internal */\nexport function parseKeys(keys: string | string[]) {\n const normalizedKeys = normalizeKeys(keys);\n return {\n keys: normalizedKeys.filter((key) => !Modifiers.has(key)),\n modifiers: normalizedKeys.filter((key) => Modifiers.has(key)),\n };\n}\n\n/**\n * Creates a keybinding controller and adds to it to the passed `element`\n * with the provided `options`.\n */\nexport function addKeybindings(\n element: ReactiveControllerHost & Element,\n options?: KeyBindingControllerOptions\n): KeyBindingController {\n return new KeyBindingController(element, options);\n}\n\nexport type {\n KeyBindingHandler,\n KeyBindingObserverCleanup,\n KeyBindingSkipCallback,\n KeyBindingTrigger,\n KeyBindingControllerOptions,\n KeyBindingOptions,\n KeyBindingController,\n};\n"]}
|
|
1
|
+
{"version":3,"file":"key-bindings.js","sourceRoot":"","sources":["../../../../src/components/common/controllers/key-bindings.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from 'lit';\nimport type { Ref } from 'lit/directives/ref.js';\nimport { createAbortHandle } from '../abort-handler.js';\nimport {\n asArray,\n getElementFromPath,\n isFunction,\n partition,\n toMerged,\n} from '../util.js';\n\n//#region Keys and modifiers\n\n/* Common keys */\nexport const arrowLeft = 'ArrowLeft' as const;\nexport const arrowRight = 'ArrowRight' as const;\nexport const arrowUp = 'ArrowUp' as const;\nexport const arrowDown = 'ArrowDown' as const;\nexport const enterKey = 'Enter' as const;\nexport const spaceBar = ' ' as const;\nexport const escapeKey = 'Escape' as const;\nexport const homeKey = 'Home' as const;\nexport const endKey = 'End' as const;\nexport const pageUpKey = 'PageUp' as const;\nexport const pageDownKey = 'PageDown' as const;\nexport const tabKey = 'Tab' as const;\n\n/* Modifiers */\nexport const altKey = 'Alt' as const;\nexport const ctrlKey = 'Control' as const;\nexport const metaKey = 'Meta' as const;\nexport const shiftKey = 'Shift' as const;\n\n//#endregion\n\n//#region Types\n\n/* Types */\ntype KeyBindingHandler = (event: KeyboardEvent) => void;\ntype KeyBindingObserverCleanup = { unsubscribe: () => void };\n\n/**\n * Whether the current event should be ignored by the controller.\n *\n * @param node - The event target\n * @param event - The event object\n *\n * When `true` is returned, the current event is ignored.\n */\ntype KeyBindingSkipCallback = (node: Element, event: KeyboardEvent) => boolean;\n\n/**\n * The event type which will trigger the bound handler.\n */\ntype KeyBindingTrigger = 'keydown' | 'keyup';\n\n/**\n * Configuration object for the controller.\n * @ignore\n */\ninterface KeyBindingControllerOptions {\n /**\n * By default, the controller listens for keypress events in the context of the host element.\n * If you pass a `ref`, you can limit the observation to a certain DOM part of the host scope.\n */\n ref?: Ref;\n /**\n * Option to ignore key press events.\n *\n * If passed an array of CSS selectors, it will ignore key presses originating from elements in the event composed path\n * that match one of the selectors.\n * Otherwise you can pass a {@link KeyBindingSkipCallback} function.\n *\n * Defaults to `['input', 'textarea', 'select']`.\n *\n * @example\n * ```ts\n * {\n * // Skip events originating from elements with `readonly` attribute\n * skip: ['[readonly]']\n * }\n * ...\n * {\n * // Same as above but with a callback\n * skip: (node: Element) => node.hasAttribute('readonly')\n * }\n * ```\n */\n skip?: string[] | KeyBindingSkipCallback;\n /**\n * A set of KeyBindingOptions configuration which is applied to every handler\n * that is added to the controller.\n *\n * Any additional KeyBindingOptions values passed when `set` is called\n * will be merged with `bindingDefaults`.\n */\n bindingDefaults?: KeyBindingOptions;\n}\n\n/**\n * Configuration object for customizing the behavior of\n * the registered handler.\n */\ninterface KeyBindingOptions {\n /**\n * The event type(s) on which the handler will be invoked.\n *\n * Defaults to `keydown` if not set.\n */\n triggers?: KeyBindingTrigger[];\n /**\n * Whether the handler should fire on auto-repeated keydown events (i.e. when a key is held down).\n *\n * Defaults to `false`.\n */\n repeat?: boolean;\n /**\n * Whether to call `preventDefault` on the target event before the handler is invoked.\n */\n preventDefault?: boolean;\n /**\n * Whether to call `stopPropagation` on the target event before the handler is invoked.\n */\n stopPropagation?: boolean;\n}\n\ninterface KeyBinding {\n keys: string[];\n handler: KeyBindingHandler;\n options?: KeyBindingOptions;\n modifiers: string[];\n}\n\n//#endregion\n\n//#region Internal functions and constants\n\nconst MODIFIERS = new Set(['alt', 'control', 'meta', 'shift']);\nconst ALL_MODIFIER_VALUES = Array.from(MODIFIERS).sort();\n\n/**\n * Maps internal modifier names to their corresponding `KeyboardEvent` boolean property names.\n * Needed because `ctrlKey` in the DOM is the property for the `'control'` modifier (not `'controlKey'`).\n */\nexport const MODIFIER_EVENT_KEYS: Record<string, string> = {\n alt: 'altKey',\n control: 'ctrlKey',\n meta: 'metaKey',\n shift: 'shiftKey',\n};\n\nfunction normalizeKeys(keys: string | string[]): string[] {\n return asArray(keys).map((key) => key.toLowerCase());\n}\n\nfunction isKeydown(event: Event): boolean {\n return event.type === 'keydown';\n}\n\nfunction isKeyup(event: Event): boolean {\n return event.type === 'keyup';\n}\n\n/**\n * Creates a normalized combination key string from the provided keys and modifiers.\n *\n * The combination key is a string that uniquely identifies a specific combination of keys and modifiers.\n * It is created by sorting the keys and modifiers alphabetically and joining them with a '+' separator.\n */\nfunction createCombinationKey(keys: string[], modifiers: string[]): string {\n const sortedKeys = keys.toSorted();\n const sortedModifiers = ALL_MODIFIER_VALUES.filter((mod) =>\n modifiers.includes(mod)\n ).sort();\n\n return sortedModifiers.concat(sortedKeys).join('+');\n}\n\n//#endregion\n\n/**\n * A controller for managing key bindings on a host element. It allows you to register handlers for specific key combinations,\n * with support for modifier keys and event options such as `preventDefault` and `stopPropagation`.\n *\n * The controller listens for keyboard events on the host element (or an optionally specified element) and invokes the appropriate handlers\n * when the registered key combinations are detected.\n *\n */\nclass KeyBindingController implements ReactiveController {\n //#region Private properties and state\n\n private static readonly _defaultOptions: KeyBindingControllerOptions = {\n skip: ['input', 'textarea', 'select'],\n bindingDefaults: { preventDefault: true },\n };\n\n private readonly _host: ReactiveControllerHost & Element;\n private readonly _ref?: Ref;\n private readonly _abortHandle = createAbortHandle();\n\n private readonly _bindings = new Map<string, KeyBinding>();\n private readonly _allowedKeys = new Set<string>();\n private readonly _pressedKeys = new Set<string>();\n\n private readonly _options: KeyBindingControllerOptions;\n private readonly _skipSelector: string | undefined;\n\n private _observedElement?: Element;\n\n private get _element(): Element {\n if (this._observedElement) {\n return this._observedElement;\n }\n return this._ref?.value || this._host;\n }\n\n //#endregion\n\n constructor(\n host: ReactiveControllerHost & Element,\n options?: KeyBindingControllerOptions\n ) {\n this._host = host;\n this._ref = options?.ref;\n this._options = toMerged(\n KeyBindingController._defaultOptions,\n options ?? {}\n );\n\n if (Array.isArray(this._options.skip)) {\n this._skipSelector = this._options.skip.join(',');\n }\n\n host.addController(this);\n }\n\n //#region Private API\n\n /**\n * Applies the event modifiers specified in the binding options to the provided keyboard event.\n * If `preventDefault` is set, it calls `event.preventDefault()`.\n * If `stopPropagation` is set, it calls `event.stopPropagation()`.\n */\n private _applyEventModifiers(\n binding: KeyBinding,\n event: KeyboardEvent\n ): void {\n if (binding.options?.preventDefault) {\n event.preventDefault();\n }\n\n if (binding.options?.stopPropagation) {\n event.stopPropagation();\n }\n }\n\n /**\n * Determines whether the provided keyboard event matches the specified key binding,\n * taking into account the event type and the binding's trigger options.\n */\n private _bindingMatches(binding: KeyBinding, event: KeyboardEvent): boolean {\n const triggers = binding.options?.triggers ?? ['keydown'];\n\n if (isKeydown(event) && triggers.includes('keydown')) {\n return !event.repeat || Boolean(binding.options?.repeat);\n }\n\n if (isKeyup(event) && triggers.includes('keyup')) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Determines whether the provided event should be ignored based on the controller's configuration and the event's context.\n * The method checks if the event's key is among the allowed keys, if the event originated from within the controller's scope,\n * and if it matches any of the skip conditions defined in the controller's options.\n */\n private _shouldSkip(event: KeyboardEvent): boolean {\n const skip = this._options.skip;\n\n if (!this._allowedKeys.has(event.key.toLowerCase())) {\n return true;\n }\n\n if (!getElementFromPath((e) => e === this._element, event)) {\n return true;\n }\n\n if (Array.isArray(skip)) {\n if (!this._skipSelector) {\n return false;\n }\n\n return Boolean(getElementFromPath(this._skipSelector, event));\n }\n\n return isFunction(skip)\n ? skip.call(this._host, event.target as Element, event)\n : false;\n }\n\n //#endregion\n\n //#region Controller lifecycle\n\n /** @internal */\n public hostConnected(): void {\n const { signal } = this._abortHandle;\n this._host.addEventListener('keyup', this, { signal });\n this._host.addEventListener('keydown', this, { signal });\n globalThis.addEventListener('blur', this, { signal });\n }\n\n /** @internal */\n public hostDisconnected(): void {\n this._abortHandle.abort();\n }\n\n //#endregion\n\n //#region Event handling\n\n /**\n * Handles the global blur event to clear the internal state of pressed keys.\n *\n * This is necessary to prevent \"stuck\" keys when the user switches to another application\n * or tab while holding down a key.\n */\n private _handleGlobalBlur(): void {\n this._pressedKeys.clear();\n }\n\n /**\n * Handles keyboard events on the observed element.\n *\n * It checks if the event should be skipped based on the controller's configuration,\n * and if not, it determines if there is a registered handler for the combination of pressed keys and active modifiers.\n *\n * If a matching handler is found, it applies the specified event modifiers and invokes the handler.\n * It also manages the internal state of currently pressed keys to accurately detect key combinations.\n *\n */\n private _handleKeyEvent(event: KeyboardEvent): void {\n if (this._shouldSkip(event)) {\n // Always clean up on keyup regardless of whether the event is otherwise skipped.\n const key = event.key.toLowerCase();\n if (!MODIFIERS.has(key) && isKeyup(event)) {\n this._pressedKeys.delete(key);\n }\n return;\n }\n\n const key = event.key.toLowerCase();\n\n if (!MODIFIERS.has(key)) {\n this._pressedKeys.add(key);\n }\n\n const activeModifiers = ALL_MODIFIER_VALUES.filter(\n (mod) => event[MODIFIER_EVENT_KEYS[mod] as keyof KeyboardEvent]\n );\n\n const combination = createCombinationKey(\n Array.from(this._pressedKeys),\n activeModifiers\n );\n let binding = this._bindings.get(combination);\n\n // When multiple non-modifier keys are simultaneously in _pressedKeys (due to overlapping\n // key presses, e.g. pressing ArrowUp before ArrowDown's keyup fires), the full combination\n // won't match any single-key binding. Fall back to just the current key + modifiers so that\n // single-key bindings continue to fire even when other keys are still \"held\".\n if (!binding && this._pressedKeys.size > 1) {\n binding = this._bindings.get(\n createCombinationKey([key], activeModifiers)\n );\n }\n\n if (binding && this._bindingMatches(binding, event)) {\n this._applyEventModifiers(binding, event);\n binding.handler.call(this._host, event);\n }\n\n if (!MODIFIERS.has(key) && isKeyup(event)) {\n this._pressedKeys.delete(key);\n }\n }\n\n /** @internal */\n public handleEvent(event: KeyboardEvent | FocusEvent): void {\n switch (event.type) {\n case 'keydown':\n case 'keyup':\n this._handleKeyEvent(event as KeyboardEvent);\n break;\n case 'blur':\n this._handleGlobalBlur();\n break;\n }\n }\n\n //#endregion\n\n //#region Public API\n\n /**\n * Registers a key binding with the specified key(s), handler function, and optional configuration.\n *\n * The `key` parameter can be a single key or an array of keys, and can include modifier keys (e.g., 'ctrl+s', ['shift', 'a']).\n * The `handler` is a function that will be called when the specified key combination is detected.\n * The `bindingOptions` allow you to customize the behavior of the binding, such as which event types trigger the handler,\n * whether it should fire on auto-repeated keydown events, and whether to call `preventDefault` or `stopPropagation`.\n *\n * The method returns the controller instance to allow for method chaining.\n */\n public set(\n key: string | string[],\n handler: KeyBindingHandler,\n bindingOptions?: KeyBindingOptions\n ): this {\n const { keys, modifiers } = parseKeys(key);\n const combination = createCombinationKey(keys, modifiers);\n const options = toMerged(\n this._options.bindingDefaults!,\n bindingOptions ?? {}\n );\n\n for (const each of [...keys, ...modifiers]) {\n this._allowedKeys.add(each);\n }\n\n this._bindings.set(combination, { keys, handler, options, modifiers });\n\n return this;\n }\n\n /**\n * Registers the provided handler function to be called when either the Enter key or Space bar is pressed.\n *\n * This is a common pattern for activating buttons or interactive elements, and this method provides a convenient way to set up such bindings.\n *\n * The method accepts optional `KeyBindingOptions` which are applied to both the Enter key and Space bar bindings.\n * It returns the controller instance to allow for method chaining.\n *\n */\n public setActivateHandler(\n handler: KeyBindingHandler,\n options?: KeyBindingOptions\n ): this {\n this.set(enterKey, handler, options);\n this.set(spaceBar, handler, options);\n\n return this;\n }\n\n /**\n * Sets the controller to listen for keyboard events on an arbitrary `element` in the page context.\n * All the configuration and event handlers are applied as well.\n *\n * Returns an object with an `unsubscribe` function which should be called when the observing of keyboard\n * events on the `element` should cease.\n */\n public observeElement(element: Element): KeyBindingObserverCleanup {\n element.addEventListener('keydown', this);\n element.addEventListener('keyup', this);\n this._observedElement = element;\n\n return {\n unsubscribe: () => {\n element.removeEventListener('keydown', this);\n element.removeEventListener('keyup', this);\n if (this._observedElement === element) {\n this._observedElement = undefined;\n }\n },\n };\n }\n\n //#endregion\n}\n\n/**\n * Parses the provided key(s) and separates them into modifiers and regular keys.\n *\n * Modifiers are keys like Alt, Ctrl, Meta and Shift which modify the behavior of other keys when pressed in combination.\n * Regular keys are all other keys which trigger the bound handler when pressed.\n *\n * The returned `keys` and `modifiers` are normalized to lowercase for consistency.\n *\n * @internal\n *\n * @param inputKeys - The key or keys to parse, provided as a string or an array of strings.\n * @returns An object containing the separated `keys` and `modifiers`.\n */\nexport function parseKeys(inputKeys: string | string[]): {\n keys: string[];\n modifiers: string[];\n} {\n const [modifiers, keys] = partition(normalizeKeys(inputKeys), (key) =>\n MODIFIERS.has(key)\n );\n return { keys, modifiers };\n}\n\n/**\n * Controller factory function which creates a {@link KeyBindingController} instance and attaches it to the provided host.\n *\n * @param element - The host element to which the controller will be attached.\n * @param options - Optional configuration for the controller.\n * @returns The created {@link KeyBindingController} instance.\n *\n * @example\n * ```ts\n * class MyComponent extends LitElement {\n * private _keyBindings = addKeybindings(this, {\n * skip: ['input', 'textarea'], // Optional: Skip key events originating from these elements\n * bindingDefaults: { preventDefault: true }, // Optional: Default options for all bindings\n * });\n *\n * constructor() {\n * super();\n * this._keyBindings.set('ctrl+s', this._handleSave); // Register a key binding\n * }\n * ```\n */\nexport function addKeybindings(\n element: ReactiveControllerHost & Element,\n options?: KeyBindingControllerOptions\n): KeyBindingController {\n return new KeyBindingController(element, options);\n}\n\nexport type {\n KeyBindingController,\n KeyBindingControllerOptions,\n KeyBindingHandler,\n KeyBindingObserverCleanup,\n KeyBindingOptions,\n KeyBindingSkipCallback,\n KeyBindingTrigger,\n};\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createAbortHandle } from '../abort-handler.js';
|
|
2
|
-
import {
|
|
2
|
+
import { getElementFromPath, isEmpty } from '../util.js';
|
|
3
3
|
let ROOT_CLICK_LISTENER_ACTIVE = false;
|
|
4
4
|
const SHARED_ABORT_HANDLER = createAbortHandle();
|
|
5
5
|
const POINTER_DOWN_HOSTS = new Set();
|
|
@@ -13,7 +13,7 @@ function handlePointerDown(event) {
|
|
|
13
13
|
for (const host of ACTIVE_HOSTS) {
|
|
14
14
|
const config = HOST_CONFIGURATIONS.get(host);
|
|
15
15
|
const targets = getHostTargets(host, config);
|
|
16
|
-
if (
|
|
16
|
+
if (getElementFromPath((node) => targets.has(node), event)) {
|
|
17
17
|
POINTER_DOWN_HOSTS.add(host);
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -25,7 +25,7 @@ function handleRootClick(event) {
|
|
|
25
25
|
}
|
|
26
26
|
const config = HOST_CONFIGURATIONS.get(host);
|
|
27
27
|
const targets = getHostTargets(host, config);
|
|
28
|
-
if (!
|
|
28
|
+
if (!getElementFromPath((node) => targets.has(node), event)) {
|
|
29
29
|
config?.onHide ? config.onHide.call(host) : host.hide();
|
|
30
30
|
}
|
|
31
31
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-click.js","sourceRoot":"","sources":["../../../../src/components/common/controllers/root-click.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"root-click.js","sourceRoot":"","sources":["../../../../src/components/common/controllers/root-click.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from 'lit';\nimport { createAbortHandle } from '../abort-handler.js';\nimport { getElementFromPath, isEmpty } from '../util.js';\n\n/** Configuration options for the RootClickController */\ntype RootClickControllerConfig = {\n /**\n * An optional callback function to execute when an outside click occurs.\n * If not provided, the `hide()` method of the host will be called.\n */\n onHide?: () => void;\n /**\n * An optional additional HTMLElement that, if clicked, should not trigger the hide action.\n * This is useful for elements like a toggle button that opens the component.\n */\n target?: HTMLElement;\n};\n\n/** Interface for the host element that the RootClickController will be attached to. */\ninterface RootClickControllerHost extends ReactiveControllerHost, HTMLElement {\n /**\n * Indicates whether the host element is currently open or visible.\n */\n open: boolean;\n /**\n * If true, outside clicks will not trigger the hide action.\n */\n keepOpenOnOutsideClick?: boolean;\n /**\n * A method on the host to hide or close itself.\n * This will be called if `hideCallback` is not provided in the config.\n */\n hide(): void;\n}\n\nlet ROOT_CLICK_LISTENER_ACTIVE = false;\n\n/** Shared abort handler for the singleton document listeners. */\nconst SHARED_ABORT_HANDLER = createAbortHandle();\n\n/** Tracks which hosts had a pointerdown event inside them. */\nconst POINTER_DOWN_HOSTS = new Set<RootClickControllerHost>();\n\nconst HOST_CONFIGURATIONS = new WeakMap<\n RootClickControllerHost,\n RootClickControllerConfig\n>();\n\nconst ACTIVE_HOSTS = new Set<RootClickControllerHost>();\n\n/** Returns the set of elements that should be considered as \"inside\" the host. */\nfunction getHostTargets(\n host: RootClickControllerHost,\n config?: RootClickControllerConfig\n): Set<Element> {\n return new Set(config?.target ? [host, config.target] : [host]);\n}\n\nfunction handlePointerDown(event: PointerEvent): void {\n POINTER_DOWN_HOSTS.clear();\n\n for (const host of ACTIVE_HOSTS) {\n const config = HOST_CONFIGURATIONS.get(host);\n const targets = getHostTargets(host, config);\n\n if (getElementFromPath((node) => targets.has(node), event)) {\n POINTER_DOWN_HOSTS.add(host);\n }\n }\n}\n\nfunction handleRootClick(event: PointerEvent): void {\n for (const host of [...ACTIVE_HOSTS]) {\n if (host.keepOpenOnOutsideClick || POINTER_DOWN_HOSTS.has(host)) {\n continue;\n }\n\n const config = HOST_CONFIGURATIONS.get(host);\n const targets = getHostTargets(host, config);\n\n if (!getElementFromPath((node) => targets.has(node), event)) {\n config?.onHide ? config.onHide.call(host) : host.hide();\n }\n }\n\n POINTER_DOWN_HOSTS.clear();\n}\n\n/* blazorSuppress */\n/**\n * A Lit ReactiveController that manages global click listeners to hide a component\n * when a click occurs outside of the component or its specified target.\n *\n * This controller implements a singleton pattern for the document click listener,\n * meaning only one event listener is attached to `document` regardless of how many\n * instances of `RootClickController` are active. Each controller instance\n * subscribes to this single listener.\n */\nclass RootClickController implements ReactiveController {\n private readonly _host: RootClickControllerHost;\n private _config?: RootClickControllerConfig;\n\n constructor(\n host: RootClickControllerHost,\n config?: RootClickControllerConfig\n ) {\n this._host = host;\n this._config = config;\n this._host.addController(this);\n\n if (this._config) {\n HOST_CONFIGURATIONS.set(this._host, this._config);\n }\n }\n\n /**\n * Adds the host to the set of active hosts and ensures the global\n * document click listener is active if needed.\n */\n private _addActiveHost(): void {\n ACTIVE_HOSTS.add(this._host);\n\n if (this._config) {\n HOST_CONFIGURATIONS.set(this._host, this._config);\n }\n\n if (!ROOT_CLICK_LISTENER_ACTIVE) {\n const options: AddEventListenerOptions = {\n capture: true,\n signal: SHARED_ABORT_HANDLER.signal,\n };\n\n document.addEventListener('pointerdown', handlePointerDown, {\n ...options,\n passive: true,\n });\n document.addEventListener('click', handleRootClick, options);\n ROOT_CLICK_LISTENER_ACTIVE = true;\n }\n }\n\n /**\n * Removes the host from the set of active hosts and removes the global\n * document click listener if no other hosts are active.\n */\n private _removeActiveHost(): void {\n ACTIVE_HOSTS.delete(this._host);\n HOST_CONFIGURATIONS.delete(this._host);\n POINTER_DOWN_HOSTS.delete(this._host);\n\n if (isEmpty(ACTIVE_HOSTS) && ROOT_CLICK_LISTENER_ACTIVE) {\n SHARED_ABORT_HANDLER.abort();\n ROOT_CLICK_LISTENER_ACTIVE = false;\n }\n }\n\n /**\n * Configures the active state of the controller based on the host's `open` property.\n * If `host.open` is true, the controller becomes active; otherwise, it becomes inactive.\n */\n private _configureListeners(): void {\n this._host.open && !this._host.keepOpenOnOutsideClick\n ? this._addActiveHost()\n : this._removeActiveHost();\n }\n\n /** Updates the controller configuration and active state. */\n public update(config?: RootClickControllerConfig): void {\n if (config) {\n this._config = { ...this._config, ...config };\n HOST_CONFIGURATIONS.set(this._host, this._config);\n }\n\n this._configureListeners();\n }\n\n /** @internal */\n public hostConnected(): void {\n this._configureListeners();\n }\n\n /** @internal */\n public hostDisconnected(): void {\n this._removeActiveHost();\n }\n}\n\n/**\n * Creates and adds a {@link RootClickController} instance with a {@link RootClickControllerConfig | configuration}\n * to the given {@link RootClickControllerHost | host}.\n */\nexport function addRootClickController(\n host: RootClickControllerHost,\n config?: RootClickControllerConfig\n): RootClickController {\n return new RootClickController(host, config);\n}\n\nexport type { RootClickController };\n"]}
|
|
@@ -83,5 +83,5 @@ declare function addSlotController<K extends readonly string[]>(host: ReactiveCo
|
|
|
83
83
|
slots?: K;
|
|
84
84
|
}): SlotController<InferSlotNames<K>>;
|
|
85
85
|
declare function setSlots<const T extends readonly string[]>(...slots: T): readonly ["[default]", ...T];
|
|
86
|
+
export type { InferSlotNames, SlotChangeCallback, SlotChangeCallbackParameters, SlotController, SlotControllerOptions, SlotQueryOptions, };
|
|
86
87
|
export { addSlotController, DefaultSlot, setSlots };
|
|
87
|
-
export type { InferSlotNames, SlotController, SlotQueryOptions, SlotChangeCallback, SlotChangeCallbackParameters, SlotControllerOptions, };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slot.js","sourceRoot":"","sources":["../../../../src/components/common/controllers/slot.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"slot.js","sourceRoot":"","sources":["../../../../src/components/common/controllers/slot.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AA4CrC,MAAM,WAAW,GAAG,WAAW,CAAC;AAEhC,MAAM,cAAc;IAMlB,YACE,IAAyC,EACzC,OAAkC;QAJ5B,iBAAY,GAAG,KAAK,CAAC;QAM3B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAE/B,IAAI,CAAC,QAAQ,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;QAC/B,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACpE,CAAC;IAEO,QAAQ,CAAC,QAAY;QAC3B,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,aAAa,CACxC,kBAAkB,CACnB,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,aAAa,CACxC,aAAa,QAAQ,GAAG,CACzB,CAAC;IACJ,CAAC;IASM,gBAAgB,CAAC,IAAO,EAAE,OAAO,GAAG,KAAK;QAC9C,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC;IAC/D,CAAC;IAOM,mBAAmB,CACxB,IAAO,EACP,OAA0B;QAE1B,MAAM,QAAQ,GACX,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,gBAAgB,CAAC;YACrC,OAAO,EAAE,OAAO,EAAE,OAAO;SAC1B,CAAS,IAAI,EAAE,CAAC;QAEnB,OAAO,OAAO,EAAE,QAAQ;YACtB,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,QAAS,CAAC,CAAC;YACtD,CAAC,CAAC,QAAQ,CAAC;IACf,CAAC;IASM,gBAAgB,CAAC,IAAO,EAAE,OAAO,GAAG,KAAK;QAC9C,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IACxD,CAAC;IAOM,mBAAmB,CAAC,IAAO,EAAE,OAA0B;QAC5D,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAC3D,CAAC;IAGM,WAAW,CAAC,KAAY;QAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,MAAyB,CAAC;QAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAS,CAAC;QAC5B,MAAM,SAAS,GAAG,IAAI,KAAK,EAAE,CAAC;QAE9B,IACE,CAAC,IAAI,CAAC,MAAM;YACZ,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAE,WAAiB,CAAC,CAAC,CAAE,IAAI,CAAC,IAAU,CAAC,EAClE,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;gBACvC,IAAI,EAAE,IAAI;gBACV,SAAS;gBACT,SAAS,EAAE,KAAK;aACjB,CAAC,CAAC;YACH,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;QAC7B,CAAC;IACH,CAAC;IAGM,aAAa;QAClB,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,gBAAgB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAC7D,CAAC;IAGM,gBAAgB;QACrB,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,mBAAmB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAChE,CAAC;IAGM,WAAW;QAChB,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;YAChD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;YACzB,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;gBACvC,IAAI,EAAE,WAAgB;gBACtB,SAAS,EAAE,KAAK;gBAChB,SAAS,EAAE,IAAI;aAChB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF;AAED,SAAS,iBAAiB,CACxB,IAA4B,EAC5B,OAEC;IAED,OAAO,IAAI,cAAc,CAAC,IAA2C,EAAE;QACrE,GAAG,OAAO;QACV,KAAK,EAAE,OAAO,EAAE,KAAoC;KACrD,CAAC,CAAC;AACL,CAAC;AAED,SAAS,QAAQ,CAAoC,GAAG,KAAQ;IAC9D,OAAO,CAAC,WAAW,EAAE,GAAG,KAAK,CAAU,CAAC;AAC1C,CAAC;AAUD,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC","sourcesContent":["import type {\n LitElement,\n ReactiveController,\n ReactiveControllerHost,\n} from 'lit';\nimport { isEmpty } from '../util.js';\n\ntype InferSlotNames<T> = T extends readonly (infer U)[] ? U : never;\n\n/**\n * Additional query options for the slot controller methods.\n */\ntype SlotQueryOptions = {\n /**\n * If set to `true`, it returns a sequence of both the elements assigned to the queried slot,\n * as well as elements assigned to any other slots that are descendants of this slot. If no\n * assigned elements are found, it returns the slot's fallback content.\n *\n * Defaults to `false`.\n */\n flatten?: boolean;\n /**\n * CSS selector used to filter the elements returned.\n */\n selector?: string;\n};\n\ntype SlotChangeCallback<T> = (\n parameters: SlotChangeCallbackParameters<T>\n) => void;\n\ntype SlotChangeCallbackParameters<T> = {\n /** The slot name that has its assigned nodes changed. */\n slot: T;\n /** `true` if the slot is the default slot. */\n isDefault: boolean;\n /** `true` if the callback handler is called for the initial host update. */\n isInitial: boolean;\n};\n\ntype SlotControllerOptions<T> = {\n /** An iterable collection of slot names to observe. */\n slots?: Iterable<T>;\n /** Callback function which is invoked a slot's assigned nodes change. */\n onChange?: SlotChangeCallback<T>;\n /** If set to `true`, the `onChange` callback is invoked once after the host is updated for the first time. */\n initial?: boolean;\n};\n\nconst DefaultSlot = '[default]';\n\nclass SlotController<T> implements ReactiveController {\n private readonly _host: ReactiveControllerHost & LitElement;\n private readonly _options: SlotControllerOptions<T>;\n private readonly _slots?: Set<T>;\n private _initialized = false;\n\n constructor(\n host: ReactiveControllerHost & LitElement,\n options?: SlotControllerOptions<T>\n ) {\n this._host = host;\n this._host.addController(this);\n\n this._options = { ...options };\n this._slots = options?.slots ? new Set(options.slots) : undefined;\n }\n\n private _getSlot(slotName?: T): HTMLSlotElement | null {\n if (slotName === DefaultSlot) {\n return this._host.renderRoot.querySelector<HTMLSlotElement>(\n 'slot:not([name])'\n );\n }\n\n return this._host.renderRoot.querySelector<HTMLSlotElement>(\n `slot[name=${slotName}]`\n );\n }\n\n /**\n * Returns an array of the assigned nodes for `slot`.\n *\n * If `flatten` is set to `true`, it returns a sequence of both the nodes assigned to the queried slot,\n * as well as nodes assigned to any other slots that are descendants of this slot. If no\n * assigned nodes are found, it returns the slot's fallback content.\n */\n public getAssignedNodes(slot: T, flatten = false): Node[] {\n return this._getSlot(slot)?.assignedNodes({ flatten }) ?? [];\n }\n\n /**\n * Returns an array of the assigned elements for `slot` with additional `options`.\n *\n * See {@link SlotQueryOptions.flatten} and {@link SlotQueryOptions.selector} for more information.\n */\n public getAssignedElements<U extends Element>(\n slot: T,\n options?: SlotQueryOptions\n ): U[] {\n const elements =\n (this._getSlot(slot)?.assignedElements({\n flatten: options?.flatten,\n }) as U[]) ?? [];\n\n return options?.selector\n ? elements.filter((e) => e.matches(options.selector!))\n : elements;\n }\n\n /**\n * Return whether `slot` has assigned nodes.\n *\n * If `flatten` is set to `true`, it returns a sequence of both the nodes assigned to the queried slot,\n * as well as nodes assigned to any other slots that are descendants of this slot. If no\n * assigned nodes are found, it returns the slot's fallback content.\n */\n public hasAssignedNodes(slot: T, flatten = false): boolean {\n return !isEmpty(this.getAssignedNodes(slot, flatten));\n }\n\n /**\n * Return whether `slot` has assigned elements accepting additional `options`.\n *\n * See {@link SlotQueryOptions.flatten} and {@link SlotQueryOptions.selector} for more information.\n */\n public hasAssignedElements(slot: T, options?: SlotQueryOptions): boolean {\n return !isEmpty(this.getAssignedElements(slot, options));\n }\n\n /** @internal */\n public handleEvent(event: Event): void {\n const slot = event.target as HTMLSlotElement;\n const name = slot.name as T;\n const isDefault = name === '';\n\n if (\n !this._slots ||\n this._slots.has(isDefault ? (DefaultSlot as T) : (slot.name as T))\n ) {\n this._options.onChange?.call(this._host, {\n slot: name,\n isDefault,\n isInitial: false,\n });\n this._host.requestUpdate();\n }\n }\n\n /** @internal */\n public hostConnected(): void {\n this._host.renderRoot.addEventListener('slotchange', this);\n }\n\n /** @internal */\n public hostDisconnected(): void {\n this._host.renderRoot.removeEventListener('slotchange', this);\n }\n\n /** @internal */\n public hostUpdated(): void {\n if (!this._initialized && this._options.initial) {\n this._initialized = true;\n this._options.onChange?.call(this._host, {\n slot: '<initial>' as T,\n isDefault: false,\n isInitial: true,\n });\n }\n }\n}\n\nfunction addSlotController<K extends readonly string[]>(\n host: ReactiveControllerHost,\n options?: SlotControllerOptions<InferSlotNames<K>> & {\n slots?: K;\n }\n): SlotController<InferSlotNames<K>> {\n return new SlotController(host as ReactiveControllerHost & LitElement, {\n ...options,\n slots: options?.slots as Iterable<InferSlotNames<K>>,\n });\n}\n\nfunction setSlots<const T extends readonly string[]>(...slots: T) {\n return [DefaultSlot, ...slots] as const;\n}\n\nexport type {\n InferSlotNames,\n SlotChangeCallback,\n SlotChangeCallbackParameters,\n SlotController,\n SlotControllerOptions,\n SlotQueryOptions,\n};\nexport { addSlotController, DefaultSlot, setSlots };\n"]}
|