@getmicdrop/svelte-components 5.12.0 → 5.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.spec.js +0 -1
- package/dist/patterns/navigation/Header.svelte +23 -27
- package/dist/patterns/navigation/Header.svelte.d.ts.map +1 -1
- package/dist/primitives/AvatarButton/AvatarButton.svelte +57 -0
- package/dist/primitives/AvatarButton/AvatarButton.svelte.d.ts +18 -0
- package/dist/primitives/AvatarButton/AvatarButton.svelte.d.ts.map +1 -0
- package/dist/primitives/BottomSheet/BottomSheet.spec.js +19 -19
- package/dist/primitives/BottomSheet/BottomSheet.svelte +5 -5
- package/dist/primitives/BottomSheet/BottomSheet.svelte.d.ts +2 -2
- package/dist/primitives/BottomSheet/BottomSheet.svelte.d.ts.map +1 -1
- package/dist/primitives/BottomSheet/BottomSheetWrapper.test.svelte +3 -3
- package/dist/primitives/BottomSheet/BottomSheetWrapper.test.svelte.d.ts +1 -1
- package/dist/primitives/Button/Button.spec.js +8 -8
- package/dist/primitives/Button/Button.svelte +9 -45
- package/dist/primitives/Button/Button.svelte.d.ts.map +1 -1
- package/dist/primitives/CardAction/CardAction.svelte +68 -0
- package/dist/primitives/CardAction/CardAction.svelte.d.ts +20 -0
- package/dist/primitives/CardAction/CardAction.svelte.d.ts.map +1 -0
- package/dist/primitives/Drawer/Drawer.spec.js +33 -33
- package/dist/primitives/Drawer/Drawer.svelte +5 -9
- package/dist/primitives/Drawer/Drawer.svelte.d.ts +2 -3
- package/dist/primitives/Drawer/Drawer.svelte.d.ts.map +1 -1
- package/dist/primitives/LandingButton/LandingButton.svelte +92 -0
- package/dist/primitives/LandingButton/LandingButton.svelte.d.ts +22 -0
- package/dist/primitives/LandingButton/LandingButton.svelte.d.ts.map +1 -0
- package/dist/primitives/MenuItem/MenuItem.svelte +85 -0
- package/dist/primitives/MenuItem/MenuItem.svelte.d.ts +24 -0
- package/dist/primitives/MenuItem/MenuItem.svelte.d.ts.map +1 -0
- package/dist/primitives/Modal/Modal.spec.js +7 -7
- package/dist/primitives/Modal/Modal.stories.svelte +3 -3
- package/dist/primitives/Modal/Modal.svelte +25 -18
- package/dist/primitives/Modal/Modal.svelte.d.ts +5 -5
- package/dist/primitives/Modal/Modal.svelte.d.ts.map +1 -1
- package/dist/primitives/Modal/ModalTestWrapper.svelte +3 -3
- package/dist/primitives/Modal/ModalTestWrapper.svelte.d.ts +2 -2
- package/dist/primitives/NavItem/NavItem.svelte +75 -0
- package/dist/primitives/NavItem/NavItem.svelte.d.ts +20 -0
- package/dist/primitives/NavItem/NavItem.svelte.d.ts.map +1 -0
- package/dist/primitives/SearchResultItem/SearchResultItem.svelte +109 -0
- package/dist/primitives/SearchResultItem/SearchResultItem.svelte.d.ts +26 -0
- package/dist/primitives/SearchResultItem/SearchResultItem.svelte.d.ts.map +1 -0
- package/dist/primitives/SidebarToggle/SidebarToggle.svelte +55 -0
- package/dist/primitives/SidebarToggle/SidebarToggle.svelte.d.ts +18 -0
- package/dist/primitives/SidebarToggle/SidebarToggle.svelte.d.ts.map +1 -0
- package/dist/primitives/index.d.ts +7 -0
- package/dist/primitives/index.js +21 -0
- package/dist/recipes/SuperLogin/SuperLogin.svelte +3 -3
- package/dist/recipes/SuperLogin/SuperLogin.svelte.d.ts.map +1 -1
- package/dist/recipes/inputs/index.d.ts +0 -1
- package/dist/recipes/inputs/index.js +0 -1
- package/dist/recipes/modals/AlertModal.spec.js +2 -2
- package/dist/recipes/modals/AlertModal.svelte +6 -6
- package/dist/recipes/modals/AlertModal.svelte.d.ts +3 -3
- package/dist/recipes/modals/ConfirmationModal.spec.js +2 -2
- package/dist/recipes/modals/ConfirmationModal.svelte +5 -5
- package/dist/recipes/modals/ConfirmationModal.svelte.d.ts +3 -3
- package/dist/recipes/modals/InputModal.spec.js +2 -2
- package/dist/recipes/modals/InputModal.svelte +4 -4
- package/dist/recipes/modals/InputModal.svelte.d.ts +3 -3
- package/dist/recipes/modals/ModalTestWrapper.spec.js +49 -49
- package/dist/recipes/modals/ModalTestWrapper.svelte +3 -3
- package/dist/recipes/modals/ModalTestWrapper.svelte.d.ts +2 -2
- package/dist/recipes/modals/StatusModal.spec.js +2 -2
- package/dist/recipes/modals/StatusModal.svelte +4 -4
- package/dist/recipes/modals/StatusModal.svelte.d.ts +3 -3
- package/dist/stories/ComponentConsolidation.stories.svelte +10 -10
- package/dist/stories/PrimitivesGallery.svelte +25 -21
- package/dist/stories/PrimitivesGallery.svelte.d.ts.map +1 -1
- package/dist/stories/RecipesGallery.spec.js +9 -18
- package/dist/stories/RecipesGallery.svelte +5 -22
- package/dist/stories/RecipesGallery.svelte.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/recipes/inputs/SelectDropdown.spec.d.ts +0 -2
- package/dist/recipes/inputs/SelectDropdown.spec.d.ts.map +0 -1
- package/dist/recipes/inputs/SelectDropdown.spec.js +0 -518
- package/dist/recipes/inputs/SelectDropdown.svelte +0 -171
- package/dist/recipes/inputs/SelectDropdown.svelte.d.ts +0 -16
- package/dist/recipes/inputs/SelectDropdown.svelte.d.ts.map +0 -1
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
/** Size variant */
|
|
4
|
+
size?: 'sm' | 'md' | 'lg';
|
|
5
|
+
/** Disabled state */
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
/** Selected/active state */
|
|
8
|
+
selected?: boolean;
|
|
9
|
+
/** Content */
|
|
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 CardAction: import("svelte").Component<Props, {}, "">;
|
|
18
|
+
type CardAction = ReturnType<typeof CardAction>;
|
|
19
|
+
export default CardAction;
|
|
20
|
+
//# sourceMappingURL=CardAction.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CardAction.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/CardAction/CardAction.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAIpC,UAAU,KAAK;IACb,mBAAmB;IACnB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,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;AA8CH,QAAA,MAAM,UAAU,2CAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|
|
@@ -14,52 +14,52 @@ describe('Drawer Component', () => {
|
|
|
14
14
|
document.body.style.overflow = '';
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
test('does not render when
|
|
18
|
-
const { container } = render(Drawer, { props: {
|
|
17
|
+
test('does not render when open is false', () => {
|
|
18
|
+
const { container } = render(Drawer, { props: { open: false } });
|
|
19
19
|
expect(container.querySelector('[role="dialog"]')).not.toBeInTheDocument();
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
-
test('renders when
|
|
23
|
-
const { container } = render(Drawer, { props: {
|
|
22
|
+
test('renders when open is true', () => {
|
|
23
|
+
const { container } = render(Drawer, { props: { open: true } });
|
|
24
24
|
expect(container.querySelector('[role="dialog"]')).toBeInTheDocument();
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
test('renders when
|
|
28
|
-
const { container } = render(Drawer, { props: {
|
|
27
|
+
test('renders when open is true (explicit)', () => {
|
|
28
|
+
const { container } = render(Drawer, { props: { open: true } });
|
|
29
29
|
expect(container.querySelector('[role="dialog"]')).toBeInTheDocument();
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
test('has role="dialog" and aria-modal="true"', () => {
|
|
33
|
-
const { container } = render(Drawer, { props: {
|
|
33
|
+
const { container } = render(Drawer, { props: { open: true } });
|
|
34
34
|
const dialog = container.querySelector('[role="dialog"]');
|
|
35
35
|
expect(dialog).toHaveAttribute('aria-modal', 'true');
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
test('renders title when provided', () => {
|
|
39
|
-
render(Drawer, { props: {
|
|
39
|
+
render(Drawer, { props: { open: true, title: 'Test Drawer', id: 'test-drawer' } });
|
|
40
40
|
expect(screen.getByText('Test Drawer')).toBeInTheDocument();
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
test('applies custom className', () => {
|
|
44
|
-
const { container } = render(Drawer, { props: {
|
|
44
|
+
const { container } = render(Drawer, { props: { open: true, class: 'custom-drawer' } });
|
|
45
45
|
const dialog = container.querySelector('[role="dialog"]');
|
|
46
46
|
expect(dialog).toHaveClass('custom-drawer');
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
test('renders backdrop by default when visible', () => {
|
|
50
|
-
const { container } = render(Drawer, { props: {
|
|
50
|
+
const { container } = render(Drawer, { props: { open: true } });
|
|
51
51
|
const backdrop = container.querySelector('[role="presentation"]');
|
|
52
52
|
expect(backdrop).toBeInTheDocument();
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
test('does not render backdrop when backdrop is false', () => {
|
|
56
|
-
const { container } = render(Drawer, { props: {
|
|
56
|
+
const { container } = render(Drawer, { props: { open: true, backdrop: false } });
|
|
57
57
|
const backdrop = container.querySelector('[role="presentation"]');
|
|
58
58
|
expect(backdrop).not.toBeInTheDocument();
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
test('passes through id prop', () => {
|
|
62
|
-
const { container } = render(Drawer, { props: {
|
|
62
|
+
const { container } = render(Drawer, { props: { open: true, id: 'my-drawer' } });
|
|
63
63
|
const dialog = container.querySelector('#my-drawer');
|
|
64
64
|
expect(dialog).toBeInTheDocument();
|
|
65
65
|
});
|
|
@@ -67,25 +67,25 @@ describe('Drawer Component', () => {
|
|
|
67
67
|
|
|
68
68
|
describe('Drawer Placements', () => {
|
|
69
69
|
test('left placement has left-0 class', () => {
|
|
70
|
-
const { container } = render(Drawer, { props: {
|
|
70
|
+
const { container } = render(Drawer, { props: { open: true, placement: 'left' } });
|
|
71
71
|
const dialog = container.querySelector('[role="dialog"]');
|
|
72
72
|
expect(dialog).toHaveClass('left-0');
|
|
73
73
|
});
|
|
74
74
|
|
|
75
75
|
test('right placement has right-0 class', () => {
|
|
76
|
-
const { container } = render(Drawer, { props: {
|
|
76
|
+
const { container } = render(Drawer, { props: { open: true, placement: 'right' } });
|
|
77
77
|
const dialog = container.querySelector('[role="dialog"]');
|
|
78
78
|
expect(dialog).toHaveClass('right-0');
|
|
79
79
|
});
|
|
80
80
|
|
|
81
81
|
test('top placement has top-0 class', () => {
|
|
82
|
-
const { container } = render(Drawer, { props: {
|
|
82
|
+
const { container } = render(Drawer, { props: { open: true, placement: 'top' } });
|
|
83
83
|
const dialog = container.querySelector('[role="dialog"]');
|
|
84
84
|
expect(dialog).toHaveClass('top-0');
|
|
85
85
|
});
|
|
86
86
|
|
|
87
87
|
test('bottom placement has bottom-0 class', () => {
|
|
88
|
-
const { container } = render(Drawer, { props: {
|
|
88
|
+
const { container } = render(Drawer, { props: { open: true, placement: 'bottom' } });
|
|
89
89
|
const dialog = container.querySelector('[role="dialog"]');
|
|
90
90
|
expect(dialog).toHaveClass('bottom-0');
|
|
91
91
|
});
|
|
@@ -93,25 +93,25 @@ describe('Drawer Placements', () => {
|
|
|
93
93
|
|
|
94
94
|
describe('Drawer Widths', () => {
|
|
95
95
|
test('sm width applies w-64', () => {
|
|
96
|
-
const { container } = render(Drawer, { props: {
|
|
96
|
+
const { container } = render(Drawer, { props: { open: true, width: 'sm' } });
|
|
97
97
|
const dialog = container.querySelector('[role="dialog"]');
|
|
98
98
|
expect(dialog).toHaveClass('w-64');
|
|
99
99
|
});
|
|
100
100
|
|
|
101
101
|
test('md width applies w-80 (default)', () => {
|
|
102
|
-
const { container } = render(Drawer, { props: {
|
|
102
|
+
const { container } = render(Drawer, { props: { open: true } });
|
|
103
103
|
const dialog = container.querySelector('[role="dialog"]');
|
|
104
104
|
expect(dialog).toHaveClass('w-80');
|
|
105
105
|
});
|
|
106
106
|
|
|
107
107
|
test('lg width applies w-96', () => {
|
|
108
|
-
const { container } = render(Drawer, { props: {
|
|
108
|
+
const { container } = render(Drawer, { props: { open: true, width: 'lg' } });
|
|
109
109
|
const dialog = container.querySelector('[role="dialog"]');
|
|
110
110
|
expect(dialog).toHaveClass('w-96');
|
|
111
111
|
});
|
|
112
112
|
|
|
113
113
|
test('full width applies w-full', () => {
|
|
114
|
-
const { container } = render(Drawer, { props: {
|
|
114
|
+
const { container } = render(Drawer, { props: { open: true, width: 'full' } });
|
|
115
115
|
const dialog = container.querySelector('[role="dialog"]');
|
|
116
116
|
expect(dialog).toHaveClass('w-full');
|
|
117
117
|
});
|
|
@@ -119,13 +119,13 @@ describe('Drawer Widths', () => {
|
|
|
119
119
|
|
|
120
120
|
describe('Drawer Accessibility', () => {
|
|
121
121
|
test('has tabindex="-1" for focus management', () => {
|
|
122
|
-
const { container } = render(Drawer, { props: {
|
|
122
|
+
const { container } = render(Drawer, { props: { open: true } });
|
|
123
123
|
const dialog = container.querySelector('[role="dialog"]');
|
|
124
124
|
expect(dialog).toHaveAttribute('tabindex', '-1');
|
|
125
125
|
});
|
|
126
126
|
|
|
127
127
|
test('has aria-labelledby when title and id are provided', () => {
|
|
128
|
-
const { container } = render(Drawer, { props: {
|
|
128
|
+
const { container } = render(Drawer, { props: { open: true, title: 'Test', id: 'test-drawer' } });
|
|
129
129
|
const dialog = container.querySelector('[role="dialog"]');
|
|
130
130
|
expect(dialog).toHaveAttribute('aria-labelledby', 'test-drawer-label');
|
|
131
131
|
});
|
|
@@ -133,32 +133,32 @@ describe('Drawer Accessibility', () => {
|
|
|
133
133
|
|
|
134
134
|
describe('Drawer Styling', () => {
|
|
135
135
|
test('has fixed positioning', () => {
|
|
136
|
-
const { container } = render(Drawer, { props: {
|
|
136
|
+
const { container } = render(Drawer, { props: { open: true } });
|
|
137
137
|
const dialog = container.querySelector('[role="dialog"]');
|
|
138
138
|
expect(dialog).toHaveClass('fixed');
|
|
139
139
|
});
|
|
140
140
|
|
|
141
141
|
test('has z-40 for stacking', () => {
|
|
142
|
-
const { container } = render(Drawer, { props: {
|
|
142
|
+
const { container } = render(Drawer, { props: { open: true } });
|
|
143
143
|
const dialog = container.querySelector('[role="dialog"]');
|
|
144
144
|
expect(dialog).toHaveClass('z-40');
|
|
145
145
|
});
|
|
146
146
|
|
|
147
147
|
test('has flex flex-col layout', () => {
|
|
148
|
-
const { container } = render(Drawer, { props: {
|
|
148
|
+
const { container } = render(Drawer, { props: { open: true } });
|
|
149
149
|
const dialog = container.querySelector('[role="dialog"]');
|
|
150
150
|
expect(dialog).toHaveClass('flex');
|
|
151
151
|
expect(dialog).toHaveClass('flex-col');
|
|
152
152
|
});
|
|
153
153
|
|
|
154
154
|
test('has bg-white background', () => {
|
|
155
|
-
const { container } = render(Drawer, { props: {
|
|
155
|
+
const { container } = render(Drawer, { props: { open: true } });
|
|
156
156
|
const dialog = container.querySelector('[role="dialog"]');
|
|
157
157
|
expect(dialog).toHaveClass('bg-white');
|
|
158
158
|
});
|
|
159
159
|
|
|
160
160
|
test('has dark mode background', () => {
|
|
161
|
-
const { container } = render(Drawer, { props: {
|
|
161
|
+
const { container } = render(Drawer, { props: { open: true } });
|
|
162
162
|
const dialog = container.querySelector('[role="dialog"]');
|
|
163
163
|
expect(dialog).toHaveClass('dark:bg-gray-800');
|
|
164
164
|
});
|
|
@@ -166,13 +166,13 @@ describe('Drawer Styling', () => {
|
|
|
166
166
|
|
|
167
167
|
describe('Drawer Edge Mode', () => {
|
|
168
168
|
test('shows edge trigger when edge=true, placement=bottom, and not visible', () => {
|
|
169
|
-
const { container } = render(Drawer, { props: { edge: true, placement: 'bottom',
|
|
169
|
+
const { container } = render(Drawer, { props: { edge: true, placement: 'bottom', open: false } });
|
|
170
170
|
const edgeTrigger = container.querySelector('.cursor-pointer');
|
|
171
171
|
expect(edgeTrigger).toBeInTheDocument();
|
|
172
172
|
});
|
|
173
173
|
|
|
174
174
|
test('hides edge trigger when drawer is visible', () => {
|
|
175
|
-
const { container } = render(Drawer, { props: { edge: true, placement: 'bottom',
|
|
175
|
+
const { container } = render(Drawer, { props: { edge: true, placement: 'bottom', open: true } });
|
|
176
176
|
// Edge trigger should not be visible when drawer is open
|
|
177
177
|
const edgeTriggers = container.querySelectorAll('.cursor-pointer.fixed');
|
|
178
178
|
// The drawer itself might have cursor classes, so check for the specific edge trigger pattern
|
|
@@ -184,20 +184,20 @@ describe('Drawer Callbacks', () => {
|
|
|
184
184
|
test('onclose prop is accepted', () => {
|
|
185
185
|
const onclose = vi.fn();
|
|
186
186
|
const { container } = render(Drawer, {
|
|
187
|
-
props: {
|
|
187
|
+
props: { open: true, closeOnBackdropClick: true, onclose }
|
|
188
188
|
});
|
|
189
189
|
// Verify drawer renders with onclose callback
|
|
190
190
|
expect(container.querySelector('[role="dialog"]')).toBeInTheDocument();
|
|
191
191
|
});
|
|
192
192
|
|
|
193
193
|
test('closeOnBackdropClick prop defaults to true', () => {
|
|
194
|
-
const { container } = render(Drawer, { props: {
|
|
194
|
+
const { container } = render(Drawer, { props: { open: true } });
|
|
195
195
|
// Drawer renders with default closeOnBackdropClick behavior
|
|
196
196
|
expect(container.querySelector('[role="presentation"]')).toBeInTheDocument();
|
|
197
197
|
});
|
|
198
198
|
|
|
199
199
|
test('closeOnEscape prop defaults to true', () => {
|
|
200
|
-
const { container } = render(Drawer, { props: {
|
|
200
|
+
const { container } = render(Drawer, { props: { open: true } });
|
|
201
201
|
// Drawer accepts closeOnEscape prop
|
|
202
202
|
expect(container.querySelector('[role="dialog"]')).toBeInTheDocument();
|
|
203
203
|
});
|
|
@@ -205,7 +205,7 @@ describe('Drawer Callbacks', () => {
|
|
|
205
205
|
test('onopen prop is accepted', () => {
|
|
206
206
|
const onopen = vi.fn();
|
|
207
207
|
const { container } = render(Drawer, {
|
|
208
|
-
props: {
|
|
208
|
+
props: { open: true, onopen }
|
|
209
209
|
});
|
|
210
210
|
expect(container.querySelector('[role="dialog"]')).toBeInTheDocument();
|
|
211
211
|
});
|
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
import type { Snippet } from "svelte";
|
|
6
6
|
|
|
7
7
|
interface Props {
|
|
8
|
-
|
|
9
|
-
hidden?: boolean;
|
|
8
|
+
open?: boolean;
|
|
10
9
|
title?: string;
|
|
11
10
|
placement?: string;
|
|
12
11
|
width?: string;
|
|
@@ -26,8 +25,7 @@
|
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
let {
|
|
29
|
-
|
|
30
|
-
hidden = $bindable(true),
|
|
28
|
+
open = $bindable(false),
|
|
31
29
|
title = "",
|
|
32
30
|
placement = "left",
|
|
33
31
|
width = "md",
|
|
@@ -46,7 +44,7 @@
|
|
|
46
44
|
...restProps
|
|
47
45
|
}: Props = $props();
|
|
48
46
|
|
|
49
|
-
let isVisible = $derived(
|
|
47
|
+
let isVisible = $derived(open);
|
|
50
48
|
let drawerElement: HTMLElement | null = $state(null);
|
|
51
49
|
let previouslyFocusedElement: Element | null = $state(null);
|
|
52
50
|
|
|
@@ -89,8 +87,7 @@
|
|
|
89
87
|
});
|
|
90
88
|
|
|
91
89
|
function close() {
|
|
92
|
-
|
|
93
|
-
show = false;
|
|
90
|
+
open = false;
|
|
94
91
|
onclose?.();
|
|
95
92
|
}
|
|
96
93
|
|
|
@@ -128,8 +125,7 @@
|
|
|
128
125
|
|
|
129
126
|
function handleEdgeClick() {
|
|
130
127
|
if (edge && placement === "bottom") {
|
|
131
|
-
|
|
132
|
-
show = true;
|
|
128
|
+
open = true;
|
|
133
129
|
onopen?.();
|
|
134
130
|
}
|
|
135
131
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { Snippet } from "svelte";
|
|
2
2
|
interface Props {
|
|
3
|
-
|
|
4
|
-
hidden?: boolean;
|
|
3
|
+
open?: boolean;
|
|
5
4
|
title?: string;
|
|
6
5
|
placement?: string;
|
|
7
6
|
width?: string;
|
|
@@ -19,7 +18,7 @@ interface Props {
|
|
|
19
18
|
class?: string;
|
|
20
19
|
[key: string]: unknown;
|
|
21
20
|
}
|
|
22
|
-
declare const Drawer: import("svelte").Component<Props, {}, "
|
|
21
|
+
declare const Drawer: import("svelte").Component<Props, {}, "open">;
|
|
23
22
|
type Drawer = ReturnType<typeof Drawer>;
|
|
24
23
|
export default Drawer;
|
|
25
24
|
//# sourceMappingURL=Drawer.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Drawer.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/Drawer/Drawer.svelte.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGpC,UAAU,KAAK;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,
|
|
1
|
+
{"version":3,"file":"Drawer.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/primitives/Drawer/Drawer.svelte.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGpC,UAAU,KAAK;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAmMH,QAAA,MAAM,MAAM,+CAAwC,CAAC;AACrD,KAAK,MAAM,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC;AACxC,eAAe,MAAM,CAAC"}
|
|
@@ -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
|
|
17
|
+
test('Renders Modal when open is true', () => {
|
|
18
18
|
setupTest({
|
|
19
|
-
|
|
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
|
|
32
|
+
test('Does not render Modal when open is false', () => {
|
|
33
33
|
setupTest({
|
|
34
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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>
|