@getmicdrop/svelte-components 5.12.0 → 5.14.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 (86) hide show
  1. package/dist/calendar/OrderSummary/OrderSummary.svelte +67 -7
  2. package/dist/calendar/OrderSummary/OrderSummary.svelte.d.ts +2 -0
  3. package/dist/calendar/OrderSummary/OrderSummary.svelte.d.ts.map +1 -1
  4. package/dist/index.spec.js +0 -1
  5. package/dist/patterns/navigation/Header.svelte +23 -27
  6. package/dist/patterns/navigation/Header.svelte.d.ts.map +1 -1
  7. package/dist/primitives/AvatarButton/AvatarButton.svelte +57 -0
  8. package/dist/primitives/AvatarButton/AvatarButton.svelte.d.ts +18 -0
  9. package/dist/primitives/AvatarButton/AvatarButton.svelte.d.ts.map +1 -0
  10. package/dist/primitives/BottomSheet/BottomSheet.spec.js +19 -19
  11. package/dist/primitives/BottomSheet/BottomSheet.svelte +5 -5
  12. package/dist/primitives/BottomSheet/BottomSheet.svelte.d.ts +2 -2
  13. package/dist/primitives/BottomSheet/BottomSheet.svelte.d.ts.map +1 -1
  14. package/dist/primitives/BottomSheet/BottomSheetWrapper.test.svelte +3 -3
  15. package/dist/primitives/BottomSheet/BottomSheetWrapper.test.svelte.d.ts +1 -1
  16. package/dist/primitives/Button/Button.spec.js +16 -14
  17. package/dist/primitives/Button/Button.svelte +9 -45
  18. package/dist/primitives/Button/Button.svelte.d.ts.map +1 -1
  19. package/dist/primitives/CardAction/CardAction.svelte +68 -0
  20. package/dist/primitives/CardAction/CardAction.svelte.d.ts +20 -0
  21. package/dist/primitives/CardAction/CardAction.svelte.d.ts.map +1 -0
  22. package/dist/primitives/Drawer/Drawer.spec.js +33 -33
  23. package/dist/primitives/Drawer/Drawer.svelte +5 -9
  24. package/dist/primitives/Drawer/Drawer.svelte.d.ts +2 -3
  25. package/dist/primitives/Drawer/Drawer.svelte.d.ts.map +1 -1
  26. package/dist/primitives/Input/Input.svelte +1 -1
  27. package/dist/primitives/LandingButton/LandingButton.svelte +92 -0
  28. package/dist/primitives/LandingButton/LandingButton.svelte.d.ts +22 -0
  29. package/dist/primitives/LandingButton/LandingButton.svelte.d.ts.map +1 -0
  30. package/dist/primitives/MenuItem/MenuItem.svelte +85 -0
  31. package/dist/primitives/MenuItem/MenuItem.svelte.d.ts +24 -0
  32. package/dist/primitives/MenuItem/MenuItem.svelte.d.ts.map +1 -0
  33. package/dist/primitives/Modal/Modal.spec.js +7 -7
  34. package/dist/primitives/Modal/Modal.stories.svelte +3 -3
  35. package/dist/primitives/Modal/Modal.svelte +25 -18
  36. package/dist/primitives/Modal/Modal.svelte.d.ts +5 -5
  37. package/dist/primitives/Modal/Modal.svelte.d.ts.map +1 -1
  38. package/dist/primitives/Modal/ModalTestWrapper.svelte +3 -3
  39. package/dist/primitives/Modal/ModalTestWrapper.svelte.d.ts +2 -2
  40. package/dist/primitives/NavItem/NavItem.svelte +75 -0
  41. package/dist/primitives/NavItem/NavItem.svelte.d.ts +20 -0
  42. package/dist/primitives/NavItem/NavItem.svelte.d.ts.map +1 -0
  43. package/dist/primitives/SearchResultItem/SearchResultItem.svelte +109 -0
  44. package/dist/primitives/SearchResultItem/SearchResultItem.svelte.d.ts +26 -0
  45. package/dist/primitives/SearchResultItem/SearchResultItem.svelte.d.ts.map +1 -0
  46. package/dist/primitives/SidebarToggle/SidebarToggle.svelte +55 -0
  47. package/dist/primitives/SidebarToggle/SidebarToggle.svelte.d.ts +18 -0
  48. package/dist/primitives/SidebarToggle/SidebarToggle.svelte.d.ts.map +1 -0
  49. package/dist/primitives/index.d.ts +7 -0
  50. package/dist/primitives/index.js +21 -0
  51. package/dist/recipes/SuperLogin/SuperLogin.svelte +3 -3
  52. package/dist/recipes/SuperLogin/SuperLogin.svelte.d.ts.map +1 -1
  53. package/dist/recipes/inputs/index.d.ts +0 -1
  54. package/dist/recipes/inputs/index.js +0 -1
  55. package/dist/recipes/modals/AlertModal.spec.js +2 -2
  56. package/dist/recipes/modals/AlertModal.svelte +6 -6
  57. package/dist/recipes/modals/AlertModal.svelte.d.ts +3 -3
  58. package/dist/recipes/modals/ConfirmationModal.spec.js +2 -2
  59. package/dist/recipes/modals/ConfirmationModal.svelte +5 -5
  60. package/dist/recipes/modals/ConfirmationModal.svelte.d.ts +3 -3
  61. package/dist/recipes/modals/InputModal.spec.js +2 -2
  62. package/dist/recipes/modals/InputModal.svelte +4 -4
  63. package/dist/recipes/modals/InputModal.svelte.d.ts +3 -3
  64. package/dist/recipes/modals/ModalTestWrapper.spec.js +49 -49
  65. package/dist/recipes/modals/ModalTestWrapper.svelte +3 -3
  66. package/dist/recipes/modals/ModalTestWrapper.svelte.d.ts +2 -2
  67. package/dist/recipes/modals/StatusModal.spec.js +2 -2
  68. package/dist/recipes/modals/StatusModal.svelte +4 -4
  69. package/dist/recipes/modals/StatusModal.svelte.d.ts +3 -3
  70. package/dist/stories/ComponentConsolidation.stories.svelte +10 -10
  71. package/dist/stories/PrimitivesGallery.svelte +25 -21
  72. package/dist/stories/PrimitivesGallery.svelte.d.ts.map +1 -1
  73. package/dist/stories/RecipesGallery.spec.js +9 -18
  74. package/dist/stories/RecipesGallery.svelte +5 -22
  75. package/dist/stories/RecipesGallery.svelte.d.ts.map +1 -1
  76. package/dist/tokens/__tests__/sizing.test.js +5 -7
  77. package/dist/tokens/sizing.d.ts +20 -19
  78. package/dist/tokens/sizing.d.ts.map +1 -1
  79. package/dist/tokens/sizing.js +20 -19
  80. package/package.json +1 -1
  81. package/dist/recipes/inputs/SelectDropdown.spec.d.ts +0 -2
  82. package/dist/recipes/inputs/SelectDropdown.spec.d.ts.map +0 -1
  83. package/dist/recipes/inputs/SelectDropdown.spec.js +0 -518
  84. package/dist/recipes/inputs/SelectDropdown.svelte +0 -171
  85. package/dist/recipes/inputs/SelectDropdown.svelte.d.ts +0 -16
  86. package/dist/recipes/inputs/SelectDropdown.svelte.d.ts.map +0 -1
