flowbite-svelte 1.2.3 → 1.2.5
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/dist/drawer/Drawer.svelte +3 -2
- package/dist/forms/{checkbox-button → checkbox}/CheckboxButton.svelte +2 -2
- package/dist/forms/checkbox/index.d.ts +3 -3
- package/dist/forms/checkbox/index.js +3 -3
- package/dist/forms/checkbox/theme.d.ts +25 -0
- package/dist/forms/checkbox/theme.js +15 -0
- package/dist/forms/{radio-button → radio}/RadioButton.svelte +2 -3
- package/dist/forms/radio/index.d.ts +3 -3
- package/dist/forms/radio/index.js +3 -3
- package/dist/forms/radio/theme.d.ts +16 -0
- package/dist/forms/radio/theme.js +12 -0
- package/dist/index.d.ts +2 -4
- package/dist/index.js +2 -4
- package/dist/modal/Modal.svelte +17 -8
- package/dist/sidebar/Sidebar.svelte +8 -6
- package/dist/theme/index.d.ts +1 -1
- package/dist/theme/index.js +2 -2
- package/dist/types.d.ts +1 -1
- package/dist/utils/Popper.svelte +8 -1
- package/dist/utils/actions.svelte.d.ts +16 -0
- package/dist/utils/actions.svelte.js +114 -0
- package/package.json +9 -9
- package/dist/forms/checkbox-button/index.d.ts +0 -2
- package/dist/forms/checkbox-button/index.js +0 -2
- package/dist/forms/checkbox-button/theme.d.ts +0 -25
- package/dist/forms/checkbox-button/theme.js +0 -16
- package/dist/forms/radio-button/index.d.ts +0 -3
- package/dist/forms/radio-button/index.js +0 -3
- package/dist/forms/radio-button/theme.d.ts +0 -16
- package/dist/forms/radio-button/theme.js +0 -13
- package/dist/utils/focusTrap.d.ts +0 -4
- package/dist/utils/focusTrap.js +0 -38
- /package/dist/{buttongroup → button-group}/ButtonGroup.svelte +0 -0
- /package/dist/{buttongroup → button-group}/ButtonGroup.svelte.d.ts +0 -0
- /package/dist/{buttongroup → button-group}/index.d.ts +0 -0
- /package/dist/{buttongroup → button-group}/index.js +0 -0
- /package/dist/{buttongroup → button-group}/theme.d.ts +0 -0
- /package/dist/{buttongroup → button-group}/theme.js +0 -0
- /package/dist/forms/{checkbox-button → checkbox}/CheckboxButton.svelte.d.ts +0 -0
- /package/dist/forms/{floating-label-input → floating-label}/FloatingLabelInput.svelte +0 -0
- /package/dist/forms/{floating-label-input → floating-label}/FloatingLabelInput.svelte.d.ts +0 -0
- /package/dist/forms/{floating-label-input → floating-label}/index.d.ts +0 -0
- /package/dist/forms/{floating-label-input → floating-label}/index.js +0 -0
- /package/dist/forms/{floating-label-input → floating-label}/theme.d.ts +0 -0
- /package/dist/forms/{floating-label-input → floating-label}/theme.js +0 -0
- /package/dist/forms/{radio-button → radio}/RadioButton.svelte.d.ts +0 -0
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { drawer } from ".";
|
|
6
6
|
import type { DrawerProps } from "../types";
|
|
7
7
|
import clsx from "clsx";
|
|
8
|
+
import { trapFocus } from "../utils/actions.svelte";
|
|
8
9
|
|
|
9
10
|
let { children, hidden = $bindable(), closeDrawer = () => (hidden = true), activateClickOutside = true, position, width, backdrop = true, backdropClass, placement = "left", class: className, transitionParams, transitionType = fly, ...restProps }: DrawerProps = $props();
|
|
10
11
|
|
|
@@ -26,11 +27,11 @@
|
|
|
26
27
|
let transition_params = $derived(Object.assign({}, { x, y, duration: 200, easing: sineIn }));
|
|
27
28
|
</script>
|
|
28
29
|
|
|
29
|
-
<svelte:window
|
|
30
|
+
<svelte:window bind:innerWidth bind:innerHeight />
|
|
30
31
|
|
|
31
32
|
{#if !hidden}
|
|
32
33
|
<div role="presentation" class={backdropCls({ class: backdropClass })} onclick={activateClickOutside ? closeDrawer : undefined}></div>
|
|
33
|
-
<div {...restProps} class={base({ class: clsx(className) })} transition:transitionType={transitionParams ? transitionParams : (transition_params as ParamsType)} tabindex="-1">
|
|
34
|
+
<div use:trapFocus={{ onEscape: closeDrawer }} {...restProps} class={base({ class: clsx(className) })} transition:transitionType={transitionParams ? transitionParams : (transition_params as ParamsType)} tabindex="-1">
|
|
34
35
|
{@render children?.()}
|
|
35
36
|
</div>
|
|
36
37
|
{/if}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import Button from "../../buttons/Button.svelte";
|
|
3
3
|
import clsx from "clsx";
|
|
4
4
|
import type { CheckboxButtonProps } from "../../types";
|
|
5
|
-
import {
|
|
5
|
+
import { checkboxbutton } from "./theme";
|
|
6
6
|
|
|
7
7
|
let { children, class: className, group = $bindable([]), value, checked, inline, pill, outline, size, color, shadow, ...restProps }: CheckboxButtonProps = $props();
|
|
8
8
|
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
let buttonClass: string = $derived(
|
|
46
|
+
let buttonClass: string = $derived(checkboxbutton({ inline, checked, class: clsx(className) }));
|
|
47
47
|
</script>
|
|
48
48
|
|
|
49
49
|
<Button tag="label" {checked} {pill} {outline} {size} {color} {shadow} class={buttonClass}>
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export {
|
|
1
|
+
export { default as Checkbox } from "./Checkbox.svelte";
|
|
2
|
+
export { default as ChecboxButton } from "./CheckboxButton.svelte";
|
|
3
|
+
export { checkbox, checkboxbutton } from "./theme";
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export {
|
|
1
|
+
export { default as Checkbox } from "./Checkbox.svelte";
|
|
2
|
+
export { default as ChecboxButton } from "./CheckboxButton.svelte";
|
|
3
|
+
export { checkbox, checkboxbutton } from "./theme";
|
|
@@ -287,3 +287,28 @@ export declare const checkbox: import("tailwind-variants").TVReturnType<{
|
|
|
287
287
|
base: string;
|
|
288
288
|
div: string;
|
|
289
289
|
}, undefined, unknown, unknown, undefined>>;
|
|
290
|
+
export declare const checkboxbutton: import("tailwind-variants").TVReturnType<{
|
|
291
|
+
inline: {
|
|
292
|
+
true: string;
|
|
293
|
+
false: string;
|
|
294
|
+
};
|
|
295
|
+
checked: {
|
|
296
|
+
true: string;
|
|
297
|
+
};
|
|
298
|
+
}, undefined, "", {
|
|
299
|
+
inline: {
|
|
300
|
+
true: string;
|
|
301
|
+
false: string;
|
|
302
|
+
};
|
|
303
|
+
checked: {
|
|
304
|
+
true: string;
|
|
305
|
+
};
|
|
306
|
+
}, undefined, import("tailwind-variants").TVReturnType<{
|
|
307
|
+
inline: {
|
|
308
|
+
true: string;
|
|
309
|
+
false: string;
|
|
310
|
+
};
|
|
311
|
+
checked: {
|
|
312
|
+
true: string;
|
|
313
|
+
};
|
|
314
|
+
}, undefined, "", unknown, unknown, undefined>>;
|
|
@@ -96,3 +96,18 @@ export const checkbox = tv({
|
|
|
96
96
|
disabled: false
|
|
97
97
|
}
|
|
98
98
|
});
|
|
99
|
+
export const checkboxbutton = tv({
|
|
100
|
+
base: "",
|
|
101
|
+
variants: {
|
|
102
|
+
inline: {
|
|
103
|
+
true: "inline-flex",
|
|
104
|
+
false: "flex"
|
|
105
|
+
},
|
|
106
|
+
checked: {
|
|
107
|
+
true: "outline-4 outline-green-500"
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
defaultVariants: {
|
|
111
|
+
inline: true
|
|
112
|
+
}
|
|
113
|
+
});
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
<script lang="ts" generics="T">
|
|
2
2
|
import { Button, type RadioButtonProps } from "../..";
|
|
3
3
|
import { twMerge } from "tailwind-merge";
|
|
4
|
-
import
|
|
5
|
-
import { radioButton } from ".";
|
|
4
|
+
import { radiobutton } from ".";
|
|
6
5
|
|
|
7
6
|
let { children, group = $bindable<T>(), value = $bindable<T>(), inline, pill, outline, size, color, shadow, checkedClass, class: className, ...restProps }: RadioButtonProps<T> = $props();
|
|
8
7
|
|
|
9
8
|
let inputEl: HTMLInputElement;
|
|
10
9
|
let isChecked = $derived(value == group);
|
|
11
|
-
let base = $derived(twMerge(
|
|
10
|
+
let base = $derived(twMerge(radiobutton({ inline }), isChecked && checkedClass, className));
|
|
12
11
|
|
|
13
12
|
function clickHandler() {
|
|
14
13
|
inputEl?.click(); // manually trigger the click on the hidden input
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export {
|
|
1
|
+
export { default as Radio } from "./Radio.svelte";
|
|
2
|
+
export { default as RadioButton } from "./RadioButton.svelte";
|
|
3
|
+
export { radio, radiobutton } from "./theme";
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export {
|
|
1
|
+
export { default as Radio } from "./Radio.svelte";
|
|
2
|
+
export { default as RadioButton } from "./RadioButton.svelte";
|
|
3
|
+
export { radio, radiobutton } from "./theme";
|
|
@@ -271,3 +271,19 @@ export declare const radio: import("tailwind-variants").TVReturnType<{
|
|
|
271
271
|
input: string;
|
|
272
272
|
label: string;
|
|
273
273
|
}, undefined, unknown, unknown, undefined>>;
|
|
274
|
+
export declare const radiobutton: import("tailwind-variants").TVReturnType<{
|
|
275
|
+
inline: {
|
|
276
|
+
true: string;
|
|
277
|
+
false: string;
|
|
278
|
+
};
|
|
279
|
+
}, undefined, "", {
|
|
280
|
+
inline: {
|
|
281
|
+
true: string;
|
|
282
|
+
false: string;
|
|
283
|
+
};
|
|
284
|
+
}, undefined, import("tailwind-variants").TVReturnType<{
|
|
285
|
+
inline: {
|
|
286
|
+
true: string;
|
|
287
|
+
false: string;
|
|
288
|
+
};
|
|
289
|
+
}, undefined, "", unknown, unknown, undefined>>;
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export * from "./badge";
|
|
|
6
6
|
export * from "./banner";
|
|
7
7
|
export * from "./bottom-navigation";
|
|
8
8
|
export * from "./breadcrumb";
|
|
9
|
-
export * from "./
|
|
9
|
+
export * from "./button-group";
|
|
10
10
|
export * from "./buttons";
|
|
11
11
|
export * from "./card";
|
|
12
12
|
export * from "./carousel";
|
|
@@ -42,17 +42,15 @@ export * from "./tooltip";
|
|
|
42
42
|
export * from "./utils";
|
|
43
43
|
export * from "./video";
|
|
44
44
|
export * from "./forms/checkbox";
|
|
45
|
-
export * from "./forms/checkbox-button";
|
|
46
45
|
export * from "./forms/dropzone";
|
|
47
46
|
export * from "./forms/fileupload";
|
|
48
|
-
export * from "./forms/floating-label
|
|
47
|
+
export * from "./forms/floating-label";
|
|
49
48
|
export * from "./forms/helper";
|
|
50
49
|
export * from "./forms/input";
|
|
51
50
|
export * from "./forms/input-addon";
|
|
52
51
|
export * from "./forms/label";
|
|
53
52
|
export * from "./forms/select";
|
|
54
53
|
export * from "./forms/radio";
|
|
55
|
-
export * from "./forms/radio-button";
|
|
56
54
|
export * from "./forms/range";
|
|
57
55
|
export * from "./forms/search";
|
|
58
56
|
export * from "./forms/tags";
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ export * from "./badge";
|
|
|
6
6
|
export * from "./banner";
|
|
7
7
|
export * from "./bottom-navigation";
|
|
8
8
|
export * from "./breadcrumb";
|
|
9
|
-
export * from "./
|
|
9
|
+
export * from "./button-group";
|
|
10
10
|
export * from "./buttons";
|
|
11
11
|
export * from "./card";
|
|
12
12
|
export * from "./carousel";
|
|
@@ -43,17 +43,15 @@ export * from "./utils";
|
|
|
43
43
|
export * from "./video";
|
|
44
44
|
// forms
|
|
45
45
|
export * from "./forms/checkbox";
|
|
46
|
-
export * from "./forms/checkbox-button";
|
|
47
46
|
export * from "./forms/dropzone";
|
|
48
47
|
export * from "./forms/fileupload";
|
|
49
|
-
export * from "./forms/floating-label
|
|
48
|
+
export * from "./forms/floating-label";
|
|
50
49
|
export * from "./forms/helper";
|
|
51
50
|
export * from "./forms/input";
|
|
52
51
|
export * from "./forms/input-addon";
|
|
53
52
|
export * from "./forms/label";
|
|
54
53
|
export * from "./forms/select";
|
|
55
54
|
export * from "./forms/radio";
|
|
56
|
-
export * from "./forms/radio-button";
|
|
57
55
|
export * from "./forms/range";
|
|
58
56
|
export * from "./forms/search";
|
|
59
57
|
export * from "./forms/tags";
|
package/dist/modal/Modal.svelte
CHANGED
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
import { fade } from "svelte/transition";
|
|
7
7
|
import { modal as modalTheme } from ".";
|
|
8
8
|
import type { ModalProps } from "../types";
|
|
9
|
-
|
|
10
|
-
// TODO: missing focus trap
|
|
9
|
+
import { trapFocus } from "../utils/actions.svelte";
|
|
11
10
|
|
|
12
11
|
let { children, oncancel, onclose, modal = true, autoclose = false, header, footer, title, open = $bindable(false), permanent = false, dismissable = true, closeBtnClass, headerClass, bodyClass, footerClass, outsideclose = true, size = "md", placement, class: className, params, transition = fade, ...restProps }: ModalProps = $props();
|
|
13
12
|
|
|
@@ -25,13 +24,13 @@
|
|
|
25
24
|
};
|
|
26
25
|
|
|
27
26
|
function _oncancel(ev: Event & { currentTarget: HTMLDialogElement }) {
|
|
28
|
-
// this event
|
|
27
|
+
// this event gets called when user presses ESC key
|
|
28
|
+
// We'll handle ESC via the trapFocus action instead
|
|
29
29
|
if (ev.currentTarget instanceof HTMLDialogElement) {
|
|
30
|
-
|
|
31
|
-
//
|
|
32
|
-
if (ev.defaultPrevented || permanent) return;
|
|
30
|
+
// Stop the default ESC handling from dialog element
|
|
31
|
+
// as we're handling it in our trapFocus action
|
|
33
32
|
ev.preventDefault();
|
|
34
|
-
|
|
33
|
+
oncancel?.(ev); // propagate the event to the user
|
|
35
34
|
}
|
|
36
35
|
}
|
|
37
36
|
|
|
@@ -53,10 +52,20 @@
|
|
|
53
52
|
open = true;
|
|
54
53
|
}
|
|
55
54
|
});
|
|
55
|
+
|
|
56
|
+
// Handler for Escape key that respects component state
|
|
57
|
+
const handleEscape = () => {
|
|
58
|
+
if (!permanent) {
|
|
59
|
+
oncancel?.({ currentTarget: dlg } as any);
|
|
60
|
+
// If oncancel prevented default, we don't close
|
|
61
|
+
if (oncancel && event?.defaultPrevented) return;
|
|
62
|
+
closeModal();
|
|
63
|
+
}
|
|
64
|
+
};
|
|
56
65
|
</script>
|
|
57
66
|
|
|
58
67
|
{#if open}
|
|
59
|
-
<dialog bind:this={dlg} {...restProps} class={base({ class: clsx(className) })} tabindex="-1" oncancel={_oncancel} onclick={_onclick} transition:transition={paramsOptions as ParamsType} onintrostart={() => (modal ? dlg?.showModal() : dlg?.show())} onoutroend={() => dlg?.close()}>
|
|
68
|
+
<dialog use:trapFocus={{ onEscape: handleEscape }} bind:this={dlg} {...restProps} class={base({ class: clsx(className) })} tabindex="-1" oncancel={_oncancel} onclick={_onclick} transition:transition={paramsOptions as ParamsType} onintrostart={() => (modal ? dlg?.showModal() : dlg?.show())} onoutroend={() => dlg?.close()}>
|
|
60
69
|
{#if title || header}
|
|
61
70
|
<div class={headerCls({ class: headerClass })}>
|
|
62
71
|
{#if title}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { sidebar } from ".";
|
|
7
7
|
import type { SidebarProps, SidebarCtxType } from "../types";
|
|
8
8
|
import clsx from "clsx";
|
|
9
|
+
import { trapFocus } from "../utils/actions.svelte";
|
|
9
10
|
|
|
10
11
|
let { children, isOpen = false, closeSidebar, isSingle = true, breakpoint = "md", position = "fixed", activateClickOutside = true, backdrop = true, backdropClass, transition = fly, params, divClass, ariaLabel, nonActiveClass, activeClass, activeUrl = "", class: className, ...restProps }: SidebarProps = $props();
|
|
11
12
|
|
|
@@ -20,11 +21,7 @@
|
|
|
20
21
|
let innerWidth: number = $state(-1);
|
|
21
22
|
let isLargeScreen = $derived(innerWidth >= breakpointValues[breakpoint]);
|
|
22
23
|
|
|
23
|
-
const initialPosition = position;
|
|
24
|
-
|
|
25
|
-
$effect(() => {
|
|
26
|
-
// position = isLargeScreen ? "static" : initialPosition;
|
|
27
|
-
});
|
|
24
|
+
// const initialPosition = position;
|
|
28
25
|
|
|
29
26
|
const activeUrlStore = writable("");
|
|
30
27
|
setContext("activeUrl", activeUrlStore);
|
|
@@ -50,6 +47,11 @@
|
|
|
50
47
|
let transitionParams = params ? params : { x: -320, duration: 200, easing: sineIn };
|
|
51
48
|
|
|
52
49
|
setContext("sidebarContext", sidebarCtx);
|
|
50
|
+
|
|
51
|
+
// Handler for Escape key
|
|
52
|
+
const handleEscape = () => {
|
|
53
|
+
closeSidebar?.();
|
|
54
|
+
};
|
|
53
55
|
</script>
|
|
54
56
|
|
|
55
57
|
<svelte:window bind:innerWidth />
|
|
@@ -66,7 +68,7 @@
|
|
|
66
68
|
<div role="presentation" class="fixed start-0 top-0 z-50 h-full w-full"></div>
|
|
67
69
|
{/if}
|
|
68
70
|
{/if}
|
|
69
|
-
<aside transition:transition={transitionParams} {...restProps} class={base({ class: clsx(className) })} aria-label={ariaLabel}>
|
|
71
|
+
<aside use:trapFocus={!isLargeScreen && isOpen ? { onEscape: closeSidebar ? handleEscape : undefined } : null} transition:transition={transitionParams} {...restProps} class={base({ class: clsx(className) })} aria-label={ariaLabel}>
|
|
70
72
|
<div class={div({ class: divClass })}>
|
|
71
73
|
{@render children()}
|
|
72
74
|
</div>
|
package/dist/theme/index.d.ts
CHANGED
|
@@ -8684,7 +8684,7 @@ export declare const baseThemes: {
|
|
|
8684
8684
|
input: string;
|
|
8685
8685
|
label: string;
|
|
8686
8686
|
}, undefined, unknown, unknown, undefined>>;
|
|
8687
|
-
|
|
8687
|
+
radiobutton: import("tailwind-variants").TVReturnType<{
|
|
8688
8688
|
inline: {
|
|
8689
8689
|
true: string;
|
|
8690
8690
|
false: string;
|
package/dist/theme/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { accordion, accordionitem, activity, activityitem, advancedrating, alert, anchor, android, avatar, badge, banner, blockquote, bottomNav, bottomNavItem, bottomnavheader, bottomnavheaderitem, breadcrumb, button, buttonGroup, card, cardPlaceholder, checkbox, darkmode, defaultMockup, descriptionList, desktop, drawer, drawerhead, dropdown, dropdownHeader, dropdownDivider, dropdownItem, dropdownGroup, dropzone, fileupload, floatingLabelInput, footer, footerBrand, footerCopyright, footerIcon, footerLink, footerLinkGroup, gallery, gradientButton, group, groupitem, heading, helper, hr, imagePlaceholder, img, indicator, input, ios, kbd, label, laptop, layout, list, listGroup, listGroupItem, listPlaceholder, mark, megamenu, modal, navbar_li, navbar_ul, navbar, navbar_brand, navbar_hamburger, pagination, paginationItem, paragraph, popover, progressbar, radio,
|
|
1
|
+
import { accordion, accordionitem, activity, activityitem, advancedrating, alert, anchor, android, avatar, badge, banner, blockquote, bottomNav, bottomNavItem, bottomnavheader, bottomnavheaderitem, breadcrumb, button, buttonGroup, card, cardPlaceholder, checkbox, darkmode, defaultMockup, descriptionList, desktop, drawer, drawerhead, dropdown, dropdownHeader, dropdownDivider, dropdownItem, dropdownGroup, dropzone, fileupload, floatingLabelInput, footer, footerBrand, footerCopyright, footerIcon, footerLink, footerLinkGroup, gallery, gradientButton, group, groupitem, heading, helper, hr, imagePlaceholder, img, indicator, input, ios, kbd, label, laptop, layout, list, listGroup, listGroupItem, listPlaceholder, mark, megamenu, modal, navbar_li, navbar_ul, navbar, navbar_brand, navbar_hamburger, pagination, paginationItem, paragraph, popover, progressbar, radio, radiobutton, range, rating, review, scorerating, search, secondary, select, sidebar, sidebarbutton, sidebarcta, sidebardropdownwrapper, sitebarbrand, skeleton, smartwatch, span, spinner, tabItem, table, tablebodycell, tablebodyrow, tablehead, tableheadcell, tablet, tabs, testimonialPlaceholder, textPlaceholder, textarea, timeline, timelineitem, toast, toggle, toolbar, toolbarButton, toolbarGroup, tooltip, videoPlaceholder, widgetPlaceholder } from "..";
|
|
2
2
|
export const baseThemes = {
|
|
3
3
|
accordion,
|
|
4
4
|
accordionitem,
|
|
@@ -96,7 +96,7 @@ export const baseThemes = {
|
|
|
96
96
|
input,
|
|
97
97
|
label,
|
|
98
98
|
radio,
|
|
99
|
-
|
|
99
|
+
radiobutton,
|
|
100
100
|
range,
|
|
101
101
|
search,
|
|
102
102
|
select,
|
package/dist/types.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ import type Slide from "./carousel/Slide.svelte";
|
|
|
14
14
|
import type { ApexOptions } from "apexcharts";
|
|
15
15
|
import type { DrawerVariants } from "./drawer/theme";
|
|
16
16
|
import type { FileuploadViariants } from "./forms/fileupload/theme";
|
|
17
|
-
import type { FloatingLabelInputVaratiants } from "./forms/floating-label
|
|
17
|
+
import type { FloatingLabelInputVaratiants } from "./forms/floating-label/theme";
|
|
18
18
|
import type { HelperVariants } from "./forms/helper/theme";
|
|
19
19
|
import type { InputVariants } from "./forms/input/theme";
|
|
20
20
|
import type { LabelVariants } from "./forms/label/theme";
|
package/dist/utils/Popper.svelte
CHANGED
|
@@ -99,10 +99,11 @@
|
|
|
99
99
|
if (ev.newState === "open") {
|
|
100
100
|
autoUpdateDestroy = dom.autoUpdate(referenceElement ?? invoker, popover, updatePopoverPosition);
|
|
101
101
|
popover.ownerDocument.addEventListener("click", closeOnClickOutside);
|
|
102
|
+
popover.ownerDocument.addEventListener("keydown", closeOnEscape); // ✅ Add this line
|
|
102
103
|
} else {
|
|
103
|
-
// When closing the popover, we destroy the autoUpdate instance
|
|
104
104
|
autoUpdateDestroy();
|
|
105
105
|
popover.ownerDocument.removeEventListener("click", closeOnClickOutside);
|
|
106
|
+
popover.ownerDocument.removeEventListener("keydown", closeOnEscape); // ✅ Add this line
|
|
106
107
|
}
|
|
107
108
|
}
|
|
108
109
|
|
|
@@ -150,6 +151,12 @@
|
|
|
150
151
|
});
|
|
151
152
|
}
|
|
152
153
|
|
|
154
|
+
function closeOnEscape(event: KeyboardEvent) {
|
|
155
|
+
if (event.key === "Escape") {
|
|
156
|
+
isOpen = false;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
153
160
|
/**
|
|
154
161
|
* Close the popper when clicking outside of it.
|
|
155
162
|
* This is necessary to get around a bug in Safari where clicking outside of the open popper does not close it.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svelte action that traps focus within a DOM node and handles Escape key
|
|
3
|
+
* @param node - The DOM node to trap focus within
|
|
4
|
+
* @param options - Optional configuration object
|
|
5
|
+
* @returns An action object with destroy method
|
|
6
|
+
*/
|
|
7
|
+
export declare function trapFocus(node: HTMLElement, options?: {
|
|
8
|
+
onEscape?: () => void;
|
|
9
|
+
isClosing?: boolean;
|
|
10
|
+
} | null): {
|
|
11
|
+
update(newOptions?: {
|
|
12
|
+
onEscape?: () => void;
|
|
13
|
+
isClosing?: boolean;
|
|
14
|
+
} | null): void;
|
|
15
|
+
destroy(): void;
|
|
16
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svelte action that traps focus within a DOM node and handles Escape key
|
|
3
|
+
* @param node - The DOM node to trap focus within
|
|
4
|
+
* @param options - Optional configuration object
|
|
5
|
+
* @returns An action object with destroy method
|
|
6
|
+
*/
|
|
7
|
+
export function trapFocus(node, options = {}) {
|
|
8
|
+
// If options is null, don't trap focus at all
|
|
9
|
+
if (options === null) {
|
|
10
|
+
return {
|
|
11
|
+
update(newOptions = {}) {
|
|
12
|
+
options = newOptions;
|
|
13
|
+
},
|
|
14
|
+
destroy() { }
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
const previous = document.activeElement;
|
|
18
|
+
// Track if we're currently closing via outside click
|
|
19
|
+
let isClosingViaOutsideClick = false;
|
|
20
|
+
// Create a flag to prevent re-focusing when focus is moved outside
|
|
21
|
+
let isFocusMovedOutside = false;
|
|
22
|
+
function focusable() {
|
|
23
|
+
return Array.from(node.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'));
|
|
24
|
+
}
|
|
25
|
+
function handleKeydown(event) {
|
|
26
|
+
if (event.key === "Tab" && options !== null) {
|
|
27
|
+
const current = document.activeElement;
|
|
28
|
+
const elements = focusable();
|
|
29
|
+
const first = elements.at(0);
|
|
30
|
+
const last = elements.at(-1);
|
|
31
|
+
if (event.shiftKey && current === first) {
|
|
32
|
+
last?.focus();
|
|
33
|
+
event.preventDefault();
|
|
34
|
+
}
|
|
35
|
+
if (!event.shiftKey && current === last) {
|
|
36
|
+
first?.focus();
|
|
37
|
+
event.preventDefault();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else if (event.key === "Escape" && options !== null && options.onEscape) {
|
|
41
|
+
event.preventDefault();
|
|
42
|
+
// Mark as closing via escape to prevent focus restoration
|
|
43
|
+
isClosingViaOutsideClick = true;
|
|
44
|
+
options.onEscape();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Handler for when focus moves outside the trapped area
|
|
48
|
+
function handleFocusOut(event) {
|
|
49
|
+
// If focus is moving outside our node and not to one of our triggers
|
|
50
|
+
if (!node.contains(event.relatedTarget) && event.relatedTarget !== previous) {
|
|
51
|
+
isFocusMovedOutside = true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
$effect(() => {
|
|
55
|
+
// Only add event listeners if options is not null
|
|
56
|
+
if (options !== null) {
|
|
57
|
+
// Check if we're currently in a closing state
|
|
58
|
+
isClosingViaOutsideClick = !!options.isClosing;
|
|
59
|
+
// Only auto-focus if not closing from outside click
|
|
60
|
+
if (!isClosingViaOutsideClick && !isFocusMovedOutside) {
|
|
61
|
+
const elements = focusable();
|
|
62
|
+
if (elements.length > 0) {
|
|
63
|
+
elements[0].focus();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
node.addEventListener("keydown", handleKeydown);
|
|
67
|
+
node.addEventListener("focusout", handleFocusOut);
|
|
68
|
+
return () => {
|
|
69
|
+
node.removeEventListener("keydown", handleKeydown);
|
|
70
|
+
node.removeEventListener("focusout", handleFocusOut);
|
|
71
|
+
// Only restore focus if not closing via outside click and focus hasn't moved outside
|
|
72
|
+
if (!isClosingViaOutsideClick && !isFocusMovedOutside && previous) {
|
|
73
|
+
setTimeout(() => {
|
|
74
|
+
previous.focus({ preventScroll: true });
|
|
75
|
+
}, 0);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
// Return the action object with destroy method
|
|
81
|
+
return {
|
|
82
|
+
update(newOptions = {}) {
|
|
83
|
+
// Update the closing state
|
|
84
|
+
if (newOptions && newOptions.isClosing !== undefined) {
|
|
85
|
+
isClosingViaOutsideClick = newOptions.isClosing;
|
|
86
|
+
}
|
|
87
|
+
options = newOptions;
|
|
88
|
+
// Clean up existing listeners if options becomes null
|
|
89
|
+
if (options === null) {
|
|
90
|
+
node.removeEventListener("keydown", handleKeydown);
|
|
91
|
+
node.removeEventListener("focusout", handleFocusOut);
|
|
92
|
+
}
|
|
93
|
+
else if (options !== null) {
|
|
94
|
+
// Add listener if it wasn't already there
|
|
95
|
+
node.removeEventListener("keydown", handleKeydown);
|
|
96
|
+
node.removeEventListener("focusout", handleFocusOut);
|
|
97
|
+
node.addEventListener("keydown", handleKeydown);
|
|
98
|
+
node.addEventListener("focusout", handleFocusOut);
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
destroy() {
|
|
102
|
+
if (options !== null) {
|
|
103
|
+
node.removeEventListener("keydown", handleKeydown);
|
|
104
|
+
node.removeEventListener("focusout", handleFocusOut);
|
|
105
|
+
// Only restore focus if not closing via outside click and focus hasn't moved outside
|
|
106
|
+
if (!isClosingViaOutsideClick && !isFocusMovedOutside && previous) {
|
|
107
|
+
setTimeout(() => {
|
|
108
|
+
previous.focus({ preventScroll: true });
|
|
109
|
+
}, 0);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flowbite-svelte",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.5",
|
|
4
4
|
"description": "Flowbite components for Svelte",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"author": {
|
|
@@ -172,8 +172,8 @@
|
|
|
172
172
|
"svelte": "./dist/breadcrumb/BreadcrumbItem.svelte"
|
|
173
173
|
},
|
|
174
174
|
"./ButtonGroup.svelte": {
|
|
175
|
-
"types": "./dist/
|
|
176
|
-
"svelte": "./dist/
|
|
175
|
+
"types": "./dist/button-group/ButtonGroup.svelte.d.ts",
|
|
176
|
+
"svelte": "./dist/button-group/ButtonGroup.svelte"
|
|
177
177
|
},
|
|
178
178
|
"./Button.svelte": {
|
|
179
179
|
"types": "./dist/buttons/Button.svelte.d.ts",
|
|
@@ -316,8 +316,8 @@
|
|
|
316
316
|
"svelte": "./dist/forms/checkbox/Checkbox.svelte"
|
|
317
317
|
},
|
|
318
318
|
"./CheckboxButton.svelte": {
|
|
319
|
-
"types": "./dist/forms/checkbox
|
|
320
|
-
"svelte": "./dist/forms/checkbox
|
|
319
|
+
"types": "./dist/forms/checkbox/CheckboxButton.svelte.d.ts",
|
|
320
|
+
"svelte": "./dist/forms/checkbox/CheckboxButton.svelte"
|
|
321
321
|
},
|
|
322
322
|
"./Dropzone.svelte": {
|
|
323
323
|
"types": "./dist/forms/dropzone/Dropzone.svelte.d.ts",
|
|
@@ -328,8 +328,8 @@
|
|
|
328
328
|
"svelte": "./dist/forms/fileupload/Fileupload.svelte"
|
|
329
329
|
},
|
|
330
330
|
"./FloatingLabelInput.svelte": {
|
|
331
|
-
"types": "./dist/forms/floating-label
|
|
332
|
-
"svelte": "./dist/forms/floating-label
|
|
331
|
+
"types": "./dist/forms/floating-label/FloatingLabelInput.svelte.d.ts",
|
|
332
|
+
"svelte": "./dist/forms/floating-label/FloatingLabelInput.svelte"
|
|
333
333
|
},
|
|
334
334
|
"./Helper.svelte": {
|
|
335
335
|
"types": "./dist/forms/helper/Helper.svelte.d.ts",
|
|
@@ -352,8 +352,8 @@
|
|
|
352
352
|
"svelte": "./dist/forms/radio/Radio.svelte"
|
|
353
353
|
},
|
|
354
354
|
"./RadioButton.svelte": {
|
|
355
|
-
"types": "./dist/forms/radio
|
|
356
|
-
"svelte": "./dist/forms/radio
|
|
355
|
+
"types": "./dist/forms/radio/RadioButton.svelte.d.ts",
|
|
356
|
+
"svelte": "./dist/forms/radio/RadioButton.svelte"
|
|
357
357
|
},
|
|
358
358
|
"./Range.svelte": {
|
|
359
359
|
"types": "./dist/forms/range/Range.svelte.d.ts",
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export declare const checkButton: import("tailwind-variants").TVReturnType<{
|
|
2
|
-
inline: {
|
|
3
|
-
true: string;
|
|
4
|
-
false: string;
|
|
5
|
-
};
|
|
6
|
-
checked: {
|
|
7
|
-
true: string;
|
|
8
|
-
};
|
|
9
|
-
}, undefined, "", {
|
|
10
|
-
inline: {
|
|
11
|
-
true: string;
|
|
12
|
-
false: string;
|
|
13
|
-
};
|
|
14
|
-
checked: {
|
|
15
|
-
true: string;
|
|
16
|
-
};
|
|
17
|
-
}, undefined, import("tailwind-variants").TVReturnType<{
|
|
18
|
-
inline: {
|
|
19
|
-
true: string;
|
|
20
|
-
false: string;
|
|
21
|
-
};
|
|
22
|
-
checked: {
|
|
23
|
-
true: string;
|
|
24
|
-
};
|
|
25
|
-
}, undefined, "", unknown, unknown, undefined>>;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { tv } from "tailwind-variants";
|
|
2
|
-
export const checkButton = tv({
|
|
3
|
-
base: "",
|
|
4
|
-
variants: {
|
|
5
|
-
inline: {
|
|
6
|
-
true: "inline-flex",
|
|
7
|
-
false: "flex"
|
|
8
|
-
},
|
|
9
|
-
checked: {
|
|
10
|
-
true: "outline-4 outline-green-500"
|
|
11
|
-
}
|
|
12
|
-
},
|
|
13
|
-
defaultVariants: {
|
|
14
|
-
inline: true
|
|
15
|
-
}
|
|
16
|
-
});
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export declare const radioButton: import("tailwind-variants").TVReturnType<{
|
|
2
|
-
inline: {
|
|
3
|
-
true: string;
|
|
4
|
-
false: string;
|
|
5
|
-
};
|
|
6
|
-
}, undefined, "", {
|
|
7
|
-
inline: {
|
|
8
|
-
true: string;
|
|
9
|
-
false: string;
|
|
10
|
-
};
|
|
11
|
-
}, undefined, import("tailwind-variants").TVReturnType<{
|
|
12
|
-
inline: {
|
|
13
|
-
true: string;
|
|
14
|
-
false: string;
|
|
15
|
-
};
|
|
16
|
-
}, undefined, "", unknown, unknown, undefined>>;
|
package/dist/utils/focusTrap.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Taken from github.com/carbon-design-system/carbon/packages/react/src/internal/keyboard/navigation.js
|
|
3
|
-
//
|
|
4
|
-
const selectorTabbable = `
|
|
5
|
-
a[href], area[href], input:not([disabled]):not([tabindex='-1']),
|
|
6
|
-
button:not([disabled]):not([tabindex='-1']),select:not([disabled]):not([tabindex='-1']),
|
|
7
|
-
textarea:not([disabled]):not([tabindex='-1']),
|
|
8
|
-
iframe, object, embed, *[tabindex]:not([tabindex='-1']):not([disabled]), *[contenteditable=true]
|
|
9
|
-
`;
|
|
10
|
-
const focusTrap = (node) => {
|
|
11
|
-
const handleFocusTrap = (e) => {
|
|
12
|
-
const isTabPressed = e.key === "Tab" || e.keyCode === 9;
|
|
13
|
-
if (!isTabPressed) {
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
const tabbable = Array.from(node.querySelectorAll(selectorTabbable)).filter((el) => el instanceof HTMLElement && el.hidden !== true);
|
|
17
|
-
let index = tabbable.indexOf(node.ownerDocument.activeElement);
|
|
18
|
-
if (index === -1 && e.shiftKey) {
|
|
19
|
-
index = 0;
|
|
20
|
-
}
|
|
21
|
-
index += tabbable.length + (e.shiftKey ? -1 : 1);
|
|
22
|
-
index %= tabbable.length;
|
|
23
|
-
tabbable[index].focus();
|
|
24
|
-
e.preventDefault();
|
|
25
|
-
};
|
|
26
|
-
node.ownerDocument.addEventListener("keydown", handleFocusTrap, true);
|
|
27
|
-
return {
|
|
28
|
-
destroy() {
|
|
29
|
-
node.ownerDocument.removeEventListener("keydown", handleFocusTrap, true);
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
};
|
|
33
|
-
export default focusTrap;
|
|
34
|
-
export function isFocusable(element) {
|
|
35
|
-
if (!element)
|
|
36
|
-
return false;
|
|
37
|
-
return element.matches(selectorTabbable);
|
|
38
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|