ui-svelte 0.2.1 → 0.2.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.
Files changed (61) hide show
  1. package/dist/charts/ArcChart.svelte +3 -3
  2. package/dist/charts/ArcChart.svelte.d.ts +1 -1
  3. package/dist/charts/AreaChart.svelte +3 -3
  4. package/dist/charts/AreaChart.svelte.d.ts +1 -1
  5. package/dist/charts/BarChart.svelte +3 -3
  6. package/dist/charts/BarChart.svelte.d.ts +1 -1
  7. package/dist/charts/Candlestick.svelte +3 -3
  8. package/dist/charts/Candlestick.svelte.d.ts +1 -1
  9. package/dist/charts/LineChart.svelte +3 -3
  10. package/dist/charts/LineChart.svelte.d.ts +1 -1
  11. package/dist/charts/PieChart.svelte +3 -3
  12. package/dist/charts/PieChart.svelte.d.ts +1 -1
  13. package/dist/control/Button.svelte +2 -8
  14. package/dist/control/Button.svelte.d.ts +0 -2
  15. package/dist/control/IconButton.svelte +0 -3
  16. package/dist/control/IconButton.svelte.d.ts +0 -1
  17. package/dist/control/css/btn.css +0 -4
  18. package/dist/css/base.css +262 -45
  19. package/dist/css/utilities.css +0 -4
  20. package/dist/display/Accordion.svelte +3 -3
  21. package/dist/display/Accordion.svelte.d.ts +1 -1
  22. package/dist/display/Alert.svelte +0 -2
  23. package/dist/display/Card.svelte +4 -17
  24. package/dist/display/Card.svelte.d.ts +1 -3
  25. package/dist/display/Carousel.svelte +3 -3
  26. package/dist/display/Carousel.svelte.d.ts +1 -1
  27. package/dist/display/ChatBox.svelte +3 -3
  28. package/dist/display/ChatBox.svelte.d.ts +1 -1
  29. package/dist/display/Collapsible.svelte +3 -3
  30. package/dist/display/Collapsible.svelte.d.ts +1 -1
  31. package/dist/display/Empty.svelte +11 -5
  32. package/dist/display/Marquee.svelte +3 -3
  33. package/dist/display/Marquee.svelte.d.ts +1 -1
  34. package/dist/display/Section.svelte +3 -3
  35. package/dist/display/Section.svelte.d.ts +1 -1
  36. package/dist/display/css/alert.css +1 -1
  37. package/dist/display/css/card.css +7 -126
  38. package/dist/display/css/section.css +5 -1
  39. package/dist/form/Select.svelte +3 -3
  40. package/dist/form/Select.svelte.d.ts +1 -1
  41. package/dist/form/TextField.svelte +4 -6
  42. package/dist/form/TextField.svelte.d.ts +2 -2
  43. package/dist/form/css/control.css +1 -1
  44. package/dist/index.d.ts +3 -2
  45. package/dist/index.js +2 -2
  46. package/dist/layout/AppBar.svelte +3 -3
  47. package/dist/layout/AppBar.svelte.d.ts +1 -1
  48. package/dist/layout/Footer.svelte +3 -3
  49. package/dist/layout/Footer.svelte.d.ts +1 -1
  50. package/dist/layout/Sidebar.svelte +4 -11
  51. package/dist/layout/Sidebar.svelte.d.ts +1 -1
  52. package/dist/navigation/BottomNav.svelte +80 -0
  53. package/dist/navigation/SideNav.svelte +17 -16
  54. package/dist/navigation/SideNav.svelte.d.ts +33 -0
  55. package/dist/navigation/Tabs.svelte +3 -3
  56. package/dist/navigation/Tabs.svelte.d.ts +1 -1
  57. package/dist/navigation/css/bottom-nav.css +134 -0
  58. package/package.json +2 -2
  59. package/dist/navigation/BottomNav.svelte.d.ts +0 -26
  60. /package/dist/{types.d.ts → types.svelte.d.ts} +0 -0
  61. /package/dist/{types.js → types.svelte.js} +0 -0
@@ -17,13 +17,13 @@
17
17
  fade?: boolean;
18
18
  fadeColor?: string;
19
19
  gap?: string;
20
- class?: string;
20
+ rootClass?: string;
21
21
  itemClass?: string;
22
22
  children?: Snippet;
23
23
  };
24
24
 
