ui-svelte 0.2.4 → 0.2.6

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 (45) hide show
  1. package/dist/assets/country-flags.d.ts +1 -0
  2. package/dist/assets/country-flags.js +1612 -0
  3. package/dist/charts/ArcChart.svelte +291 -48
  4. package/dist/charts/ArcChart.svelte.d.ts +32 -1
  5. package/dist/charts/Candlestick.svelte +663 -115
  6. package/dist/charts/Candlestick.svelte.d.ts +40 -0
  7. package/dist/charts/css/arc-chart.css +76 -6
  8. package/dist/charts/css/candlestick.css +234 -11
  9. package/dist/control/Button.svelte +3 -1
  10. package/dist/control/Button.svelte.d.ts +1 -0
  11. package/dist/control/IconButton.svelte +3 -1
  12. package/dist/control/IconButton.svelte.d.ts +1 -0
  13. package/dist/control/ToggleGroup.svelte +82 -0
  14. package/dist/control/ToggleGroup.svelte.d.ts +20 -0
  15. package/dist/control/css/toggle-group.css +85 -0
  16. package/dist/css/base.css +23 -43
  17. package/dist/css/utilities.css +45 -0
  18. package/dist/display/AvatarGroup.svelte +59 -0
  19. package/dist/display/AvatarGroup.svelte.d.ts +17 -0
  20. package/dist/display/Code.svelte +14 -7
  21. package/dist/display/Code.svelte.d.ts +1 -0
  22. package/dist/display/Section.svelte +1 -1
  23. package/dist/display/css/avatar-group.css +46 -0
  24. package/dist/display/css/avatar.css +1 -10
  25. package/dist/display/css/badge.css +14 -11
  26. package/dist/form/ComboBox.svelte.d.ts +1 -1
  27. package/dist/form/PhoneField.svelte +8 -4
  28. package/dist/form/Select.svelte.d.ts +1 -1
  29. package/dist/index.css +43 -21
  30. package/dist/index.d.ts +3 -1
  31. package/dist/index.js +3 -1
  32. package/dist/navigation/BottomNav.svelte +43 -16
  33. package/dist/navigation/NavMenu.svelte +25 -4
  34. package/dist/navigation/SideNav.svelte +20 -2
  35. package/dist/navigation/SideNav.svelte.d.ts +2 -0
  36. package/dist/navigation/css/bottom-nav.css +139 -15
  37. package/dist/navigation/css/nav-menu.css +192 -7
  38. package/dist/navigation/css/side-nav.css +80 -0
  39. package/dist/navigation/css/tabs.css +4 -4
  40. package/dist/utils/popover.js +6 -6
  41. package/package.json +2 -2
  42. /package/dist/{form/js → assets}/countries.d.ts +0 -0
  43. /package/dist/{form/js → assets}/countries.js +0 -0
  44. /package/dist/{form/js → assets}/phone-examples.d.ts +0 -0
  45. /package/dist/{form/js → assets}/phone-examples.js +0 -0
package/dist/index.css CHANGED
@@ -8,6 +8,7 @@
8
8
  @import './control/css/btn.css';
9
9
  @import './control/css/media.css';
10
10
  @import './control/css/video.css';
11
+ @import './control/css/toggle-group.css';
11
12
 
12
13
  @import './charts/css/arc-chart.css';
13
14
  @import './charts/css/area-chart.css';
@@ -19,6 +20,7 @@
19
20
  @import './display/css/accordion.css';
20
21
  @import './display/css/alert.css';
21
22
  @import './display/css/avatar.css';
23
+ @import './display/css/avatar-group.css';
22
24
  @import './display/css/badge.css';
23
25
  @import './display/css/carousel.css';
24
26
  @import './display/css/card.css';
@@ -69,48 +71,68 @@
69
71
  @import './overlay/css/tooltip.css';
70
72
 
