@neovici/cosmoz-dropdown 7.4.0 → 7.4.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.
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { component, css, useEffect, useProperty, useRef } from '@pionjs/pion';
|
|
1
|
+
import { component, css, useCallback, 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';
|
|
@@ -88,43 +88,57 @@ const CosmozDropdownNext = (host) => {
|
|
|
88
88
|
const { placement = 'bottom span-right', openOnHover, openOnFocus } = host;
|
|
89
89
|
const popoverRef = useRef();
|
|
90
90
|
const [opened, setOpened] = useProperty('opened', false);
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
91
|
+
// Call showPopover/hidePopover synchronously so the browser associates
|
|
92
|
+
// the popover with the current user-gesture. Deferring to a microtask
|
|
93
|
+
// (useEffect) causes light-dismiss to immediately close the popover.
|
|
94
|
+
const open = useCallback(() => {
|
|
95
|
+
setOpened(true);
|
|
96
|
+
popoverRef.current?.showPopover();
|
|
97
|
+
}, []);
|
|
98
|
+
const close = useCallback(() => {
|
|
99
|
+
setOpened(false);
|
|
100
|
+
popoverRef.current?.hidePopover();
|
|
101
|
+
}, []);
|
|
102
|
+
const toggle = useCallback(() => {
|
|
103
|
+
const popover = popoverRef.current;
|
|
104
|
+
if (popover?.matches(':popover-open'))
|
|
105
|
+
close();
|
|
106
|
+
else
|
|
107
|
+
open();
|
|
108
|
+
}, []);
|
|
109
|
+
// Sync native popover when `opened` is set externally via property binding
|
|
95
110
|
useEffect(() => {
|
|
96
111
|
const popover = popoverRef.current;
|
|
97
112
|
if (!popover)
|
|
98
113
|
return;
|
|
99
|
-
if (opened
|
|
114
|
+
if (opened)
|
|
100
115
|
popover.showPopover();
|
|
101
|
-
|
|
116
|
+
else
|
|
102
117
|
popover.hidePopover();
|
|
103
118
|
}, [opened]);
|
|
104
|
-
// Attribute reflection — sync property → attribute for CSS selectors.
|
|
105
119
|
useEffect(() => {
|
|
106
120
|
host.toggleAttribute('opened', !!opened);
|
|
107
121
|
}, [opened]);
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
122
|
+
const { scheduleClose, cancelClose } = useAutoOpen({
|
|
123
|
+
host,
|
|
124
|
+
popoverRef,
|
|
125
|
+
openOnHover,
|
|
126
|
+
openOnFocus,
|
|
127
|
+
open,
|
|
128
|
+
close,
|
|
129
|
+
});
|
|
130
|
+
// With open-on-focus, only open (not toggle) on click to avoid racing
|
|
131
|
+
// with the focusin handler
|
|
112
132
|
const handleClick = openOnFocus ? open : toggle;
|
|
113
|
-
const onToggle = (e) => {
|
|
133
|
+
const onToggle = useCallback((e) => {
|
|
114
134
|
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
135
|
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
136
|
host.dispatchEvent(new ToggleEvent('dropdown-toggle', {
|
|
123
137
|
newState: e.newState,
|
|
124
138
|
oldState: e.oldState,
|
|
125
139
|
composed: true,
|
|
126
140
|
}));
|
|
127
|
-
};
|
|
141
|
+
}, []);
|
|
128
142
|
return html `
|
|
129
143
|
<slot name="button" @click=${handleClick}></slot>
|
|
130
144
|
<div
|
|
@@ -132,6 +146,8 @@ const CosmozDropdownNext = (host) => {
|
|
|
132
146
|
style="position-area: ${placement}"
|
|
133
147
|
@toggle=${onToggle}
|
|
134
148
|
@select=${close}
|
|
149
|
+
@focusout=${scheduleClose}
|
|
150
|
+
@focusin=${cancelClose}
|
|
135
151
|
${ref((el) => el && (popoverRef.current = el))}
|
|
136
152
|
>
|
|
137
153
|
<slot></slot>
|
|
@@ -8,5 +8,8 @@ interface UseAutoOpenOptions {
|
|
|
8
8
|
open: () => void;
|
|
9
9
|
close: () => void;
|
|
10
10
|
}
|
|
11
|
-
export declare const useAutoOpen: ({ host, popoverRef, openOnHover, openOnFocus, open, close, }: UseAutoOpenOptions) =>
|
|
11
|
+
export declare const useAutoOpen: ({ host, popoverRef, openOnHover, openOnFocus, open, close, }: UseAutoOpenOptions) => {
|
|
12
|
+
scheduleClose: () => void;
|
|
13
|
+
cancelClose: () => void;
|
|
14
|
+
};
|
|
12
15
|
export {};
|
|
@@ -10,8 +10,7 @@ export const useAutoOpen = ({ host, popoverRef, openOnHover, openOnFocus, open,
|
|
|
10
10
|
(host.matches(':hover') || popover?.matches(':hover'))) {
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
13
|
-
if (
|
|
14
|
-
(host.matches(':focus-within') || popover?.matches(':focus-within'))) {
|
|
13
|
+
if (host.matches(':focus-within') || popover?.matches(':focus-within')) {
|
|
15
14
|
return;
|
|
16
15
|
}
|
|
17
16
|
close();
|
|
@@ -45,4 +44,5 @@ export const useAutoOpen = ({ host, popoverRef, openOnHover, openOnFocus, open,
|
|
|
45
44
|
host.removeEventListener('focusout', scheduleClose);
|
|
46
45
|
};
|
|
47
46
|
}, [openOnFocus, host]);
|
|
47
|
+
return { scheduleClose, cancelClose };
|
|
48
48
|
};
|