@@ -0,0 +1,92 @@
1
+ <script lang="ts">
2
+ /**
3
+ * LandingButton Component
4
+ * Hero/landing page CTA buttons with shadow and prominent styling.
5
+ *
6
+ * Replaces: Button variant="landing" and variant="landing-secondary"
7
+ */
8
+ import { twMerge } from 'tailwind-merge';
9
+ import type { Snippet } from 'svelte';
10
+ import { buttonSizes } from '../../tokens/sizing.js';
11
+
12
+ interface Props {
13
+ /** Visual style: primary (blue) or secondary (outline) */
14
+ variant?: 'primary' | 'secondary';
15
+ /** Disabled state */
16
+ disabled?: boolean;
17
+ /** Loading state */
18
+ loading?: boolean;
19
+ /** Link href (renders as <a> if provided) */
20
+ href?: string | null;
21
+ /** Content */
22
+ children?: Snippet;
23
+ /** Additional classes */
24
+ class?: string;
25
+ /** Click handler */
26
+ onclick?: (e: MouseEvent) => void;
27
+ [key: string]: unknown;
28
+ }
29
+
30
+ let {
31
+ variant = 'primary',
32
+ disabled = false,
33
+ loading = false,
34
+ href = null,
35
+ children,
36
+ class: className = '',
37
+ onclick,
38
+ ...restProps
39
+ }: Props = $props();
40
+
41
+ let effectiveDisabled = $derived(disabled || loading);
42
+
43
+ const baseClasses = 'inline-flex items-center justify-center rounded-xl font-medium leading-none focus:outline-hidden transition-all duration-150 ease-out select-none no-underline hover:no-underline shadow hover:shadow-md';
44
+
45
+ const variantClasses = {
46
+ primary: 'text-white bg-blue-600 border border-blue-600 hover:bg-blue-700 dark:bg-blue-600 dark:border-blue-600 dark:hover:bg-blue-700',
47
+ secondary: 'text-gray-700 bg-white border border-gray-200 hover:border-gray-400 hover:text-gray-900 dark:text-gray-300 dark:bg-gray-800 dark:border-gray-600 dark:hover:border-gray-500 dark:hover:text-gray-100',
48
+ };
49
+
50
+ const disabledClasses = 'bg-gray-200 border-gray-200 text-gray-400 cursor-not-allowed shadow-none dark:bg-gray-700 dark:border-gray-700 dark:text-gray-500';
51
+
52
+ // Landing size from tokens
53
+ let sizeClass = $derived(buttonSizes.landing);
54
+
55
+ let variantClass = $derived(() => {
56
+ if (effectiveDisabled) return disabledClasses;
57
+ return variantClasses[variant] || variantClasses.primary;
58
+ });
59
+
60
+ let classes = $derived(twMerge(
61
+ baseClasses,
62
+ sizeClass,
63
+ variantClass(),
64
+ effectiveDisabled ? 'cursor-not-allowed' : 'cursor-pointer active:scale-[0.97] active:opacity-90',
65
+ className
66
+ ));
67
+ </script>
68
+
69
+ {#if href}
70
+ <a
71
+ {href}
72
+ class={classes}
73
+ {onclick}
74
+ {...restProps}
75
+ >
76
+ <span class="inline-flex items-center gap-1.5" class:invisible={loading}>
77
+ {#if typeof children === 'function'}{@render children()}{:else if children}{children}{/if}
78
+ </span>
79
+ </a>
80
+ {:else}
81
+ <button
82
+ type="button"
83
+ class={classes}
84
+ disabled={effectiveDisabled}
85
+ {onclick}
86
+ {...restProps}
87
+ >
88
+ <span class="inline-flex items-center gap-1.5" class:invisible={loading}>
89
+ {#if typeof children === 'function'}{@render children()}{:else if children}{children}{/if}
90
+ </span>
91
+ </button>
92
+ {/if}
@@ -0,0 +1,22 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ /** Visual style: primary (blue) or secondary (outline) */
4
+ variant?: 'primary' | 'secondary';
5
+ /** Disabled state */
6
+ disabled?: boolean;
7
+ /** Loading state */
8
+ loading?: boolean;
9
+ /** Link href (renders as <a> if provided) */
10
+ href?: string | null;
11
+ /** Content */
12
+ children?: Snippet;
13
+ /** Additional classes */
14
+ class?: string;
15
+ /** Click handler */
16
+ onclick?: (e: MouseEvent) => void;
17
+ [key: string]: unknown;
18
+ }
19
+ declare const LandingButton: import("svelte").Component<Props, {}, "">;
20
+ type LandingButton = ReturnType<typeof LandingButton>;
21
+ export default LandingButton;
22
+ //# sourceMappingURL=LandingButton.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LandingButton.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/LandingButton/LandingButton.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAIpC,UAAU,KAAK;IACb,0DAA0D;IAC1D,OAAO,CAAC,EAAE,SAAS,GAAG,WAAW,CAAC;IAClC,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oBAAoB;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,cAAc;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yBAAyB;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;IAClC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AA+DH,QAAA,MAAM,aAAa,2CAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
@@ -0,0 +1,85 @@
1
+ <script lang="ts">
2
+ /**
3
+ * MenuItem Component
4
+ * For dropdown menus, action sheets, and sidebar navigation items.
5
+ *
6
+ * Replaces: Button variant="menu-item" and variant="menu-item-danger"
7
+ */
8
+ import { twMerge } from 'tailwind-merge';
9
+ import type { Snippet } from 'svelte';
10
+ import { buttonMenuItemSizes } from '../../tokens/sizing.js';
11
+
12
+ interface Props {
13
+ /** Destructive/danger styling (red text) */
14
+ danger?: boolean;
15
+ /** Size variant */
16
+ size?: 'sm' | 'md' | 'lg' | 'nav';
17
+ /** Disabled state */
18
+ disabled?: boolean;
19
+ /** Active/selected state */
20
+ active?: boolean;
21
+ /** Content */
22
+ children?: Snippet;
23
+ /** Trailing content (icons, badges) */
24
+ trailing?: Snippet;
25
+ /** Additional classes */
26
+ class?: string;
27
+ /** Click handler */
28
+ onclick?: (e: MouseEvent) => void;
29
+ [key: string]: unknown;
30
+ }
31
+
32
+ let {
33
+ danger = false,
34
+ size = 'md',
35
+ disabled = false,
36
+ active = false,
37
+ children,
38
+ trailing,
39
+ class: className = '',
40
+ onclick,
41
+ ...restProps
42
+ }: Props = $props();
43
+
44
+ const baseClasses = 'w-full text-left whitespace-nowrap bg-transparent border-transparent rounded-lg font-medium leading-none focus:outline-hidden transition-all duration-150 ease-out select-none';
45
+
46
+ const variantClasses = {
47
+ default: 'text-gray-900 hover:bg-gray-100 dark:text-white dark:hover:bg-gray-600',
48
+ danger: 'text-red-600 hover:bg-red-50 dark:text-red-500 dark:hover:bg-gray-600',
49
+ };
50
+
51
+ const activeClasses = 'bg-blue-50 dark:bg-gray-700';
52
+ const disabledClasses = 'text-gray-400 cursor-not-allowed dark:text-gray-500';
53
+
54
+ let sizeClass = $derived(buttonMenuItemSizes[size] || buttonMenuItemSizes.md);
55
+
56
+ let variantClass = $derived(() => {
57
+ if (disabled) return disabledClasses;
58
+ if (active) return `${variantClasses[danger ? 'danger' : 'default']} ${activeClasses}`;
59
+ return variantClasses[danger ? 'danger' : 'default'];
60
+ });
61
+
62
+ let hasTrailing = $derived(typeof trailing === 'function' || trailing);
63
+
64
+ let classes = $derived(twMerge(
65
+ baseClasses,
66
+ hasTrailing ? 'flex items-center justify-between' : 'flex items-center justify-start',
67
+ sizeClass,
68
+ variantClass(),
69
+ disabled ? 'cursor-not-allowed' : 'cursor-pointer active:scale-[0.97] active:opacity-90',
70
+ className
71
+ ));
72
+ </script>
73
+
74
+ <button
75
+ type="button"
76
+ class={classes}
77
+ {disabled}
78
+ {onclick}
79
+ {...restProps}
80
+ >
81
+ <span class="inline-flex items-center gap-1.5">
82
+ {#if typeof children === 'function'}{@render children()}{:else if children}{children}{/if}
83
+ </span>
84
+ {#if typeof trailing === 'function'}{@render trailing()}{:else if trailing}{trailing}{/if}
85
+ </button>
@@ -0,0 +1,24 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ /** Destructive/danger styling (red text) */
4
+ danger?: boolean;
5
+ /** Size variant */
6
+ size?: 'sm' | 'md' | 'lg' | 'nav';
7
+ /** Disabled state */
8
+ disabled?: boolean;
9
+ /** Active/selected state */
10
+ active?: boolean;
11
+ /** Content */
12
+ children?: Snippet;
13
+ /** Trailing content (icons, badges) */
14
+ trailing?: Snippet;
15
+ /** Additional classes */
16
+ class?: string;
17
+ /** Click handler */
18
+ onclick?: (e: MouseEvent) => void;
19
+ [key: string]: unknown;
20
+ }
21
+ declare const MenuItem: import("svelte").Component<Props, {}, "">;
22
+ type MenuItem = ReturnType<typeof MenuItem>;
23
+ export default MenuItem;
24
+ //# sourceMappingURL=MenuItem.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MenuItem.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/MenuItem/MenuItem.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAIpC,UAAU,KAAK;IACb,4CAA4C;IAC5C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,mBAAmB;IACnB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC;IAClC,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,4BAA4B;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,cAAc;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yBAAyB;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;IAClC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AA2DH,QAAA,MAAM,QAAQ,2CAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
@@ -14,9 +14,9 @@ describe('Modal Component Tests', () => {
14
14
  // CSS hides one based on viewport, but in tests both are in DOM
15
15
  // Use getAllByText and check that at least one exists
16
16
 
17
- test('Renders Modal when show is true', () => {
17
+ test('Renders Modal when open is true', () => {
18
18
  setupTest({
19
- show: true,
19
+ open: true,
20
20
  title: 'Test Title',
21
21
  description: 'Test Description',
22
22
  warningText: 'Test Warning'
@@ -29,9 +29,9 @@ describe('Modal Component Tests', () => {
29
29
  expect(screen.getAllByRole('button', { name: /Confirm/i }).length).toBeGreaterThan(0);
30
30
  });
31
31
 
32
- test('Does not render Modal when show is false', () => {
32
+ test('Does not render Modal when open is false', () => {
33
33
  setupTest({
34
- show: false,
34
+ open: false,
35
35
  title: 'Test Title',
36
36
  description: 'Test Description',
37
37
  warningText: 'Test Warning'
@@ -46,7 +46,7 @@ describe('Modal Component Tests', () => {
46
46
  const description = 'Correct Description';
47
47
  const warningText = 'Correct Warning';
48
48
  setupTest({
49
- show: true,
49
+ open: true,
50
50
  title,
51
51
  description,
52
52
  warningText,
@@ -62,7 +62,7 @@ describe('Modal Component Tests', () => {
62
62
  const oncancel = vi.fn();
63
63
 
64
64
  const { user } = setupTest({
65
- show: true,
65
+ open: true,
66
66
  title: 'Test Title',
67
67
  oncancel
68
68
  });
@@ -79,7 +79,7 @@ describe('Modal Component Tests', () => {
79
79
 
80
80
  test('Prevents propagation of click events within modal', async () => {
81
81
  const { user } = setupTest({
82
- show: true,
82
+ open: true,
83
83
  title: 'Test Title'
84
84
  });
85
85
 
@@ -22,7 +22,7 @@
22
22
  >
23
23
  Open Basic Modal
24
24
  </button>
25
- <ModalProgress bind:show={show1}>
25
+ <ModalProgress bind:open={show1}>
26
26
  {#snippet header()}
27
27
  <h2 class="text-xl font-semibold mb-2">Modal Title</h2>
28
28
  {/snippet}
@@ -47,7 +47,7 @@
47
47
  >
48
48
  Open Processing Modal
49
49
  </button>
50
- <ModalProgress bind:show={show2} isProcessing={true}>
50
+ <ModalProgress bind:open={show2} isProcessing={true}>
51
51
  {#snippet body()}
52
52
  <div class="flex flex-col items-center gap-4">
53
53
  <div
@@ -66,7 +66,7 @@
66
66
  >
67
67
  Open Success Modal
68
68
  </button>
69
- <ModalProgress bind:show={show3} isSuccess={true}>
69
+ <ModalProgress bind:open={show3} isSuccess={true}>
70
70
  {#snippet body()}
71
71
  <div class="flex flex-col items-center gap-4 text-center">
72
72
  <div class="text-green-600 dark:text-green-400 text-5xl">✓</div>
@@ -13,10 +13,10 @@
13
13
  import { triggerHaptic } from "../../utils/haptic.js";
14
14
 
15
15
  /** @type {{
16
- show?: boolean,
16
+ open?: boolean,
17
17
  isProcessing?: boolean,
18
18
  isSuccess?: boolean,
19
- size?: 'default' | 'small' | 'large' | 'xlarge',
19
+ size?: 'sm' | 'md' | 'lg' | 'xl',
20
20
  persistent?: boolean,
21
21
  haptic?: boolean,
22
22
  oncancel?: () => void,
@@ -26,10 +26,10 @@
26
26
  class?: string,
27
27
  }} */
28
28
  let {
29
- show = $bindable(false),
29
+ open = $bindable(false),
30
30
  isProcessing = false,
31
31
  isSuccess = false,
32
- size = "default",
32
+ size = "md",
33
33
  persistent = false,
34
34
  haptic = true,
35
35
  oncancel,
@@ -43,55 +43,61 @@
43
43
  // Store scroll position for iOS scroll lock
44
44
  let scrollY = $state(0);
45
45
 
46
- // Track previous show state to detect open transitions
47
- let prevShow = $state(false);
46
+ // Track previous open state to detect open transitions
47
+ let prevOpen = $state(false);
48
48
 
49
49
  // Trigger haptic on modal open (QOL Bible)
50
50
  $effect(() => {
51
- if (show && !prevShow && haptic) {
51
+ if (open && !prevOpen && haptic) {
52
52
  triggerHaptic('light');
53
53
  }
54
- prevShow = show;
54
+ prevOpen = open;
55
55
  });
56
56
 
57
57
  // Handle escape key
58
58
  function handleKeydown(event) {
59
- if (event.key === "Escape" && show && !persistent) {
59
+ if (event.key === "Escape" && open && !persistent) {
60
60
  resetModal();
61
61
  }
62
62
  }
63
63
 
64
64
  const resetModal = () => {
65
65
  oncancel?.();
66
- show = false;
66
+ open = false;
67
67
  };
68
68
 
69
- // Size classes for desktop modal (Tailwind scale)
69
+ // Size classes for desktop modal (xs/sm/md/lg/xl scale)
70
70
  const sizeClasses = {
71
- default: "max-w-md",
72
- small: "max-w-sm",
73
- large: "max-w-xl",
74
- xlarge: "max-w-2xl"
71
+ sm: "max-w-sm",
72
+ md: "max-w-md",
73
+ lg: "max-w-xl",
74
+ xl: "max-w-2xl"
75
75
  };
76
76
 
77
- let modalSizeClass = $derived(sizeClasses[size] || sizeClasses.default);
77
+ let modalSizeClass = $derived(sizeClasses[size] || sizeClasses.md);
78
78
 
79
79
  // iOS-compatible scroll lock using position:fixed approach
80
+ // Also compensates for scrollbar width to prevent layout shift
80
81
  $effect(() => {
81
82
  if (typeof document !== "undefined") {
82
- if (show) {
83
+ if (open) {
83
84
  scrollY = window.scrollY;
85
+ // Calculate scrollbar width before hiding it
86
+ const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
84
87
  document.body.style.position = "fixed";
85
88
  document.body.style.top = `-${scrollY}px`;
86
89
  document.body.style.left = "0";
87
90
  document.body.style.right = "0";
88
91
  document.body.style.overflow = "hidden";
92
+ // Add padding to compensate for scrollbar disappearing
93
+ document.body.style.paddingRight = `${scrollbarWidth}px`;
89
94
  } else {
90
95
  document.body.style.position = "";
91
96
  document.body.style.top = "";
92
97
  document.body.style.left = "";
93
98
  document.body.style.right = "";
94
99
  document.body.style.overflow = "";
100
+ document.body.style.paddingRight = "";
95
101
  window.scrollTo(0, scrollY);
96
102
  }
97
103
  }
@@ -104,13 +110,14 @@
104
110
  document.body.style.left = "";
105
111
  document.body.style.right = "";
106
112
  document.body.style.overflow = "";
113
+ document.body.style.paddingRight = "";
107
114
  }
108
115
  });
109
116
  </script>
110
117
 
111
118
  <svelte:window onkeydown={handleKeydown} />
112
119
 
113
- {#if show}
120
+ {#if open}
114
121
  <!-- svelte-ignore a11y_click_events_have_key_events -->
115
122
  <!-- svelte-ignore a11y_no_static_element_interactions -->
116
123
  <div
@@ -2,10 +2,10 @@ export default Modal;
2
2
  type Modal = {
3
3
  $on?(type: string, callback: (e: any) => void): () => void;
4
4
  $set?(props: Partial<{
5
- show?: boolean | undefined;
5
+ open?: boolean | undefined;
6
6
  isProcessing?: boolean | undefined;
7
7
  isSuccess?: boolean | undefined;
8
- size?: "small" | "large" | "default" | "xlarge" | undefined;
8
+ size?: "sm" | "md" | "lg" | "xl" | undefined;
9
9
  persistent?: boolean | undefined;
10
10
  haptic?: boolean | undefined;
11
11
  oncancel?: (() => void) | undefined;
@@ -16,10 +16,10 @@ type Modal = {
16
16
  }>): void;
17
17
  };
18
18
  declare const Modal: import("svelte").Component<{
19
- show?: boolean;
19
+ open?: boolean;
20
20
  isProcessing?: boolean;
21
21
  isSuccess?: boolean;
22
- size?: "default" | "small" | "large" | "xlarge";
22
+ size?: "sm" | "md" | "lg" | "xl";
23
23
  persistent?: boolean;
24
24
  haptic?: boolean;
25
25
  oncancel?: () => void;
@@ -27,5 +27,5 @@ declare const Modal: import("svelte").Component<{
27
27
  body?: import("svelte").Snippet;
28
28
  footer?: import("svelte").Snippet;
29
29
  class?: string;
30
- }, {}, "show">;
30
+ }, {}, "open">;
31
31
  //# sourceMappingURL=Modal.svelte.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Modal.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/Modal/Modal.svelte.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAsLA;WAZW,OAAO;mBACC,OAAO;gBACV,OAAO;WACZ,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ;iBAClC,OAAO;aACX,OAAO;eACL,MAAM,IAAI;aACZ,OAAO,QAAQ,EAAE,OAAO;WAC1B,OAAO,QAAQ,EAAE,OAAO;aACtB,OAAO,QAAQ,EAAE,OAAO;YACzB,MAAM;eAEkC"}
1
+ {"version":3,"file":"Modal.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/Modal/Modal.svelte.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AA6LA;WAZW,OAAO;mBACC,OAAO;gBACV,OAAO;WACZ,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI;iBACnB,OAAO;aACX,OAAO;eACL,MAAM,IAAI;aACZ,OAAO,QAAQ,EAAE,OAAO;WAC1B,OAAO,QAAQ,EAAE,OAAO;aACtB,OAAO,QAAQ,EAAE,OAAO;YACzB,MAAM;eAEkC"}
@@ -5,7 +5,7 @@
5
5
 
6
6
  interface Props {
7
7
  /** Whether the modal is visible */
8
- show?: boolean;
8
+ open?: boolean;
9
9
  /** Modal title */
10
10
  title?: string;
11
11
  /** Modal description */
@@ -23,7 +23,7 @@
23
23
  }
24
24
 
25
25
  let {
26
- show = $bindable(false),
26
+ open = $bindable(false),
27
27
  title = '',
28
28
  description = '',
29
29
  warningText = '',
@@ -34,7 +34,7 @@
34
34
  }: Props = $props();
35
35
  </script>
36
36
 
37
- <Modal bind:show {oncancel}>
37
+ <Modal bind:open {oncancel}>
38
38
  {#snippet header()}
39
39
  {#if customHeader}
40
40
  {@render customHeader()}
@@ -1,7 +1,7 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  interface Props {
3
3
  /** Whether the modal is visible */
4
- show?: boolean;
4
+ open?: boolean;
5
5
  /** Modal title */
6
6
  title?: string;
7
7
  /** Modal description */
@@ -17,7 +17,7 @@ interface Props {
17
17
  /** Custom footer snippet */
18
18
  customFooter?: Snippet;
19
19
  }
20
- declare const ModalTestWrapper: import("svelte").Component<Props, {}, "show">;
20
+ declare const ModalTestWrapper: import("svelte").Component<Props, {}, "open">;
21
21
  type ModalTestWrapper = ReturnType<typeof ModalTestWrapper>;
22
22
  export default ModalTestWrapper;
23
23
  //# sourceMappingURL=ModalTestWrapper.svelte.d.ts.map
@@ -0,0 +1,75 @@
1
+ <script lang="ts">
2
+ /**
3
+ * NavItem Component
4
+ * Bottom navigation item with vertical layout.
5
+ *
6
+ * Replaces: Button variant="nav"
7
+ */
8
+ import { twMerge } from 'tailwind-merge';
9
+ import type { Snippet } from 'svelte';
10
+
11
+ interface Props {
12
+ /** Active/selected state */
13
+ active?: boolean;
14
+ /** Disabled state */
15
+ disabled?: boolean;
16
+ /** Link href (renders as <a> if provided) */
17
+ href?: string | null;
18
+ /** Content (icon + label) */
19
+ children?: Snippet;
20
+ /** Additional classes */
21
+ class?: string;
22
+ /** Click handler */
23
+ onclick?: (e: MouseEvent) => void;
24
+ [key: string]: unknown;
25
+ }
26
+
27
+ let {
28
+ active = false,
29
+ disabled = false,
30
+ href = null,
31
+ children,
32
+ class: className = '',
33
+ onclick,
34
+ ...restProps
35
+ }: Props = $props();
36
+
37
+ const baseClasses = 'flex flex-col items-center justify-center h-full py-2 bg-transparent border-transparent rounded-lg font-medium leading-none focus:outline-hidden transition-all duration-150 ease-out select-none';
38
+ const defaultClasses = 'text-gray-500 hover:text-blue-600 dark:text-gray-400 dark:hover:text-blue-500';
39
+ const activeClasses = 'text-blue-600 dark:text-blue-500';
40
+ const disabledClasses = 'text-gray-400 cursor-not-allowed dark:text-gray-500';
41
+
42
+ let variantClass = $derived(() => {
43
+ if (disabled) return disabledClasses;
44
+ if (active) return activeClasses;
45
+ return defaultClasses;
46
+ });
47
+
48
+ let classes = $derived(twMerge(
49
+ baseClasses,
50
+ variantClass(),
51
+ disabled ? 'cursor-not-allowed' : 'cursor-pointer',
52
+ className
53
+ ));
54
+ </script>
55
+
56
+ {#if href}
57
+ <a
58
+ {href}
59
+ class={classes}
60
+ {onclick}
61
+ {...restProps}
62
+ >
63
+ {#if typeof children === 'function'}{@render children()}{:else if children}{children}{/if}
64
+ </a>
65
+ {:else}
66
+ <button
67
+ type="button"
68
+ class={classes}
69
+ {disabled}
70
+ {onclick}
71
+ {...restProps}
72
+ >
73
+ {#if typeof children === 'function'}{@render children()}{:else if children}{children}{/if}
74
+ </button>
75
+ {/if}
@@ -0,0 +1,20 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ /** Active/selected state */
4
+ active?: boolean;
5
+ /** Disabled state */
6
+ disabled?: boolean;
7
+ /** Link href (renders as <a> if provided) */
8
+ href?: string | null;
9
+ /** Content (icon + label) */
10
+ children?: Snippet;
11
+ /** Additional classes */
12
+ class?: string;
13
+ /** Click handler */
14
+ onclick?: (e: MouseEvent) => void;
15
+ [key: string]: unknown;
16
+ }
17
+ declare const NavItem: import("svelte").Component<Props, {}, "">;
18
+ type NavItem = ReturnType<typeof NavItem>;
19
+ export default NavItem;
20
+ //# sourceMappingURL=NavItem.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NavItem.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/NavItem/NavItem.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGpC,UAAU,KAAK;IACb,4BAA4B;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yBAAyB;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;IAClC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAgDH,QAAA,MAAM,OAAO,2CAAwC,CAAC;AACtD,KAAK,OAAO,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAC1C,eAAe,OAAO,CAAC"}