71
73
  @theme {
72
- --color-primary: var(--primary, oklch(54.6% 0.245 262.881)); /* blue-600 */
73
- --color-on-primary: var(--on-primary, oklch(93.2% 0.032 255.585)); /* blue-100 */
74
+ --color-primary: var(--primary, oklch(54.6% 0.245 262.881));
75
+ /* blue-600 */
76
+ --color-on-primary: var(--on-primary, oklch(93.2% 0.032 255.585));
77
+ /* blue-100 */
74
78
 
75
- --color-secondary: var(--secondary, oklch(0.592 0.249 0.584)); /* pink-600 */
76
- --color-on-secondary: var(--on-secondary, oklch(0.948 0.028 342.258)); /* pink-100 */
79
+ --color-secondary: var(--secondary, oklch(0.592 0.249 0.584));
80
+ /* pink-600 */
81
+ --color-on-secondary: var(--on-secondary, oklch(0.948 0.028 342.258));
82
+ /* pink-100 */
77
83
 
78
- --color-muted: var(--muted, oklch(87.2% 0.01 258.338)); /* gray-300 */
79
- --color-on-muted: var(--on-muted, oklch(27.8% 0.033 256.848)); /* gray-700 */
84
+ --color-muted: var(--muted, oklch(87.2% 0.01 258.338));
85
+ /* gray-300 */
86
+ --color-on-muted: var(--on-muted, oklch(27.8% 0.033 256.848));
87
+ /* gray-700 */
80
88
 
81
89
  /* dark */
82
90
  /*--color-muted: var(--muted, oklch(37.3% 0.034 259.733)); /* gray-700 */
83
91
  /*--color-on-muted: var(--on-muted, oklch(87.2% 0.01 258.338)); /* gray-300 */
84
92
 
85
- --color-background: var(--background, oklch(98.5% 0.002 247.839)); /* gray-50 */
86
- --color-on-background: var(--on-background, oklch(21% 0.034 264.665)); /* gray-900 */
93
+ --color-background: var(--background, oklch(98.5% 0.002 247.839));
94
+ /* gray-50 */
95
+ --color-on-background: var(--on-background, oklch(21% 0.034 264.665));
96
+ /* gray-900 */
87
97
 
88
98
  /* dark */
89
99
  /*--color-background: var(--background, oklch(13% 0.028 261.692)); /* gray-950 */
90
100
  /*--color-on-background: var(--on-background, oklch(96.7% 0.003 264.542)); /* gray-100 */
91
101
 
92
- --color-surface: var(--surface, oklch(96.7% 0.003 264.542)); /* gray-100 */
93
- --color-on-surface: var(--on-surface, oklch(27.9% 0.041 260.031)); /* gray-800 */
102
+ --color-surface: var(--surface, oklch(96.7% 0.003 264.542));
103
+ /* gray-100 */
104
+ --color-on-surface: var(--on-surface, oklch(27.9% 0.041 260.031));
105
+ /* gray-800 */
94
106
 
95
107
  /* dark */
96
108
  /*--color-surface: var(--surface, oklch(21% 0.034 264.665)); /* gray-900 */
97
109
  /*--color-on-surface: var(--on-surface, oklch(92.8% 0.006 264.531)); /* gray-200 */
98
110
 
99
- --color-overlay: var(--overlay, oklch(0 0 0 / 60%)); /* black/60 */
100
- --color-on-overlay: var(--on-overlay, oklch(1 0 0)); /* white */
111
+ --color-overlay: var(--overlay, oklch(0 0 0 / 60%));
112
+ /* black/60 */
113
+ --color-on-overlay: var(--on-overlay, oklch(1 0 0));
114
+ /* white */
101
115
 
102
- --color-success: var(--success, oklch(62.7% 0.194 149.214)); /* green-600 */
103
- --color-on-success: var(--on-success, oklch(96.2% 0.044 156.743)); /* green-100 */
116
+ --color-success: var(--success, oklch(62.7% 0.194 149.214));
117
+ /* green-600 */
118
+ --color-on-success: var(--on-success, oklch(96.2% 0.044 156.743));
119
+ /* green-100 */
104
120
 
105
- --color-info: var(--info, oklch(58.8% 0.158 241.966)); /* sky-600 */
106
- --color-on-info: var(--on-info, oklch(95.1% 0.026 236.824)); /* sky-100 */
121
+ --color-info: var(--info, oklch(58.8% 0.158 241.966));
122
+ /* sky-600 */
123
+ --color-on-info: var(--on-info, oklch(95.1% 0.026 236.824));
124
+ /* sky-100 */
107
125
 
108
- --color-warning: var(--warning, oklch(68.1% 0.162 75.834)); /* yellow-600 */
109
- --color-on-warning: var(--on-warning, oklch(97.3% 0.071 103.193)); /* yellow-100 */
126
+ --color-warning: var(--warning, oklch(68.1% 0.162 75.834));
127
+ /* yellow-600 */
128
+ --color-on-warning: var(--on-warning, oklch(97.3% 0.071 103.193));
129
+ /* yellow-100 */
110
130
 
111
- --color-danger: var(--danger, oklch(57.7% 0.245 27.325)); /* red-600 */
112
- --color-on-danger: var(--on-danger, oklch(93.6% 0.032 17.717)); /* red-100 */
131
+ --color-danger: var(--danger, oklch(57.7% 0.245 27.325));
132
+ /* red-600 */
133
+ --color-on-danger: var(--on-danger, oklch(93.6% 0.032 17.717));
134
+ /* red-100 */
113
135
 
114
136
  --radius-ui: 0.75rem;
115
137
  --scrollbar-size: 6px;
116
- }
138
+ }
package/dist/index.d.ts CHANGED
@@ -9,10 +9,12 @@ import Button from './control/Button.svelte';
9
9
  import IconButton from './control/IconButton.svelte';
