@finsweet/webflow-apps-utils 1.0.53 → 1.0.54
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.
|
@@ -76,6 +76,14 @@ declare const meta: {
|
|
|
76
76
|
control: string;
|
|
77
77
|
description: string;
|
|
78
78
|
};
|
|
79
|
+
closeOnEscape: {
|
|
80
|
+
control: string;
|
|
81
|
+
description: string;
|
|
82
|
+
};
|
|
83
|
+
closeOnClickOutside: {
|
|
84
|
+
control: string;
|
|
85
|
+
description: string;
|
|
86
|
+
};
|
|
79
87
|
};
|
|
80
88
|
};
|
|
81
89
|
export default meta;
|
|
@@ -90,6 +98,9 @@ export declare const CustomDimensions: Story;
|
|
|
90
98
|
export declare const CompactSelect: Story;
|
|
91
99
|
export declare const WideSelect: Story;
|
|
92
100
|
export declare const PreventDeselection: Story;
|
|
101
|
+
export declare const DisableEscapeClose: Story;
|
|
102
|
+
export declare const DisableClickOutsideClose: Story;
|
|
103
|
+
export declare const DisableAllCloseBehaviors: Story;
|
|
93
104
|
export declare const MixedOptions: Story;
|
|
94
105
|
export declare const TopPlacement: Story;
|
|
95
106
|
export declare const LeftPlacement: Story;
|
|
@@ -123,6 +123,14 @@ const meta = {
|
|
|
123
123
|
invalid: {
|
|
124
124
|
control: 'boolean',
|
|
125
125
|
description: 'Whether the select is in an invalid state'
|
|
126
|
+
},
|
|
127
|
+
closeOnEscape: {
|
|
128
|
+
control: 'boolean',
|
|
129
|
+
description: 'Whether the dropdown closes when pressing the Escape key'
|
|
130
|
+
},
|
|
131
|
+
closeOnClickOutside: {
|
|
132
|
+
control: 'boolean',
|
|
133
|
+
description: 'Whether the dropdown closes when clicking outside the component'
|
|
126
134
|
}
|
|
127
135
|
}
|
|
128
136
|
};
|
|
@@ -241,6 +249,49 @@ export const PreventDeselection = {
|
|
|
241
249
|
}
|
|
242
250
|
}
|
|
243
251
|
};
|
|
252
|
+
export const DisableEscapeClose = {
|
|
253
|
+
args: {
|
|
254
|
+
options: basicOptions,
|
|
255
|
+
defaultText: 'Press Escape (disabled)',
|
|
256
|
+
closeOnEscape: false
|
|
257
|
+
},
|
|
258
|
+
parameters: {
|
|
259
|
+
docs: {
|
|
260
|
+
description: {
|
|
261
|
+
story: 'Prevents the dropdown from closing when the Escape key is pressed. Users must select an option or click the button again to close.'
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
export const DisableClickOutsideClose = {
|
|
267
|
+
args: {
|
|
268
|
+
options: basicOptions,
|
|
269
|
+
defaultText: 'Click outside (disabled)',
|
|
270
|
+
closeOnClickOutside: false
|
|
271
|
+
},
|
|
272
|
+
parameters: {
|
|
273
|
+
docs: {
|
|
274
|
+
description: {
|
|
275
|
+
story: 'Prevents the dropdown from closing when clicking outside the component. Users must select an option or click the button again to close.'
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
export const DisableAllCloseBehaviors = {
|
|
281
|
+
args: {
|
|
282
|
+
options: basicOptions,
|
|
283
|
+
defaultText: 'Must select to close',
|
|
284
|
+
closeOnEscape: false,
|
|
285
|
+
closeOnClickOutside: false
|
|
286
|
+
},
|
|
287
|
+
parameters: {
|
|
288
|
+
docs: {
|
|
289
|
+
description: {
|
|
290
|
+
story: 'Disables both Escape key and click outside behaviors. The dropdown can only be closed by selecting an option or clicking the select button. Useful for modal-like contexts where you want to force a selection.'
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
};
|
|
244
295
|
export const MixedOptions = {
|
|
245
296
|
args: {
|
|
246
297
|
options: mixedOptions,
|
|
@@ -42,6 +42,8 @@
|
|
|
42
42
|
alert = null,
|
|
43
43
|
invalid = false,
|
|
44
44
|
className = '',
|
|
45
|
+
closeOnEscape = true,
|
|
46
|
+
closeOnClickOutside = true,
|
|
45
47
|
onchange,
|
|
46
48
|
children,
|
|
47
49
|
footer
|
|
@@ -94,6 +96,28 @@
|
|
|
94
96
|
}
|
|
95
97
|
});
|
|
96
98
|
|
|
99
|
+
// Handle global Escape key when dropdown is open
|
|
100
|
+
$effect(() => {
|
|
101
|
+
const handleGlobalKeyDown = (event: KeyboardEvent) => {
|
|
102
|
+
if (event.key === 'Escape' && closeOnEscape && isOpen) {
|
|
103
|
+
event.preventDefault();
|
|
104
|
+
closeDropdown();
|
|
105
|
+
// Remove focus to prevent focus ring after closing
|
|
106
|
+
if (document.activeElement instanceof HTMLElement) {
|
|
107
|
+
document.activeElement.blur();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
if (isOpen) {
|
|
113
|
+
document?.addEventListener('keydown', handleGlobalKeyDown);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return () => {
|
|
117
|
+
document?.removeEventListener('keydown', handleGlobalKeyDown);
|
|
118
|
+
};
|
|
119
|
+
});
|
|
120
|
+
|
|
97
121
|
// Computed states
|
|
98
122
|
let hasAlert = $derived(alert?.message);
|
|
99
123
|
|
|
@@ -159,6 +183,8 @@
|
|
|
159
183
|
* Dismiss dropdown when clicking outside of it.
|
|
160
184
|
*/
|
|
161
185
|
const dismissTooltip = (event: Event): void => {
|
|
186
|
+
if (!closeOnClickOutside) return;
|
|
187
|
+
|
|
162
188
|
const isClickInside = dropdownWrapper?.contains(event.target as Node);
|
|
163
189
|
|
|
164
190
|
if (!isClickInside) {
|
|
@@ -247,7 +273,13 @@
|
|
|
247
273
|
break;
|
|
248
274
|
}
|
|
249
275
|
case 'Escape':
|
|
250
|
-
|
|
276
|
+
if (closeOnEscape) {
|
|
277
|
+
closeDropdown();
|
|
278
|
+
// Remove focus to prevent focus ring after closing
|
|
279
|
+
if (document.activeElement instanceof HTMLElement) {
|
|
280
|
+
document.activeElement.blur();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
251
283
|
break;
|
|
252
284
|
}
|
|
253
285
|
|
|
@@ -301,7 +333,9 @@
|
|
|
301
333
|
|
|
302
334
|
if (!dropdownItems || !target) return instances;
|
|
303
335
|
|
|
304
|
-
|
|
336
|
+
if (closeOnClickOutside) {
|
|
337
|
+
document?.addEventListener('click', dismissTooltip);
|
|
338
|
+
}
|
|
305
339
|
instances.push(setupDropdown(target, dropdownItems));
|
|
306
340
|
|
|
307
341
|
return instances;
|
|
@@ -312,6 +346,9 @@
|
|
|
312
346
|
*/
|
|
313
347
|
const cleanupDropdownInstances = (instances: DropdownInstance[]) => {
|
|
314
348
|
instances.forEach((instance) => instance.cleanup());
|
|
349
|
+
if (closeOnClickOutside) {
|
|
350
|
+
document?.removeEventListener('click', dismissTooltip);
|
|
351
|
+
}
|
|
315
352
|
};
|
|
316
353
|
|
|
317
354
|
/**
|
|
@@ -679,6 +716,10 @@
|
|
|
679
716
|
display: flex;
|
|
680
717
|
align-items: center;
|
|
681
718
|
gap: 4px;
|
|
719
|
+
outline: none; /* Remove default focus outline since we have custom focus styling */
|
|
720
|
+
}
|
|
721
|
+
.dropdown:focus-visible {
|
|
722
|
+
outline: none; /* Prevent browser's default focus ring */
|
|
682
723
|
}
|
|
683
724
|
.dropdown.disabled {
|
|
684
725
|
cursor: not-allowed !important;
|
|
@@ -712,6 +753,10 @@
|
|
|
712
753
|
background: var(--background3);
|
|
713
754
|
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.15);
|
|
714
755
|
z-index: 99999;
|
|
756
|
+
outline: none; /* Remove focus outline */
|
|
757
|
+
}
|
|
758
|
+
.dropdown-list:focus-visible {
|
|
759
|
+
outline: none; /* Prevent browser's default focus ring */
|
|
715
760
|
}
|
|
716
761
|
|
|
717
762
|
.dropdown-items-scroll {
|
|
@@ -778,6 +823,10 @@
|
|
|
778
823
|
font-weight: 400;
|
|
779
824
|
line-height: 16px;
|
|
780
825
|
border: 1px solid transparent;
|
|
826
|
+
outline: none; /* Remove focus outline */
|
|
827
|
+
}
|
|
828
|
+
.dropdown-item:focus-visible {
|
|
829
|
+
outline: none; /* Prevent browser's default focus ring */
|
|
781
830
|
}
|
|
782
831
|
.dropdown-item .icon,
|
|
783
832
|
.dropdown-list .selected .icon {
|
|
@@ -49,6 +49,16 @@ export interface SelectProps {
|
|
|
49
49
|
* Alert configuration for showing validation messages
|
|
50
50
|
*/
|
|
51
51
|
alert?: AlertConfig | null;
|
|
52
|
+
/**
|
|
53
|
+
* If true, the dropdown will close when the Escape key is pressed
|
|
54
|
+
* @default true
|
|
55
|
+
*/
|
|
56
|
+
closeOnEscape?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* If true, the dropdown will close when clicking outside the component
|
|
59
|
+
* @default true
|
|
60
|
+
*/
|
|
61
|
+
closeOnClickOutside?: boolean;
|
|
52
62
|
/**
|
|
53
63
|
* If true, the select will be invalid
|
|
54
64
|
*/
|