@reshape-biotech/design-system 2.0.3 → 2.1.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/components/modal/Modal.stories.svelte +234 -26
- package/dist/components/modal/Modal.stories.svelte.d.ts +1 -1
- package/dist/components/modal/components/modal-bottom.svelte +14 -0
- package/dist/components/modal/components/modal-bottom.svelte.d.ts +4 -0
- package/dist/components/modal/components/modal-close.svelte +19 -0
- package/dist/components/modal/components/modal-close.svelte.d.ts +4 -0
- package/dist/components/modal/components/modal-content.svelte +68 -0
- package/dist/components/modal/components/modal-content.svelte.d.ts +4 -0
- package/dist/components/modal/components/modal-overlay.svelte +23 -0
- package/dist/components/modal/components/modal-overlay.svelte.d.ts +4 -0
- package/dist/components/modal/components/modal-title.svelte +20 -0
- package/dist/components/modal/components/modal-title.svelte.d.ts +4 -0
- package/dist/components/modal/components/modal-trigger.svelte +10 -0
- package/dist/components/modal/components/modal-trigger.svelte.d.ts +4 -0
- package/dist/components/modal/index.d.ts +12 -1
- package/dist/components/modal/index.js +15 -1
- package/dist/components/modal/types.d.ts +32 -0
- package/dist/components/modal/types.js +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/components/modal/Modal.svelte +0 -81
- package/dist/components/modal/Modal.svelte.d.ts +0 -20
|
@@ -1,39 +1,247 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
|
-
import Button from '../button/Button.svelte';
|
|
3
|
-
import Modal from '../modal/Modal.svelte';
|
|
4
2
|
import { defineMeta } from '@storybook/addon-svelte-csf';
|
|
3
|
+
import { Root as ModalRootForMeta } from './index';
|
|
4
|
+
import * as Modal from './index';
|
|
5
|
+
import Button from '../button/Button.svelte';
|
|
6
|
+
import { Icon } from '../icons';
|
|
5
7
|
|
|
6
8
|
const { Story } = defineMeta({
|
|
7
|
-
component:
|
|
9
|
+
component: ModalRootForMeta,
|
|
8
10
|
title: 'Design System/Modal',
|
|
9
11
|
tags: ['autodocs'],
|
|
12
|
+
parameters: {
|
|
13
|
+
layout: 'centered',
|
|
14
|
+
docs: {
|
|
15
|
+
description: {
|
|
16
|
+
component:
|
|
17
|
+
'A modal component built with Bits UI Dialog. Features smooth Svelte transitions with scale and fade effects. Supports compound component pattern with Modal.Root, Modal.Trigger, Modal.Content, etc.',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
10
21
|
});
|
|
11
|
-
|
|
12
|
-
let defaultOpen = $state(true);
|
|
13
22
|
</script>
|
|
14
23
|
|
|
15
24
|
<Story name="Default" asChild>
|
|
16
|
-
<Modal>
|
|
17
|
-
|
|
18
|
-
<Button
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
<
|
|
22
|
-
|
|
25
|
+
<Modal.Root>
|
|
26
|
+
<Modal.Trigger>
|
|
27
|
+
<Button variant="primary">Open Modal</Button>
|
|
28
|
+
</Modal.Trigger>
|
|
29
|
+
<Modal.Content>
|
|
30
|
+
<Modal.Title>Edit Profile</Modal.Title>
|
|
31
|
+
<div class="space-y-4">
|
|
32
|
+
<p class="text-sm text-secondary">
|
|
33
|
+
Make changes to your profile here. Click save when you're done.
|
|
34
|
+
</p>
|
|
35
|
+
<div class="space-y-2">
|
|
36
|
+
<label class="text-sm font-medium" for="name">Name</label>
|
|
37
|
+
<input id="name" class="w-full rounded border border-input px-3 py-2" value="John Doe" />
|
|
38
|
+
</div>
|
|
39
|
+
<div class="space-y-2">
|
|
40
|
+
<label class="text-sm font-medium" for="username">Username</label>
|
|
41
|
+
<input
|
|
42
|
+
id="username"
|
|
43
|
+
class="w-full rounded border border-input px-3 py-2"
|
|
44
|
+
value="@johndoe"
|
|
45
|
+
/>
|
|
46
|
+
</div>
|
|
23
47
|
</div>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
</
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
48
|
+
<Modal.Bottom>
|
|
49
|
+
<Modal.Close variant="secondary">Cancel</Modal.Close>
|
|
50
|
+
<Modal.Close variant="primary">Save Changes</Modal.Close>
|
|
51
|
+
</Modal.Bottom>
|
|
52
|
+
</Modal.Content>
|
|
53
|
+
</Modal.Root>
|
|
54
|
+
</Story>
|
|
55
|
+
|
|
56
|
+
<Story name="With Description" asChild>
|
|
57
|
+
<Modal.Root open>
|
|
58
|
+
<Modal.Trigger>
|
|
59
|
+
<Button variant="primary">Open Modal with Description</Button>
|
|
60
|
+
</Modal.Trigger>
|
|
61
|
+
<Modal.Content>
|
|
62
|
+
<Modal.Title>Are you absolutely sure?</Modal.Title>
|
|
63
|
+
<Modal.Description class="text-sm leading-[1.43] tracking-[1.14%] text-secondary">
|
|
64
|
+
This action cannot be undone. This will permanently delete your account and remove your data
|
|
65
|
+
from our servers.
|
|
66
|
+
</Modal.Description>
|
|
67
|
+
<Modal.Bottom>
|
|
68
|
+
<Modal.Close variant="secondary">Cancel</Modal.Close>
|
|
69
|
+
<Modal.Close variant="danger" onclick={() => console.log('something')}
|
|
70
|
+
>Delete Account</Modal.Close
|
|
71
|
+
>
|
|
72
|
+
</Modal.Bottom>
|
|
73
|
+
</Modal.Content>
|
|
74
|
+
</Modal.Root>
|
|
75
|
+
</Story>
|
|
76
|
+
|
|
77
|
+
<Story name="Alert Modal (Figma Design)" asChild>
|
|
78
|
+
<Modal.Root open>
|
|
79
|
+
<Modal.Trigger>
|
|
80
|
+
<Button variant="primary">Open Alert Modal</Button>
|
|
81
|
+
</Modal.Trigger>
|
|
82
|
+
<Modal.Content class="w-[544px] max-w-[544px] p-0">
|
|
83
|
+
<Modal.Title>
|
|
84
|
+
{#snippet icon()}
|
|
85
|
+
<div class="flex h-12 w-12 items-center justify-center rounded-lg bg-danger p-2">
|
|
86
|
+
<Icon iconName="Warning" class="h-7 w-7 text-danger" />
|
|
87
|
+
</div>
|
|
88
|
+
{/snippet}
|
|
89
|
+
Delete this job?
|
|
90
|
+
</Modal.Title>
|
|
91
|
+
<Modal.Description class="text-sm text-secondary">
|
|
92
|
+
"CFU Air" will be permanently deleted for all users in your organization. This action cannot
|
|
93
|
+
be undone.
|
|
94
|
+
</Modal.Description>
|
|
95
|
+
|
|
96
|
+
<Modal.Bottom>
|
|
97
|
+
<Modal.Close variant="secondary">Cancel</Modal.Close>
|
|
98
|
+
<Modal.Close variant="danger">Delete job</Modal.Close>
|
|
99
|
+
</Modal.Bottom>
|
|
100
|
+
</Modal.Content>
|
|
101
|
+
</Modal.Root>
|
|
102
|
+
</Story>
|
|
103
|
+
|
|
104
|
+
<Story name="Custom Button Rendering" asChild>
|
|
105
|
+
<Modal.Root open>
|
|
106
|
+
<Modal.Trigger>
|
|
107
|
+
<Button variant="primary">Open Custom Button Modal</Button>
|
|
108
|
+
</Modal.Trigger>
|
|
109
|
+
<Modal.Content>
|
|
110
|
+
<Modal.Title>Custom Button Rendering</Modal.Title>
|
|
111
|
+
<Modal.Description class="text-sm text-secondary">
|
|
112
|
+
This modal demonstrates rendering custom buttons within Modal.Close components for proper
|
|
113
|
+
functionality.
|
|
114
|
+
</Modal.Description>
|
|
115
|
+
|
|
116
|
+
<Modal.Bottom>
|
|
117
|
+
<Modal.Close variant="secondary" onclick={() => console.log('Custom cancel action')}>
|
|
118
|
+
Custom Cancel
|
|
119
|
+
</Modal.Close>
|
|
120
|
+
<Modal.Close variant="primary" onclick={() => console.log('Custom confirm action')}>
|
|
121
|
+
Custom Confirm
|
|
122
|
+
</Modal.Close>
|
|
123
|
+
</Modal.Bottom>
|
|
124
|
+
</Modal.Content>
|
|
125
|
+
</Modal.Root>
|
|
126
|
+
</Story>
|
|
127
|
+
|
|
128
|
+
<Story name="No Close Button" asChild>
|
|
129
|
+
<Modal.Root open>
|
|
130
|
+
<Modal.Trigger>
|
|
131
|
+
<Button variant="primary">Open Modal (No Close)</Button>
|
|
132
|
+
</Modal.Trigger>
|
|
133
|
+
<Modal.Content withClose={false}>
|
|
134
|
+
<Modal.Title>Alert</Modal.Title>
|
|
135
|
+
<div class="space-y-4">
|
|
136
|
+
<p class="text-sm text-secondary">
|
|
137
|
+
This modal doesn't have a close button. You must use the action buttons below.
|
|
138
|
+
</p>
|
|
139
|
+
</div>
|
|
140
|
+
<Modal.Bottom>
|
|
141
|
+
<Modal.Close variant="secondary">Cancel</Modal.Close>
|
|
142
|
+
<Modal.Close variant="primary">Continue</Modal.Close>
|
|
143
|
+
</Modal.Bottom>
|
|
144
|
+
</Modal.Content>
|
|
145
|
+
</Modal.Root>
|
|
146
|
+
</Story>
|
|
147
|
+
|
|
148
|
+
<Story name="Custom Styling" asChild>
|
|
149
|
+
<Modal.Root open>
|
|
150
|
+
<Modal.Trigger>
|
|
151
|
+
<Button variant="primary">Open Custom Modal</Button>
|
|
152
|
+
</Modal.Trigger>
|
|
153
|
+
<Modal.Content class="min-w-full !bg-accent p-8">
|
|
154
|
+
<Modal.Title class="text-xl text-primary-inverse">Custom Styled Modal</Modal.Title>
|
|
155
|
+
<div class="space-y-4 pt-4">
|
|
156
|
+
<p class="text-sm text-secondary-inverse">
|
|
157
|
+
This modal has custom styling applied to demonstrate the flexibility of the component.
|
|
158
|
+
</p>
|
|
159
|
+
<div class="rounded bg-surface p-4">
|
|
160
|
+
<h3 class="font-medium">Content Box</h3>
|
|
161
|
+
<p class="text-sm text-secondary">Some content in a styled box.</p>
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
<Modal.Bottom>
|
|
165
|
+
<Modal.Close variant="secondary">Close</Modal.Close>
|
|
166
|
+
</Modal.Bottom>
|
|
167
|
+
</Modal.Content>
|
|
168
|
+
</Modal.Root>
|
|
169
|
+
</Story>
|
|
170
|
+
|
|
171
|
+
<Story name="API Documentation" asChild>
|
|
172
|
+
<Modal.Root open>
|
|
173
|
+
<Modal.Trigger>
|
|
174
|
+
<Button variant="primary">API Example</Button>
|
|
175
|
+
</Modal.Trigger>
|
|
176
|
+
<Modal.Content>
|
|
177
|
+
<Modal.Title>Modal API Documentation</Modal.Title>
|
|
178
|
+
<Modal.Description>
|
|
179
|
+
The Modal component is built with Bits UI Dialog and follows the compound component pattern
|
|
180
|
+
with simplified usage.
|
|
181
|
+
</Modal.Description>
|
|
182
|
+
<div class="space-y-4 pt-4">
|
|
183
|
+
<div class="space-y-2">
|
|
184
|
+
<h4 class="font-medium">Available Components:</h4>
|
|
185
|
+
<ul class="space-y-1 text-sm text-secondary">
|
|
186
|
+
<li>• <code>Modal.Root</code> - The root modal container</li>
|
|
187
|
+
<li>• <code>Modal.Trigger</code> - Button to open the modal</li>
|
|
188
|
+
<li>• <code>Modal.Content</code> - Main modal content (includes Portal & Overlay)</li>
|
|
189
|
+
<li>• <code>Modal.Title</code> - Modal title (supports optional icon snippet)</li>
|
|
190
|
+
<li>• <code>Modal.Description</code> - Modal description</li>
|
|
191
|
+
<li>• <code>Modal.Bottom</code> - Modal footer with consistent styling</li>
|
|
192
|
+
<li>• <code>Modal.Close</code> - Close button wrapper</li>
|
|
193
|
+
</ul>
|
|
194
|
+
</div>
|
|
195
|
+
<div class="space-y-2">
|
|
196
|
+
<h4 class="font-medium">Simple Usage:</h4>
|
|
197
|
+
<pre class="overflow-x-auto rounded bg-surface p-2 text-xs">
|
|
198
|
+
{`import { Modal } from 'design-system';
|
|
199
|
+
|
|
200
|
+
<Modal.Root>
|
|
201
|
+
<Modal.Trigger>Open</Modal.Trigger>
|
|
202
|
+
<Modal.Content>
|
|
203
|
+
<Modal.Title>Title</Modal.Title>
|
|
204
|
+
Content here
|
|
205
|
+
</Modal.Content>
|
|
206
|
+
</Modal.Root>`}
|
|
207
|
+
</pre>
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
<Modal.Bottom>
|
|
211
|
+
<Modal.Close variant="primary">Got it</Modal.Close>
|
|
212
|
+
</Modal.Bottom>
|
|
213
|
+
</Modal.Content>
|
|
214
|
+
</Modal.Root>
|
|
215
|
+
</Story>
|
|
216
|
+
|
|
217
|
+
<Story name="No Portal" asChild>
|
|
218
|
+
<Modal.Root open>
|
|
219
|
+
<Modal.Trigger>
|
|
220
|
+
<Button variant="primary">Open Modal</Button>
|
|
221
|
+
</Modal.Trigger>
|
|
222
|
+
<Modal.Content withPortal={false}>
|
|
223
|
+
<Modal.Title>Edit Profile</Modal.Title>
|
|
224
|
+
<div class="space-y-4">
|
|
225
|
+
<p class="text-sm text-secondary">
|
|
226
|
+
Make changes to your profile here. Click save when you're done.
|
|
227
|
+
</p>
|
|
228
|
+
<div class="space-y-2">
|
|
229
|
+
<label class="text-sm font-medium" for="name">Name</label>
|
|
230
|
+
<input id="name" class="w-full rounded border border-input px-3 py-2" value="John Doe" />
|
|
231
|
+
</div>
|
|
232
|
+
<div class="space-y-2">
|
|
233
|
+
<label class="text-sm font-medium" for="username">Username</label>
|
|
234
|
+
<input
|
|
235
|
+
id="username"
|
|
236
|
+
class="w-full rounded border border-input px-3 py-2"
|
|
237
|
+
value="@johndoe"
|
|
238
|
+
/>
|
|
239
|
+
</div>
|
|
36
240
|
</div>
|
|
37
|
-
|
|
38
|
-
|
|
241
|
+
<Modal.Bottom>
|
|
242
|
+
<Modal.Close variant="secondary">Cancel</Modal.Close>
|
|
243
|
+
<Modal.Close variant="primary">Save Changes</Modal.Close>
|
|
244
|
+
</Modal.Bottom>
|
|
245
|
+
</Modal.Content>
|
|
246
|
+
</Modal.Root>
|
|
39
247
|
</Story>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Modal from '
|
|
1
|
+
import * as Modal from './index';
|
|
2
2
|
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
3
3
|
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
4
|
$$bindings?: Bindings;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ModalBottomProps } from '../types';
|
|
3
|
+
|
|
4
|
+
let { children, class: className = '', ...restProps }: ModalBottomProps = $props();
|
|
5
|
+
|
|
6
|
+
const baseClasses = 'border-t border-static -mx-5';
|
|
7
|
+
const finalClasses = `${baseClasses} ${className}`;
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<div class={finalClasses} {...restProps}>
|
|
11
|
+
<div class="flex justify-end gap-4 px-5 py-4 pb-0">
|
|
12
|
+
{@render children()}
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Dialog } from 'bits-ui';
|
|
3
|
+
import Button from '../../button/Button.svelte';
|
|
4
|
+
import type { ModalCloseProps } from '../types';
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
children,
|
|
8
|
+
variant = 'secondary',
|
|
9
|
+
disabled = false,
|
|
10
|
+
class: className = '',
|
|
11
|
+
...restProps
|
|
12
|
+
}: ModalCloseProps = $props();
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<Dialog.Close class={className} {...restProps} {disabled}>
|
|
16
|
+
<Button {variant} {disabled} tabindex={-1}>
|
|
17
|
+
{@render children()}
|
|
18
|
+
</Button>
|
|
19
|
+
</Dialog.Close>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Dialog } from 'bits-ui';
|
|
3
|
+
import { scale } from 'svelte/transition';
|
|
4
|
+
import { Icon } from '../../icons';
|
|
5
|
+
import type { ModalContentProps } from '../types';
|
|
6
|
+
import Overlay from './modal-overlay.svelte';
|
|
7
|
+
|
|
8
|
+
let {
|
|
9
|
+
children,
|
|
10
|
+
class: className = '',
|
|
11
|
+
withClose = true,
|
|
12
|
+
withPortal = true,
|
|
13
|
+
'data-testid': dataTestId,
|
|
14
|
+
...restProps
|
|
15
|
+
}: ModalContentProps = $props();
|
|
16
|
+
|
|
17
|
+
const baseClasses =
|
|
18
|
+
'fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 bg-surface p-5 shadow-lg sm:rounded-lg';
|
|
19
|
+
const finalClasses = `${baseClasses} ${className}`;
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
{#snippet withCloseButton()}
|
|
23
|
+
{#if withClose}
|
|
24
|
+
<Dialog.Close
|
|
25
|
+
class="ring-offset-background focus:ring-ring absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none"
|
|
26
|
+
>
|
|
27
|
+
<Icon iconName="X" />
|
|
28
|
+
</Dialog.Close>
|
|
29
|
+
{/if}
|
|
30
|
+
{/snippet}
|
|
31
|
+
|
|
32
|
+
{#if withPortal}
|
|
33
|
+
<Dialog.Portal>
|
|
34
|
+
<Overlay />
|
|
35
|
+
<Dialog.Content forceMount {...restProps}>
|
|
36
|
+
{#snippet child({ props, open })}
|
|
37
|
+
{#if open}
|
|
38
|
+
<div
|
|
39
|
+
{...props}
|
|
40
|
+
class={finalClasses}
|
|
41
|
+
data-testid={dataTestId}
|
|
42
|
+
transition:scale={{ duration: 200, start: 0.95 }}
|
|
43
|
+
>
|
|
44
|
+
{@render withCloseButton()}
|
|
45
|
+
{@render children()}
|
|
46
|
+
</div>
|
|
47
|
+
{/if}
|
|
48
|
+
{/snippet}
|
|
49
|
+
</Dialog.Content>
|
|
50
|
+
</Dialog.Portal>
|
|
51
|
+
{:else}
|
|
52
|
+
<Overlay />
|
|
53
|
+
<Dialog.Content forceMount {...restProps}>
|
|
54
|
+
{#snippet child({ props, open })}
|
|
55
|
+
{#if open}
|
|
56
|
+
<div
|
|
57
|
+
{...props}
|
|
58
|
+
class={finalClasses}
|
|
59
|
+
data-testid={dataTestId}
|
|
60
|
+
transition:scale={{ duration: 200, start: 0.95 }}
|
|
61
|
+
>
|
|
62
|
+
{@render withCloseButton()}
|
|
63
|
+
{@render children()}
|
|
64
|
+
</div>
|
|
65
|
+
{/if}
|
|
66
|
+
{/snippet}
|
|
67
|
+
</Dialog.Content>
|
|
68
|
+
{/if}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Dialog, type WithoutChildrenOrChild } from 'bits-ui';
|
|
3
|
+
import type { ModalOverlayProps } from '../types';
|
|
4
|
+
import { fade } from 'svelte/transition';
|
|
5
|
+
|
|
6
|
+
let { children, ...restProps }: ModalOverlayProps = $props();
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<Dialog.Overlay forceMount {...restProps}>
|
|
10
|
+
{#snippet child({ props, open })}
|
|
11
|
+
{#if open}
|
|
12
|
+
<div
|
|
13
|
+
{...props}
|
|
14
|
+
class="fixed inset-0 z-50 bg-overlay backdrop-blur-sm"
|
|
15
|
+
transition:fade={{ duration: 200 }}
|
|
16
|
+
>
|
|
17
|
+
{#if children}
|
|
18
|
+
{@render children()}
|
|
19
|
+
{/if}
|
|
20
|
+
</div>
|
|
21
|
+
{/if}
|
|
22
|
+
{/snippet}
|
|
23
|
+
</Dialog.Overlay>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Dialog } from 'bits-ui';
|
|
3
|
+
import type { ModalTitleProps } from '../types';
|
|
4
|
+
|
|
5
|
+
let { children, class: className = '', icon, ...restProps }: ModalTitleProps = $props();
|
|
6
|
+
|
|
7
|
+
const baseClasses = 'text-xl font-semibold tracking-tight text-primary';
|
|
8
|
+
const finalClasses = `${baseClasses} ${className}`;
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<div class="space-y-6">
|
|
12
|
+
{#if icon}
|
|
13
|
+
<div class="flex justify-start">
|
|
14
|
+
{@render icon()}
|
|
15
|
+
</div>
|
|
16
|
+
{/if}
|
|
17
|
+
<Dialog.Title class={finalClasses} {...restProps}>
|
|
18
|
+
{@render children()}
|
|
19
|
+
</Dialog.Title>
|
|
20
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Dialog } from 'bits-ui';
|
|
3
|
+
import type { ModalTriggerProps } from '../types';
|
|
4
|
+
|
|
5
|
+
let { children, ...restProps }: ModalTriggerProps = $props();
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<Dialog.Trigger {...restProps}>
|
|
9
|
+
{@render children()}
|
|
10
|
+
</Dialog.Trigger>
|
|
@@ -1 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
import { Dialog } from 'bits-ui';
|
|
2
|
+
import Content from './components/modal-content.svelte';
|
|
3
|
+
import Overlay from './components/modal-overlay.svelte';
|
|
4
|
+
import Trigger from './components/modal-trigger.svelte';
|
|
5
|
+
import Title from './components/modal-title.svelte';
|
|
6
|
+
import Bottom from './components/modal-bottom.svelte';
|
|
7
|
+
import Close from './components/modal-close.svelte';
|
|
8
|
+
export declare const Root: import("svelte").Component<import("bits-ui").AlertDialogRootPropsWithoutHTML, {}, "open">;
|
|
9
|
+
export declare const Portal: import("svelte").Component<import("bits-ui").PortalProps, {}, "">;
|
|
10
|
+
export declare const Description: import("svelte").Component<Dialog.DescriptionProps, {}, "ref">;
|
|
11
|
+
export { Content, Overlay, Trigger, Title, Bottom, Close };
|
|
12
|
+
export * from './types';
|
|
@@ -1 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
import { Dialog } from 'bits-ui';
|
|
2
|
+
// Custom Svelte components
|
|
3
|
+
import Content from './components/modal-content.svelte';
|
|
4
|
+
import Overlay from './components/modal-overlay.svelte';
|
|
5
|
+
import Trigger from './components/modal-trigger.svelte';
|
|
6
|
+
import Title from './components/modal-title.svelte';
|
|
7
|
+
import Bottom from './components/modal-bottom.svelte';
|
|
8
|
+
import Close from './components/modal-close.svelte';
|
|
9
|
+
// Re-export Dialog primitives
|
|
10
|
+
export const Root = Dialog.Root;
|
|
11
|
+
export const Portal = Dialog.Portal;
|
|
12
|
+
export const Description = Dialog.Description;
|
|
13
|
+
// Export custom components
|
|
14
|
+
export { Content, Overlay, Trigger, Title, Bottom, Close };
|
|
15
|
+
export * from './types';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type DialogContentProps as BitsDialogContentProps, type DialogOverlayProps as BitsDialogOverlayProps, type DialogTriggerProps as BitsDialogTriggerProps, type DialogTitleProps as BitsDialogTitleProps, type DialogCloseProps as BitsDialogCloseProps } from 'bits-ui';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
+
import type { ButtonVariant } from '../button/Button.svelte';
|
|
5
|
+
export type ModalTriggerProps = {
|
|
6
|
+
children: Snippet;
|
|
7
|
+
} & BitsDialogTriggerProps;
|
|
8
|
+
export type ModalOverlayProps = {
|
|
9
|
+
children?: Snippet;
|
|
10
|
+
} & BitsDialogOverlayProps;
|
|
11
|
+
export type ModalContentProps = {
|
|
12
|
+
children: Snippet;
|
|
13
|
+
class?: string;
|
|
14
|
+
withClose?: boolean;
|
|
15
|
+
withPortal?: boolean;
|
|
16
|
+
} & BitsDialogContentProps;
|
|
17
|
+
export type ModalTitleProps = {
|
|
18
|
+
children: Snippet;
|
|
19
|
+
class?: string;
|
|
20
|
+
icon?: Snippet;
|
|
21
|
+
} & BitsDialogTitleProps;
|
|
22
|
+
export type ModalBottomProps = {
|
|
23
|
+
children: Snippet;
|
|
24
|
+
class?: string;
|
|
25
|
+
} & HTMLAttributes<HTMLDivElement>;
|
|
26
|
+
export type ModalCloseProps = {
|
|
27
|
+
children: Snippet;
|
|
28
|
+
class?: string;
|
|
29
|
+
variant?: ButtonVariant;
|
|
30
|
+
onclick?: (event: MouseEvent) => void;
|
|
31
|
+
disabled?: boolean;
|
|
32
|
+
} & BitsDialogCloseProps;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {} from 'bits-ui';
|
package/dist/index.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export * from './components/input/';
|
|
|
19
19
|
export * from './components/list/';
|
|
20
20
|
export * from './components/logo/';
|
|
21
21
|
export * from './components/markdown/';
|
|
22
|
-
export * from './components/modal/';
|
|
22
|
+
export * as Modal from './components/modal/';
|
|
23
23
|
export * from './components/manual-cfu-counter/';
|
|
24
24
|
export * from './components/multi-cfu-counter/';
|
|
25
25
|
export * from './components/notification-popup/';
|
package/dist/index.js
CHANGED
|
@@ -20,7 +20,7 @@ export * from './components/input/';
|
|
|
20
20
|
export * from './components/list/';
|
|
21
21
|
export * from './components/logo/';
|
|
22
22
|
export * from './components/markdown/';
|
|
23
|
-
export * from './components/modal/';
|
|
23
|
+
export * as Modal from './components/modal/';
|
|
24
24
|
export * from './components/manual-cfu-counter/';
|
|
25
25
|
export * from './components/multi-cfu-counter/';
|
|
26
26
|
export * from './components/notification-popup/';
|
package/package.json
CHANGED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { type Snippet } from 'svelte';
|
|
3
|
-
import { v4 as uuidv4 } from 'uuid';
|
|
4
|
-
import IconButton from '../icon-button/IconButton.svelte';
|
|
5
|
-
import { Icon } from '../icons';
|
|
6
|
-
import Divider from '../divider/Divider.svelte';
|
|
7
|
-
|
|
8
|
-
type ModalProps = {
|
|
9
|
-
Trigger?: Snippet<[{ openModal: () => void; closeModal: () => void }]>;
|
|
10
|
-
Header?: Snippet;
|
|
11
|
-
Content: Snippet;
|
|
12
|
-
Footer?: Snippet;
|
|
13
|
-
onclose?: () => void;
|
|
14
|
-
defaultOpen?: boolean;
|
|
15
|
-
id?: string;
|
|
16
|
-
withClose?: boolean;
|
|
17
|
-
closeOnClickOutside?: boolean;
|
|
18
|
-
class?: string;
|
|
19
|
-
contentClass?: string;
|
|
20
|
-
};
|
|
21
|
-
let {
|
|
22
|
-
Trigger,
|
|
23
|
-
Header,
|
|
24
|
-
Content,
|
|
25
|
-
Footer,
|
|
26
|
-
onclose,
|
|
27
|
-
defaultOpen = false,
|
|
28
|
-
id = 'modal-' + uuidv4(),
|
|
29
|
-
withClose = true,
|
|
30
|
-
closeOnClickOutside = true,
|
|
31
|
-
class: modalClass,
|
|
32
|
-
contentClass = 'p-4',
|
|
33
|
-
}: ModalProps = $props();
|
|
34
|
-
|
|
35
|
-
const modalOpen = $state(defaultOpen);
|
|
36
|
-
const openModal = () => {
|
|
37
|
-
const dialog = document.getElementById(id) as HTMLDialogElement | null;
|
|
38
|
-
dialog?.showModal();
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const closeModal = () => {
|
|
42
|
-
const dialog = document.getElementById(id) as HTMLDialogElement | null;
|
|
43
|
-
dialog?.close();
|
|
44
|
-
onclose?.();
|
|
45
|
-
};
|
|
46
|
-
</script>
|
|
47
|
-
|
|
48
|
-
{#if Trigger}
|
|
49
|
-
{@render Trigger({ openModal, closeModal })}
|
|
50
|
-
{/if}
|
|
51
|
-
<dialog {id} class="modal w-full max-w-full" class:modal-open={modalOpen}>
|
|
52
|
-
<div class="modal-box relative flex max-w-full flex-col rounded-xl bg-surface p-0 {modalClass}">
|
|
53
|
-
{#if Header}
|
|
54
|
-
<div class="flex h-12 items-center px-4">
|
|
55
|
-
{@render Header()}
|
|
56
|
-
</div>
|
|
57
|
-
<Divider />
|
|
58
|
-
{/if}
|
|
59
|
-
{#if withClose}
|
|
60
|
-
<div class="absolute right-0 top-0 z-10 p-2">
|
|
61
|
-
<IconButton onclick={closeModal} size="md" variant="transparent" rounded={false}>
|
|
62
|
-
<Icon iconName="X" />
|
|
63
|
-
</IconButton>
|
|
64
|
-
</div>
|
|
65
|
-
{/if}
|
|
66
|
-
<div class="flex-1 {contentClass}">
|
|
67
|
-
{@render Content()}
|
|
68
|
-
</div>
|
|
69
|
-
{#if Footer}
|
|
70
|
-
<Divider />
|
|
71
|
-
<div class="px-4 py-2">
|
|
72
|
-
{@render Footer()}
|
|
73
|
-
</div>
|
|
74
|
-
{/if}
|
|
75
|
-
</div>
|
|
76
|
-
{#if closeOnClickOutside}
|
|
77
|
-
<form method="dialog" class="modal-backdrop">
|
|
78
|
-
<button onclick={closeModal}>close</button>
|
|
79
|
-
</form>
|
|
80
|
-
{/if}
|
|
81
|
-
</dialog>
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { type Snippet } from 'svelte';
|
|
2
|
-
type ModalProps = {
|
|
3
|
-
Trigger?: Snippet<[{
|
|
4
|
-
openModal: () => void;
|
|
5
|
-
closeModal: () => void;
|
|
6
|
-
}]>;
|
|
7
|
-
Header?: Snippet;
|
|
8
|
-
Content: Snippet;
|
|
9
|
-
Footer?: Snippet;
|
|
10
|
-
onclose?: () => void;
|
|
11
|
-
defaultOpen?: boolean;
|
|
12
|
-
id?: string;
|
|
13
|
-
withClose?: boolean;
|
|
14
|
-
closeOnClickOutside?: boolean;
|
|
15
|
-
class?: string;
|
|
16
|
-
contentClass?: string;
|
|
17
|
-
};
|
|
18
|
-
declare const Modal: import("svelte").Component<ModalProps, {}, "">;
|
|
19
|
-
type Modal = ReturnType<typeof Modal>;
|
|
20
|
-
export default Modal;
|