10
10
  import Record from './control/Record.svelte';
11
11
  import ToggleTheme from './control/ToggleTheme.svelte';
12
+ import ToggleGroup from './control/ToggleGroup.svelte';
12
13
  import Video from './control/Video.svelte';
13
14
  import Accordion from './display/Accordion.svelte';
14
15
  import Alert from './display/Alert.svelte';
15
16
  import Avatar from './display/Avatar.svelte';
17
+ import AvatarGroup from './display/AvatarGroup.svelte';
16
18
  import Badge from './display/Badge.svelte';
17
19
  import Carousel from './display/Carousel.svelte';
18
20
  import Card from './display/Card.svelte';
@@ -74,5 +76,5 @@ import { useAuth } from './hooks/use-auth.svelte.js';
74
76
  import { theme } from './stores/theme.svelte.js';
75
77
  import { useSearch } from './hooks/use-search.svelte.js';
76
78
  import { useChat } from './hooks/use-chat.svelte.js';
77
- 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, FooterNav, FooterGroup, 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 };
79
+ export { AreaChart, ArcChart, BarChart, Candlestick, LineChart, PieChart, Alert, AlertDialog, AppBar, Accordion, Avatar, AvatarGroup, Audio, Badge, Button, BottomNav, Carousel, Card, ChatBox, Checkbox, Chip, Code, Collapsible, Command, ComboBox, CsvField, DateField, Drawer, Dropzone, Divider, Dropdown, Empty, Footer, FooterNav, FooterGroup, 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, ToggleGroup, ToggleTheme, Tooltip, useAuth, useChat, useClipboard, useFetch, useForm, useLocalStorage, useScroll, useSearch, useTable, useWebSocket, Video };
78
80
  export type { IconData, SideNavItem, SideNavSubItem };
package/dist/index.js CHANGED
@@ -9,10 +9,12 @@ import Button from './control/Button.svelte';
9
9
  import IconButton from './control/IconButton.svelte';
10
10
  import Record from './control/Record.svelte';
