@neovici/cosmoz-dropdown 7.2.0 → 7.4.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 CHANGED
@@ -62,7 +62,8 @@ The `open-on-hover` and `open-on-focus` attributes can be used independently or
62
62
  When auto-open is enabled:
63
63
 
64
64
  - The dropdown closes with a 100ms delay to allow moving between trigger and content
65
- - Click still works as a toggle regardless of these settings
65
+ - When `open-on-focus` is active, clicking the button only opens (does not toggle)
66
+ - Otherwise, click works as a toggle
66
67
 
67
68
  #### Slots
68
69
 
@@ -79,6 +80,14 @@ The dropdown listens for a `select` event on its content and automatically close
79
80
  menuItem.dispatchEvent(new Event('select', { bubbles: true }));
80
81
  ```
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
+
82
91
  ## Development
83
92
 
84
93
  ```bash
@@ -1,365 +1,5 @@
1
- declare global {
2
- interface HTMLElement {
3
- connectedCallback(): void;
4
- disconnectedCallback(): void;
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';
@@ -1,10 +1,5 @@
1
- export const connectable = (base = HTMLElement) => class extends base {
2
- connectedCallback() {
3
- super.connectedCallback?.();
4
- this.dispatchEvent(new CustomEvent('connected'));
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,4 +1,4 @@
1
- import { component, css, useRef } from '@pionjs/pion';
1
+ import { component, css, useEffect, useProperty, useRef } from '@pionjs/pion';
2
2
  import { html } from 'lit-html';
3
3
  import { ref } from 'lit-html/directives/ref.js';
4
4
  import { useAutoOpen } from './use-auto-open.js';
@@ -50,6 +50,7 @@ const style = css `
50
50
  padding: 0;
51
51
  background: transparent;
52
52
  overflow: visible;
53
+ min-width: anchor-size(width);
53
54
 
54
55
  /* Animation - open state */
55
56
  opacity: 1;
@@ -86,16 +87,50 @@ const style = css `
86
87
  const CosmozDropdownNext = (host) => {
87
88
  const { placement = 'bottom span-right', openOnHover, openOnFocus } = host;
88
89
  const popoverRef = useRef();
89
- const open = () => popoverRef.current?.showPopover();
90
- const close = () => popoverRef.current?.hidePopover();
91
- const toggle = () => popoverRef.current?.togglePopover();
90
+ const [opened, setOpened] = useProperty('opened', false);
91
+ const open = () => setOpened(true);
92
+ const close = () => setOpened(false);
93
+ const toggle = () => setOpened((v) => !v);
94
+ // Drive the native popover from the `opened` property
95
+ useEffect(() => {
96
+ const popover = popoverRef.current;
97
+ if (!popover)
98
+ return;
99
+ if (opened && !popover.matches(':popover-open'))
100
+ popover.showPopover();
101
+ if (!opened && popover.matches(':popover-open'))
102
+ popover.hidePopover();
103
+ }, [opened]);
104
+ // Attribute reflection — sync property → attribute for CSS selectors.
105
+ useEffect(() => {
106
+ host.toggleAttribute('opened', !!opened);
107
+ }, [opened]);
92
108
  useAutoOpen({ host, popoverRef, openOnHover, openOnFocus, open, close });
109
+ // When open-on-focus is active, clicking the button should only open
110
+ // (not toggle), since focusin already handles opening and toggle would
111
+ // race with the focusin handler (focusin opens, then click toggles closed).
112
+ const handleClick = openOnFocus ? open : toggle;
113
+ const onToggle = (e) => {
114
+ autofocus(e);
115
+ // Sync browser-initiated state changes (light-dismiss, Escape)
116
+ // back to the property. The useEffect guards against redundant
117
+ // showPopover/hidePopover calls.
118
+ setOpened(e.newState === 'open');
119
+ // Re-dispatch as a composed event so parent components across
120
+ // shadow boundaries can observe popover state changes.
121
+ // The native ToggleEvent is composed: false, bubbles: false.
122
+ host.dispatchEvent(new ToggleEvent('dropdown-toggle', {
123
+ newState: e.newState,
124
+ oldState: e.oldState,
125
+ composed: true,
126
+ }));
127
+ };
93
128
  return html `
94
- <slot name="button" @click=${toggle}></slot>
129
+ <slot name="button" @click=${handleClick}></slot>
95
130
  <div
96
131
  popover
97
132
  style="position-area: ${placement}"
98
- @toggle=${autofocus}
133
+ @toggle=${onToggle}
99
134
  @select=${close}
100
135
  ${ref((el) => el && (popoverRef.current = el))}
101
136
  >
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neovici/cosmoz-dropdown",
3
- "version": "7.2.0",
3
+ "version": "7.4.0",
4
4
  "description": "A simple dropdown web component",
5
5
  "keywords": [
6
6
  "lit-html",
@@ -76,7 +76,7 @@
76
76
  },
77
77
  "dependencies": {
78
78
  "@floating-ui/dom": "^1.6.12",
79
- "@neovici/cosmoz-utils": "^6.8.1",
79
+ "@neovici/cosmoz-utils": "^6.19.0",
80
80
  "@pionjs/pion": "^2.5.2",
81
81
  "lit-html": "^3.1.2"
82
82
  },