25
25
  const {
26
- class: className,
26
+ rootClass,
27
27
  itemClass,
28
28
  items = [],
29
29
  speed = 'normal',
@@ -106,7 +106,7 @@
106
106
  </script>
107
107
 
108
108
  <div
109
- class={cn('marquee', isVertical && 'is-vertical', fade && 'has-fade', className)}
109
+ class={cn('marquee', isVertical && 'is-vertical', fade && 'has-fade', rootClass)}
110
110
  bind:this={containerEl}
111
111
  onmouseenter={handleMouseEnter}
112
112
  onmouseleave={handleMouseLeave}
@@ -12,7 +12,7 @@ type Props = {
12
12
  fade?: boolean;
13
13
  fadeColor?: string;
14
14
  gap?: string;
15
- class?: string;
15
+ rootClass?: string;
16
16
  itemClass?: string;
17
17
  children?: Snippet;
18
18
  };
@@ -3,7 +3,7 @@
3
3
  import type { Snippet } from 'svelte';
4
4
 
5
5
  type Props = {
6
- class?: string;
6
+ rootClass?: string;
7
7
  bodyClass?: string;
8
8
  coverClass?: string;
9
9
  overlayClass?: string;
@@ -25,7 +25,7 @@
25
25
  };
26
26
 
27
27
  const {
28
- class: className,
28
+ rootClass,
29
29
  bodyClass,
30
30
  coverClass,
31
31
  overlayClass,
@@ -56,7 +56,7 @@
56
56
  variantClasses[variant],
57
57
  isSolid && 'is-solid',
58
58
  isBoxed && 'boxed',
59
- className
59
+ rootClass
60
60
  )}
61
61
  >
62
62
  {#if cover}
@@ -1,6 +1,6 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  type Props = {
3
- class?: string;
3
+ rootClass?: string;
4
4
  bodyClass?: string;
5
5
  coverClass?: string;
6
6
  overlayClass?: string;
@@ -1,6 +1,6 @@
1
1
  @layer components {
2
2
  .alert {
3
- @apply flex rounded-ui text-sm w-full p-2 gap-2;
3
+ @apply flex rounded-ui text-sm w-full px-4 py-2 md:px-6 md:py-4 gap-4;
4
4
 
5
5
  &.is-solid {
6
6
  &.is-success {
@@ -8,75 +8,22 @@
8
8
  }
9
9
  }
10
10
 
11
- .card.has-divider {
12
- .card-header {
13
- @apply border-b;
14
- }
15
- .card-footer {
16
- @apply border-t;
17
- }
18
- }
19
-
20
- .card.has-shadow {
21
- @apply shadow-sm shadow-muted;
22
- }
23
-
24
11
  .card.is-primary {
25
12
  @apply bg-on-primary text-primary;
26
13
  }
27
14
 
28
- .card.is-primary.has-divider {
29
- .card-header {
30
- @apply border-primary;
31
- }
32
-
33
- .card-footer {
34
- @apply border-primary;
35
- }
36
- }
37
-
38
15
  .card.is-primary.is-solid {
39
16
  @apply bg-primary text-on-primary;
40
17
  }
41
18
 
42
- .card.is-primary.is-solid.has-divider {
43
- .card-header {
44
- @apply border-on-primary;
45
- }
46
-
47
- .card-footer {
48
- @apply border-on-primary;
49
- }
50
- }
51
-
52
19
  .card.is-secondary {
53
20
  @apply bg-on-secondary text-secondary;
54
21
  }
55
22
 
56
- .card.is-secondary.has-divider {
57
- .card-header {
58
- @apply border-secondary;
59
- }
60
-
61
- .card-footer {
62
- @apply border-secondary;
63
- }
64
- }
65
-
66
23
  .card.is-secondary.is-solid {
67
24
  @apply bg-secondary text-on-secondary;
68
25
  }
69
26
 
70
- .card.is-secondary.is-solid.has-divider {
71
- .card-header {
72
- @apply border-on-secondary;
73
- }
74
-
75
- .card-footer {
76
- @apply border-on-secondary;
77
- }
78
- }
79
-
80
27
  .card.is-success {
81
28
  @apply bg-on-success text-success;
82
29
  }
@@ -85,16 +32,6 @@
85
32
  @apply bg-success text-on-success;
86
33
  }
87
34
 
88
- .card.is-success.is-solid.has-divider {
89
- .card-header {
90
- @apply border-on-success;
91
- }
92
-
93
- .card-footer {
94
- @apply border-on-success;
95
- }
96
- }
97
-
98
35
  .card.is-info {
99
36
  @apply bg-on-info text-info;
100
37
  }
@@ -103,16 +40,6 @@
103
40
  @apply bg-info text-on-info;
104
41
  }
105
42
 
106
- .card.is-info.is-solid.has-divider {
107
- .card-header {
108
- @apply border-on-info;
109
- }
110
-
111
- .card-footer {
112
- @apply border-on-info;
113
- }
114
- }
115
-
116
43
  .card.is-warning {
117
44
  @apply bg-on-warning text-warning;
118
45
  }
@@ -121,16 +48,6 @@
121
48
  @apply bg-warning text-on-warning;
122
49
  }
123
50
 
124
- .card.is-warning.is-solid.has-divider {
125
- .card-header {
126
- @apply border-on-warning;
127
- }
128
-
129
- .card-footer {
130
- @apply border-on-warning;
131
- }
132
- }
133
-
134
51
  .card.is-danger {
135
52
  @apply bg-on-danger text-danger;
136
53
  }
@@ -139,58 +56,18 @@
139
56
  @apply bg-danger text-on-danger;
140
57
  }
