@getmicdrop/svelte-components 2.2.0 → 2.4.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/Accordion/Accordion.svelte +44 -0
- package/dist/components/Accordion/Accordion.svelte.d.ts +42 -0
- package/dist/components/Accordion/Accordion.svelte.d.ts.map +1 -0
- package/dist/components/Accordion/AccordionItem.svelte +141 -0
- package/dist/components/Accordion/AccordionItem.svelte.d.ts +50 -0
- package/dist/components/Accordion/AccordionItem.svelte.d.ts.map +1 -0
- package/dist/components/Badges/Badge.svelte +129 -3
- package/dist/components/Badges/Badge.svelte.d.ts +8 -2
- package/dist/components/Badges/Badge.svelte.d.ts.map +1 -1
- package/dist/components/Breadcrumb/Breadcrumb.svelte +65 -36
- package/dist/components/Breadcrumb/Breadcrumb.svelte.d.ts +16 -2
- package/dist/components/Breadcrumb/Breadcrumb.svelte.d.ts.map +1 -1
- package/dist/components/Button/Button.svelte +1 -0
- package/dist/components/Checkbox/Checkbox.svelte +116 -0
- package/dist/components/Checkbox/Checkbox.svelte.d.ts +52 -0
- package/dist/components/Checkbox/Checkbox.svelte.d.ts.map +1 -0
- package/dist/components/Drawer/Drawer.svelte +207 -0
- package/dist/components/Drawer/Drawer.svelte.d.ts +74 -0
- package/dist/components/Drawer/Drawer.svelte.d.ts.map +1 -0
- package/dist/components/Dropdown/Dropdown.svelte +129 -0
- package/dist/components/Dropdown/Dropdown.svelte.d.ts +48 -0
- package/dist/components/Dropdown/Dropdown.svelte.d.ts.map +1 -0
- package/dist/components/Dropdown/DropdownItem.svelte +111 -0
- package/dist/components/Dropdown/DropdownItem.svelte.d.ts +48 -0
- package/dist/components/Dropdown/DropdownItem.svelte.d.ts.map +1 -0
- package/dist/components/Input/Input.svelte.d.ts +6 -6
- package/dist/components/Input/MultiSelect.svelte +4 -5
- package/dist/components/Input/MultiSelect.svelte.d.ts +6 -6
- package/dist/components/Input/MultiSelect.svelte.d.ts.map +1 -1
- package/dist/components/Input/Search.svelte +173 -0
- package/dist/components/Input/Search.svelte.d.ts +68 -0
- package/dist/components/Input/Search.svelte.d.ts.map +1 -0
- package/dist/components/Input/Select.svelte +4 -5
- package/dist/components/Input/Select.svelte.d.ts +6 -6
- package/dist/components/Input/Select.svelte.d.ts.map +1 -1
- package/dist/components/Input/Textarea.svelte +160 -0
- package/dist/components/Input/Textarea.svelte.d.ts +69 -0
- package/dist/components/Input/Textarea.svelte.d.ts.map +1 -0
- package/dist/components/Label/Label.svelte +60 -0
- package/dist/components/Label/Label.svelte.d.ts +48 -0
- package/dist/components/Label/Label.svelte.d.ts.map +1 -0
- package/dist/components/Layout/Header.svelte +14 -4
- package/dist/components/Modal/ConfirmationModal.svelte +69 -17
- package/dist/components/Modal/ConfirmationModal.svelte.d.ts +22 -0
- package/dist/components/Modal/ConfirmationModal.svelte.d.ts.map +1 -1
- package/dist/components/Modal/InputModal.svelte +180 -0
- package/dist/components/Modal/InputModal.svelte.d.ts +77 -0
- package/dist/components/Modal/InputModal.svelte.d.ts.map +1 -0
- package/dist/components/Modal/Modal.svelte +34 -8
- package/dist/components/Modal/Modal.svelte.d.ts +2 -0
- package/dist/components/Modal/Modal.svelte.d.ts.map +1 -1
- package/dist/components/Modal/StatusModal.svelte +221 -0
- package/dist/components/Modal/StatusModal.svelte.d.ts +59 -0
- package/dist/components/Modal/StatusModal.svelte.d.ts.map +1 -0
- package/dist/components/OrderSummary/OrderSummary.svelte +2 -2
- package/dist/components/OrderSummary/OrderSummary.svelte.d.ts.map +1 -1
- package/dist/components/Pagination/Pagination.svelte +197 -0
- package/dist/components/Pagination/Pagination.svelte.d.ts +53 -0
- package/dist/components/Pagination/Pagination.svelte.d.ts.map +1 -0
- package/dist/components/PasswordStrengthIndicator/PasswordStrengthIndicator.svelte.d.ts +2 -2
- package/dist/components/Radio/Radio.svelte +119 -0
- package/dist/components/Radio/Radio.svelte.d.ts +54 -0
- package/dist/components/Radio/Radio.svelte.d.ts.map +1 -0
- package/dist/components/Skeleton/Skeleton.svelte +68 -0
- package/dist/components/Skeleton/Skeleton.svelte.d.ts +37 -0
- package/dist/components/Skeleton/Skeleton.svelte.d.ts.map +1 -0
- package/dist/components/Tabs/TabItem.svelte +39 -0
- package/dist/components/Tabs/TabItem.svelte.d.ts +52 -0
- package/dist/components/Tabs/TabItem.svelte.d.ts.map +1 -0
- package/dist/components/Tabs/Tabs.svelte +181 -0
- package/dist/components/Tabs/Tabs.svelte.d.ts +46 -0
- package/dist/components/Tabs/Tabs.svelte.d.ts.map +1 -0
- package/dist/components/pages/performers/ShowItemCard.svelte.d.ts +2 -2
- package/dist/components/pages/performers/SwitchOption.svelte.d.ts +2 -2
- package/dist/components/pages/performers/VenueInfo.svelte.d.ts +2 -2
- package/dist/components/pages/performers/VenueItemCard.svelte +2 -2
- package/dist/components/pages/performers/VenueItemCard.svelte.d.ts +2 -2
- package/dist/components/pages/profile/profile-form.svelte +1 -1
- package/dist/constants/formOptions.d.ts +5 -2
- package/dist/constants/formOptions.d.ts.map +1 -1
- package/dist/constants/formOptions.js +2 -1
- package/dist/index.d.ts +16 -0
- package/dist/index.js +18 -0
- package/package.json +1 -1
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { createEventDispatcher } from "svelte";
|
|
3
|
+
import Button from "../Button/Button.svelte";
|
|
4
|
+
import Cancel from "../../assets/svg/cancel.svg";
|
|
5
|
+
import Modal from "./Modal.svelte";
|
|
6
|
+
|
|
7
|
+
export let show = false;
|
|
8
|
+
export let size = "default"; // "small" | "default" | "large"
|
|
9
|
+
export let title = "";
|
|
10
|
+
export let description = "";
|
|
11
|
+
export let closeBtn = false; // To show close button
|
|
12
|
+
export let persistent = false; // When true, prevents closing by clicking backdrop or pressing Escape
|
|
13
|
+
|
|
14
|
+
// Input configuration
|
|
15
|
+
export let inputLabel = "";
|
|
16
|
+
export let inputPlaceholder = "";
|
|
17
|
+
export let inputType = "text"; // text | email | password | textarea
|
|
18
|
+
export let inputValue = "";
|
|
19
|
+
export let inputRequired = false;
|
|
20
|
+
export let inputRows = 4; // For textarea
|
|
21
|
+
export let inputIcon = null; // SVG component for input prefix icon
|
|
22
|
+
export let helpText = ""; // Helper text below input
|
|
23
|
+
|
|
24
|
+
// Validation
|
|
25
|
+
export let errorMessage = "";
|
|
26
|
+
export let showError = false;
|
|
27
|
+
export let validateEmail = false; // Auto-validate email format
|
|
28
|
+
|
|
29
|
+
// Buttons
|
|
30
|
+
export let primaryButtonText = "Confirm";
|
|
31
|
+
export let secondaryButtonText = "Cancel";
|
|
32
|
+
export let primaryButtonVariant = "blue-solid"; // blue-solid | red-solid
|
|
33
|
+
|
|
34
|
+
// State
|
|
35
|
+
export let disabled = false;
|
|
36
|
+
export let loading = false;
|
|
37
|
+
|
|
38
|
+
const dispatch = createEventDispatcher();
|
|
39
|
+
|
|
40
|
+
// Email validation
|
|
41
|
+
const isValidEmail = (email) => {
|
|
42
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
43
|
+
return emailRegex.test(email);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
$: emailError = validateEmail && inputValue && !isValidEmail(inputValue);
|
|
47
|
+
$: isEmpty = inputRequired && (!inputValue || inputValue.trim() === "");
|
|
48
|
+
$: hasError = showError || emailError;
|
|
49
|
+
$: isDisabled = disabled || loading || isEmpty || emailError;
|
|
50
|
+
|
|
51
|
+
const handlePrimaryAction = () => {
|
|
52
|
+
if (!isDisabled) {
|
|
53
|
+
dispatch("confirm", { value: inputValue });
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const handleSecondaryAction = () => {
|
|
58
|
+
if (!disabled && !loading) {
|
|
59
|
+
dispatch("cancel");
|
|
60
|
+
closeModal();
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const closeModal = () => {
|
|
65
|
+
show = false;
|
|
66
|
+
dispatch("close");
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const handleClose = () => {
|
|
70
|
+
if (disabled || loading) return;
|
|
71
|
+
closeModal();
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// Reset input when modal closes
|
|
75
|
+
$: if (!show) {
|
|
76
|
+
// Optionally reset - controlled externally via inputValue prop
|
|
77
|
+
}
|
|
78
|
+
</script>
|
|
79
|
+
|
|
80
|
+
<Modal bind:show {size} {persistent}>
|
|
81
|
+
<div slot="header" class="text-left">
|
|
82
|
+
{#if closeBtn}
|
|
83
|
+
<div class="flex justify-end -mt-2 -mr-2 mb-2">
|
|
84
|
+
<button
|
|
85
|
+
class="p-1 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none transition-colors"
|
|
86
|
+
on:click={handleClose}
|
|
87
|
+
{disabled}
|
|
88
|
+
>
|
|
89
|
+
<img src={Cancel} alt="Close" class="w-5 h-5" />
|
|
90
|
+
</button>
|
|
91
|
+
</div>
|
|
92
|
+
{/if}
|
|
93
|
+
{#if title}
|
|
94
|
+
<h3 class="text-xl font-medium text-gray-900 dark:text-white">{title}</h3>
|
|
95
|
+
{/if}
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
<div slot="body" class="text-left mt-4">
|
|
99
|
+
{#if description}
|
|
100
|
+
<p class="text-sm text-gray-500 dark:text-gray-400 leading-relaxed mb-4">
|
|
101
|
+
{description}
|
|
102
|
+
</p>
|
|
103
|
+
{/if}
|
|
104
|
+
|
|
105
|
+
<div>
|
|
106
|
+
{#if inputLabel}
|
|
107
|
+
<label
|
|
108
|
+
for="modal-input"
|
|
109
|
+
class="block text-sm font-medium text-gray-900 dark:text-white mb-2"
|
|
110
|
+
>
|
|
111
|
+
{inputLabel}
|
|
112
|
+
</label>
|
|
113
|
+
{/if}
|
|
114
|
+
|
|
115
|
+
{#if inputType === "textarea"}
|
|
116
|
+
<textarea
|
|
117
|
+
id="modal-input"
|
|
118
|
+
bind:value={inputValue}
|
|
119
|
+
placeholder={inputPlaceholder}
|
|
120
|
+
rows={inputRows}
|
|
121
|
+
class="w-full px-3 py-2 border {hasError ? 'border-red-500' : 'border-gray-300 dark:border-gray-600'} bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-white rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-none"
|
|
122
|
+
disabled={disabled || loading}
|
|
123
|
+
></textarea>
|
|
124
|
+
{:else}
|
|
125
|
+
<div class="relative">
|
|
126
|
+
{#if inputIcon}
|
|
127
|
+
<div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
|
|
128
|
+
<svelte:component this={inputIcon} class="w-5 h-5 text-gray-500 dark:text-gray-400" />
|
|
129
|
+
</div>
|
|
130
|
+
{/if}
|
|
131
|
+
<input
|
|
132
|
+
id="modal-input"
|
|
133
|
+
type={inputType}
|
|
134
|
+
bind:value={inputValue}
|
|
135
|
+
placeholder={inputPlaceholder}
|
|
136
|
+
required={inputRequired}
|
|
137
|
+
disabled={disabled || loading}
|
|
138
|
+
class="w-full {inputIcon ? 'pl-10' : 'px-3'} py-2 border {hasError ? 'border-red-500' : 'border-gray-300 dark:border-gray-600'} rounded-lg text-gray-900 dark:text-white bg-white dark:bg-gray-700 focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed"
|
|
139
|
+
/>
|
|
140
|
+
</div>
|
|
141
|
+
{/if}
|
|
142
|
+
|
|
143
|
+
{#if hasError && (errorMessage || emailError)}
|
|
144
|
+
<p class="mt-2 text-sm text-red-600 dark:text-red-400 font-medium flex items-center gap-1">
|
|
145
|
+
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
146
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
|
147
|
+
</svg>
|
|
148
|
+
{emailError ? "Please enter a valid email address" : errorMessage}
|
|
149
|
+
</p>
|
|
150
|
+
{:else if helpText && !hasError}
|
|
151
|
+
<p class="text-xs font-normal text-gray-500 dark:text-gray-400 pt-2">
|
|
152
|
+
{helpText}
|
|
153
|
+
</p>
|
|
154
|
+
{/if}
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
<div slot="footer" class="flex gap-3">
|
|
159
|
+
{#if secondaryButtonText}
|
|
160
|
+
<Button
|
|
161
|
+
size="full"
|
|
162
|
+
variant="gray-outline"
|
|
163
|
+
on:click={handleSecondaryAction}
|
|
164
|
+
disabled={disabled || loading}
|
|
165
|
+
>
|
|
166
|
+
{secondaryButtonText}
|
|
167
|
+
</Button>
|
|
168
|
+
{/if}
|
|
169
|
+
|
|
170
|
+
<Button
|
|
171
|
+
size="full"
|
|
172
|
+
variant={primaryButtonVariant}
|
|
173
|
+
on:click={handlePrimaryAction}
|
|
174
|
+
disabled={isDisabled}
|
|
175
|
+
{loading}
|
|
176
|
+
>
|
|
177
|
+
{primaryButtonText}
|
|
178
|
+
</Button>
|
|
179
|
+
</div>
|
|
180
|
+
</Modal>
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export default InputModal;
|
|
2
|
+
type InputModal = SvelteComponent<{
|
|
3
|
+
title?: string | undefined;
|
|
4
|
+
size?: string | undefined;
|
|
5
|
+
show?: boolean | undefined;
|
|
6
|
+
disabled?: boolean | undefined;
|
|
7
|
+
loading?: boolean | undefined;
|
|
8
|
+
persistent?: boolean | undefined;
|
|
9
|
+
description?: string | undefined;
|
|
10
|
+
closeBtn?: boolean | undefined;
|
|
11
|
+
primaryButtonText?: string | undefined;
|
|
12
|
+
secondaryButtonText?: string | undefined;
|
|
13
|
+
inputLabel?: string | undefined;
|
|
14
|
+
inputPlaceholder?: string | undefined;
|
|
15
|
+
inputType?: string | undefined;
|
|
16
|
+
inputValue?: string | undefined;
|
|
17
|
+
inputRequired?: boolean | undefined;
|
|
18
|
+
inputRows?: number | undefined;
|
|
19
|
+
inputIcon?: null | undefined;
|
|
20
|
+
helpText?: string | undefined;
|
|
21
|
+
errorMessage?: string | undefined;
|
|
22
|
+
showError?: boolean | undefined;
|
|
23
|
+
validateEmail?: boolean | undefined;
|
|
24
|
+
primaryButtonVariant?: string | undefined;
|
|
25
|
+
}, {
|
|
26
|
+
confirm: CustomEvent<any>;
|
|
27
|
+
cancel: CustomEvent<any>;
|
|
28
|
+
close: CustomEvent<any>;
|
|
29
|
+
} & {
|
|
30
|
+
[evt: string]: CustomEvent<any>;
|
|
31
|
+
}, {}> & {
|
|
32
|
+
$$bindings?: string | undefined;
|
|
33
|
+
};
|
|
34
|
+
declare const InputModal: $$__sveltets_2_IsomorphicComponent<{
|
|
35
|
+
title?: string | undefined;
|
|
36
|
+
size?: string | undefined;
|
|
37
|
+
show?: boolean | undefined;
|
|
38
|
+
disabled?: boolean | undefined;
|
|
39
|
+
loading?: boolean | undefined;
|
|
40
|
+
persistent?: boolean | undefined;
|
|
41
|
+
description?: string | undefined;
|
|
42
|
+
closeBtn?: boolean | undefined;
|
|
43
|
+
primaryButtonText?: string | undefined;
|
|
44
|
+
secondaryButtonText?: string | undefined;
|
|
45
|
+
inputLabel?: string | undefined;
|
|
46
|
+
inputPlaceholder?: string | undefined;
|
|
47
|
+
inputType?: string | undefined;
|
|
48
|
+
inputValue?: string | undefined;
|
|
49
|
+
inputRequired?: boolean | undefined;
|
|
50
|
+
inputRows?: number | undefined;
|
|
51
|
+
inputIcon?: null | undefined;
|
|
52
|
+
helpText?: string | undefined;
|
|
53
|
+
errorMessage?: string | undefined;
|
|
54
|
+
showError?: boolean | undefined;
|
|
55
|
+
validateEmail?: boolean | undefined;
|
|
56
|
+
primaryButtonVariant?: string | undefined;
|
|
57
|
+
}, {
|
|
58
|
+
confirm: CustomEvent<any>;
|
|
59
|
+
cancel: CustomEvent<any>;
|
|
60
|
+
close: CustomEvent<any>;
|
|
61
|
+
} & {
|
|
62
|
+
[evt: string]: CustomEvent<any>;
|
|
63
|
+
}, {}, {}, string>;
|
|
64
|
+
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> {
|
|
65
|
+
new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
|
|
66
|
+
$$bindings?: Bindings;
|
|
67
|
+
} & Exports;
|
|
68
|
+
(internal: unknown, props: Props & {
|
|
69
|
+
$$events?: Events;
|
|
70
|
+
$$slots?: Slots;
|
|
71
|
+
}): Exports & {
|
|
72
|
+
$set?: any;
|
|
73
|
+
$on?: any;
|
|
74
|
+
};
|
|
75
|
+
z_$$bindings?: Bindings;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=InputModal.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InputModal.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/Modal/InputModal.svelte.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAAka;6CATrX,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,OAAO,OAAO,QAAQ;IAC3L,cAAc,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,WAAW,OAAO,SAAS,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,eAAe,QAAQ,CAAC"}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
export let isProcessing = false;
|
|
9
9
|
export let isSuccess = false;
|
|
10
10
|
export let size = "default"; // "default" | "small" | "large"
|
|
11
|
+
export let persistent = false; // When true, prevents closing by clicking backdrop or pressing Escape
|
|
11
12
|
|
|
12
13
|
const dispatch = createEventDispatcher();
|
|
13
14
|
|
|
@@ -16,7 +17,7 @@
|
|
|
16
17
|
|
|
17
18
|
// Handle escape key
|
|
18
19
|
function handleKeydown(event) {
|
|
19
|
-
if (event.key === "Escape" && show) {
|
|
20
|
+
if (event.key === "Escape" && show && !persistent) {
|
|
20
21
|
resetModal();
|
|
21
22
|
}
|
|
22
23
|
}
|
|
@@ -72,7 +73,7 @@
|
|
|
72
73
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
73
74
|
<div
|
|
74
75
|
class="modal-backdrop"
|
|
75
|
-
on:click={resetModal}
|
|
76
|
+
on:click={persistent ? null : resetModal}
|
|
76
77
|
transition:fade={{ duration: 300 }}
|
|
77
78
|
role="dialog"
|
|
78
79
|
aria-modal="true"
|
|
@@ -122,12 +123,17 @@
|
|
|
122
123
|
{/if}
|
|
123
124
|
|
|
124
125
|
<style>
|
|
126
|
+
/*
|
|
127
|
+
* Modal uses Tailwind-compatible colors with dark mode support.
|
|
128
|
+
* Works across projects without requiring CSS variable synchronization.
|
|
129
|
+
*/
|
|
130
|
+
|
|
125
131
|
.modal-backdrop {
|
|
126
132
|
position: fixed;
|
|
127
133
|
inset: 0;
|
|
128
134
|
display: flex;
|
|
129
135
|
background-color: rgba(0, 0, 0, 0.5);
|
|
130
|
-
z-index:
|
|
136
|
+
z-index: 50;
|
|
131
137
|
|
|
132
138
|
/* iOS scroll lock - prevent scroll bleed-through */
|
|
133
139
|
touch-action: none;
|
|
@@ -149,7 +155,7 @@
|
|
|
149
155
|
|
|
150
156
|
/* Mobile: Bottom sheet style */
|
|
151
157
|
.modal-sheet {
|
|
152
|
-
background-color:
|
|
158
|
+
background-color: #ffffff;
|
|
153
159
|
border-radius: 1.5rem 1.5rem 0 0;
|
|
154
160
|
width: 100%;
|
|
155
161
|
max-height: 90vh;
|
|
@@ -164,6 +170,10 @@
|
|
|
164
170
|
overscroll-behavior: contain;
|
|
165
171
|
}
|
|
166
172
|
|
|
173
|
+
:global(.dark) .modal-sheet {
|
|
174
|
+
background-color: #1f2937; /* gray-800 */
|
|
175
|
+
}
|
|
176
|
+
|
|
167
177
|
/* Hide sheet on desktop */
|
|
168
178
|
@media (min-width: 768px) {
|
|
169
179
|
.modal-sheet {
|
|
@@ -181,13 +191,18 @@
|
|
|
181
191
|
.sheet-handle {
|
|
182
192
|
width: 2.5rem;
|
|
183
193
|
height: 0.25rem;
|
|
184
|
-
background-color:
|
|
194
|
+
background-color: #d1d5db; /* gray-300 */
|
|
185
195
|
border-radius: 0.125rem;
|
|
186
196
|
}
|
|
187
197
|
|
|
198
|
+
:global(.dark) .sheet-handle {
|
|
199
|
+
background-color: #4b5563; /* gray-600 */
|
|
200
|
+
}
|
|
201
|
+
|
|
188
202
|
.modal-inner {
|
|
189
|
-
padding:
|
|
190
|
-
|
|
203
|
+
padding: 1.5rem;
|
|
204
|
+
/* Account for bottom nav bars (~70px) plus safe area */
|
|
205
|
+
padding-bottom: calc(5rem + env(safe-area-inset-bottom, 0px));
|
|
191
206
|
overflow-y: auto;
|
|
192
207
|
flex: 1;
|
|
193
208
|
}
|
|
@@ -195,13 +210,18 @@
|
|
|
195
210
|
/* Desktop: Centered modal style */
|
|
196
211
|
.modal-centered {
|
|
197
212
|
display: none;
|
|
198
|
-
background-color:
|
|
213
|
+
background-color: #ffffff;
|
|
199
214
|
padding: 1.5rem;
|
|
200
215
|
border-radius: 1rem;
|
|
201
216
|
max-width: 420px;
|
|
202
217
|
width: 100%;
|
|
203
218
|
max-height: calc(100vh - 4rem);
|
|
204
219
|
overflow-y: auto;
|
|
220
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
:global(.dark) .modal-centered {
|
|
224
|
+
background-color: #1f2937; /* gray-800 */
|
|
205
225
|
}
|
|
206
226
|
|
|
207
227
|
@media (min-width: 768px) {
|
|
@@ -223,6 +243,12 @@
|
|
|
223
243
|
display: flex;
|
|
224
244
|
flex-direction: column;
|
|
225
245
|
gap: 0.75rem;
|
|
246
|
+
margin-top: 1.5rem; /* 24px - consistent gap before buttons */
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.modal-footer:empty {
|
|
250
|
+
display: none;
|
|
251
|
+
margin-top: 0;
|
|
226
252
|
}
|
|
227
253
|
|
|
228
254
|
@media (min-width: 768px) {
|
|
@@ -4,6 +4,7 @@ type Modal = SvelteComponent<{
|
|
|
4
4
|
show?: boolean | undefined;
|
|
5
5
|
isSuccess?: boolean | undefined;
|
|
6
6
|
isProcessing?: boolean | undefined;
|
|
7
|
+
persistent?: boolean | undefined;
|
|
7
8
|
}, {
|
|
8
9
|
click: PointerEvent;
|
|
9
10
|
cancel: CustomEvent<any>;
|
|
@@ -21,6 +22,7 @@ declare const Modal: $$__sveltets_2_IsomorphicComponent<{
|
|
|
21
22
|
show?: boolean | undefined;
|
|
22
23
|
isSuccess?: boolean | undefined;
|
|
23
24
|
isProcessing?: boolean | undefined;
|
|
25
|
+
persistent?: boolean | undefined;
|
|
24
26
|
}, {
|
|
25
27
|
click: PointerEvent;
|
|
26
28
|
cancel: CustomEvent<any>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Modal.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/Modal/Modal.svelte.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Modal.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/Modal/Modal.svelte.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AAmIA;;;;;;;;;;;;;;;eAAgL;6CAdnI,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,OAAO,OAAO,QAAQ;IAC3L,cAAc,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,WAAW,OAAO,SAAS,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { createEventDispatcher } from "svelte";
|
|
3
|
+
import Button from "../Button/Button.svelte";
|
|
4
|
+
import Cancel from "../../assets/svg/cancel.svg";
|
|
5
|
+
import Modal from "./Modal.svelte";
|
|
6
|
+
|
|
7
|
+
export let show = false;
|
|
8
|
+
export let size = "small"; // "small" | "default" | "large"
|
|
9
|
+
export let title = "";
|
|
10
|
+
export let subtitle = ""; // For profile-style modals (e.g., performer email)
|
|
11
|
+
export let description = "";
|
|
12
|
+
export let buttonText = "Ok";
|
|
13
|
+
export let iconType = "success"; // success | error | warning | info
|
|
14
|
+
export let customIcon = null;
|
|
15
|
+
export let image = null; // For profile photos (rounded square instead of circular icon)
|
|
16
|
+
export let disabled = false;
|
|
17
|
+
export let loading = false;
|
|
18
|
+
export let variant = null; // Alternative to iconType for consistency with ConfirmationModal
|
|
19
|
+
export let actions = []; // For multiple buttons (like ProfileAddedModal)
|
|
20
|
+
export let closeBtn = false; // To show close button
|
|
21
|
+
|
|
22
|
+
const dispatch = createEventDispatcher();
|
|
23
|
+
|
|
24
|
+
// Use variant if provided, otherwise fallback to iconType
|
|
25
|
+
$: effectiveVariant = variant || iconType;
|
|
26
|
+
|
|
27
|
+
// Check if we're in profile mode (image instead of icon)
|
|
28
|
+
$: isProfileMode = !!image;
|
|
29
|
+
|
|
30
|
+
const handleButtonClick = () => {
|
|
31
|
+
if (!disabled && !loading) {
|
|
32
|
+
dispatch("confirm");
|
|
33
|
+
closeModal();
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const handleAction = (action) => {
|
|
38
|
+
if (!disabled && !loading) {
|
|
39
|
+
action.onClick?.();
|
|
40
|
+
dispatch(action.label.toLowerCase());
|
|
41
|
+
if (!action.keepOpen) {
|
|
42
|
+
closeModal();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const closeModal = () => {
|
|
48
|
+
show = false;
|
|
49
|
+
dispatch("close");
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const handleClose = () => {
|
|
53
|
+
if (disabled || loading) return;
|
|
54
|
+
closeModal();
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Get button variant for action buttons
|
|
58
|
+
const getActionVariant = (action) => {
|
|
59
|
+
if (action.variant) return action.variant;
|
|
60
|
+
const label = action.label.toLowerCase();
|
|
61
|
+
if (label.startsWith('delete') || label.startsWith('archive') || action.danger) {
|
|
62
|
+
return 'red-solid';
|
|
63
|
+
}
|
|
64
|
+
if (label === 'continue' || label === 'finish' || label === 'done' || label === 'save & notify') {
|
|
65
|
+
return 'blue-solid';
|
|
66
|
+
}
|
|
67
|
+
return 'gray-outline';
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Icon colors based on variant
|
|
71
|
+
const getIconColors = (type) => {
|
|
72
|
+
switch (type) {
|
|
73
|
+
case "success":
|
|
74
|
+
return {
|
|
75
|
+
bg: "bg-green-100 dark:bg-green-900/30",
|
|
76
|
+
icon: "text-green-600 dark:text-green-400",
|
|
77
|
+
};
|
|
78
|
+
case "error":
|
|
79
|
+
return {
|
|
80
|
+
bg: "bg-red-100 dark:bg-red-900/30",
|
|
81
|
+
icon: "text-red-600 dark:text-red-400",
|
|
82
|
+
};
|
|
83
|
+
case "warning":
|
|
84
|
+
return {
|
|
85
|
+
bg: "bg-amber-100 dark:bg-amber-900/30",
|
|
86
|
+
icon: "text-amber-600 dark:text-amber-400",
|
|
87
|
+
};
|
|
88
|
+
case "info":
|
|
89
|
+
return {
|
|
90
|
+
bg: "bg-blue-100 dark:bg-blue-900/30",
|
|
91
|
+
icon: "text-blue-600 dark:text-blue-400",
|
|
92
|
+
};
|
|
93
|
+
default:
|
|
94
|
+
return {
|
|
95
|
+
bg: "bg-green-100 dark:bg-green-900/30",
|
|
96
|
+
icon: "text-green-600 dark:text-green-400",
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// Button variant based on status type
|
|
102
|
+
const getButtonVariant = (type) => {
|
|
103
|
+
switch (type) {
|
|
104
|
+
case "error":
|
|
105
|
+
return "red-solid";
|
|
106
|
+
case "warning":
|
|
107
|
+
return "blue-solid";
|
|
108
|
+
default:
|
|
109
|
+
return "blue-solid";
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
$: colors = getIconColors(effectiveVariant);
|
|
114
|
+
$: buttonVariant = getButtonVariant(effectiveVariant);
|
|
115
|
+
</script>
|
|
116
|
+
|
|
117
|
+
<Modal bind:show {size}>
|
|
118
|
+
<div slot="header" class="text-center">
|
|
119
|
+
{#if closeBtn}
|
|
120
|
+
<div class="flex justify-end -mt-2 -mr-2 mb-2">
|
|
121
|
+
<button
|
|
122
|
+
class="p-1 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none transition-colors"
|
|
123
|
+
on:click={handleClose}
|
|
124
|
+
{disabled}
|
|
125
|
+
>
|
|
126
|
+
<img src={Cancel} alt="Close" class="w-5 h-5" />
|
|
127
|
+
</button>
|
|
128
|
+
</div>
|
|
129
|
+
{/if}
|
|
130
|
+
{#if isProfileMode}
|
|
131
|
+
<!-- Profile mode: show image as rounded square -->
|
|
132
|
+
<div class="flex justify-center">
|
|
133
|
+
<img
|
|
134
|
+
src={image}
|
|
135
|
+
alt={title}
|
|
136
|
+
class="w-16 h-16 rounded-lg object-cover"
|
|
137
|
+
/>
|
|
138
|
+
</div>
|
|
139
|
+
<div class="mt-4">
|
|
140
|
+
{#if title}
|
|
141
|
+
<h2 class="text-xl font-medium text-gray-900 dark:text-white">{title}</h2>
|
|
142
|
+
{/if}
|
|
143
|
+
{#if subtitle}
|
|
144
|
+
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">{subtitle}</p>
|
|
145
|
+
{/if}
|
|
146
|
+
</div>
|
|
147
|
+
{:else}
|
|
148
|
+
<!-- Status mode: show icon in colored circle -->
|
|
149
|
+
<div class="flex justify-center items-center">
|
|
150
|
+
{#if customIcon}
|
|
151
|
+
<div class="w-14 h-14 rounded-full {colors.bg} flex items-center justify-center">
|
|
152
|
+
<img src={customIcon} alt="Status icon" class="w-8 h-8" />
|
|
153
|
+
</div>
|
|
154
|
+
{:else}
|
|
155
|
+
<div class="w-14 h-14 rounded-full {colors.bg} flex items-center justify-center">
|
|
156
|
+
{#if effectiveVariant === "success"}
|
|
157
|
+
<svg class="w-7 h-7 {colors.icon}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
158
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
|
159
|
+
</svg>
|
|
160
|
+
{:else if effectiveVariant === "error"}
|
|
161
|
+
<svg class="w-7 h-7 {colors.icon}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
162
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
163
|
+
</svg>
|
|
164
|
+
{:else if effectiveVariant === "warning"}
|
|
165
|
+
<svg class="w-7 h-7 {colors.icon}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
166
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
|
167
|
+
</svg>
|
|
168
|
+
{:else if effectiveVariant === "info"}
|
|
169
|
+
<svg class="w-7 h-7 {colors.icon}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
170
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
171
|
+
</svg>
|
|
172
|
+
{/if}
|
|
173
|
+
</div>
|
|
174
|
+
{/if}
|
|
175
|
+
</div>
|
|
176
|
+
{#if title}
|
|
177
|
+
<h2 class="text-xl font-medium text-gray-900 dark:text-white mt-4">{title}</h2>
|
|
178
|
+
{/if}
|
|
179
|
+
{/if}
|
|
180
|
+
</div>
|
|
181
|
+
|
|
182
|
+
<div slot="body" class="text-center mt-4">
|
|
183
|
+
{#if description}
|
|
184
|
+
<p class="text-sm leading-relaxed {isProfileMode ? 'text-gray-900 dark:text-white font-medium' : 'text-gray-500 dark:text-gray-400'}">
|
|
185
|
+
{description}
|
|
186
|
+
</p>
|
|
187
|
+
{/if}
|
|
188
|
+
</div>
|
|
189
|
+
|
|
190
|
+
<div slot="footer" class="w-full">
|
|
191
|
+
{#if actions.length > 0}
|
|
192
|
+
<!-- Multiple buttons mode -->
|
|
193
|
+
<div class="flex gap-3">
|
|
194
|
+
{#each actions as action}
|
|
195
|
+
<Button
|
|
196
|
+
size="full"
|
|
197
|
+
variant={getActionVariant(action)}
|
|
198
|
+
beforeIcon={action.beforeIcon}
|
|
199
|
+
afterIcon={action.afterIcon}
|
|
200
|
+
disabled={action.disabled || disabled}
|
|
201
|
+
loading={action.loading || (loading && action.primary)}
|
|
202
|
+
on:click={() => handleAction(action)}
|
|
203
|
+
>
|
|
204
|
+
{action.label}
|
|
205
|
+
</Button>
|
|
206
|
+
{/each}
|
|
207
|
+
</div>
|
|
208
|
+
{:else}
|
|
209
|
+
<!-- Single button mode -->
|
|
210
|
+
<Button
|
|
211
|
+
size="full"
|
|
212
|
+
variant={buttonVariant}
|
|
213
|
+
{disabled}
|
|
214
|
+
{loading}
|
|
215
|
+
on:click={handleButtonClick}
|
|
216
|
+
>
|
|
217
|
+
{buttonText}
|
|
218
|
+
</Button>
|
|
219
|
+
{/if}
|
|
220
|
+
</div>
|
|
221
|
+
</Modal>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export default StatusModal;
|
|
2
|
+
type StatusModal = SvelteComponent<{
|
|
3
|
+
title?: string | undefined;
|
|
4
|
+
size?: string | undefined;
|
|
5
|
+
variant?: null | undefined;
|
|
6
|
+
actions?: any[] | undefined;
|
|
7
|
+
show?: boolean | undefined;
|
|
8
|
+
subtitle?: string | undefined;
|
|
9
|
+
disabled?: boolean | undefined;
|
|
10
|
+
loading?: boolean | undefined;
|
|
11
|
+
image?: null | undefined;
|
|
12
|
+
buttonText?: string | undefined;
|
|
13
|
+
description?: string | undefined;
|
|
14
|
+
customIcon?: null | undefined;
|
|
15
|
+
closeBtn?: boolean | undefined;
|
|
16
|
+
iconType?: string | undefined;
|
|
17
|
+
}, {
|
|
18
|
+
confirm: CustomEvent<any>;
|
|
19
|
+
close: CustomEvent<any>;
|
|
20
|
+
} & {
|
|
21
|
+
[evt: string]: CustomEvent<any>;
|
|
22
|
+
}, {}> & {
|
|
23
|
+
$$bindings?: string | undefined;
|
|
24
|
+
};
|
|
25
|
+
declare const StatusModal: $$__sveltets_2_IsomorphicComponent<{
|
|
26
|
+
title?: string | undefined;
|
|
27
|
+
size?: string | undefined;
|
|
28
|
+
variant?: null | undefined;
|
|
29
|
+
actions?: any[] | undefined;
|
|
30
|
+
show?: boolean | undefined;
|
|
31
|
+
subtitle?: string | undefined;
|
|
32
|
+
disabled?: boolean | undefined;
|
|
33
|
+
loading?: boolean | undefined;
|
|
34
|
+
image?: null | undefined;
|
|
35
|
+
buttonText?: string | undefined;
|
|
36
|
+
description?: string | undefined;
|
|
37
|
+
customIcon?: null | undefined;
|
|
38
|
+
closeBtn?: boolean | undefined;
|
|
39
|
+
iconType?: string | undefined;
|
|
40
|
+
}, {
|
|
41
|
+
confirm: CustomEvent<any>;
|
|
42
|
+
close: CustomEvent<any>;
|
|
43
|
+
} & {
|
|
44
|
+
[evt: string]: CustomEvent<any>;
|
|
45
|
+
}, {}, {}, string>;
|
|
46
|
+
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> {
|
|
47
|
+
new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
|
|
48
|
+
$$bindings?: Bindings;
|
|
49
|
+
} & Exports;
|
|
50
|
+
(internal: unknown, props: Props & {
|
|
51
|
+
$$events?: Events;
|
|
52
|
+
$$slots?: Slots;
|
|
53
|
+
}): Exports & {
|
|
54
|
+
$set?: any;
|
|
55
|
+
$on?: any;
|
|
56
|
+
};
|
|
57
|
+
z_$$bindings?: Bindings;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=StatusModal.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatusModal.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/Modal/StatusModal.svelte.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA2NA;;;;;;;;;;;;;;;;;;;;mBAA0Q;6CAT7N,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,OAAO,OAAO,QAAQ;IAC3L,cAAc,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,WAAW,OAAO,SAAS,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,eAAe,QAAQ,CAAC"}
|