zabi-components 5.0.21 → 6.0.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 +42 -44
- package/THEME.md +473 -0
- package/THEMING.md +248 -0
- package/dist/atoms/Card.svelte +40 -67
- package/dist/atoms/Card.svelte.d.ts +3 -3
- package/dist/atoms/CardContent.svelte +1 -1
- package/dist/atoms/CardHeader.svelte +10 -1
- package/dist/atoms/CardHeader.svelte.d.ts +3 -0
- package/dist/atoms/Checkbox.svelte +1 -7
- package/dist/atoms/CodeBlock.svelte +7 -7
- package/dist/atoms/ColorPicker.svelte +81 -73
- package/dist/atoms/Input.svelte +16 -12
- package/dist/atoms/Input.svelte.d.ts +2 -0
- package/dist/atoms/List.svelte +47 -0
- package/dist/atoms/List.svelte.d.ts +19 -0
- package/dist/atoms/ListItem.svelte +148 -0
- package/dist/atoms/ListItem.svelte.d.ts +35 -0
- package/dist/atoms/Progress.svelte +4 -6
- package/dist/atoms/Select.svelte +65 -20
- package/dist/atoms/Select.svelte.d.ts +13 -1
- package/dist/atoms/Textarea.svelte +13 -11
- package/dist/atoms/Textarea.svelte.d.ts +1 -0
- package/dist/atoms/Toast.svelte +1 -1
- package/dist/atoms/Toggle.svelte +1 -7
- package/dist/atoms/Tooltip.svelte +8 -15
- package/dist/atoms/index.d.ts +2 -0
- package/dist/atoms/index.js +2 -0
- package/dist/components/atoms/index.d.ts +2 -0
- package/dist/components/atoms/index.d.ts.map +1 -1
- package/dist/components/index.d.ts +4 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/molecules/index.d.ts +0 -1
- package/dist/components/molecules/index.d.ts.map +1 -1
- package/dist/components/molecules/navigation-menu-context.d.ts +7 -0
- package/dist/components/molecules/navigation-menu-context.d.ts.map +1 -0
- package/dist/components/organisms/index.d.ts +2 -1
- package/dist/components/organisms/index.d.ts.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +5 -9
- package/dist/lib/showcase/components-catalog.d.ts +3 -0
- package/dist/lib/showcase/components-catalog.d.ts.map +1 -0
- package/dist/lib/showcase/components-showcase-constants.d.ts +63 -0
- package/dist/lib/showcase/components-showcase-constants.d.ts.map +1 -0
- package/dist/lib/showcase/docs-sidebar-helpers.d.ts +15 -0
- package/dist/lib/showcase/docs-sidebar-helpers.d.ts.map +1 -0
- package/dist/molecules/Alert.svelte +9 -4
- package/dist/molecules/ComponentDemo.svelte +53 -50
- package/dist/molecules/ContactForm.svelte +113 -76
- package/dist/molecules/ContactForm.svelte.d.ts +1 -4
- package/dist/molecules/Dropdown.svelte +4 -2
- package/dist/molecules/ImageUpload.svelte +27 -4
- package/dist/molecules/ImageUpload.svelte.d.ts +1 -0
- package/dist/molecules/Modal.svelte +46 -45
- package/dist/molecules/NavigationMenu.svelte +7 -10
- package/dist/molecules/NavigationMenuContent.svelte +9 -9
- package/dist/molecules/NavigationMenuItem.svelte +7 -6
- package/dist/molecules/NavigationMenuLink.svelte +8 -6
- package/dist/molecules/NavigationMenuList.svelte +0 -7
- package/dist/molecules/NavigationMenuTrigger.svelte +8 -11
- package/dist/molecules/Section.svelte +12 -12
- package/dist/molecules/SlideUp.svelte +32 -2
- package/dist/molecules/Tabs.svelte +74 -7
- package/dist/molecules/index.d.ts +0 -1
- package/dist/molecules/index.js +0 -1
- package/dist/molecules/navigation-menu-context.d.ts +6 -0
- package/dist/molecules/navigation-menu-context.js +1 -0
- package/dist/organisms/Navbar.svelte +170 -53
- package/dist/organisms/Navbar.svelte.d.ts +31 -4
- package/dist/organisms/SidebarNavigation.svelte +464 -0
- package/dist/organisms/SidebarNavigation.svelte.d.ts +49 -0
- package/dist/organisms/SidebarPanel.svelte +175 -0
- package/dist/organisms/SidebarPanel.svelte.d.ts +32 -0
- package/dist/organisms/index.d.ts +2 -1
- package/dist/organisms/index.js +2 -1
- package/dist/types/page.types.d.ts +32 -0
- package/dist/types/page.types.d.ts.map +1 -0
- package/dist/types/variants.ts +76 -0
- package/dist/zabi-components-colors.css +347 -324
- package/dist/zabi-components-theme-dark-only.css +159 -151
- package/dist/zabi-components-theme-dark.css +159 -151
- package/dist/zabi-components-theme-only.css +245 -230
- package/dist/zabi-components-theme.css +245 -230
- package/dist/zabi-components.css +722 -84
- package/docs/theme-imports.md +112 -0
- package/package.json +20 -9
- package/dist/molecules/Sidebar.svelte +0 -324
- package/dist/molecules/Sidebar.svelte.d.ts +0 -30
- package/dist/organisms/Navigation.svelte +0 -116
- package/dist/organisms/Navigation.svelte.d.ts +0 -20
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
|
-
import {
|
|
3
|
+
import { setContext } from "svelte";
|
|
4
4
|
import { onMount } from "svelte";
|
|
5
5
|
import NavigationMenuList from "./NavigationMenuList.svelte";
|
|
6
6
|
import NavigationMenuItem from "./NavigationMenuItem.svelte";
|
|
@@ -8,13 +8,10 @@
|
|
|
8
8
|
import NavigationMenuContent from "./NavigationMenuContent.svelte";
|
|
9
9
|
import NavigationMenuLink from "./NavigationMenuLink.svelte";
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const NAVIGATION_MENU_CONTEXT = Symbol("navigation-menu");
|
|
11
|
+
import {
|
|
12
|
+
NAVIGATION_MENU_CONTEXT_KEY,
|
|
13
|
+
type NavigationMenuContextValue,
|
|
14
|
+
} from "./navigation-menu-context.js";
|
|
18
15
|
|
|
19
16
|
export interface NavigationMenuItemData {
|
|
20
17
|
value: string;
|
|
@@ -76,7 +73,7 @@
|
|
|
76
73
|
}
|
|
77
74
|
});
|
|
78
75
|
|
|
79
|
-
const context:
|
|
76
|
+
const context: NavigationMenuContextValue = {
|
|
80
77
|
get activeItem() {
|
|
81
78
|
return activeItem;
|
|
82
79
|
},
|
|
@@ -86,7 +83,7 @@
|
|
|
86
83
|
},
|
|
87
84
|
};
|
|
88
85
|
|
|
89
|
-
setContext(
|
|
86
|
+
setContext(NAVIGATION_MENU_CONTEXT_KEY, context);
|
|
90
87
|
</script>
|
|
91
88
|
|
|
92
89
|
<nav
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
3
|
import { getContext } from "svelte";
|
|
4
|
-
import { onMount
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import { onMount } from "svelte";
|
|
5
|
+
import {
|
|
6
|
+
NAVIGATION_MENU_CONTEXT_KEY,
|
|
7
|
+
type NavigationMenuContextValue,
|
|
8
|
+
} from "./navigation-menu-context.js";
|
|
7
9
|
|
|
8
10
|
interface Props {
|
|
9
11
|
value?: string;
|
|
@@ -21,11 +23,9 @@
|
|
|
21
23
|
let contentElement = $state<HTMLElement | null>(null);
|
|
22
24
|
let parentItem = $state<HTMLElement | null>(null);
|
|
23
25
|
|
|
24
|
-
const context = getContext<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
isMobile: boolean;
|
|
28
|
-
}>(NAVIGATION_MENU_CONTEXT);
|
|
26
|
+
const context = getContext<NavigationMenuContextValue>(
|
|
27
|
+
NAVIGATION_MENU_CONTEXT_KEY,
|
|
28
|
+
);
|
|
29
29
|
|
|
30
30
|
const isActive = $derived(context?.activeItem === value);
|
|
31
31
|
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
{#if isActive}
|
|
72
72
|
<div
|
|
73
73
|
bind:this={contentElement}
|
|
74
|
-
class="absolute left-0 top-full mt-2 bg-input rounded-lg shadow-lg border border-border p-4 z-dropdown min-w-[200px] transition-all duration-200 ease-in-out {className}"
|
|
74
|
+
class="absolute left-0 top-full mt-2 bg-input rounded-lg shadow-lg border border-input-border p-4 z-dropdown min-w-[200px] transition-all duration-200 ease-in-out {className}"
|
|
75
75
|
role="menu"
|
|
76
76
|
onkeydown={handleKeydown}
|
|
77
77
|
data-navigation-menu-content
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
3
|
import { getContext } from "svelte";
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
NAVIGATION_MENU_CONTEXT_KEY,
|
|
6
|
+
type NavigationMenuContextValue,
|
|
7
|
+
} from "./navigation-menu-context.js";
|
|
6
8
|
|
|
7
9
|
interface Props {
|
|
8
10
|
value?: string;
|
|
@@ -17,10 +19,9 @@
|
|
|
17
19
|
...restProps
|
|
18
20
|
}: Props = $props();
|
|
19
21
|
|
|
20
|
-
const context = getContext<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}>(NAVIGATION_MENU_CONTEXT);
|
|
22
|
+
const context = getContext<NavigationMenuContextValue>(
|
|
23
|
+
NAVIGATION_MENU_CONTEXT_KEY,
|
|
24
|
+
);
|
|
24
25
|
|
|
25
26
|
const isActive = $derived(context?.activeItem === value);
|
|
26
27
|
</script>
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
3
|
import { getContext } from "svelte";
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
NAVIGATION_MENU_CONTEXT_KEY,
|
|
6
|
+
type NavigationMenuContextValue,
|
|
7
|
+
} from "./navigation-menu-context.js";
|
|
6
8
|
|
|
7
9
|
interface Props {
|
|
8
10
|
href?: string;
|
|
@@ -19,16 +21,16 @@
|
|
|
19
21
|
...restProps
|
|
20
22
|
}: Props = $props();
|
|
21
23
|
|
|
22
|
-
const context = getContext<
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
const context = getContext<NavigationMenuContextValue>(
|
|
25
|
+
NAVIGATION_MENU_CONTEXT_KEY,
|
|
26
|
+
);
|
|
25
27
|
|
|
26
28
|
function handleClick() {
|
|
27
29
|
context?.setActiveItem(null);
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
const linkClasses =
|
|
31
|
-
"block px-4 py-2 text-sm text-
|
|
33
|
+
"block cursor-pointer rounded-md px-4 py-2 text-sm text-nav-menu-item no-underline transition-colors duration-150 outline-none hover:bg-nav-menu-hover hover:text-nav-menu-item-hover focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-nav-menu-focus {className}";
|
|
32
34
|
</script>
|
|
33
35
|
|
|
34
36
|
{#if asChild}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
|
-
import { getContext } from "svelte";
|
|
4
|
-
|
|
5
|
-
const NAVIGATION_MENU_CONTEXT = Symbol("navigation-menu");
|
|
6
3
|
|
|
7
4
|
interface Props {
|
|
8
5
|
className?: string;
|
|
@@ -14,10 +11,6 @@
|
|
|
14
11
|
children,
|
|
15
12
|
...restProps
|
|
16
13
|
}: Props = $props();
|
|
17
|
-
|
|
18
|
-
const context = getContext<{
|
|
19
|
-
isMobile: boolean;
|
|
20
|
-
}>(NAVIGATION_MENU_CONTEXT);
|
|
21
14
|
</script>
|
|
22
15
|
|
|
23
16
|
<ul
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
3
|
import { getContext } from "svelte";
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
NAVIGATION_MENU_CONTEXT_KEY,
|
|
6
|
+
type NavigationMenuContextValue,
|
|
7
|
+
} from "./navigation-menu-context.js";
|
|
6
8
|
|
|
7
9
|
interface Props {
|
|
8
10
|
value?: string;
|
|
@@ -17,13 +19,9 @@
|
|
|
17
19
|
...restProps
|
|
18
20
|
}: Props = $props();
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
activeItem: string | null;
|
|
24
|
-
setActiveItem: (item: string | null) => void;
|
|
25
|
-
isMobile: boolean;
|
|
26
|
-
}>(NAVIGATION_MENU_CONTEXT);
|
|
22
|
+
const context = getContext<NavigationMenuContextValue>(
|
|
23
|
+
NAVIGATION_MENU_CONTEXT_KEY,
|
|
24
|
+
);
|
|
27
25
|
|
|
28
26
|
const isActive = $derived(context?.activeItem === value);
|
|
29
27
|
|
|
@@ -52,9 +50,8 @@
|
|
|
52
50
|
</script>
|
|
53
51
|
|
|
54
52
|
<button
|
|
55
|
-
bind:this={triggerElement}
|
|
56
53
|
type="button"
|
|
57
|
-
class="inline-flex items-center justify-center gap-2 px-4 py-2 text-sm font-medium text-
|
|
54
|
+
class="inline-flex cursor-pointer items-center justify-center gap-2 rounded-lg bg-transparent px-4 py-2 text-sm font-medium text-nav-menu-item transition-colors duration-150 outline-none hover:bg-nav-menu-hover hover:text-nav-menu-item-hover data-[active=true]:bg-nav-menu-active data-[active=true]:text-nav-menu-item-active focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-nav-menu-focus {className}"
|
|
58
55
|
aria-expanded={isActive ? 'true' : 'false'}
|
|
59
56
|
aria-haspopup="true"
|
|
60
57
|
onclick={handleClick}
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
...restProps
|
|
41
41
|
}: Props = $props();
|
|
42
42
|
|
|
43
|
-
const sizeClasses = $derived(() => {
|
|
43
|
+
const sizeClasses = $derived.by(() => {
|
|
44
44
|
switch (size) {
|
|
45
45
|
case "sm":
|
|
46
46
|
return "text-sm";
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
}
|
|
52
52
|
});
|
|
53
53
|
|
|
54
|
-
const maxWidthClasses = $derived(() => {
|
|
54
|
+
const maxWidthClasses = $derived.by(() => {
|
|
55
55
|
switch (maxWidth) {
|
|
56
56
|
case "sm":
|
|
57
57
|
return "max-w-screen-sm";
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
}
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
-
const backgroundClasses = $derived(() => {
|
|
75
|
+
const backgroundClasses = $derived.by(() => {
|
|
76
76
|
switch (background) {
|
|
77
77
|
case "muted":
|
|
78
78
|
return "bg-base-50";
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
}
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
-
const paddingClasses = $derived(() => {
|
|
88
|
+
const paddingClasses = $derived.by(() => {
|
|
89
89
|
switch (padding) {
|
|
90
90
|
case "none":
|
|
91
91
|
return "";
|
|
@@ -102,14 +102,14 @@
|
|
|
102
102
|
}
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
-
const containerClasses = $derived(() => {
|
|
105
|
+
const containerClasses = $derived.by(() => {
|
|
106
106
|
const base = "w-full";
|
|
107
|
-
const maxWidthClass = maxWidthClasses
|
|
107
|
+
const maxWidthClass = maxWidthClasses;
|
|
108
108
|
const centeredClass = centered ? "mx-auto" : "";
|
|
109
109
|
return `${base} ${maxWidthClass} ${centeredClass}`.trim();
|
|
110
110
|
});
|
|
111
111
|
|
|
112
|
-
const contentClasses = $derived(() => {
|
|
112
|
+
const contentClasses = $derived.by(() => {
|
|
113
113
|
const base = "px-4 sm:px-6 lg:px-8";
|
|
114
114
|
const centeredClass = centered ? "text-center" : "";
|
|
115
115
|
return `${base} ${centeredClass}`.trim();
|
|
@@ -117,18 +117,18 @@
|
|
|
117
117
|
</script>
|
|
118
118
|
|
|
119
119
|
<section
|
|
120
|
-
class="section {backgroundClasses
|
|
120
|
+
class="section {backgroundClasses} {paddingClasses} {className}"
|
|
121
121
|
{...restProps}
|
|
122
122
|
>
|
|
123
|
-
<div class={containerClasses
|
|
124
|
-
<div class={contentClasses
|
|
123
|
+
<div class={containerClasses}>
|
|
124
|
+
<div class={contentClasses}>
|
|
125
125
|
{#if title}
|
|
126
126
|
<div class="mb-6 {centered ? 'mx-auto' : ''}">
|
|
127
127
|
<Heading level={headingLevel} text={title} />
|
|
128
128
|
{#if description}
|
|
129
129
|
<p
|
|
130
|
-
class="mt-4 {sizeClasses
|
|
131
|
-
? 'mx-auto
|
|
130
|
+
class="mt-4 {sizeClasses} text-description {centered
|
|
131
|
+
? 'mx-auto'
|
|
132
132
|
: ''}"
|
|
133
133
|
>
|
|
134
134
|
{description}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
focusFirstElement,
|
|
4
|
+
returnFocus,
|
|
5
|
+
saveFocus,
|
|
6
|
+
trapFocus,
|
|
7
|
+
} from "../../routes/lib/focus-utils.js";
|
|
8
|
+
|
|
2
9
|
interface Props {
|
|
3
10
|
isOpen?: boolean;
|
|
4
11
|
title?: string;
|
|
@@ -13,13 +20,35 @@
|
|
|
13
20
|
...restProps
|
|
14
21
|
} = $props<Props & { children?: any }>();
|
|
15
22
|
|
|
23
|
+
let slideUpContainer = $state<HTMLDivElement>();
|
|
24
|
+
let cleanupFocusTrap: (() => void) | null = null;
|
|
25
|
+
|
|
16
26
|
function closeSlideUp(event?: Event) {
|
|
17
27
|
isOpen = false;
|
|
28
|
+
if (cleanupFocusTrap) {
|
|
29
|
+
cleanupFocusTrap();
|
|
30
|
+
cleanupFocusTrap = null;
|
|
31
|
+
}
|
|
32
|
+
returnFocus();
|
|
18
33
|
if (onclick && event) {
|
|
19
34
|
(onclick as (event: Event) => void)(event);
|
|
20
35
|
}
|
|
21
36
|
}
|
|
22
37
|
|
|
38
|
+
$effect(() => {
|
|
39
|
+
const container = slideUpContainer;
|
|
40
|
+
if (isOpen && container) {
|
|
41
|
+
saveFocus();
|
|
42
|
+
cleanupFocusTrap = trapFocus(container);
|
|
43
|
+
setTimeout(() => {
|
|
44
|
+
focusFirstElement(container);
|
|
45
|
+
}, 0);
|
|
46
|
+
} else if (!isOpen && cleanupFocusTrap) {
|
|
47
|
+
cleanupFocusTrap();
|
|
48
|
+
cleanupFocusTrap = null;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
23
52
|
function handleBackdropClick(event: Event) {
|
|
24
53
|
if (event.target === event.currentTarget) {
|
|
25
54
|
closeSlideUp(event);
|
|
@@ -39,7 +68,7 @@
|
|
|
39
68
|
|
|
40
69
|
{#if isOpen}
|
|
41
70
|
<div
|
|
42
|
-
class="fixed inset-0 bg-overlay
|
|
71
|
+
class="fixed inset-0 z-modal cursor-pointer bg-overlay"
|
|
43
72
|
onclick={handleBackdropClick}
|
|
44
73
|
onkeydown={handleKeydown}
|
|
45
74
|
role="dialog"
|
|
@@ -48,7 +77,8 @@
|
|
|
48
77
|
tabindex="-1"
|
|
49
78
|
>
|
|
50
79
|
<div
|
|
51
|
-
|
|
80
|
+
bind:this={slideUpContainer}
|
|
81
|
+
class="fixed bottom-0 left-0 right-0 z-modal flex max-h-[90vh] cursor-default flex-col overflow-y-auto rounded-t-3xl bg-card shadow-xl animate-[slideUp_0.3s_ease-out]"
|
|
52
82
|
>
|
|
53
83
|
{#if title}
|
|
54
84
|
<div class="flex items-center justify-between px-6 pt-6 pb-4">
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
function createId(prefix: string): string {
|
|
3
|
+
if (typeof window !== "undefined") {
|
|
4
|
+
return `${prefix}-${Math.random().toString(36).slice(2, 11)}`;
|
|
5
|
+
}
|
|
6
|
+
return `${prefix}-ssr-${Date.now()}`;
|
|
7
|
+
}
|
|
8
|
+
|
|
2
9
|
interface Props {
|
|
3
10
|
tabs?: Array<{
|
|
4
11
|
id: string;
|
|
@@ -19,17 +26,69 @@
|
|
|
19
26
|
...restProps
|
|
20
27
|
}: Props & { children?: any } = $props();
|
|
21
28
|
|
|
29
|
+
const tabsBaseId = createId("tabs");
|
|
30
|
+
|
|
22
31
|
function selectTab(tabId: string) {
|
|
23
32
|
activeTab = tabId;
|
|
24
33
|
}
|
|
25
34
|
|
|
35
|
+
function getEnabledTabs() {
|
|
36
|
+
return tabs.filter((tab) => !tab.disabled);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getTabIndex(tabId: string) {
|
|
40
|
+
return tabs.findIndex((tab) => tab.id === tabId);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getTabId(tabId: string) {
|
|
44
|
+
return `${tabsBaseId}-tab-${tabId}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function getPanelId(tabId: string) {
|
|
48
|
+
return `${tabsBaseId}-panel-${tabId}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
$effect(() => {
|
|
52
|
+
if (tabs.length === 0) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const activeExists = tabs.some((tab) => tab.id === activeTab && !tab.disabled);
|
|
57
|
+
if (!activeExists) {
|
|
58
|
+
const firstEnabledTab = tabs.find((tab) => !tab.disabled);
|
|
59
|
+
if (firstEnabledTab) {
|
|
60
|
+
activeTab = firstEnabledTab.id;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
26
65
|
function handleKeydown(event: KeyboardEvent) {
|
|
66
|
+
const enabledTabs = getEnabledTabs();
|
|
67
|
+
if (enabledTabs.length === 0) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const currentIndex = enabledTabs.findIndex((tab) => tab.id === activeTab);
|
|
72
|
+
const fallbackIndex = currentIndex === -1 ? 0 : currentIndex;
|
|
73
|
+
|
|
27
74
|
if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
|
|
28
|
-
|
|
75
|
+
event.preventDefault();
|
|
29
76
|
const direction = event.key === "ArrowLeft" ? -1 : 1;
|
|
30
77
|
const nextIndex =
|
|
31
|
-
(
|
|
32
|
-
|
|
78
|
+
(fallbackIndex + direction + enabledTabs.length) %
|
|
79
|
+
enabledTabs.length;
|
|
80
|
+
selectTab(enabledTabs[nextIndex].id);
|
|
81
|
+
} else if (event.key === "Home") {
|
|
82
|
+
event.preventDefault();
|
|
83
|
+
selectTab(enabledTabs[0].id);
|
|
84
|
+
} else if (event.key === "End") {
|
|
85
|
+
event.preventDefault();
|
|
86
|
+
selectTab(enabledTabs[enabledTabs.length - 1].id);
|
|
87
|
+
} else if (event.key === "Enter" || event.key === " ") {
|
|
88
|
+
event.preventDefault();
|
|
89
|
+
if (currentIndex === -1) {
|
|
90
|
+
selectTab(enabledTabs[0].id);
|
|
91
|
+
}
|
|
33
92
|
}
|
|
34
93
|
}
|
|
35
94
|
</script>
|
|
@@ -45,22 +104,30 @@
|
|
|
45
104
|
<button
|
|
46
105
|
type="button"
|
|
47
106
|
role="tab"
|
|
48
|
-
|
|
107
|
+
id={getTabId(tab.id)}
|
|
108
|
+
class="cursor-pointer border-b-2 px-4 py-2 text-sm font-medium transition-colors disabled:cursor-not-allowed {activeTab ===
|
|
49
109
|
tab.id
|
|
50
110
|
? variant === 'pills'
|
|
51
|
-
? 'bg-brand-100 text-brand-700
|
|
111
|
+
? 'border-brand-500 bg-brand-100 text-brand-700'
|
|
52
112
|
: 'border-brand-500 text-body'
|
|
53
|
-
: 'border-transparent text-description hover:
|
|
113
|
+
: 'border-transparent text-description hover:border-base-300 hover:text-body'}"
|
|
54
114
|
onclick={() => selectTab(tab.id)}
|
|
55
115
|
disabled={tab.disabled}
|
|
56
116
|
aria-selected={activeTab === tab.id}
|
|
117
|
+
aria-controls={getPanelId(tab.id)}
|
|
118
|
+
tabindex={activeTab === tab.id ? 0 : -1}
|
|
57
119
|
>
|
|
58
120
|
{tab.label}
|
|
59
121
|
</button>
|
|
60
122
|
{/each}
|
|
61
123
|
</div>
|
|
62
124
|
|
|
63
|
-
<div
|
|
125
|
+
<div
|
|
126
|
+
class="mt-4"
|
|
127
|
+
role="tabpanel"
|
|
128
|
+
id={getPanelId(activeTab)}
|
|
129
|
+
aria-labelledby={getTabId(activeTab)}
|
|
130
|
+
>
|
|
64
131
|
{@render children?.({ activeTab })}
|
|
65
132
|
</div>
|
|
66
133
|
</div>
|
|
@@ -12,6 +12,5 @@ export { default as NavigationMenuTrigger } from './NavigationMenuTrigger.svelte
|
|
|
12
12
|
export { default as NavigationMenuContent } from './NavigationMenuContent.svelte';
|
|
13
13
|
export { default as NavigationMenuLink } from './NavigationMenuLink.svelte';
|
|
14
14
|
export { default as Section } from './Section.svelte';
|
|
15
|
-
export { default as Sidebar } from './Sidebar.svelte';
|
|
16
15
|
export { default as SlideUp } from './SlideUp.svelte';
|
|
17
16
|
export { default as Tabs } from './Tabs.svelte';
|
package/dist/molecules/index.js
CHANGED
|
@@ -12,6 +12,5 @@ export { default as NavigationMenuTrigger } from './NavigationMenuTrigger.svelte
|
|
|
12
12
|
export { default as NavigationMenuContent } from './NavigationMenuContent.svelte';
|
|
13
13
|
export { default as NavigationMenuLink } from './NavigationMenuLink.svelte';
|
|
14
14
|
export { default as Section } from './Section.svelte';
|
|
15
|
-
export { default as Sidebar } from './Sidebar.svelte';
|
|
16
15
|
export { default as SlideUp } from './SlideUp.svelte';
|
|
17
16
|
export { default as Tabs } from './Tabs.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const NAVIGATION_MENU_CONTEXT_KEY = Symbol("navigation-menu");
|