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.
Files changed (89) hide show
  1. package/README.md +42 -44
  2. package/THEME.md +473 -0
  3. package/THEMING.md +248 -0
  4. package/dist/atoms/Card.svelte +40 -67
  5. package/dist/atoms/Card.svelte.d.ts +3 -3
  6. package/dist/atoms/CardContent.svelte +1 -1
  7. package/dist/atoms/CardHeader.svelte +10 -1
  8. package/dist/atoms/CardHeader.svelte.d.ts +3 -0
  9. package/dist/atoms/Checkbox.svelte +1 -7
  10. package/dist/atoms/CodeBlock.svelte +7 -7
  11. package/dist/atoms/ColorPicker.svelte +81 -73
  12. package/dist/atoms/Input.svelte +16 -12
  13. package/dist/atoms/Input.svelte.d.ts +2 -0
  14. package/dist/atoms/List.svelte +47 -0
  15. package/dist/atoms/List.svelte.d.ts +19 -0
  16. package/dist/atoms/ListItem.svelte +148 -0
  17. package/dist/atoms/ListItem.svelte.d.ts +35 -0
  18. package/dist/atoms/Progress.svelte +4 -6
  19. package/dist/atoms/Select.svelte +65 -20
  20. package/dist/atoms/Select.svelte.d.ts +13 -1
  21. package/dist/atoms/Textarea.svelte +13 -11
  22. package/dist/atoms/Textarea.svelte.d.ts +1 -0
  23. package/dist/atoms/Toast.svelte +1 -1
  24. package/dist/atoms/Toggle.svelte +1 -7
  25. package/dist/atoms/Tooltip.svelte +8 -15
  26. package/dist/atoms/index.d.ts +2 -0
  27. package/dist/atoms/index.js +2 -0
  28. package/dist/components/atoms/index.d.ts +2 -0
  29. package/dist/components/atoms/index.d.ts.map +1 -1
  30. package/dist/components/index.d.ts +4 -1
  31. package/dist/components/index.d.ts.map +1 -1
  32. package/dist/components/molecules/index.d.ts +0 -1
  33. package/dist/components/molecules/index.d.ts.map +1 -1
  34. package/dist/components/molecules/navigation-menu-context.d.ts +7 -0
  35. package/dist/components/molecules/navigation-menu-context.d.ts.map +1 -0
  36. package/dist/components/organisms/index.d.ts +2 -1
  37. package/dist/components/organisms/index.d.ts.map +1 -1
  38. package/dist/index.d.ts +4 -1
  39. package/dist/index.js +5 -9
  40. package/dist/lib/showcase/components-catalog.d.ts +3 -0
  41. package/dist/lib/showcase/components-catalog.d.ts.map +1 -0
  42. package/dist/lib/showcase/components-showcase-constants.d.ts +63 -0
  43. package/dist/lib/showcase/components-showcase-constants.d.ts.map +1 -0
  44. package/dist/lib/showcase/docs-sidebar-helpers.d.ts +15 -0
  45. package/dist/lib/showcase/docs-sidebar-helpers.d.ts.map +1 -0
  46. package/dist/molecules/Alert.svelte +9 -4
  47. package/dist/molecules/ComponentDemo.svelte +53 -50
  48. package/dist/molecules/ContactForm.svelte +113 -76
  49. package/dist/molecules/ContactForm.svelte.d.ts +1 -4
  50. package/dist/molecules/Dropdown.svelte +4 -2
  51. package/dist/molecules/ImageUpload.svelte +27 -4
  52. package/dist/molecules/ImageUpload.svelte.d.ts +1 -0
  53. package/dist/molecules/Modal.svelte +46 -45
  54. package/dist/molecules/NavigationMenu.svelte +7 -10
  55. package/dist/molecules/NavigationMenuContent.svelte +9 -9
  56. package/dist/molecules/NavigationMenuItem.svelte +7 -6
  57. package/dist/molecules/NavigationMenuLink.svelte +8 -6
  58. package/dist/molecules/NavigationMenuList.svelte +0 -7
  59. package/dist/molecules/NavigationMenuTrigger.svelte +8 -11
  60. package/dist/molecules/Section.svelte +12 -12
  61. package/dist/molecules/SlideUp.svelte +32 -2
  62. package/dist/molecules/Tabs.svelte +74 -7
  63. package/dist/molecules/index.d.ts +0 -1
  64. package/dist/molecules/index.js +0 -1
  65. package/dist/molecules/navigation-menu-context.d.ts +6 -0
  66. package/dist/molecules/navigation-menu-context.js +1 -0
  67. package/dist/organisms/Navbar.svelte +170 -53
  68. package/dist/organisms/Navbar.svelte.d.ts +31 -4
  69. package/dist/organisms/SidebarNavigation.svelte +464 -0
  70. package/dist/organisms/SidebarNavigation.svelte.d.ts +49 -0
  71. package/dist/organisms/SidebarPanel.svelte +175 -0
  72. package/dist/organisms/SidebarPanel.svelte.d.ts +32 -0
  73. package/dist/organisms/index.d.ts +2 -1
  74. package/dist/organisms/index.js +2 -1
  75. package/dist/types/page.types.d.ts +32 -0
  76. package/dist/types/page.types.d.ts.map +1 -0
  77. package/dist/types/variants.ts +76 -0
  78. package/dist/zabi-components-colors.css +347 -324
  79. package/dist/zabi-components-theme-dark-only.css +159 -151
  80. package/dist/zabi-components-theme-dark.css +159 -151
  81. package/dist/zabi-components-theme-only.css +245 -230
  82. package/dist/zabi-components-theme.css +245 -230
  83. package/dist/zabi-components.css +722 -84
  84. package/docs/theme-imports.md +112 -0
  85. package/package.json +20 -9
  86. package/dist/molecules/Sidebar.svelte +0 -324
  87. package/dist/molecules/Sidebar.svelte.d.ts +0 -30
  88. package/dist/organisms/Navigation.svelte +0 -116
  89. 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 { getContext, setContext } from "svelte";
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
- interface NavigationMenuContext {
12
- activeItem: string | null;
13
- setActiveItem: (item: string | null) => void;
14
- isMobile: boolean;
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: NavigationMenuContext = {
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(NAVIGATION_MENU_CONTEXT, context);
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, onDestroy } from "svelte";
5
-
6
- const NAVIGATION_MENU_CONTEXT = Symbol("navigation-menu");
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
- activeItem: string | null;
26
- setActiveItem: (item: string | null) => void;
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
- const NAVIGATION_MENU_CONTEXT = Symbol("navigation-menu");
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
- activeItem: string | null;
22
- setActiveItem: (item: string | null) => void;
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
- const NAVIGATION_MENU_CONTEXT = Symbol("navigation-menu");
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
- setActiveItem: (item: string | null) => void;
24
- }>(NAVIGATION_MENU_CONTEXT);
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-headline hover:bg-base-100 rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-brand-500 focus:ring-offset-2 no-underline {className}";
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
- const NAVIGATION_MENU_CONTEXT = Symbol("navigation-menu");
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
- let triggerElement = $state<HTMLElement | null>(null);
21
-
22
- const context = getContext<{
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-headline bg-transparent hover:bg-base-100 rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-brand-500 focus:ring-offset-2 {className}"
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()} {paddingClasses()} {className}"
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()} text-description {centered
131
- ? 'mx-auto max-w-2xl'
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 z-modal"
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
- class="fixed bottom-0 left-0 right-0 bg-card rounded-t-3xl shadow-xl z-modal max-h-[90vh] overflow-y-auto animate-[slideUp_0.3s_ease-out] flex flex-col"
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
- const currentIndex = tabs.findIndex((tab) => tab.id === activeTab);
75
+ event.preventDefault();
29
76
  const direction = event.key === "ArrowLeft" ? -1 : 1;
30
77
  const nextIndex =
31
- (currentIndex + direction + tabs.length) % tabs.length;
32
- selectTab(tabs[nextIndex].id);
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
- class="px-4 py-2 text-sm font-medium border-b-2 transition-colors {activeTab ===
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 border-brand-500'
111
+ ? 'border-brand-500 bg-brand-100 text-brand-700'
52
112
  : 'border-brand-500 text-body'
53
- : 'border-transparent text-description hover:text-body hover:border-base-300'}"
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 class="mt-4">
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';
@@ -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,6 @@
1
+ export interface NavigationMenuContextValue {
2
+ activeItem: string | null;
3
+ setActiveItem: (item: string | null) => void;
4
+ isMobile: boolean;
5
+ }
6
+ export declare const NAVIGATION_MENU_CONTEXT_KEY: unique symbol;
@@ -0,0 +1 @@
1
+ export const NAVIGATION_MENU_CONTEXT_KEY = Symbol("navigation-menu");