@neovici/cosmoz-dropdown 7.1.0 → 7.3.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 +83 -25
- package/dist/connectable.d.ts +5 -365
- package/dist/connectable.js +5 -10
- package/dist/next/cosmoz-dropdown-next.js +33 -13
- package/dist/next/use-auto-open.d.ts +12 -0
- package/dist/next/use-auto-open.js +48 -0
- package/package.json +11 -4
package/README.md
CHANGED
|
@@ -1,48 +1,106 @@
|
|
|
1
|
-
# cosmoz-dropdown
|
|
1
|
+
# @neovici/cosmoz-dropdown
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Dropdown components for Neovici applications.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
|
-
```
|
|
7
|
+
```bash
|
|
8
8
|
npm install @neovici/cosmoz-dropdown
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## Components
|
|
12
12
|
|
|
13
|
-
### cosmoz-dropdown
|
|
13
|
+
### cosmoz-dropdown-next
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Modern dropdown using the Popover API and CSS Anchor Positioning.
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
import '@neovici/cosmoz-dropdown';
|
|
19
|
-
```
|
|
17
|
+
#### Usage
|
|
20
18
|
|
|
21
19
|
```html
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
<script type="module">
|
|
21
|
+
import '@neovici/cosmoz-dropdown';
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<cosmoz-dropdown-next placement="bottom span-right">
|
|
25
|
+
<button slot="button">Open Menu</button>
|
|
26
|
+
<div>Dropdown content</div>
|
|
27
|
+
</cosmoz-dropdown-next>
|
|
27
28
|
```
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
#### Properties
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
| Property | Type | Default | Description |
|
|
33
|
+
| --------------- | --------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
34
|
+
| `placement` | `string` | `'bottom span-right'` | CSS anchor `position-area` value. See [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/position-area) for options. |
|
|
35
|
+
| `open-on-hover` | `boolean` | `false` | Open on pointer hover. |
|
|
36
|
+
| `open-on-focus` | `boolean` | `false` | Open when the trigger receives focus. |
|
|
32
37
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
#### Auto-open Modes
|
|
39
|
+
|
|
40
|
+
The `open-on-hover` and `open-on-focus` attributes can be used independently or together:
|
|
36
41
|
|
|
37
42
|
```html
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
<!-- Open on hover only -->
|
|
44
|
+
<cosmoz-dropdown-next open-on-hover>
|
|
45
|
+
<button slot="button">Hover me</button>
|
|
46
|
+
<div>Content appears on hover</div>
|
|
47
|
+
</cosmoz-dropdown-next>
|
|
48
|
+
|
|
49
|
+
<!-- Open on focus only -->
|
|
50
|
+
<cosmoz-dropdown-next open-on-focus>
|
|
51
|
+
<button slot="button">Focus me</button>
|
|
52
|
+
<div>Content appears on focus</div>
|
|
53
|
+
</cosmoz-dropdown-next>
|
|
54
|
+
|
|
55
|
+
<!-- Open on hover or focus -->
|
|
56
|
+
<cosmoz-dropdown-next open-on-hover open-on-focus>
|
|
57
|
+
<button slot="button">Hover or focus</button>
|
|
58
|
+
<div>Content appears on either</div>
|
|
41
59
|
</cosmoz-dropdown-next>
|
|
42
60
|
```
|
|
43
61
|
|
|
44
|
-
|
|
62
|
+
When auto-open is enabled:
|
|
63
|
+
|
|
64
|
+
- The dropdown closes with a 100ms delay to allow moving between trigger and content
|
|
65
|
+
- When `open-on-focus` is active, clicking the button only opens (does not toggle)
|
|
66
|
+
- Otherwise, click works as a toggle
|
|
67
|
+
|
|
68
|
+
#### Slots
|
|
69
|
+
|
|
70
|
+
| Slot | Description |
|
|
71
|
+
| --------- | ------------------------------------------- |
|
|
72
|
+
| `button` | The trigger element that opens the dropdown |
|
|
73
|
+
| (default) | The dropdown content |
|
|
74
|
+
|
|
75
|
+
#### Events
|
|
76
|
+
|
|
77
|
+
The dropdown listens for a `select` event on its content and automatically closes when triggered. This allows menu items to close the dropdown when selected:
|
|
78
|
+
|
|
79
|
+
```javascript
|
|
80
|
+
menuItem.dispatchEvent(new Event('select', { bubbles: true }));
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The dropdown dispatches a `dropdown-toggle` event (a [`ToggleEvent`](https://developer.mozilla.org/en-US/docs/Web/API/ToggleEvent)) when the popover opens or closes, allowing parent components across shadow boundaries to observe state changes:
|
|
84
|
+
|
|
85
|
+
```javascript
|
|
86
|
+
dropdown.addEventListener('dropdown-toggle', (e) => {
|
|
87
|
+
console.log(e.oldState, '->', e.newState); // 'closed' -> 'open' or 'open' -> 'closed'
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Development
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npm install
|
|
95
|
+
npm run storybook:start
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Testing
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
npm test
|
|
102
|
+
```
|
|
45
103
|
|
|
46
|
-
##
|
|
104
|
+
## License
|
|
47
105
|
|
|
48
|
-
|
|
106
|
+
Apache-2.0
|
package/dist/connectable.d.ts
CHANGED
|
@@ -1,365 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
export declare const connectable: (base?: {
|
|
8
|
-
new (): HTMLElement;
|
|
9
|
-
prototype: HTMLElement;
|
|
10
|
-
}) => {
|
|
11
|
-
new (): {
|
|
12
|
-
connectedCallback(): void;
|
|
13
|
-
disconnectedCallback(): void;
|
|
14
|
-
accessKey: string;
|
|
15
|
-
readonly accessKeyLabel: string;
|
|
16
|
-
autocapitalize: string;
|
|
17
|
-
autocorrect: boolean;
|
|
18
|
-
dir: string;
|
|
19
|
-
draggable: boolean;
|
|
20
|
-
hidden: boolean;
|
|
21
|
-
inert: boolean;
|
|
22
|
-
innerText: string;
|
|
23
|
-
lang: string;
|
|
24
|
-
readonly offsetHeight: number;
|
|
25
|
-
readonly offsetLeft: number;
|
|
26
|
-
readonly offsetParent: Element | null;
|
|
27
|
-
readonly offsetTop: number;
|
|
28
|
-
readonly offsetWidth: number;
|
|
29
|
-
outerText: string;
|
|
30
|
-
popover: string | null;
|
|
31
|
-
spellcheck: boolean;
|
|
32
|
-
title: string;
|
|
33
|
-
translate: boolean;
|
|
34
|
-
writingSuggestions: string;
|
|
35
|
-
attachInternals(): ElementInternals;
|
|
36
|
-
click(): void;
|
|
37
|
-
hidePopover(): void;
|
|
38
|
-
showPopover(): void;
|
|
39
|
-
togglePopover(options?: boolean): boolean;
|
|
40
|
-
addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
|
41
|
-
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
|
42
|
-
removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
|
43
|
-
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
|
44
|
-
readonly attributes: NamedNodeMap;
|
|
45
|
-
get classList(): DOMTokenList;
|
|
46
|
-
set classList(value: string);
|
|
47
|
-
className: string;
|
|
48
|
-
readonly clientHeight: number;
|
|
49
|
-
readonly clientLeft: number;
|
|
50
|
-
readonly clientTop: number;
|
|
51
|
-
readonly clientWidth: number;
|
|
52
|
-
readonly currentCSSZoom: number;
|
|
53
|
-
id: string;
|
|
54
|
-
innerHTML: string;
|
|
55
|
-
readonly localName: string;
|
|
56
|
-
readonly namespaceURI: string | null;
|
|
57
|
-
onfullscreenchange: ((this: Element, ev: Event) => any) | null;
|
|
58
|
-
onfullscreenerror: ((this: Element, ev: Event) => any) | null;
|
|
59
|
-
outerHTML: string;
|
|
60
|
-
readonly ownerDocument: Document;
|
|
61
|
-
get part(): DOMTokenList;
|
|
62
|
-
set part(value: string);
|
|
63
|
-
readonly prefix: string | null;
|
|
64
|
-
readonly scrollHeight: number;
|
|
65
|
-
scrollLeft: number;
|
|
66
|
-
scrollTop: number;
|
|
67
|
-
readonly scrollWidth: number;
|
|
68
|
-
readonly shadowRoot: ShadowRoot | null;
|
|
69
|
-
slot: string;
|
|
70
|
-
readonly tagName: string;
|
|
71
|
-
attachShadow(init: ShadowRootInit): ShadowRoot;
|
|
72
|
-
checkVisibility(options?: CheckVisibilityOptions): boolean;
|
|
73
|
-
closest<K extends keyof HTMLElementTagNameMap>(selector: K): HTMLElementTagNameMap[K] | null;
|
|
74
|
-
closest<K extends keyof SVGElementTagNameMap>(selector: K): SVGElementTagNameMap[K] | null;
|
|
75
|
-
closest<K extends keyof MathMLElementTagNameMap>(selector: K): MathMLElementTagNameMap[K] | null;
|
|
76
|
-
closest<E extends Element = Element>(selectors: string): E | null;
|
|
77
|
-
computedStyleMap(): StylePropertyMapReadOnly;
|
|
78
|
-
getAttribute(qualifiedName: string): string | null;
|
|
79
|
-
getAttributeNS(namespace: string | null, localName: string): string | null;
|
|
80
|
-
getAttributeNames(): string[];
|
|
81
|
-
getAttributeNode(qualifiedName: string): Attr | null;
|
|
82
|
-
getAttributeNodeNS(namespace: string | null, localName: string): Attr | null;
|
|
83
|
-
getBoundingClientRect(): DOMRect;
|
|
84
|
-
getClientRects(): DOMRectList;
|
|
85
|
-
getElementsByClassName(classNames: string): HTMLCollectionOf<Element>;
|
|
86
|
-
getElementsByTagName<K extends keyof HTMLElementTagNameMap>(qualifiedName: K): HTMLCollectionOf<HTMLElementTagNameMap[K]>;
|
|
87
|
-
getElementsByTagName<K extends keyof SVGElementTagNameMap>(qualifiedName: K): HTMLCollectionOf<SVGElementTagNameMap[K]>;
|
|
88
|
-
getElementsByTagName<K extends keyof MathMLElementTagNameMap>(qualifiedName: K): HTMLCollectionOf<MathMLElementTagNameMap[K]>;
|
|
89
|
-
getElementsByTagName<K extends keyof HTMLElementDeprecatedTagNameMap>(qualifiedName: K): HTMLCollectionOf<HTMLElementDeprecatedTagNameMap[K]>;
|
|
90
|
-
getElementsByTagName(qualifiedName: string): HTMLCollectionOf<Element>;
|
|
91
|
-
getElementsByTagNameNS(namespaceURI: "http://www.w3.org/1999/xhtml", localName: string): HTMLCollectionOf<HTMLElement>;
|
|
92
|
-
getElementsByTagNameNS(namespaceURI: "http://www.w3.org/2000/svg", localName: string): HTMLCollectionOf<SVGElement>;
|
|
93
|
-
getElementsByTagNameNS(namespaceURI: "http://www.w3.org/1998/Math/MathML", localName: string): HTMLCollectionOf<MathMLElement>;
|
|
94
|
-
getElementsByTagNameNS(namespace: string | null, localName: string): HTMLCollectionOf<Element>;
|
|
95
|
-
getHTML(options?: GetHTMLOptions): string;
|
|
96
|
-
hasAttribute(qualifiedName: string): boolean;
|
|
97
|
-
hasAttributeNS(namespace: string | null, localName: string): boolean;
|
|
98
|
-
hasAttributes(): boolean;
|
|
99
|
-
hasPointerCapture(pointerId: number): boolean;
|
|
100
|
-
insertAdjacentElement(where: InsertPosition, element: Element): Element | null;
|
|
101
|
-
insertAdjacentHTML(position: InsertPosition, string: string): void;
|
|
102
|
-
insertAdjacentText(where: InsertPosition, data: string): void;
|
|
103
|
-
matches(selectors: string): boolean;
|
|
104
|
-
releasePointerCapture(pointerId: number): void;
|
|
105
|
-
removeAttribute(qualifiedName: string): void;
|
|
106
|
-
removeAttributeNS(namespace: string | null, localName: string): void;
|
|
107
|
-
removeAttributeNode(attr: Attr): Attr;
|
|
108
|
-
requestFullscreen(options?: FullscreenOptions): Promise<void>;
|
|
109
|
-
requestPointerLock(options?: PointerLockOptions): Promise<void>;
|
|
110
|
-
scroll(options?: ScrollToOptions): void;
|
|
111
|
-
scroll(x: number, y: number): void;
|
|
112
|
-
scrollBy(options?: ScrollToOptions): void;
|
|
113
|
-
scrollBy(x: number, y: number): void;
|
|
114
|
-
scrollIntoView(arg?: boolean | ScrollIntoViewOptions): void;
|
|
115
|
-
scrollTo(options?: ScrollToOptions): void;
|
|
116
|
-
scrollTo(x: number, y: number): void;
|
|
117
|
-
setAttribute(qualifiedName: string, value: string): void;
|
|
118
|
-
setAttributeNS(namespace: string | null, qualifiedName: string, value: string): void;
|
|
119
|
-
setAttributeNode(attr: Attr): Attr | null;
|
|
120
|
-
setAttributeNodeNS(attr: Attr): Attr | null;
|
|
121
|
-
setHTMLUnsafe(html: string): void;
|
|
122
|
-
setPointerCapture(pointerId: number): void;
|
|
123
|
-
toggleAttribute(qualifiedName: string, force?: boolean): boolean;
|
|
124
|
-
webkitMatchesSelector(selectors: string): boolean;
|
|
125
|
-
get textContent(): string;
|
|
126
|
-
set textContent(value: string | null);
|
|
127
|
-
readonly baseURI: string;
|
|
128
|
-
readonly childNodes: NodeListOf<ChildNode>;
|
|
129
|
-
readonly firstChild: ChildNode | null;
|
|
130
|
-
readonly isConnected: boolean;
|
|
131
|
-
readonly lastChild: ChildNode | null;
|
|
132
|
-
readonly nextSibling: ChildNode | null;
|
|
133
|
-
readonly nodeName: string;
|
|
134
|
-
readonly nodeType: number;
|
|
135
|
-
nodeValue: string | null;
|
|
136
|
-
readonly parentElement: HTMLElement | null;
|
|
137
|
-
readonly parentNode: ParentNode | null;
|
|
138
|
-
readonly previousSibling: ChildNode | null;
|
|
139
|
-
appendChild<T extends Node>(node: T): T;
|
|
140
|
-
cloneNode(subtree?: boolean): Node;
|
|
141
|
-
compareDocumentPosition(other: Node): number;
|
|
142
|
-
contains(other: Node | null): boolean;
|
|
143
|
-
getRootNode(options?: GetRootNodeOptions): Node;
|
|
144
|
-
hasChildNodes(): boolean;
|
|
145
|
-
insertBefore<T extends Node>(node: T, child: Node | null): T;
|
|
146
|
-
isDefaultNamespace(namespace: string | null): boolean;
|
|
147
|
-
isEqualNode(otherNode: Node | null): boolean;
|
|
148
|
-
isSameNode(otherNode: Node | null): boolean;
|
|
149
|
-
lookupNamespaceURI(prefix: string | null): string | null;
|
|
150
|
-
lookupPrefix(namespace: string | null): string | null;
|
|
151
|
-
normalize(): void;
|
|
152
|
-
removeChild<T extends Node>(child: T): T;
|
|
153
|
-
replaceChild<T extends Node>(node: Node, child: T): T;
|
|
154
|
-
readonly ELEMENT_NODE: 1;
|
|
155
|
-
readonly ATTRIBUTE_NODE: 2;
|
|
156
|
-
readonly TEXT_NODE: 3;
|
|
157
|
-
readonly CDATA_SECTION_NODE: 4;
|
|
158
|
-
readonly ENTITY_REFERENCE_NODE: 5;
|
|
159
|
-
readonly ENTITY_NODE: 6;
|
|
160
|
-
readonly PROCESSING_INSTRUCTION_NODE: 7;
|
|
161
|
-
readonly COMMENT_NODE: 8;
|
|
162
|
-
readonly DOCUMENT_NODE: 9;
|
|
163
|
-
readonly DOCUMENT_TYPE_NODE: 10;
|
|
164
|
-
readonly DOCUMENT_FRAGMENT_NODE: 11;
|
|
165
|
-
readonly NOTATION_NODE: 12;
|
|
166
|
-
readonly DOCUMENT_POSITION_DISCONNECTED: 1;
|
|
167
|
-
readonly DOCUMENT_POSITION_PRECEDING: 2;
|
|
168
|
-
readonly DOCUMENT_POSITION_FOLLOWING: 4;
|
|
169
|
-
readonly DOCUMENT_POSITION_CONTAINS: 8;
|
|
170
|
-
readonly DOCUMENT_POSITION_CONTAINED_BY: 16;
|
|
171
|
-
readonly DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: 32;
|
|
172
|
-
dispatchEvent(event: Event): boolean;
|
|
173
|
-
ariaActiveDescendantElement: Element | null;
|
|
174
|
-
ariaAtomic: string | null;
|
|
175
|
-
ariaAutoComplete: string | null;
|
|
176
|
-
ariaBrailleLabel: string | null;
|
|
177
|
-
ariaBrailleRoleDescription: string | null;
|
|
178
|
-
ariaBusy: string | null;
|
|
179
|
-
ariaChecked: string | null;
|
|
180
|
-
ariaColCount: string | null;
|
|
181
|
-
ariaColIndex: string | null;
|
|
182
|
-
ariaColIndexText: string | null;
|
|
183
|
-
ariaColSpan: string | null;
|
|
184
|
-
ariaControlsElements: ReadonlyArray<Element> | null;
|
|
185
|
-
ariaCurrent: string | null;
|
|
186
|
-
ariaDescribedByElements: ReadonlyArray<Element> | null;
|
|
187
|
-
ariaDescription: string | null;
|
|
188
|
-
ariaDetailsElements: ReadonlyArray<Element> | null;
|
|
189
|
-
ariaDisabled: string | null;
|
|
190
|
-
ariaErrorMessageElements: ReadonlyArray<Element> | null;
|
|
191
|
-
ariaExpanded: string | null;
|
|
192
|
-
ariaFlowToElements: ReadonlyArray<Element> | null;
|
|
193
|
-
ariaHasPopup: string | null;
|
|
194
|
-
ariaHidden: string | null;
|
|
195
|
-
ariaInvalid: string | null;
|
|
196
|
-
ariaKeyShortcuts: string | null;
|
|
197
|
-
ariaLabel: string | null;
|
|
198
|
-
ariaLabelledByElements: ReadonlyArray<Element> | null;
|
|
199
|
-
ariaLevel: string | null;
|
|
200
|
-
ariaLive: string | null;
|
|
201
|
-
ariaModal: string | null;
|
|
202
|
-
ariaMultiLine: string | null;
|
|
203
|
-
ariaMultiSelectable: string | null;
|
|
204
|
-
ariaOrientation: string | null;
|
|
205
|
-
ariaOwnsElements: ReadonlyArray<Element> | null;
|
|
206
|
-
ariaPlaceholder: string | null;
|
|
207
|
-
ariaPosInSet: string | null;
|
|
208
|
-
ariaPressed: string | null;
|
|
209
|
-
ariaReadOnly: string | null;
|
|
210
|
-
ariaRelevant: string | null;
|
|
211
|
-
ariaRequired: string | null;
|
|
212
|
-
ariaRoleDescription: string | null;
|
|
213
|
-
ariaRowCount: string | null;
|
|
214
|
-
ariaRowIndex: string | null;
|
|
215
|
-
ariaRowIndexText: string | null;
|
|
216
|
-
ariaRowSpan: string | null;
|
|
217
|
-
ariaSelected: string | null;
|
|
218
|
-
ariaSetSize: string | null;
|
|
219
|
-
ariaSort: string | null;
|
|
220
|
-
ariaValueMax: string | null;
|
|
221
|
-
ariaValueMin: string | null;
|
|
222
|
-
ariaValueNow: string | null;
|
|
223
|
-
ariaValueText: string | null;
|
|
224
|
-
role: string | null;
|
|
225
|
-
animate(keyframes: Keyframe[] | PropertyIndexedKeyframes | null, options?: number | KeyframeAnimationOptions): Animation;
|
|
226
|
-
getAnimations(options?: GetAnimationsOptions): Animation[];
|
|
227
|
-
after(...nodes: (Node | string)[]): void;
|
|
228
|
-
before(...nodes: (Node | string)[]): void;
|
|
229
|
-
remove(): void;
|
|
230
|
-
replaceWith(...nodes: (Node | string)[]): void;
|
|
231
|
-
readonly nextElementSibling: Element | null;
|
|
232
|
-
readonly previousElementSibling: Element | null;
|
|
233
|
-
readonly childElementCount: number;
|
|
234
|
-
readonly children: HTMLCollection;
|
|
235
|
-
readonly firstElementChild: Element | null;
|
|
236
|
-
readonly lastElementChild: Element | null;
|
|
237
|
-
append(...nodes: (Node | string)[]): void;
|
|
238
|
-
prepend(...nodes: (Node | string)[]): void;
|
|
239
|
-
querySelector<K extends keyof HTMLElementTagNameMap>(selectors: K): HTMLElementTagNameMap[K] | null;
|
|
240
|
-
querySelector<K extends keyof SVGElementTagNameMap>(selectors: K): SVGElementTagNameMap[K] | null;
|
|
241
|
-
querySelector<K extends keyof MathMLElementTagNameMap>(selectors: K): MathMLElementTagNameMap[K] | null;
|
|
242
|
-
querySelector<K extends keyof HTMLElementDeprecatedTagNameMap>(selectors: K): HTMLElementDeprecatedTagNameMap[K] | null;
|
|
243
|
-
querySelector<E extends Element = Element>(selectors: string): E | null;
|
|
244
|
-
querySelectorAll<K extends keyof HTMLElementTagNameMap>(selectors: K): NodeListOf<HTMLElementTagNameMap[K]>;
|
|
245
|
-
querySelectorAll<K extends keyof SVGElementTagNameMap>(selectors: K): NodeListOf<SVGElementTagNameMap[K]>;
|
|
246
|
-
querySelectorAll<K extends keyof MathMLElementTagNameMap>(selectors: K): NodeListOf<MathMLElementTagNameMap[K]>;
|
|
247
|
-
querySelectorAll<K extends keyof HTMLElementDeprecatedTagNameMap>(selectors: K): NodeListOf<HTMLElementDeprecatedTagNameMap[K]>;
|
|
248
|
-
querySelectorAll<E extends Element = Element>(selectors: string): NodeListOf<E>;
|
|
249
|
-
replaceChildren(...nodes: (Node | string)[]): void;
|
|
250
|
-
readonly assignedSlot: HTMLSlotElement | null;
|
|
251
|
-
readonly attributeStyleMap: StylePropertyMap;
|
|
252
|
-
get style(): CSSStyleDeclaration;
|
|
253
|
-
set style(cssText: string);
|
|
254
|
-
contentEditable: string;
|
|
255
|
-
enterKeyHint: string;
|
|
256
|
-
inputMode: string;
|
|
257
|
-
readonly isContentEditable: boolean;
|
|
258
|
-
onabort: ((this: GlobalEventHandlers, ev: UIEvent) => any) | null;
|
|
259
|
-
onanimationcancel: ((this: GlobalEventHandlers, ev: AnimationEvent) => any) | null;
|
|
260
|
-
onanimationend: ((this: GlobalEventHandlers, ev: AnimationEvent) => any) | null;
|
|
261
|
-
onanimationiteration: ((this: GlobalEventHandlers, ev: AnimationEvent) => any) | null;
|
|
262
|
-
onanimationstart: ((this: GlobalEventHandlers, ev: AnimationEvent) => any) | null;
|
|
263
|
-
onauxclick: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null;
|
|
264
|
-
onbeforeinput: ((this: GlobalEventHandlers, ev: InputEvent) => any) | null;
|
|
265
|
-
onbeforematch: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
266
|
-
onbeforetoggle: ((this: GlobalEventHandlers, ev: ToggleEvent) => any) | null;
|
|
267
|
-
onblur: ((this: GlobalEventHandlers, ev: FocusEvent) => any) | null;
|
|
268
|
-
oncancel: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
269
|
-
oncanplay: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
270
|
-
oncanplaythrough: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
271
|
-
onchange: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
272
|
-
onclick: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null;
|
|
273
|
-
onclose: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
274
|
-
oncontextlost: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
275
|
-
oncontextmenu: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null;
|
|
276
|
-
oncontextrestored: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
277
|
-
oncopy: ((this: GlobalEventHandlers, ev: ClipboardEvent) => any) | null;
|
|
278
|
-
oncuechange: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
279
|
-
oncut: ((this: GlobalEventHandlers, ev: ClipboardEvent) => any) | null;
|
|
280
|
-
ondblclick: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null;
|
|
281
|
-
ondrag: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null;
|
|
282
|
-
ondragend: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null;
|
|
283
|
-
ondragenter: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null;
|
|
284
|
-
ondragleave: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null;
|
|
285
|
-
ondragover: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null;
|
|
286
|
-
ondragstart: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null;
|
|
287
|
-
ondrop: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null;
|
|
288
|
-
ondurationchange: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
289
|
-
onemptied: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
290
|
-
onended: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
291
|
-
onerror: OnErrorEventHandler;
|
|
292
|
-
onfocus: ((this: GlobalEventHandlers, ev: FocusEvent) => any) | null;
|
|
293
|
-
onformdata: ((this: GlobalEventHandlers, ev: FormDataEvent) => any) | null;
|
|
294
|
-
ongotpointercapture: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null;
|
|
295
|
-
oninput: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
296
|
-
oninvalid: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
297
|
-
onkeydown: ((this: GlobalEventHandlers, ev: KeyboardEvent) => any) | null;
|
|
298
|
-
onkeypress: ((this: GlobalEventHandlers, ev: KeyboardEvent) => any) | null;
|
|
299
|
-
onkeyup: ((this: GlobalEventHandlers, ev: KeyboardEvent) => any) | null;
|
|
300
|
-
onload: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
301
|
-
onloadeddata: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
302
|
-
onloadedmetadata: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
303
|
-
onloadstart: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
304
|
-
onlostpointercapture: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null;
|
|
305
|
-
onmousedown: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null;
|
|
306
|
-
onmouseenter: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null;
|
|
307
|
-
onmouseleave: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null;
|
|
308
|
-
onmousemove: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null;
|
|
309
|
-
onmouseout: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null;
|
|
310
|
-
onmouseover: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null;
|
|
311
|
-
onmouseup: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null;
|
|
312
|
-
onpaste: ((this: GlobalEventHandlers, ev: ClipboardEvent) => any) | null;
|
|
313
|
-
onpause: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
314
|
-
onplay: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
315
|
-
onplaying: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
316
|
-
onpointercancel: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null;
|
|
317
|
-
onpointerdown: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null;
|
|
318
|
-
onpointerenter: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null;
|
|
319
|
-
onpointerleave: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null;
|
|
320
|
-
onpointermove: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null;
|
|
321
|
-
onpointerout: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null;
|
|
322
|
-
onpointerover: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null;
|
|
323
|
-
onpointerrawupdate: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
324
|
-
onpointerup: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null;
|
|
325
|
-
onprogress: ((this: GlobalEventHandlers, ev: ProgressEvent) => any) | null;
|
|
326
|
-
onratechange: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
327
|
-
onreset: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
328
|
-
onresize: ((this: GlobalEventHandlers, ev: UIEvent) => any) | null;
|
|
329
|
-
onscroll: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
330
|
-
onscrollend: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
331
|
-
onsecuritypolicyviolation: ((this: GlobalEventHandlers, ev: SecurityPolicyViolationEvent) => any) | null;
|
|
332
|
-
onseeked: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
333
|
-
onseeking: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
334
|
-
onselect: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
335
|
-
onselectionchange: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
336
|
-
onselectstart: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
337
|
-
onslotchange: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
338
|
-
onstalled: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
339
|
-
onsubmit: ((this: GlobalEventHandlers, ev: SubmitEvent) => any) | null;
|
|
340
|
-
onsuspend: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
341
|
-
ontimeupdate: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
342
|
-
ontoggle: ((this: GlobalEventHandlers, ev: ToggleEvent) => any) | null;
|
|
343
|
-
ontouchcancel?: ((this: GlobalEventHandlers, ev: TouchEvent) => any) | null | undefined;
|
|
344
|
-
ontouchend?: ((this: GlobalEventHandlers, ev: TouchEvent) => any) | null | undefined;
|
|
345
|
-
ontouchmove?: ((this: GlobalEventHandlers, ev: TouchEvent) => any) | null | undefined;
|
|
346
|
-
ontouchstart?: ((this: GlobalEventHandlers, ev: TouchEvent) => any) | null | undefined;
|
|
347
|
-
ontransitioncancel: ((this: GlobalEventHandlers, ev: TransitionEvent) => any) | null;
|
|
348
|
-
ontransitionend: ((this: GlobalEventHandlers, ev: TransitionEvent) => any) | null;
|
|
349
|
-
ontransitionrun: ((this: GlobalEventHandlers, ev: TransitionEvent) => any) | null;
|
|
350
|
-
ontransitionstart: ((this: GlobalEventHandlers, ev: TransitionEvent) => any) | null;
|
|
351
|
-
onvolumechange: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
352
|
-
onwaiting: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
353
|
-
onwebkitanimationend: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
354
|
-
onwebkitanimationiteration: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
355
|
-
onwebkitanimationstart: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
356
|
-
onwebkittransitionend: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
|
357
|
-
onwheel: ((this: GlobalEventHandlers, ev: WheelEvent) => any) | null;
|
|
358
|
-
autofocus: boolean;
|
|
359
|
-
readonly dataset: DOMStringMap;
|
|
360
|
-
nonce?: string;
|
|
361
|
-
tabIndex: number;
|
|
362
|
-
blur(): void;
|
|
363
|
-
focus(options?: FocusOptions): void;
|
|
364
|
-
};
|
|
365
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated Import from '@neovici/cosmoz-utils/connectable' instead.
|
|
3
|
+
* This export will be removed in the next major version.
|
|
4
|
+
*/
|
|
5
|
+
export { connectable } from '@neovici/cosmoz-utils/connectable';
|
package/dist/connectable.js
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
disconnectedCallback() {
|
|
7
|
-
super.disconnectedCallback?.();
|
|
8
|
-
this.dispatchEvent(new CustomEvent('disconnected'));
|
|
9
|
-
}
|
|
10
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated Import from '@neovici/cosmoz-utils/connectable' instead.
|
|
3
|
+
* This export will be removed in the next major version.
|
|
4
|
+
*/
|
|
5
|
+
export { connectable } from '@neovici/cosmoz-utils/connectable';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { component, css, useRef } from '@pionjs/pion';
|
|
2
2
|
import { html } from 'lit-html';
|
|
3
3
|
import { ref } from 'lit-html/directives/ref.js';
|
|
4
|
+
import { useAutoOpen } from './use-auto-open.js';
|
|
4
5
|
/**
|
|
5
6
|
* Autofocus polyfill for slotted content.
|
|
6
7
|
*
|
|
@@ -49,6 +50,7 @@ const style = css `
|
|
|
49
50
|
padding: 0;
|
|
50
51
|
background: transparent;
|
|
51
52
|
overflow: visible;
|
|
53
|
+
min-width: anchor-size(width);
|
|
52
54
|
|
|
53
55
|
/* Animation - open state */
|
|
54
56
|
opacity: 1;
|
|
@@ -75,25 +77,43 @@ const style = css `
|
|
|
75
77
|
opacity: 0;
|
|
76
78
|
transform: translateY(-4px) scale(0.96);
|
|
77
79
|
}
|
|
80
|
+
|
|
81
|
+
@media (prefers-reduced-motion: reduce) {
|
|
82
|
+
[popover] {
|
|
83
|
+
transition: none;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
78
86
|
`;
|
|
79
|
-
const CosmozDropdownNext = (
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const
|
|
85
|
-
|
|
87
|
+
const CosmozDropdownNext = (host) => {
|
|
88
|
+
const { placement = 'bottom span-right', openOnHover, openOnFocus } = host;
|
|
89
|
+
const popoverRef = useRef();
|
|
90
|
+
const open = () => popoverRef.current?.showPopover();
|
|
91
|
+
const close = () => popoverRef.current?.hidePopover();
|
|
92
|
+
const toggle = () => popoverRef.current?.togglePopover();
|
|
93
|
+
useAutoOpen({ host, popoverRef, openOnHover, openOnFocus, open, close });
|
|
94
|
+
// When open-on-focus is active, clicking the button should only open
|
|
95
|
+
// (not toggle), since focusin already handles opening and toggle would
|
|
96
|
+
// race with the focusin handler (focusin opens, then click toggles closed).
|
|
97
|
+
const handleClick = openOnFocus ? open : toggle;
|
|
98
|
+
const onToggle = (e) => {
|
|
99
|
+
autofocus(e);
|
|
100
|
+
// Re-dispatch as a composed event so parent components across
|
|
101
|
+
// shadow boundaries can observe popover state changes.
|
|
102
|
+
// The native ToggleEvent is composed: false, bubbles: false.
|
|
103
|
+
host.dispatchEvent(new ToggleEvent('dropdown-toggle', {
|
|
104
|
+
newState: e.newState,
|
|
105
|
+
oldState: e.oldState,
|
|
106
|
+
composed: true,
|
|
107
|
+
}));
|
|
86
108
|
};
|
|
87
109
|
return html `
|
|
88
|
-
<slot name="button" @click=${
|
|
110
|
+
<slot name="button" @click=${handleClick}></slot>
|
|
89
111
|
<div
|
|
90
112
|
popover
|
|
91
113
|
style="position-area: ${placement}"
|
|
92
|
-
@toggle=${
|
|
114
|
+
@toggle=${onToggle}
|
|
93
115
|
@select=${close}
|
|
94
|
-
${ref((el) =>
|
|
95
|
-
popover.current = el;
|
|
96
|
-
})}
|
|
116
|
+
${ref((el) => el && (popoverRef.current = el))}
|
|
97
117
|
>
|
|
98
118
|
<slot></slot>
|
|
99
119
|
</div>
|
|
@@ -101,6 +121,6 @@ const CosmozDropdownNext = ({ placement = 'bottom span-right', }) => {
|
|
|
101
121
|
};
|
|
102
122
|
customElements.define('cosmoz-dropdown-next', component(CosmozDropdownNext, {
|
|
103
123
|
styleSheets: [style],
|
|
104
|
-
observedAttributes: ['placement'],
|
|
124
|
+
observedAttributes: ['placement', 'open-on-hover', 'open-on-focus'],
|
|
105
125
|
shadowRootInit: { mode: 'open', delegatesFocus: true },
|
|
106
126
|
}));
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface UseAutoOpenOptions {
|
|
2
|
+
host: HTMLElement;
|
|
3
|
+
popoverRef: {
|
|
4
|
+
current?: HTMLElement;
|
|
5
|
+
};
|
|
6
|
+
openOnHover?: boolean;
|
|
7
|
+
openOnFocus?: boolean;
|
|
8
|
+
open: () => void;
|
|
9
|
+
close: () => void;
|
|
10
|
+
}
|
|
11
|
+
export declare const useAutoOpen: ({ host, popoverRef, openOnHover, openOnFocus, open, close, }: UseAutoOpenOptions) => void;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { useEffect, useRef } from '@pionjs/pion';
|
|
2
|
+
export const useAutoOpen = ({ host, popoverRef, openOnHover, openOnFocus, open, close, }) => {
|
|
3
|
+
const closeTimeout = useRef();
|
|
4
|
+
const cancelClose = () => clearTimeout(closeTimeout.current);
|
|
5
|
+
const scheduleClose = () => {
|
|
6
|
+
clearTimeout(closeTimeout.current);
|
|
7
|
+
closeTimeout.current = setTimeout(() => {
|
|
8
|
+
const popover = popoverRef.current;
|
|
9
|
+
if (openOnHover &&
|
|
10
|
+
(host.matches(':hover') || popover?.matches(':hover'))) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
if (openOnFocus &&
|
|
14
|
+
(host.matches(':focus-within') || popover?.matches(':focus-within'))) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
close();
|
|
18
|
+
}, 100);
|
|
19
|
+
};
|
|
20
|
+
const handleEnter = () => {
|
|
21
|
+
cancelClose();
|
|
22
|
+
open();
|
|
23
|
+
};
|
|
24
|
+
// Auto-open on hover
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (!openOnHover)
|
|
27
|
+
return;
|
|
28
|
+
host.addEventListener('pointerenter', handleEnter);
|
|
29
|
+
host.addEventListener('pointerleave', scheduleClose);
|
|
30
|
+
return () => {
|
|
31
|
+
cancelClose();
|
|
32
|
+
host.removeEventListener('pointerenter', handleEnter);
|
|
33
|
+
host.removeEventListener('pointerleave', scheduleClose);
|
|
34
|
+
};
|
|
35
|
+
}, [openOnHover, host]);
|
|
36
|
+
// Auto-open on focus
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (!openOnFocus)
|
|
39
|
+
return;
|
|
40
|
+
host.addEventListener('focusin', handleEnter);
|
|
41
|
+
host.addEventListener('focusout', scheduleClose);
|
|
42
|
+
return () => {
|
|
43
|
+
cancelClose();
|
|
44
|
+
host.removeEventListener('focusin', handleEnter);
|
|
45
|
+
host.removeEventListener('focusout', scheduleClose);
|
|
46
|
+
};
|
|
47
|
+
}, [openOnFocus, host]);
|
|
48
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neovici/cosmoz-dropdown",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.3.0",
|
|
4
4
|
"description": "A simple dropdown web component",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lit-html",
|
|
@@ -25,8 +25,10 @@
|
|
|
25
25
|
"check:duplicates": "check-duplicate-components",
|
|
26
26
|
"build": "tsc -p tsconfig.build.json",
|
|
27
27
|
"start": "wds",
|
|
28
|
-
"test": "wtr --coverage",
|
|
28
|
+
"test": "wtr --coverage && vitest --project=storybook --run",
|
|
29
29
|
"test:watch": "wtr --watch",
|
|
30
|
+
"test:storybook": "vitest --project=storybook --run",
|
|
31
|
+
"test:storybook:watch": "vitest --project=storybook",
|
|
30
32
|
"storybook:start": "storybook dev -p 8000",
|
|
31
33
|
"storybook:build": "storybook build",
|
|
32
34
|
"storybook:deploy": "storybook-to-ghpages",
|
|
@@ -74,7 +76,7 @@
|
|
|
74
76
|
},
|
|
75
77
|
"dependencies": {
|
|
76
78
|
"@floating-ui/dom": "^1.6.12",
|
|
77
|
-
"@neovici/cosmoz-utils": "^6.
|
|
79
|
+
"@neovici/cosmoz-utils": "^6.19.0",
|
|
78
80
|
"@pionjs/pion": "^2.5.2",
|
|
79
81
|
"lit-html": "^3.1.2"
|
|
80
82
|
},
|
|
@@ -88,18 +90,23 @@
|
|
|
88
90
|
"@semantic-release/changelog": "^6.0.0",
|
|
89
91
|
"@semantic-release/git": "^10.0.0",
|
|
90
92
|
"@storybook/addon-docs": "^10.0.0",
|
|
93
|
+
"@storybook/addon-vitest": "^10.2.4",
|
|
91
94
|
"@storybook/web-components-vite": "^10.0.0",
|
|
92
95
|
"@types/mocha": "^10.0.6",
|
|
93
96
|
"@types/node": "^24.0.0",
|
|
97
|
+
"@vitest/browser": "^4.0.18",
|
|
98
|
+
"@vitest/browser-playwright": "^4.0.18",
|
|
94
99
|
"esbuild": "^0.25.0",
|
|
95
100
|
"http-server": "^14.1.1",
|
|
96
101
|
"husky": "^9.0.11",
|
|
97
102
|
"lint-staged": "^16.2.7",
|
|
98
103
|
"rollup-plugin-esbuild": "^6.1.1",
|
|
99
104
|
"semantic-release": "^25.0.0",
|
|
105
|
+
"shadow-dom-testing-library": "^1.13.1",
|
|
100
106
|
"sinon": "^21.0.0",
|
|
101
107
|
"storybook": "^10.0.0",
|
|
102
|
-
"typescript": "^5.4.3"
|
|
108
|
+
"typescript": "^5.4.3",
|
|
109
|
+
"vitest": "^4.0.18"
|
|
103
110
|
},
|
|
104
111
|
"overrides": {
|
|
105
112
|
"conventional-changelog-conventionalcommits": ">= 8.0.0"
|