141
58
 
142
- .card.is-danger.is-solid.has-divider {
143
- .card-header {
144
- @apply border-on-danger;
145
- }
146
-
147
- .card-footer {
148
- @apply border-on-danger;
149
- }
150
- }
151
-
152
59
  .card.is-muted {
153
60
  @apply bg-muted text-on-muted;
154
61
  }
155
62
 
156
- .card.is-muted.has-divider {
157
- .card-header {
158
- @apply border-on-muted;
159
- }
160
-
161
- .card-footer {
162
- @apply border-on-muted;
163
- }
164
- }
165
-
166
63
  .card.is-muted.is-solid {
167
64
  @apply bg-on-muted text-muted;
168
65
  }
169
66
 
170
- .card.is-muted.is-solid.has-divider {
171
- .card-header {
172
- @apply border-muted;
173
- }
174
-
175
- .card-footer {
176
- @apply border-muted;
177
- }
178
- }
179
-
180
67
  .card.is-outlined {
181
68
  @apply border border-muted;
182
69
  }
183
70
 
184
- .card.is-outlined.has-divider {
185
- .card-header {
186
- @apply border-muted;
187
- }
188
-
189
- .card-footer {
190
- @apply border-muted;
191
- }
192
- }
193
-
194
71
  .card.is-surface {
195
72
  @apply bg-surface text-on-surface;
196
73
  }
@@ -218,14 +95,18 @@
218
95
  }
219
96
 
220
97
  .card-body {
221
- @apply flex-1 w-full column p-3 gap-3;
98
+ @apply flex-1 w-full p-4 md:p-6;
99
+ }
100
+
101
+ .card-body:not(.prose) {
102
+ @apply column gap-4 md:gap-6;
222
103
  }
223
104
 
224
105
  .card-header {
225
- @apply w-full flex justify-between items-center p-3 gap-3;
106
+ @apply w-full flex justify-between items-center px-4 pt-4 gap-4 md:px-6 md:pt-6 md:gap-6;
226
107
  }
227
108
 
228
109
  .card-footer {
229
- @apply w-full flex justify-between items-center p-3 gap-3;
110
+ @apply w-full flex justify-between items-center px-4 pb-4 gap-4 md:px-6 md:pb-6 md:gap-6;
230
111
  }
231
112
  }
@@ -15,7 +15,11 @@
15
15
  }
16
16
 
17
17
  .section-body {
18
- @apply w-full column p-3 gap-3;
18
+ @apply w-full p-4 md:p-6;
19
+ }
20
+
21
+ .section-body:not(.prose) {
22
+ @apply column gap-4 md:gap-6;
19
23
  }
20
24
  }
21
25
 
@@ -20,7 +20,7 @@
20
20
  variant?: 'primary' | 'secondary' | 'muted' | 'outlined' | 'line';
21
21
  size?: 'sm' | 'md' | 'lg';
22
22
  name?: string;
23
- class?: string;
23
+ rootClass?: string;
24
24
  label?: string;
25
25
  isLabelActive?: boolean;
26
26
  helpText?: string;
@@ -30,7 +30,7 @@
30
30
  };
31
31
 
32
32
  let {
33
- class: className,
33
+ rootClass,
34
34
  options = [],
35
35
  value = $bindable(),
36
36
  selected = $bindable(),
@@ -268,7 +268,7 @@
268
268
  });