11
11
  import ToggleTheme from './control/ToggleTheme.svelte';
12
+ import ToggleGroup from './control/ToggleGroup.svelte';
12
13
  import Video from './control/Video.svelte';
13
14
  import Accordion from './display/Accordion.svelte';
14
15
  import Alert from './display/Alert.svelte';
15
16
  import Avatar from './display/Avatar.svelte';
17
+ import AvatarGroup from './display/AvatarGroup.svelte';
16
18
  import Badge from './display/Badge.svelte';
17
19
  import Carousel from './display/Carousel.svelte';
18
20
  import Card from './display/Card.svelte';
@@ -74,4 +76,4 @@ import { useAuth } from './hooks/use-auth.svelte.js';
74
76
  import { theme } from './stores/theme.svelte.js';
75
77
  import { useSearch } from './hooks/use-search.svelte.js';
76
78
  import { useChat } from './hooks/use-chat.svelte.js';
77
- 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, FooterNav, FooterGroup, 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 };
79
+ export { AreaChart, ArcChart, BarChart, Candlestick, LineChart, PieChart, Alert, AlertDialog, AppBar, Accordion, Avatar, AvatarGroup, Audio, Badge, Button, BottomNav, Carousel, Card, ChatBox, Checkbox, Chip, Code, Collapsible, Command, ComboBox, CsvField, DateField, Drawer, Dropzone, Divider, Dropdown, Empty, Footer, FooterNav, FooterGroup, 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, ToggleGroup, ToggleTheme, Tooltip, useAuth, useChat, useClipboard, useFetch, useForm, useLocalStorage, useScroll, useSearch, useTable, useWebSocket, Video };
@@ -9,13 +9,17 @@
9
9
  icon: IconData;
10
10
  href?: string;
11
11
  onclick?: (item: BottomNavItem) => void;
12
+ badge?: string | number;
13
+ isFab?: boolean;
14
+ isActive?: boolean;
12
15
  };
13
16
 
14
17
  type Props = {
15
18
  items: BottomNavItem[];
16
- variant?: 'primary' | 'secondary' | 'muted';
19
+ variant?: 'primary' | 'secondary' | 'ghost' | 'line';
17
20
  size?: 'sm' | 'md' | 'lg';
18
- showLabels?: boolean;
21
+ isSolid?: boolean;
22
+ isBlock?: boolean;
19
23
  class?: string;
20
24
  };
21
25
 
@@ -24,13 +28,15 @@
24
28
  class: className,
25
29
  variant = 'primary',
26
30
  size = 'md',
27
- showLabels = true
31
+ isSolid = false,
32
+ isBlock = false
28
33
  }: Props = $props();
29
34
 
30
35
  const variantClasses = {
31
- primary: 'bottomnav-primary',
32
- secondary: 'bottomnav-secondary',
33
- muted: 'bottomnav-muted'
36
+ primary: 'is-primary',
37
+ secondary: 'is-secondary',
38
+ ghost: 'is-ghost',
39
+ line: 'is-line'
34
40
  };
35
41
 
36
42
  const sizeClasses = {
@@ -39,9 +45,15 @@
39
45
  lg: 'is-lg'
40
46
  };
41
47
 
42
- function isItemActive(href?: string): boolean {
43
- if (!href) return false;
44
- return page.url.pathname === href || page.url.pathname.startsWith(href + '/');
48
+ // Determine if any item has a label
49
+ const hasLabels = $derived(items.some((item) => item.label));
50
+
51
+ function isItemActive(item: BottomNavItem): boolean {
52
+ // If item has explicit isActive, use that
53
+ if (item.isActive !== undefined) return item.isActive;
54
+ // Otherwise check against current URL
55
+ if (!item.href) return false;
56
+ return page.url.pathname === item.href || page.url.pathname.startsWith(item.href + '/');
45
57
  }
46
58
 
47
59
  function handleItemClick(item: BottomNavItem) {
@@ -56,22 +68,37 @@
56
68
  'bottomnav',
57
69
  variantClasses[variant],
58
70
  sizeClasses[size],
59
- !showLabels && 'is-icon-only',
71
+ isSolid && 'is-solid',
72
+ !hasLabels && 'is-icon-only',
73
+ !isBlock && 'is-fixed',
60
74
  className
61
75
  )}
62
76
  >
63
77
  {#each items as item}
78
+ {@const active = isItemActive(item)}
79
+ {@const itemClass = cn('bottomnav-item', active && 'is-active', item.isFab && 'is-fab')}
80
+
64
81
  {#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}
82
+ <a href={item.href} class={itemClass}>
83
+ <span class="bottomnav-icon-wrapper">
84
+ <Icon icon={item.icon} class="bottomnav-icon" />
85
+ {#if item.badge !== undefined}
86
+ <span class="bottomnav-badge">{item.badge}</span>
87
+ {/if}
88
+ </span>
89
+ {#if item.label}
68
90
  <span class="bottomnav-label">{item.label}</span>
69
91
  {/if}
70
92
  </a>
71
93
  {:else}
72
- <button type="button" class="bottomnav-item" onclick={() => handleItemClick(item)}>
73
- <Icon icon={item.icon} class="bottomnav-icon" />
74
- {#if showLabels && item.label}
94
+ <button type="button" class={itemClass} onclick={() => handleItemClick(item)}>
95
+ <span class="bottomnav-icon-wrapper">
96
+ <Icon icon={item.icon} class="bottomnav-icon" />
97
+ {#if item.badge !== undefined}
98
+ <span class="bottomnav-badge">{item.badge}</span>
99
+ {/if}
100
+ </span>
101
+ {#if item.label}
75
102
  <span class="bottomnav-label">{item.label}</span>
76
103
  {/if}
77
104
  </button>
@@ -26,10 +26,18 @@
26
26
  type Props = {
27
27
  items: MenuItem[];
28
28
  size?: 'sm' | 'md' | 'lg';
29
+ isSolid?: boolean;
30
+ variant?: 'primary' | 'secondary' | 'muted' | 'success' | 'info' | 'warning' | 'danger';
29
31
  class?: string;
30
32
  };
31
33
 
32
- const { items = [], class: className, size = 'md' }: Props = $props();
34
+ const {
35
+ items = [],
36
+ class: className,
37
+ size = 'md',
38
+ isSolid = false,
39
+ variant = 'muted'
40
+ }: Props = $props();
33
41
 
34
42
  let openSubmenuIndex = $state<number | null>(null);
35
43
  let triggerElements = $state<Record<number, HTMLElement>>({});
@@ -48,6 +56,18 @@
48
56
  lg: 'is-lg'
49
57
  };
50
58
 
59
+ const solidClass = $derived(isSolid ? 'is-filled' : 'is-default');
60
+
61
+ const variantClasses = {
62
+ primary: 'is-primary',
63
+ secondary: 'is-secondary',
64
+ muted: 'is-muted',
65
+ success: 'is-success',
66
+ info: 'is-info',
67
+ warning: 'is-warning',
68
+ danger: 'is-danger'
69
+ };
70
+
51
71
  const style = $derived(
52
72
  `top: ${position.top}px; left: ${position.left}px; ${position.width !== 'auto' ? `width: ${position.width}px;` : ''} transform-origin: ${position.isBottomHalf ? 'bottom' : 'top'} center;`
53
73
  );
@@ -165,11 +185,11 @@
165
185
  });
166
186
  </script>
167
187
 
168
- <nav class={cn('navmenu', sizeClasses[size], className)}>
188
+ <nav class={cn('navmenu', sizeClasses[size], solidClass, variantClasses[variant], className)}>
169
189
  {#each items as item, index}
170
190
  {#if item.href && !item.subitems && !item.megamenu}
171
191
  <a href={item.href} class={cn('navmenu-item', isItemActive(item.href) && 'is-active')}>
172
- <span class="navmenu-label">{item.label}</span>
192
+ <span class="navmenu-label" data-text={item.label}>{item.label}</span>
173
193
  </a>
174
194
  {:else}
175
195
  <button
@@ -182,7 +202,7 @@
182
202
  bind:this={triggerElements[index]}
183
203
  onclick={() => handleItemClick(item, index)}
184
204
  >
185
- <span class="navmenu-label">{item.label}</span>
205
+ <span class="navmenu-label" data-text={item.label}>{item.label}</span>
186
206
  {#if item.subitems || item.megamenu}
187
207
  <Icon
188
208
  icon={ChevronDown24RegularIcon}
@@ -199,6 +219,7 @@
199
219
  <div
200
220
  class={cn(
201
221
  'navmenu-popover',
222
+ sizeClasses[size],
202
223
  openSubmenuIndex !== null && 'is-active',
203
224
  position.isMegamenu && 'is-megamenu'
204
225
  )}
@@ -36,6 +36,8 @@
36
36
  isWide?: boolean;
37
37
  isCompact?: boolean;
38
38
  isCollapsible?: boolean;
39
+ isSolid?: boolean;
40
+ variant?: 'primary' | 'secondary' | 'muted' | 'success' | 'info' | 'warning' | 'danger';
39
41
  };
40
42
 
41
43
  const {
@@ -44,7 +46,9 @@
44
46
  size = 'md',
45
47
  isWide,
46
48
  isCompact,
47
- isCollapsible
49
+ isCollapsible,
50
+ isSolid = false,
51
+ variant = 'muted'
48
52
  }: Props = $props();
49
53
 
50
54
  let openSubmenus = $state<Record<number, boolean>>({});
@@ -74,13 +78,25 @@
74
78
  lg: 'is-lg'
75
79
  };
76
80
 
81
+ const solidClass = $derived(isSolid ? 'is-solid' : '');
82
+
83
+ const variantClasses = {
84
+ primary: 'is-primary',
85
+ secondary: 'is-secondary',
86
+ muted: 'is-muted',
87
+ success: 'is-success',
88
+ info: 'is-info',
89
+ warning: 'is-warning',
90
+ danger: 'is-danger'
91
+ };
92
+
77
93
  function toggleSubmenu(index: number) {
78
94
  openSubmenus[index] = !openSubmenus[index];
79
95
  }
80
96
 
81
97
  function isItemActive(href?: string): boolean {
82
98
  if (!href) return false;
83
- return page.url.pathname.includes(href);
99
+ return page.url.pathname === href;
84
100
  }
85
101
 
86
102
  function toggleExpand() {
@@ -112,6 +128,8 @@
112
128
  class={cn(
113
129
  'sidenav',
114
130
  sizeClasses[size],
131
+ solidClass,
132
+ isSolid && variantClasses[variant],
115
133
  isCompact && 'is-compact',
116
134
  isCollapsible && 'is-collapsible',
117
135
  !isExpanded && 'is-collapsed',
@@ -26,6 +26,8 @@ type Props = {
26
26
  isWide?: boolean;
27
27
  isCompact?: boolean;
28
28
  isCollapsible?: boolean;
29
+ isSolid?: boolean;
30
+ variant?: 'primary' | 'secondary' | 'muted' | 'success' | 'info' | 'warning' | 'danger';
29
31
  };
30
32
  declare const SideNav: import("svelte").Component<Props, {}, "">;
31
33
  type SideNav = ReturnType<typeof SideNav>;
@@ -1,19 +1,26 @@
1
1
  @layer components {
2
2
  .bottomnav {
3
- @apply fixed bottom-0 left-0 right-0 z-50;
4
3
  @apply flex items-center justify-around;
5
4
  @apply bg-background text-on-background;
6
5
  @apply border-t border-muted;
7
6
  @apply shadow-lg;
8
- padding-bottom: env(safe-area-inset-bottom);
7
+
8
+ &.is-fixed {
9
+ @apply fixed bottom-0 left-0 right-0 z-50;
10
+ padding-bottom: env(safe-area-inset-bottom);
11
+ }
9
12
 
10
13
  .bottomnav-item {
11
14
  @apply flex flex-col items-center justify-center gap-1;
12
- @apply flex-1 py-2 px-1;
15
+ @apply flex-1 py-3 px-2;
13
16
  @apply cursor-pointer select-none outline-none;
14
17
  @apply transition-all duration-200;
15
18
  @apply relative;
16
19
 
20
+ .bottomnav-icon-wrapper {
21
+ @apply relative inline-flex;
22
+ }
23
+
17
24
  .bottomnav-icon {
18
25
  @apply h-6 w-6 shrink-0;
19
26
  @apply transition-all duration-200;
@@ -24,22 +31,55 @@
24
31
  @apply transition-all duration-200;
25
32
  }
26
33
 
34
+ .bottomnav-badge {
35
+ @apply absolute -top-1.5 -right-2;
36
+ @apply min-w-4 h-4 px-1;
37
+ @apply flex items-center justify-center;
38
+ @apply text-[10px] font-bold;
39
+ @apply bg-danger text-on-danger;
40
+ @apply rounded-full;
41
+ }
42
+
27
43
  &:hover {
28
44
  @apply bg-muted/50;
29
45
  }
30
46
 
31
- &.is-active {
32
- @apply text-primary;
47
+ /* FAB Style */
48
+ &.is-fab {
49
+ @apply flex-none;
50
+
51
+ &:hover {
52
+ @apply bg-transparent;
53
+ }
54
+
55
+ .bottomnav-icon-wrapper {
56
+ @apply w-12 h-12 -mt-6;
57
+ @apply flex items-center justify-center;
58
+ @apply bg-primary text-on-primary;
59
+ @apply rounded-full shadow-lg;
60
+ @apply transition-all duration-200;
61
+ }
33
62
 
34
63
  .bottomnav-icon {
35
- @apply text-primary;
64
+ @apply h-6 w-6 text-on-primary;
65
+ }
66
+
67
+ &:hover .bottomnav-icon-wrapper {
68
+ @apply shadow-xl shadow-primary/30;
69
+ transform: translateY(-2px);
70
+ }
71
+
72
+ &:active .bottomnav-icon-wrapper {
73
+ transform: translateY(0);
74
+ @apply shadow-md;
36
75
  }
37
76
  }
38
77
  }
39
78
 
79
+ /* Size Variants */
40
80
  &.is-sm {
41
81
  .bottomnav-item {
42
- @apply gap-0.5 py-1.5;
82
+ @apply gap-0.5 py-2 px-1;
43
83
 
44
84
  .bottomnav-icon {
45
85
  @apply h-5 w-5;
@@ -48,12 +88,16 @@
48
88
  .bottomnav-label {
49
89
  @apply text-[10px];
50
90
  }
91
+
92
+ &.is-fab .bottomnav-icon-wrapper {
93
+ @apply w-10 h-10 -mt-5;
94
+ }
51
95
  }
52
96
  }
53
97
 
54
98
  &.is-md {
55
99
  .bottomnav-item {
56
- @apply gap-1 py-2;
100
+ @apply gap-1 py-3 px-2;
57
101
 
58
102
  .bottomnav-icon {
59
103
  @apply h-6 w-6;
@@ -67,7 +111,7 @@
67
111
 
68
112
  &.is-lg {
69
113
  .bottomnav-item {
70
- @apply gap-1.5 py-3;
114
+ @apply gap-1.5 py-4 px-3;
71
115
 
72
116
  .bottomnav-icon {
73
117
  @apply h-7 w-7;
@@ -76,6 +120,14 @@
76
120
  .bottomnav-label {
77
121
  @apply text-sm;
78
122
  }
123
+
124
+ &.is-fab .bottomnav-icon-wrapper {
125
+ @apply w-14 h-14 -mt-7;
126
+
127
+ .bottomnav-icon {
128
+ @apply h-7 w-7;
129
+ }
130
+ }
79
131
  }
80
132
  }
81
133
 
@@ -89,7 +141,8 @@
89
141
  }
90
142
  }
91
143
 
92
- &.bottomnav-primary {
144
+ /* Variant: Primary */
145
+ &.is-primary {
93
146
  .bottomnav-item.is-active {
94
147
  @apply text-primary;
95
148
 
@@ -101,9 +154,14 @@
101
154
  @apply text-primary;
102
155
  }
103
156
  }
157
+
158
+ .bottomnav-item.is-fab .bottomnav-icon-wrapper {
159
+ @apply bg-primary;
160
+ }
104
161
  }
105
162
 
106
- &.bottomnav-secondary {
163
+ /* Variant: Secondary */
164
+ &.is-secondary {
107
165
  .bottomnav-item.is-active {
108
166
  @apply text-secondary;
109
167
 
@@ -115,20 +173,86 @@
115
173
  @apply text-secondary;
116
174
  }
117
175
  }
176
+
177
+ .bottomnav-item.is-fab .bottomnav-icon-wrapper {
178
+ @apply bg-secondary;
179
+ }
118
180
  }
119
181
 
120
- &.bottomnav-muted {
182
+ /* Variant: Ghost - just color change, no indicator */
183
+ &.is-ghost {
121
184
  .bottomnav-item.is-active {
122
- @apply bg-muted text-on-muted;
185
+ @apply text-on-surface;
123
186
 
124
187
  .bottomnav-icon {
125
- @apply text-on-muted;
188
+ @apply text-on-surface;
126
189
  }
127
190
 
128
191
  .bottomnav-label {
129
- @apply text-on-muted;
192
+ @apply text-on-surface font-semibold;
130
193
  }
131
194
  }
132
195
  }
196
+
197
+ /* Variant: Line - underline indicator */
198
+ &.is-line {
199
+ .bottomnav-item {
200
+ &::after {
201
+ content: '';
202
+ @apply absolute bottom-0 left-1/2 -translate-x-1/2;
203
+ @apply w-0 h-0.5 rounded-full;
204
+ @apply bg-primary;
205
+ @apply transition-all duration-200;
206
+ }
207
+
208
+ &.is-active {
209
+ @apply text-primary;
210
+
211
+ .bottomnav-icon {
212
+ @apply text-primary;
213
+ }
214
+
215
+ .bottomnav-label {
216
+ @apply text-primary;
217
+ }
218
+
219
+ &::after {
220
+ @apply w-8;
221
+ }
222
+ }
223
+ }
224
+ }
225
+
226
+ /* Solid modifier - adds background pill on active */
227
+ &.is-solid {
228
+ .bottomnav-item {
229
+ @apply relative isolate;
230
+
231
+ &::before {
232
+ content: '';
233
+ @apply absolute inset-x-2 top-1 bottom-1;
234
+ @apply rounded-xl;
235
+ @apply bg-transparent;
236
+ @apply transition-all duration-200;
237
+ z-index: -1;
238
+ }
239
+ }
240
+
241
+ &.is-primary .bottomnav-item.is-active:not(.is-fab)::before {
242
+ @apply bg-primary/10;
243
+ }
244
+
245
+ &.is-secondary .bottomnav-item.is-active:not(.is-fab)::before {
246
+ @apply bg-secondary/10;
247
+ }
248
+
249
+ &.is-ghost .bottomnav-item.is-active:not(.is-fab)::before {
250
+ @apply bg-muted;
251
+ }
252
+
253
+ &.is-line .bottomnav-item.is-active:not(.is-fab)::before {
254
+ @apply bg-primary/10;
255
+ }
256
+ }
133
257
  }
134
258
  }