269
269
  </script>
270
270
 
271
- <div class={cn('field', className)}>
271
+ <div class={cn('field', rootClass)}>
272
272
  <input type="text" {name} bind:value hidden />
273
273
 
274
274
  {#if !isFloatLabel && label}
@@ -13,7 +13,7 @@ type Props = {
13
13
  variant?: 'primary' | 'secondary' | 'muted' | 'outlined' | 'line';
14
14
  size?: 'sm' | 'md' | 'lg';
15
15
  name?: string;
16
- class?: string;
16
+ rootClass?: string;
17
17
  label?: string;
18
18
  isLabelActive?: boolean;
19
19
  helpText?: string;
@@ -1,8 +1,6 @@
1
1
  <script lang="ts">
2
- import { Icon } from '../index.js';
3
- import type { IconData } from '../types.js';
2
+ import { Icon, type IconData } from '../index.js';
4
3
  import { cn } from '../utils/class-names.js';
5
- import type { Snippet } from 'svelte';
6
4
  import type { HTMLInputAttributes } from 'svelte/elements';
7
5
 
8
6
  type Props = {
@@ -11,7 +9,7 @@
11
9
  defaultValue?: string;
12
10
  placeholder?: string;
13
11
  type?: 'text' | 'password' | 'email' | 'number' | 'tel' | 'url';
14
- class?: string;
12
+ rootClass?: string;
15
13
  controlClass?: string;
16
14
  startIcon?: IconData;
17
15
  endIcon?: IconData;
@@ -41,7 +39,7 @@
41
39
  placeholder,
42
40
  autocomplete,
43
41
  type = 'text',
44
- class: className,
42
+ rootClass,
45
43
  controlClass,
46
44
  startIcon,
47
45
  endIcon,
@@ -95,7 +93,7 @@
95
93
  });
96
94
  </script>
97
95
 
98
- <div class={cn('field', className)}>
96
+ <div class={cn('field', rootClass)}>
99
97
  {#if !isFloatLabel && label}
100
98
  <span class="field-label">{label}</span>
101
99
  {/if}
@@ -1,4 +1,4 @@
1
- import type { IconData } from '../types.js';
1
+ import { type IconData } from '../index.js';
2
2
  import type { HTMLInputAttributes } from 'svelte/elements';
3
3
  type Props = {
4
4
  el?: HTMLInputElement;
@@ -6,7 +6,7 @@ type Props = {
6
6
  defaultValue?: string;
7
7
  placeholder?: string;
8
8
  type?: 'text' | 'password' | 'email' | 'number' | 'tel' | 'url';
9
- class?: string;
9
+ rootClass?: string;
10
10
  controlClass?: string;
11
11
  startIcon?: IconData;
12
12
  endIcon?: IconData;
@@ -10,7 +10,7 @@
10
10
  }
11
11
 
12
12
  .control-label.is-active {
13
- @apply text-xs left-3 top-px! translate-y-px!;
13
+ @apply text-xs left-3 top-[1.2px]! translate-y-px!;
14
14
  }
15
15
 
16
16
  .control.is-sm {
package/dist/index.d.ts CHANGED
@@ -22,7 +22,7 @@ import Code from './display/Code.svelte';
22
22
  import Collapsible from './display/Collapsible.svelte';
23
23
  import Divider from './display/Divider.svelte';
24
24
  import Empty from './display/Empty.svelte';
25
- import Icon from './display/Icon.svelte';
25
+ import Icon, { type IconData } from './display/Icon.svelte';
26
26
  import Item from './display/Item.svelte';
27
27
  import Marquee from './display/Marquee.svelte';
28
28
  import Section from './display/Section.svelte';
@@ -50,7 +50,7 @@ import Scaffold from './layout/Scaffold.svelte';
50
50
  import Sidebar from './layout/Sidebar.svelte';
51
51
  import NavMenu from './navigation/NavMenu.svelte';
52
52
  import BottomNav from './navigation/BottomNav.svelte';
53
- import SideNav from './navigation/SideNav.svelte';
53
+ import SideNav, { type SideNavItem, type SideNavSubItem } from './navigation/SideNav.svelte';
54
54
  import Tabs from './navigation/Tabs.svelte';
55
55
  import AlertDialog from './overlay/AlertDialog.svelte';
56
56
  import Command from './overlay/Command.svelte';
@@ -74,3 +74,4 @@ import { theme } from './stores/theme.svelte.js';
74
74
  import { useSearch } from './hooks/use-search.svelte.js';
75
75
  import { useChat } from './hooks/use-chat.svelte.js';
76
76
  export { AreaChart, ArcChart, BarChart, Candlestick, LineChart, PieChart, Alert, AlertDialog, AppBar, Accordion, Avatar, Audio, Badge, Button, BottomNav, Carousel, Card, ChatBox, Checkbox, Chip, Code, Collapsible, Command, ComboBox, CsvField, DateField, Drawer, Dropzone, Divider, Dropdown, Empty, Footer, FooterLinks, formatCurrency, formatDate, formatNumber, getWeekdays, i18n, Icon, IconButton, ImageCropper, Item, initLanguage, Modal, Marquee, NavMenu, PasswordField, PhoneField, PinField, plural, PopoverStack, Provider, RadioGroup, Record, Scaffold, Section, Select, setLanguage, Sidebar, SideNav, Slider, t, Table, Tabs, TextField, Textarea, theme, Toast, toast, Toggle, ToggleTheme, Tooltip, useAuth, useChat, useClipboard, useFetch, useForm, useLocalStorage, useScroll, useSearch, useTable, useWebSocket, Video };
77
+ export type { IconData, SideNavItem, SideNavSubItem };
package/dist/index.js CHANGED
@@ -22,7 +22,7 @@ import Code from './display/Code.svelte';
22
22
  import Collapsible from './display/Collapsible.svelte';
23
23
  import Divider from './display/Divider.svelte';
24
24
  import Empty from './display/Empty.svelte';
25
- import Icon from './display/Icon.svelte';
25
+ import Icon, {} from './display/Icon.svelte';
26
26
  import Item from './display/Item.svelte';
27
27
  import Marquee from './display/Marquee.svelte';
28
28
  import Section from './display/Section.svelte';
@@ -50,7 +50,7 @@ import Scaffold from './layout/Scaffold.svelte';
50
50
  import Sidebar from './layout/Sidebar.svelte';
51
51
  import NavMenu from './navigation/NavMenu.svelte';
52
52
  import BottomNav from './navigation/BottomNav.svelte';
53
- import SideNav from './navigation/SideNav.svelte';
53
+ import SideNav, {} from './navigation/SideNav.svelte';
54
54
  import Tabs from './navigation/Tabs.svelte';
55
55
  import AlertDialog from './overlay/AlertDialog.svelte';
56
56
  import Command from './overlay/Command.svelte';
@@ -7,7 +7,7 @@
7
7
  start?: Snippet;
8
8
  center?: Snippet;
9
9
  end?: Snippet;
10
- class?: string;
10
+ rootClass?: string;
11
11
  contentClass?: string;
12
12
  startClass?: string;
13
13
  centerClass?: string;
@@ -23,7 +23,7 @@
23
23
  start,
24
24
  center,
25
25
  end,
26
- class: className,
26
+ rootClass,
27
27
  contentClass,
28
28
  startClass,
29
29
  centerClass,
@@ -80,7 +80,7 @@
80
80
  shouldBlur && 'is-blurred',
81
81
  isHidden && 'is-hidden',
82
82
  isSticky && 'is-sticky',
83
- className
83
+ rootClass
84
84
  )}
85
85
  >
86
86
  <div class={cn('appbar-content', isBoxed && 'boxed', contentClass)}>
@@ -3,7 +3,7 @@ type Props = {
3
3
  start?: Snippet;
4
4
  center?: Snippet;
5
5
  end?: Snippet;
6
- class?: string;
6
+ rootClass?: string;
7
7
  contentClass?: string;
8
8
  startClass?: string;
9
9
  centerClass?: string;
@@ -7,7 +7,7 @@
7
7
  start?: Snippet;
8
8
  center?: Snippet;
9
9
  end?: Snippet;
10
- class?: string;
10
+ rootClass?: string;
11
11
  contentClass?: string;
12
12
  startClass?: string;
13
13
  centerClass?: string;
@@ -22,7 +22,7 @@
22
22
  start,
23
23
  center,
24
24
  end,
25
- class: className,
25
+ rootClass,
26
26
  contentClass,
27
27
  startClass,
28
28
  centerClass,
@@ -73,7 +73,7 @@
73
73
  isBordered && 'is-bordered',
74
74
  shouldBlur && 'is-blurred',
75
75
  isHidden && 'is-hidden',
76
- className
76
+ rootClass
77
77
  )}
78
78
  >
79
79
  <div class={cn('footer-content', isBoxed && 'boxed', contentClass)}>
@@ -3,7 +3,7 @@ type Props = {
3
3
  start?: Snippet;
4
4
  center?: Snippet;
5
5
  end?: Snippet;
6
- class?: string;
6
+ rootClass?: string;
7
7
  contentClass?: string;
8
8
  startClass?: string;
9
9
  centerClass?: string;
@@ -6,24 +6,17 @@
6
6
  children: Snippet;
7
7
  header?: Snippet;
8
8
  footer?: Snippet;
9
- class?: string;
9
+ rootClass?: string;
10
10
  contentClass?: string;
11
11
  headerClass?: string;
12
12
  footerClass?: string;
13
13
  };
14
14
 
15
- const {
16
- children,
17
- header,
18
- footer,
19
- class: className,
20
- contentClass,
21
- headerClass,
22
- footerClass
23
- }: Props = $props();
15
+ const { children, header, footer, rootClass, contentClass, headerClass, footerClass }: Props =
16
+ $props();
24
17
  </script>
25
18
 
26
- <aside class={cn('sidebar', className)}>
19
+ <aside class={cn('sidebar', rootClass)}>
27
20
  {#if header}
28
21
  <div class={cn('sidebar-header', headerClass)}>
29
22
  {@render header()}
@@ -3,7 +3,7 @@ type Props = {
3
3
  children: Snippet;
4
4
  header?: Snippet;
5
5
  footer?: Snippet;
6
- class?: string;
6
+ rootClass?: string;
7
7
  contentClass?: string;
8
8
  headerClass?: string;
9
9
  footerClass?: string;
@@ -0,0 +1,80 @@
1
+ <script lang="ts">
2
+ import { page } from '$app/state';
3
+ import { Icon, type IconData } from '../index.js';
4
+ import { cn } from '../utils/class-names.js';
5
+
6
+ type BottomNavItem = {
7
+ id: string;
8
+ label?: string;
9
+ icon: IconData;
10
+ href?: string;
11
+ onclick?: (item: BottomNavItem) => void;
12
+ };
13
+
14
+ type Props = {
15
+ items: BottomNavItem[];
16
+ variant?: 'primary' | 'secondary' | 'muted';
17
+ size?: 'sm' | 'md' | 'lg';
18
+ showLabels?: boolean;
19
+ class?: string;
20
+ };
21
+
22
+ const {
23
+ items = [],
24
+ class: className,
25
+ variant = 'primary',
26
+ size = 'md',
27
+ showLabels = true
28
+ }: Props = $props();
29
+
30
+ const variantClasses = {
31
+ primary: 'bottomnav-primary',
32
+ secondary: 'bottomnav-secondary',
33
+ muted: 'bottomnav-muted'
34
+ };
35
+
36
+ const sizeClasses = {
37
+ sm: 'is-sm',
38
+ md: 'is-md',
39
+ lg: 'is-lg'
40
+ };
41
+
42
+ function isItemActive(href?: string): boolean {
43
+ if (!href) return false;
44
+ return page.url.pathname === href || page.url.pathname.startsWith(href + '/');
45
+ }
46
+
47
+ function handleItemClick(item: BottomNavItem) {
48
+ if (item.onclick) {
49
+ item.onclick(item);
50
+ }
51
+ }
52
+ </script>
53
+
54
+ <nav
55
+ class={cn(
56
+ 'bottomnav',
57
+ variantClasses[variant],
58
+ sizeClasses[size],
59
+ !showLabels && 'is-icon-only',
60
+ className
61
+ )}
62
+ >
63
+ {#each items as item}
64
+ {#if item.href}
65
+ <a href={item.href} class={cn('bottomnav-item', isItemActive(item.href) && 'is-active')}>
66
+ <Icon icon={item.icon} class="bottomnav-icon" />
67
+ {#if showLabels && item.label}
68
+ <span class="bottomnav-label">{item.label}</span>
69
+ {/if}
70
+ </a>
71
+ {:else}
72
+ <button type="button" class="bottomnav-item" onclick={() => handleItemClick(item)}>
73
+ <Icon icon={item.icon} class="bottomnav-icon" />
74
+ {#if showLabels && item.label}
75
+ <span class="bottomnav-label">{item.label}</span>
76
+ {/if}
77
+ </button>
78
+ {/if}
79
+ {/each}
80
+ </nav>