svelte-comp 1.2.7 → 1.3.5
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/README.md +12 -11
- package/dist/App.svelte +497 -2
- package/dist/app.css +2 -3
- package/dist/app.d.ts +10 -0
- package/dist/lang.d.ts +3 -3
- package/dist/lang.js +3 -3
- package/dist/lib/Accordion.svelte +14 -14
- package/dist/lib/Badge.svelte +44 -0
- package/dist/lib/Badge.svelte.d.ts +10 -0
- package/dist/lib/Button.svelte +23 -8
- package/dist/lib/Calendar.svelte +384 -377
- package/dist/lib/Card.svelte +6 -6
- package/dist/lib/Carousel.svelte +16 -16
- package/dist/lib/Carousel.svelte.d.ts +1 -1
- package/dist/lib/CheckBox.svelte +2 -2
- package/dist/lib/CodeView.svelte +6 -5
- package/dist/lib/ColorPicker.svelte +6 -6
- package/dist/lib/ContextMenu.svelte +328 -0
- package/dist/lib/ContextMenu.svelte.d.ts +14 -0
- package/dist/lib/DatePicker.svelte +161 -161
- package/dist/lib/Dialog.svelte +10 -10
- package/dist/lib/Field.svelte +1 -1
- package/dist/lib/FilePicker.svelte +127 -74
- package/dist/lib/FilePicker.svelte.d.ts +6 -3
- package/dist/lib/Hamburger.svelte +27 -21
- package/dist/lib/InstallPWA.svelte +94 -0
- package/dist/lib/InstallPWA.svelte.d.ts +8 -0
- package/dist/lib/Menu.svelte +18 -18
- package/dist/lib/NoticeBase.svelte +140 -0
- package/dist/lib/NoticeBase.svelte.d.ts +43 -0
- package/dist/lib/PrimaryColorSelect.svelte +6 -6
- package/dist/lib/ProgressCircle.svelte +7 -9
- package/dist/lib/ProgressCircle.svelte.d.ts +7 -9
- package/dist/lib/SearchInput.svelte +6 -6
- package/dist/lib/Select.svelte +2 -2
- package/dist/lib/Slider.svelte +1 -1
- package/dist/lib/Splitter.svelte +15 -6
- package/dist/lib/Switch.svelte +5 -4
- package/dist/lib/Tabs.svelte +6 -6
- package/dist/lib/ThemeToggle.svelte +1 -0
- package/dist/lib/TimePicker.svelte +103 -95
- package/dist/lib/TimePickerNew.svelte +634 -0
- package/dist/lib/TimePickerNew.svelte.d.ts +49 -0
- package/dist/lib/Toast.svelte +17 -120
- package/dist/lib/Tooltip.svelte +7 -7
- package/dist/lib/Topbar.svelte +112 -0
- package/dist/lib/Topbar.svelte.d.ts +44 -0
- package/dist/lib/__tests__/Accordion.test.d.ts +1 -0
- package/dist/lib/__tests__/Accordion.test.js +171 -0
- package/dist/lib/__tests__/Badge.test.d.ts +1 -0
- package/dist/lib/__tests__/Badge.test.js +41 -0
- package/dist/lib/__tests__/Button.test.d.ts +1 -0
- package/dist/lib/__tests__/Button.test.js +269 -0
- package/dist/lib/__tests__/Calendar.test.d.ts +1 -0
- package/dist/lib/__tests__/Calendar.test.js +171 -0
- package/dist/lib/__tests__/Card.test.d.ts +1 -0
- package/dist/lib/__tests__/Card.test.js +148 -0
- package/dist/lib/__tests__/Carousel.test.d.ts +1 -0
- package/dist/lib/__tests__/Carousel.test.js +439 -0
- package/dist/lib/__tests__/CheckBox.test.d.ts +1 -0
- package/dist/lib/__tests__/CheckBox.test.js +152 -0
- package/dist/lib/__tests__/CodeView.test.d.ts +1 -0
- package/dist/lib/__tests__/CodeView.test.js +157 -0
- package/dist/lib/__tests__/ColorPicker.test.d.ts +1 -0
- package/dist/lib/__tests__/ColorPicker.test.js +93 -0
- package/dist/lib/__tests__/ContextMenu.test.d.ts +1 -0
- package/dist/lib/__tests__/ContextMenu.test.js +67 -0
- package/dist/lib/__tests__/DatePicker.test.d.ts +1 -0
- package/dist/lib/__tests__/DatePicker.test.js +108 -0
- package/dist/lib/__tests__/Dialog.test.d.ts +1 -0
- package/dist/lib/__tests__/Dialog.test.js +183 -0
- package/dist/lib/__tests__/Field.test.d.ts +1 -0
- package/dist/lib/__tests__/Field.test.js +190 -0
- package/dist/lib/__tests__/FilePicker.test.d.ts +1 -0
- package/dist/lib/__tests__/FilePicker.test.js +179 -0
- package/dist/lib/__tests__/Form.integration.test.d.ts +1 -0
- package/dist/lib/__tests__/Form.integration.test.js +158 -0
- package/dist/lib/__tests__/Form.test.d.ts +1 -0
- package/dist/lib/__tests__/Form.test.js +463 -0
- package/dist/lib/__tests__/Hamburger.test.d.ts +1 -0
- package/dist/lib/__tests__/Hamburger.test.js +161 -0
- package/dist/lib/__tests__/InstallPWA.test.d.ts +1 -0
- package/dist/lib/__tests__/InstallPWA.test.js +15 -0
- package/dist/lib/__tests__/Menu.test.d.ts +1 -0
- package/dist/lib/__tests__/Menu.test.js +285 -0
- package/dist/lib/__tests__/NoticeBase.test.d.ts +1 -0
- package/dist/lib/__tests__/NoticeBase.test.js +60 -0
- package/dist/lib/__tests__/PaginatedCard.test.d.ts +1 -0
- package/dist/lib/__tests__/PaginatedCard.test.js +89 -0
- package/dist/lib/__tests__/Pagination.test.d.ts +1 -0
- package/dist/lib/__tests__/Pagination.test.js +168 -0
- package/dist/lib/__tests__/PrimaryColorSelect.test.d.ts +1 -0
- package/dist/lib/__tests__/PrimaryColorSelect.test.js +92 -0
- package/dist/lib/__tests__/ProgressBar.test.d.ts +1 -0
- package/dist/lib/__tests__/ProgressBar.test.js +69 -0
- package/dist/lib/__tests__/ProgressCircle.test.d.ts +1 -0
- package/dist/lib/__tests__/ProgressCircle.test.js +71 -0
- package/dist/lib/__tests__/Radio.test.d.ts +1 -0
- package/dist/lib/__tests__/Radio.test.js +127 -0
- package/dist/lib/__tests__/SearchInput.test.d.ts +1 -0
- package/dist/lib/__tests__/SearchInput.test.js +80 -0
- package/dist/lib/__tests__/Select.test.d.ts +1 -0
- package/dist/lib/__tests__/Select.test.js +408 -0
- package/dist/lib/__tests__/Slider.test.d.ts +1 -0
- package/dist/lib/__tests__/Slider.test.js +213 -0
- package/dist/lib/__tests__/Splitter.test.d.ts +1 -0
- package/dist/lib/__tests__/Splitter.test.js +87 -0
- package/dist/lib/__tests__/Switch.test.d.ts +1 -0
- package/dist/lib/__tests__/Switch.test.js +97 -0
- package/dist/lib/__tests__/Table.test.d.ts +1 -0
- package/dist/lib/__tests__/Table.test.js +349 -0
- package/dist/lib/__tests__/Tabs.test.d.ts +1 -0
- package/dist/lib/__tests__/Tabs.test.js +262 -0
- package/dist/lib/__tests__/ThemeToggle.test.d.ts +1 -0
- package/dist/lib/__tests__/ThemeToggle.test.js +84 -0
- package/dist/lib/__tests__/TimePicker.test.d.ts +1 -0
- package/dist/lib/__tests__/TimePicker.test.js +146 -0
- package/dist/lib/__tests__/TimePickerNew.test.d.ts +1 -0
- package/dist/lib/__tests__/TimePickerNew.test.js +322 -0
- package/dist/lib/__tests__/Toast.test.d.ts +1 -0
- package/dist/lib/__tests__/Toast.test.js +135 -0
- package/dist/lib/__tests__/Tooltip.test.d.ts +1 -0
- package/dist/lib/__tests__/Tooltip.test.js +171 -0
- package/dist/lib/__tests__/Topbar.test.d.ts +1 -0
- package/dist/lib/__tests__/Topbar.test.js +25 -0
- package/dist/lib/__tests__/setupLangContext.d.ts +1 -0
- package/dist/lib/__tests__/setupLangContext.js +65 -0
- package/dist/lib/__tests__/storage.test.d.ts +1 -0
- package/dist/lib/__tests__/storage.test.js +124 -0
- package/dist/lib/__tests__/utils.test.d.ts +1 -0
- package/dist/lib/__tests__/utils.test.js +11 -0
- package/dist/lib/index.d.ts +5 -0
- package/dist/lib/index.js +5 -0
- package/dist/lib/lang.d.ts +64 -0
- package/dist/lib/lang.js +64 -0
- package/dist/lib/types/index.d.ts +1 -0
- package/dist/styles.css +2 -0
- package/dist/utils/index.js +15 -4
- package/package.json +12 -12
|
@@ -16,6 +16,10 @@
|
|
|
16
16
|
* @prop clearable {boolean} - Shows a clear button to reset selection
|
|
17
17
|
* @default true
|
|
18
18
|
*
|
|
19
|
+
* @prop maxBytes {number} - Maximum allowed file size in bytes
|
|
20
|
+
*
|
|
21
|
+
* @prop onError {(error: string) => void} - Fired when selected files are rejected
|
|
22
|
+
*
|
|
19
23
|
* @prop placeholder {string} - Placeholder text for the drop zone
|
|
20
24
|
*
|
|
21
25
|
* @prop value {FileList | null} - Controlled selected files (bindable)
|
|
@@ -23,14 +27,12 @@
|
|
|
23
27
|
*
|
|
24
28
|
* @prop onFilesSelected {(files: FileList | null) => void} - Fired when files are chosen
|
|
25
29
|
*
|
|
26
|
-
* @prop onError {(error: string) => void} - Fired on validation errors
|
|
27
|
-
*
|
|
28
30
|
* @prop class {string} - Additional classes for the wrapper
|
|
29
31
|
* @default ""
|
|
30
32
|
*
|
|
31
33
|
* @note The entire area is clickable and supports drag-and-drop.
|
|
32
34
|
* @note After a selection, the underlying input resets its value, so choosing the same file twice still triggers updates.
|
|
33
|
-
* @note `accept`
|
|
35
|
+
* @note `accept` and `maxBytes` are enforced for both input and dropped files.
|
|
34
36
|
* @note When `clearable=true`, the user can clear selected files and the callback receives `null`.
|
|
35
37
|
* @note When `disabled=true`, clicks, drag events, focus, and keyboard input are blocked.
|
|
36
38
|
*/
|
|
@@ -43,6 +45,7 @@ type Props = HTMLAttributes<HTMLDivElement> & {
|
|
|
43
45
|
clearable?: boolean;
|
|
44
46
|
placeholder?: string;
|
|
45
47
|
value?: FileList | null;
|
|
48
|
+
maxBytes?: number;
|
|
46
49
|
onFilesSelected?: (files: FileList | null) => void;
|
|
47
50
|
onError?: (error: string) => void;
|
|
48
51
|
class?: string;
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
});
|
|
118
118
|
|
|
119
119
|
const triggerBase =
|
|
120
|
-
"fixed top-4 left-4 inline-flex items-center justify-center h-8 w-8 rounded-md border border-[var(--border-color-default)] bg-[var(--color-bg-secondary)] hover:bg-[var(--color-bg-hover)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--border-color-focus)] transition-colors z-[var(--z-modal)]";
|
|
120
|
+
"fixed top-4 left-4 inline-flex items-center justify-center h-8 w-8 rounded-[var(--radius-md)] [@media(pointer:coarse)]:min-h-11 [@media(pointer:coarse)]:min-w-11 border border-[var(--border-color-default)] bg-[var(--color-bg-secondary)] hover:bg-[var(--color-bg-hover)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--border-color-focus)] transition-colors z-[var(--z-modal)]";
|
|
121
121
|
|
|
122
122
|
const triggerClass = $derived(cx(triggerBase, externalClass));
|
|
123
123
|
</script>
|
|
@@ -133,19 +133,19 @@
|
|
|
133
133
|
<span class="relative block w-5 h-3.5">
|
|
134
134
|
<span
|
|
135
135
|
class={cx(
|
|
136
|
-
|
|
136
|
+
"absolute left-0 top-1/2 h-[2px] w-full bg-current transition-transform duration-[var(--transition-fast)]",
|
|
137
137
|
open ? "translate-y-[-50%] rotate-45" : "translate-y-[calc(-50%_-_6px)]"
|
|
138
138
|
)}
|
|
139
139
|
></span>
|
|
140
140
|
<span
|
|
141
141
|
class={cx(
|
|
142
|
-
|
|
142
|
+
"absolute left-0 top-1/2 h-[2px] w-full bg-current transition-opacity duration-[var(--transition-fast)] translate-y-[-50%]",
|
|
143
143
|
open ? "opacity-0" : "opacity-100"
|
|
144
144
|
)}
|
|
145
145
|
></span>
|
|
146
146
|
<span
|
|
147
147
|
class={cx(
|
|
148
|
-
|
|
148
|
+
"absolute left-0 top-1/2 h-[2px] w-full bg-current transition-transform duration-[var(--transition-fast)]",
|
|
149
149
|
open
|
|
150
150
|
? "translate-y-[-50%] -rotate-45"
|
|
151
151
|
: "translate-y-[calc(-50%_+_6px)]"
|
|
@@ -165,37 +165,43 @@
|
|
|
165
165
|
style={`width:${typeof width === "number" ? `${width}px` : width}`}
|
|
166
166
|
>
|
|
167
167
|
{#if header}
|
|
168
|
-
|
|
168
|
+
<div class="p-[var(--spacing-md)] border-b border-[var(--border-color-default)]">
|
|
169
169
|
{@render header?.()}
|
|
170
170
|
</div>
|
|
171
171
|
{/if}
|
|
172
172
|
|
|
173
173
|
<div class="flex-1 overflow-y-auto" tabindex="-1">
|
|
174
174
|
{#if menuItems.length === 0}
|
|
175
|
-
|
|
175
|
+
<div class="[font-size:var(--text-xs)] opacity-70 px-[calc(var(--spacing-sm)+var(--spacing-xs))] py-[var(--spacing-sm)] text-center">No items</div>
|
|
176
176
|
{:else}
|
|
177
|
-
|
|
177
|
+
<ul class="grid gap-[var(--spacing-sm)] p-[var(--spacing-md)]">
|
|
178
178
|
{#each menuItems as it (it.id)}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
type="button"
|
|
182
|
-
class="w-full text-left px-3 py-2 rounded-md hover:bg-[var(--color-bg-hover)] focus:outline-[var(--border-color-focus)] focus:outline-2 transition-colors"
|
|
183
|
-
aria-current={activeItem === it.id ? "page" : undefined}
|
|
184
|
-
onclick={() => {
|
|
185
|
-
onSelect?.(it.id);
|
|
186
|
-
if (closeOnSelect) closeMenu();
|
|
187
|
-
}}
|
|
188
|
-
>
|
|
179
|
+
{#if it.type === "section"}
|
|
180
|
+
<li class="px-[calc(var(--spacing-sm)+var(--spacing-xs))] pt-[var(--spacing-sm)] mt-[calc(var(--spacing-sm)+var(--spacing-xs))] text-[var(--color-text-muted)] [font-size:var(--text-xs)] lowercase tracking-wide opacity-70">
|
|
189
181
|
{it.label}
|
|
190
|
-
</
|
|
191
|
-
|
|
182
|
+
</li>
|
|
183
|
+
{:else}
|
|
184
|
+
<li>
|
|
185
|
+
<button
|
|
186
|
+
type="button"
|
|
187
|
+
class="w-full text-left px-[calc(var(--spacing-sm)+var(--spacing-xs))] py-[var(--spacing-sm)] rounded-[var(--radius-md)] hover:bg-[var(--color-bg-hover)] focus:outline-[var(--border-color-focus)] focus:outline-2 transition-colors"
|
|
188
|
+
aria-current={activeItem === it.id ? "page" : undefined}
|
|
189
|
+
onclick={() => {
|
|
190
|
+
onSelect?.(it.id);
|
|
191
|
+
if (closeOnSelect) closeMenu();
|
|
192
|
+
}}
|
|
193
|
+
>
|
|
194
|
+
{it.label}
|
|
195
|
+
</button>
|
|
196
|
+
</li>
|
|
197
|
+
{/if}
|
|
192
198
|
{/each}
|
|
193
199
|
</ul>
|
|
194
200
|
{/if}
|
|
195
201
|
</div>
|
|
196
202
|
|
|
197
203
|
{#if footer}
|
|
198
|
-
|
|
204
|
+
<div class="p-[var(--spacing-md)] border-t border-[var(--border-color-default)]">
|
|
199
205
|
{@render footer?.()}
|
|
200
206
|
</div>
|
|
201
207
|
{/if}
|
|
@@ -203,7 +209,7 @@
|
|
|
203
209
|
|
|
204
210
|
<button
|
|
205
211
|
type="button"
|
|
206
|
-
|
|
212
|
+
class="flex-1 bg-[oklch(0_0_0/0.4)]"
|
|
207
213
|
aria-hidden="true"
|
|
208
214
|
onclick={closeMenu}
|
|
209
215
|
></button>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<!-- src/lib/InstallPWA.svelte -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
/**
|
|
4
|
+
* @component InstallPWA
|
|
5
|
+
* @description Installs the app using the browser PWA prompt.
|
|
6
|
+
*
|
|
7
|
+
* @prop alwaysShow {boolean} - Forces the install button to be visible
|
|
8
|
+
* @default false
|
|
9
|
+
*
|
|
10
|
+
* @prop inline {boolean} - Renders the button inline instead of fixed
|
|
11
|
+
* @default false
|
|
12
|
+
*
|
|
13
|
+
* @prop class {string} - Additional button classes
|
|
14
|
+
* @default ""
|
|
15
|
+
*
|
|
16
|
+
* @note Uses the `beforeinstallprompt` event and defers the prompt until user action.
|
|
17
|
+
*/
|
|
18
|
+
import Button from "./Button.svelte";
|
|
19
|
+
|
|
20
|
+
interface BeforeInstallPromptEvent extends Event {
|
|
21
|
+
prompt: () => Promise<void>;
|
|
22
|
+
userChoice: Promise<{ outcome: "accepted" | "dismissed"; platform: string }>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type Props = {
|
|
26
|
+
alwaysShow?: boolean;
|
|
27
|
+
inline?: boolean;
|
|
28
|
+
class?: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
let {
|
|
32
|
+
alwaysShow = false,
|
|
33
|
+
inline = false,
|
|
34
|
+
class: externalClass = "",
|
|
35
|
+
}: Props = $props();
|
|
36
|
+
|
|
37
|
+
let deferredPrompt = $state<BeforeInstallPromptEvent | null>(null);
|
|
38
|
+
let showButton = $state(false);
|
|
39
|
+
|
|
40
|
+
$effect(() => {
|
|
41
|
+
const handler = (e: Event) => {
|
|
42
|
+
const bipEvent = e as BeforeInstallPromptEvent;
|
|
43
|
+
bipEvent.preventDefault();
|
|
44
|
+
deferredPrompt = bipEvent;
|
|
45
|
+
showButton = true;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
window.addEventListener("beforeinstallprompt", handler);
|
|
49
|
+
return () => window.removeEventListener("beforeinstallprompt", handler);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
function installPWA() {
|
|
53
|
+
if (deferredPrompt) {
|
|
54
|
+
deferredPrompt.prompt();
|
|
55
|
+
deferredPrompt.userChoice.then(() => {
|
|
56
|
+
showButton = false;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
{#if showButton || alwaysShow}
|
|
63
|
+
<Button
|
|
64
|
+
onClick={installPWA}
|
|
65
|
+
sz="sm"
|
|
66
|
+
class={inline
|
|
67
|
+
? `z-[1000] flex items-center gap-2.5 ${externalClass}`
|
|
68
|
+
: `fixed bottom-5 right-5 z-[10] flex items-center gap-2.5 ${externalClass}`}
|
|
69
|
+
variant="pill"
|
|
70
|
+
>
|
|
71
|
+
<span class="flex items-center gap-2">
|
|
72
|
+
<svg
|
|
73
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
74
|
+
width="24"
|
|
75
|
+
height="24"
|
|
76
|
+
viewBox="0 0 24 24"
|
|
77
|
+
fill="none"
|
|
78
|
+
stroke="currentColor"
|
|
79
|
+
stroke-width="2"
|
|
80
|
+
stroke-linecap="round"
|
|
81
|
+
stroke-linejoin="round"
|
|
82
|
+
class="w-4 h-4"
|
|
83
|
+
aria-hidden="true"
|
|
84
|
+
>
|
|
85
|
+
<path d="M12 15V3" />
|
|
86
|
+
<path
|
|
87
|
+
d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"
|
|
88
|
+
/>
|
|
89
|
+
<path d="m7 10 5 5 5-5" />
|
|
90
|
+
</svg>
|
|
91
|
+
<span>Install App</span>
|
|
92
|
+
</span>
|
|
93
|
+
</Button>
|
|
94
|
+
{/if}
|
package/dist/lib/Menu.svelte
CHANGED
|
@@ -61,20 +61,20 @@
|
|
|
61
61
|
let subMenuLeft = $state(0);
|
|
62
62
|
|
|
63
63
|
const sizes: Record<SizeKey, string> = {
|
|
64
|
-
xs: "h-
|
|
65
|
-
sm: "h-
|
|
66
|
-
md: "h-
|
|
67
|
-
lg: "h-
|
|
68
|
-
xl: "h-
|
|
64
|
+
xs: "h-[calc(var(--spacing-md)+var(--spacing-sm)+var(--spacing-xs))] px-[calc(var(--spacing-sm)+var(--spacing-xs))]",
|
|
65
|
+
sm: "h-[var(--spacing-xl)] px-[calc(var(--spacing-sm)+var(--spacing-xs))]",
|
|
66
|
+
md: "h-[calc(var(--spacing-xl)+var(--spacing-xs))] px-[var(--spacing-md)]",
|
|
67
|
+
lg: "h-[calc(var(--spacing-xl)+var(--spacing-sm))] px-[var(--spacing-md)]",
|
|
68
|
+
xl: "h-[calc(var(--spacing-xl)+var(--spacing-sm)+var(--spacing-xs))] px-[calc(var(--spacing-md)+var(--spacing-xs))]",
|
|
69
69
|
};
|
|
70
70
|
|
|
71
71
|
const navBase =
|
|
72
|
-
"flex items-stretch pl-
|
|
72
|
+
"flex items-stretch pl-[var(--spacing-sm)] gap-[var(--spacing-xs)] border-b relative z-10 bg-[var(--color-bg-surface)] text-[var(--color-text-default)] border-[var(--border-color-default)]";
|
|
73
73
|
|
|
74
74
|
const subMenuGutter = 8;
|
|
75
75
|
|
|
76
76
|
const topButtonBase =
|
|
77
|
-
"px-
|
|
77
|
+
"px-[var(--spacing-md)] rounded-[var(--radius-sm)] leading-none transition-colors outline-none [@media(pointer:coarse)]:min-h-11 focus-visible:shadow-[inset_0_0_0_2px_var(--border-color-focus)]";
|
|
78
78
|
|
|
79
79
|
const topButtonActive =
|
|
80
80
|
"bg-[var(--color-bg-muted)] text-[var(--color-text-default)]";
|
|
@@ -480,7 +480,7 @@
|
|
|
480
480
|
<div
|
|
481
481
|
bind:this={menuRefs[menuItem.name]}
|
|
482
482
|
class={cx(
|
|
483
|
-
"fixed z-50 min-w-44 p-
|
|
483
|
+
"fixed z-50 min-w-44 p-[var(--spacing-sm)] rounded-[var(--radius-sm)] shadow-[0_2px_4px_var(--shadow-color)] ",
|
|
484
484
|
"border border-[var(--border-color-default)] bg-[var(--color-bg-surface)]"
|
|
485
485
|
)}
|
|
486
486
|
style={menuStyle}
|
|
@@ -491,7 +491,7 @@
|
|
|
491
491
|
{#each menuItem.actions as action, i (actionKey(action, i))}
|
|
492
492
|
{#if isSeparator(action)}
|
|
493
493
|
<div
|
|
494
|
-
class="my-
|
|
494
|
+
class="my-[var(--spacing-xs)] mx-[var(--spacing-xs)] border-t border-[var(--border-color-default)]"
|
|
495
495
|
role="separator"
|
|
496
496
|
></div>
|
|
497
497
|
{:else}
|
|
@@ -501,8 +501,8 @@
|
|
|
501
501
|
type="button"
|
|
502
502
|
role="menuitem"
|
|
503
503
|
class={cx(
|
|
504
|
-
"relative text-left rounded-
|
|
505
|
-
"gap-
|
|
504
|
+
"relative text-left rounded-[var(--radius-sm)] transition-colors outline-none px-[calc(var(--spacing-sm)+var(--spacing-xs)/2)] py-[calc(var(--spacing-xs)/2)] my-[var(--spacing-xs)] mr-[var(--spacing-xs)] min-w-full flex items-center",
|
|
505
|
+
"gap-[calc(var(--spacing-sm)+var(--spacing-xs))] hover:bg-[var(--color-bg-muted)] focus-visible:bg-[var(--color-bg-muted)]",
|
|
506
506
|
"focus-visible:shadow-[inset_0_0_0_2px_var(--border-color-focus)]",
|
|
507
507
|
textCls
|
|
508
508
|
)}
|
|
@@ -528,11 +528,11 @@
|
|
|
528
528
|
focusMenuAction(menuItem, i);
|
|
529
529
|
}}
|
|
530
530
|
>
|
|
531
|
-
<span class="flex items-center gap-
|
|
531
|
+
<span class="flex items-center gap-[var(--spacing-sm)] flex-1 min-w-0">
|
|
532
532
|
<span class="truncate">{actionText(action)}</span>
|
|
533
533
|
</span>
|
|
534
534
|
|
|
535
|
-
<span class="flex items-center shrink-0 ml-auto gap-
|
|
535
|
+
<span class="flex items-center shrink-0 ml-auto gap-[var(--spacing-xs)]">
|
|
536
536
|
{#if actionShortcut(action)}
|
|
537
537
|
<span
|
|
538
538
|
class={cx(
|
|
@@ -562,7 +562,7 @@
|
|
|
562
562
|
<div
|
|
563
563
|
bind:this={subMenuRefs[actionId(action)]}
|
|
564
564
|
class={cx(
|
|
565
|
-
"fixed z-50 min-w-44 p-
|
|
565
|
+
"fixed z-50 min-w-44 p-[var(--spacing-sm)] rounded-[var(--radius-sm)] shadow-[0_2px_4px_var(--shadow-color)]",
|
|
566
566
|
"border border-[var(--border-color-default)] bg-[var(--color-bg-surface)]"
|
|
567
567
|
)}
|
|
568
568
|
style={subMenuStyle}
|
|
@@ -574,7 +574,7 @@
|
|
|
574
574
|
{#each action.submenu as sub, j (actionKey(sub, j))}
|
|
575
575
|
{#if isSeparator(sub)}
|
|
576
576
|
<div
|
|
577
|
-
class="my-
|
|
577
|
+
class="my-[var(--spacing-xs)] mx-[var(--spacing-xs)] border-t border-[var(--border-color-default)]"
|
|
578
578
|
role="separator"
|
|
579
579
|
></div>
|
|
580
580
|
{:else}
|
|
@@ -583,8 +583,8 @@
|
|
|
583
583
|
type="button"
|
|
584
584
|
role="menuitem"
|
|
585
585
|
class={cx(
|
|
586
|
-
"relative text-left rounded-
|
|
587
|
-
"my-
|
|
586
|
+
"relative text-left rounded-[var(--radius-sm)] transition-colors outline-none px-[calc(var(--spacing-sm)+var(--spacing-xs)/2)] py-[calc(var(--spacing-xs)/2)]",
|
|
587
|
+
"my-[var(--spacing-xs)] mr-[var(--spacing-xs)] w-full flex items-center justify-between gap-[calc(var(--spacing-sm)+var(--spacing-xs))]",
|
|
588
588
|
"hover:bg-[var(--color-bg-muted)] focus-visible:bg-[var(--color-bg-muted)]",
|
|
589
589
|
"focus-visible:shadow-[inset_0_0_0_2px_var(--border-color-focus)]",
|
|
590
590
|
"decoration-[var(--color-text-default)]",
|
|
@@ -595,7 +595,7 @@
|
|
|
595
595
|
onmouseenter={() => (activeSubIndex = j)}
|
|
596
596
|
onfocus={() => (activeSubIndex = j)}
|
|
597
597
|
>
|
|
598
|
-
<span class="flex items-center gap-
|
|
598
|
+
<span class="flex items-center gap-[var(--spacing-sm)] flex-1 min-w-0">
|
|
599
599
|
<span class="truncate">{actionText(sub)}</span>
|
|
600
600
|
</span>
|
|
601
601
|
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
<!-- src/lib/NoticeBase.svelte -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
/**
|
|
4
|
+
* @component NoticeBase
|
|
5
|
+
* @description Shared base for Toast and Badge visuals.
|
|
6
|
+
*
|
|
7
|
+
* @prop title {string} - Optional title displayed above the message
|
|
8
|
+
*
|
|
9
|
+
* @prop message {string} - Notice text content
|
|
10
|
+
*
|
|
11
|
+
* @prop variant {ToastVariant} - Visual style
|
|
12
|
+
* @options success|danger|warning|info
|
|
13
|
+
* @default info
|
|
14
|
+
*
|
|
15
|
+
* @prop showIcon {boolean} - Shows an icon matching the variant
|
|
16
|
+
* @default true
|
|
17
|
+
*
|
|
18
|
+
* @prop inline {boolean} - Inline layout without overlay styling
|
|
19
|
+
* @default false
|
|
20
|
+
*
|
|
21
|
+
* @prop size {"sm" | "md"} - Size preset for spacing and typography
|
|
22
|
+
* @default "sm"
|
|
23
|
+
*
|
|
24
|
+
* @prop end {Snippet} - Trailing content (e.g. close button)
|
|
25
|
+
*
|
|
26
|
+
* @prop class {string} - Additional wrapper classes
|
|
27
|
+
* @default ""
|
|
28
|
+
*
|
|
29
|
+
* @note Used by Toast and Badge to keep styles consistent.
|
|
30
|
+
*/
|
|
31
|
+
import type { Snippet } from "svelte";
|
|
32
|
+
import type { ToastVariant } from "./types";
|
|
33
|
+
import { cx } from "../utils";
|
|
34
|
+
|
|
35
|
+
type Props = {
|
|
36
|
+
title?: string;
|
|
37
|
+
message: string;
|
|
38
|
+
variant?: ToastVariant;
|
|
39
|
+
showIcon?: boolean;
|
|
40
|
+
class?: string;
|
|
41
|
+
inline?: boolean;
|
|
42
|
+
size?: "sm" | "md";
|
|
43
|
+
end?: Snippet;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
let {
|
|
47
|
+
title,
|
|
48
|
+
message,
|
|
49
|
+
variant = "info",
|
|
50
|
+
showIcon = true,
|
|
51
|
+
inline = false,
|
|
52
|
+
size = "sm",
|
|
53
|
+
end,
|
|
54
|
+
class: externalClass = "",
|
|
55
|
+
}: Props = $props();
|
|
56
|
+
|
|
57
|
+
function variantClasses(v: ToastVariant) {
|
|
58
|
+
switch (v) {
|
|
59
|
+
case "success":
|
|
60
|
+
return "bg-[var(--color-bg-success)] text-[var(--color-text-success)]";
|
|
61
|
+
case "danger":
|
|
62
|
+
return "bg-[var(--color-bg-danger)] text-[var(--color-text-danger)]";
|
|
63
|
+
case "warning":
|
|
64
|
+
return "bg-[var(--color-bg-warning)] text-[var(--color-text-warning)]";
|
|
65
|
+
default:
|
|
66
|
+
return "bg-[var(--color-bg-page)] text-[var(--color-text-default)]";
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const sizeClasses = $derived(
|
|
71
|
+
size === "md"
|
|
72
|
+
? "gap-[calc(var(--spacing-sm)+var(--spacing-xs))] px-[var(--spacing-md)] py-[calc(var(--spacing-sm)+var(--spacing-xs))] rounded-[var(--radius-lg)]"
|
|
73
|
+
: "gap-[var(--spacing-sm)] px-[calc(var(--spacing-sm)+var(--spacing-xs))] py-[calc(var(--spacing-sm)+var(--spacing-xs)/2)] rounded-[var(--radius-md)]"
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const iconClass = $derived(size === "md" ? "w-5 h-5" : "w-4 h-4");
|
|
77
|
+
|
|
78
|
+
const titleClass = $derived(
|
|
79
|
+
size === "md"
|
|
80
|
+
? "font-[var(--font-weight-medium)] truncate [font-size:var(--text-md)] max-sm:[font-size:var(--text-sm)]"
|
|
81
|
+
: "font-[var(--font-weight-medium)] truncate [font-size:var(--text-sm)]"
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const messageClass = $derived(
|
|
85
|
+
size === "md"
|
|
86
|
+
? "line-clamp-3 [font-size:var(--text-sm)] max-sm:[font-size:var(--text-xs)]"
|
|
87
|
+
: "truncate [font-size:var(--text-xs)]"
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const rootClass = $derived(
|
|
91
|
+
cx(
|
|
92
|
+
"flex items-center border border-[var(--border-color-default)]",
|
|
93
|
+
sizeClasses,
|
|
94
|
+
!inline && "shadow-[0_8px_16px_var(--shadow-color)] backdrop-blur-sm",
|
|
95
|
+
variantClasses(variant),
|
|
96
|
+
externalClass
|
|
97
|
+
)
|
|
98
|
+
);
|
|
99
|
+
</script>
|
|
100
|
+
|
|
101
|
+
<div class={rootClass} role="status" aria-live="polite">
|
|
102
|
+
{#if showIcon}
|
|
103
|
+
<span class={cx(iconClass, "flex-shrink-0")} aria-hidden="true">
|
|
104
|
+
{#if variant === "success"}
|
|
105
|
+
<svg fill="none" viewBox="0 0 26 26">
|
|
106
|
+
<path d="M8.5 14L11.1 16.6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
|
107
|
+
<path d="M18.2 10L11.6 16.6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
|
108
|
+
<path d="M13 25C19.6 25 25 19.6 25 13C25 6.4 19.6 1 13 1C6.4 1 1 6.4 1 13C1 19.6 6.4 25 13 25Z" stroke="currentColor" stroke-width="2"/>
|
|
109
|
+
</svg>
|
|
110
|
+
{:else if variant === "danger"}
|
|
111
|
+
<svg fill="none" viewBox="0 0 26 26">
|
|
112
|
+
<path d="M13 25C19.6 25 25 19.6 25 13C25 6.4 19.6 1 13 1C6.4 1 1 6.4 1 13C1 19.6 6.4 25 13 25Z" stroke="currentColor" stroke-width="2"/>
|
|
113
|
+
<path d="M9 9.5L16.7 17.3" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
|
114
|
+
<path d="M16.7 9.5L9 17.3" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
|
115
|
+
</svg>
|
|
116
|
+
{:else if variant === "warning"}
|
|
117
|
+
<svg fill="none" viewBox="0 0 27 27">
|
|
118
|
+
<path d="M4.6 25.9H22.5C25.2 25.9 26.8 23 25.6 20.6L16.6 3.8C15.3 1.3 11.8 1.3 10.5 3.8L1.5 20.6C0.3 23 1.9 25.9 4.6 25.9Z" stroke="currentColor" stroke-width="2"/>
|
|
119
|
+
<path d="M13.9 18H13.2L11.9 9.3C11.9 8.6 12.5 8 13.2 8H13.9C14.6 8 15.2 8.6 15.2 9.3L13.9 18Z" fill="currentColor"/>
|
|
120
|
+
<circle cx="13.5" cy="20.6" r="1.3" fill="currentColor"/>
|
|
121
|
+
</svg>
|
|
122
|
+
{:else}
|
|
123
|
+
<svg fill="none" viewBox="0 0 26 26">
|
|
124
|
+
<path d="M13 25C19.6 25 25 19.6 25 13C25 6.4 19.6 1 13 1C6.4 1 1 6.4 1 13C1 19.6 6.4 25 13 25Z" stroke="currentColor" stroke-width="2"/>
|
|
125
|
+
<circle cx="13" cy="7.7" r="1.3" fill="currentColor"/>
|
|
126
|
+
<rect x="11.6" y="10.3" width="2.7" height="9.4" rx="1.3" fill="currentColor"/>
|
|
127
|
+
</svg>
|
|
128
|
+
{/if}
|
|
129
|
+
</span>
|
|
130
|
+
{/if}
|
|
131
|
+
|
|
132
|
+
<div class="flex-1 min-w-0">
|
|
133
|
+
{#if title}
|
|
134
|
+
<div class={titleClass}>{title}</div>
|
|
135
|
+
{/if}
|
|
136
|
+
<div class={messageClass} title={message}>{message}</div>
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
{@render end?.()}
|
|
140
|
+
</div>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @component NoticeBase
|
|
3
|
+
* @description Shared base for Toast and Badge visuals.
|
|
4
|
+
*
|
|
5
|
+
* @prop title {string} - Optional title displayed above the message
|
|
6
|
+
*
|
|
7
|
+
* @prop message {string} - Notice text content
|
|
8
|
+
*
|
|
9
|
+
* @prop variant {ToastVariant} - Visual style
|
|
10
|
+
* @options success|danger|warning|info
|
|
11
|
+
* @default info
|
|
12
|
+
*
|
|
13
|
+
* @prop showIcon {boolean} - Shows an icon matching the variant
|
|
14
|
+
* @default true
|
|
15
|
+
*
|
|
16
|
+
* @prop inline {boolean} - Inline layout without overlay styling
|
|
17
|
+
* @default false
|
|
18
|
+
*
|
|
19
|
+
* @prop size {"sm" | "md"} - Size preset for spacing and typography
|
|
20
|
+
* @default "sm"
|
|
21
|
+
*
|
|
22
|
+
* @prop end {Snippet} - Trailing content (e.g. close button)
|
|
23
|
+
*
|
|
24
|
+
* @prop class {string} - Additional wrapper classes
|
|
25
|
+
* @default ""
|
|
26
|
+
*
|
|
27
|
+
* @note Used by Toast and Badge to keep styles consistent.
|
|
28
|
+
*/
|
|
29
|
+
import type { Snippet } from "svelte";
|
|
30
|
+
import type { ToastVariant } from "./types";
|
|
31
|
+
type Props = {
|
|
32
|
+
title?: string;
|
|
33
|
+
message: string;
|
|
34
|
+
variant?: ToastVariant;
|
|
35
|
+
showIcon?: boolean;
|
|
36
|
+
class?: string;
|
|
37
|
+
inline?: boolean;
|
|
38
|
+
size?: "sm" | "md";
|
|
39
|
+
end?: Snippet;
|
|
40
|
+
};
|
|
41
|
+
declare const NoticeBase: import("svelte").Component<Props, {}, "">;
|
|
42
|
+
type NoticeBase = ReturnType<typeof NoticeBase>;
|
|
43
|
+
export default NoticeBase;
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
* @note The `html` element receives `data-primary="{value}"` for theme styling.
|
|
20
20
|
* @note Uses the same onChange contract as Select and forwards palette options as-is.
|
|
21
21
|
*/
|
|
22
|
-
import Select from "./Select.svelte";
|
|
23
|
-
import type { PrimaryKey, PaletteOption, SizeKey } from "./types";
|
|
24
|
-
import { getComponentText, getLangContext, getLangKey } from "./lang-context";
|
|
22
|
+
import Select from "./Select.svelte";
|
|
23
|
+
import type { PrimaryKey, PaletteOption, SizeKey } from "./types";
|
|
24
|
+
import { getComponentText, getLangContext, getLangKey } from "./lang-context";
|
|
25
25
|
|
|
26
26
|
type Props = {
|
|
27
27
|
sz?: SizeKey;
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
|
|
32
32
|
let { sz = "sm", label, class: externalClass = "" }: Props = $props();
|
|
33
33
|
|
|
34
|
-
const langCtx = getLangContext();
|
|
35
|
-
const langKey = $derived(getLangKey(langCtx));
|
|
36
|
-
const L = $derived(getComponentText("primaryColorSelect", langKey));
|
|
34
|
+
const langCtx = getLangContext();
|
|
35
|
+
const langKey = $derived(getLangKey(langCtx));
|
|
36
|
+
const L = $derived(getComponentText("primaryColorSelect", langKey));
|
|
37
37
|
|
|
38
38
|
const labelFinal = $derived(label ?? L.text);
|
|
39
39
|
|
|
@@ -7,20 +7,18 @@
|
|
|
7
7
|
* @default 0
|
|
8
8
|
* @prop indeterminate {boolean} - Enables spinning infinite mode
|
|
9
9
|
* @default false
|
|
10
|
-
* @prop
|
|
11
|
-
* @default
|
|
12
|
-
* @prop stroke {number} - Stroke width in px
|
|
13
|
-
* @default 4
|
|
10
|
+
* @prop sz {SizeKey} - Size preset (xs|sm|md|lg|xl)
|
|
11
|
+
* @default md
|
|
14
12
|
* @prop variant {ComponentVariant} - Color/style variant
|
|
15
|
-
* @options default|neutral
|
|
13
|
+
* @options default|neutral
|
|
16
14
|
* @default default
|
|
17
|
-
* @prop label {string} - Optional text shown
|
|
15
|
+
* @prop label {string} - Optional text shown above the circle
|
|
18
16
|
* @default ""
|
|
19
|
-
* @prop
|
|
20
|
-
* @default
|
|
17
|
+
* @prop disabled {boolean} - Apply disabled styles
|
|
18
|
+
* @default false
|
|
21
19
|
* @prop class {string} - Extra wrapper classes
|
|
22
20
|
* @default ""
|
|
23
|
-
* @note Clamps value between 0-
|
|
21
|
+
* @note Clamps value between 0-100
|
|
24
22
|
* @note Uses SVG stroke-dashoffset animation
|
|
25
23
|
* @note Accessible role=progressbar with aria-valuenow
|
|
26
24
|
* @note Works in both determinate/indeterminate modes
|
|
@@ -5,20 +5,18 @@
|
|
|
5
5
|
* @default 0
|
|
6
6
|
* @prop indeterminate {boolean} - Enables spinning infinite mode
|
|
7
7
|
* @default false
|
|
8
|
-
* @prop
|
|
9
|
-
* @default
|
|
10
|
-
* @prop stroke {number} - Stroke width in px
|
|
11
|
-
* @default 4
|
|
8
|
+
* @prop sz {SizeKey} - Size preset (xs|sm|md|lg|xl)
|
|
9
|
+
* @default md
|
|
12
10
|
* @prop variant {ComponentVariant} - Color/style variant
|
|
13
|
-
* @options default|neutral
|
|
11
|
+
* @options default|neutral
|
|
14
12
|
* @default default
|
|
15
|
-
* @prop label {string} - Optional text shown
|
|
13
|
+
* @prop label {string} - Optional text shown above the circle
|
|
16
14
|
* @default ""
|
|
17
|
-
* @prop
|
|
18
|
-
* @default
|
|
15
|
+
* @prop disabled {boolean} - Apply disabled styles
|
|
16
|
+
* @default false
|
|
19
17
|
* @prop class {string} - Extra wrapper classes
|
|
20
18
|
* @default ""
|
|
21
|
-
* @note Clamps value between 0-
|
|
19
|
+
* @note Clamps value between 0-100
|
|
22
20
|
* @note Uses SVG stroke-dashoffset animation
|
|
23
21
|
* @note Accessible role=progressbar with aria-valuenow
|
|
24
22
|
* @note Works in both determinate/indeterminate modes
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
*
|
|
24
24
|
* @note Renders a leading search icon and uses `Field` with `type="search"` and `clearable`.
|
|
25
25
|
*/
|
|
26
|
-
import Field from "./Field.svelte";
|
|
27
|
-
import type { FieldVariant, SizeKey } from "./types";
|
|
28
|
-
import { getComponentText, getLangContext, getLangKey } from "./lang-context";
|
|
26
|
+
import Field from "./Field.svelte";
|
|
27
|
+
import type { FieldVariant, SizeKey } from "./types";
|
|
28
|
+
import { getComponentText, getLangContext, getLangKey } from "./lang-context";
|
|
29
29
|
|
|
30
30
|
type Props = {
|
|
31
31
|
label?: string;
|
|
@@ -47,9 +47,9 @@
|
|
|
47
47
|
...rest
|
|
48
48
|
}: Props = $props();
|
|
49
49
|
|
|
50
|
-
const langCtx = getLangContext();
|
|
51
|
-
const langKey = $derived(getLangKey(langCtx));
|
|
52
|
-
const L = $derived(getComponentText("searchInput", langKey));
|
|
50
|
+
const langCtx = getLangContext();
|
|
51
|
+
const langKey = $derived(getLangKey(langCtx));
|
|
52
|
+
const L = $derived(getComponentText("searchInput", langKey));
|
|
53
53
|
|
|
54
54
|
const placeholderFinal = $derived(placeholder ?? L.placeholder);
|
|
55
55
|
</script>
|
package/dist/lib/Select.svelte
CHANGED
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
let menuPosition = $state<"top" | "bottom">("bottom");
|
|
103
103
|
|
|
104
104
|
const base =
|
|
105
|
-
"relative w-full outline-none appearance-none cursor-pointer transition-colors duration-[var(--transition-fast)] ease-[var(--timing-default)] box-border rounded-[var(--radius-md)] border focus:border-[var(--border-color-focus)] focus:ring-2 focus:ring-[var(--border-color-focus)] [color:var(--color-text-default)] disabled:opacity-[var(--opacity-disabled)] disabled:cursor-not-allowed";
|
|
105
|
+
"relative w-full outline-none appearance-none cursor-pointer transition-colors duration-[var(--transition-fast)] ease-[var(--timing-default)] box-border rounded-[var(--radius-md)] border focus:border-[var(--border-color-focus)] focus:ring-2 focus:ring-[var(--border-color-focus)] [color:var(--color-text-default)] disabled:opacity-[var(--opacity-disabled)] disabled:cursor-not-allowed [@media(pointer:coarse)]:min-h-11";
|
|
106
106
|
|
|
107
107
|
const sizes: Record<SizeKey, string> = {
|
|
108
108
|
xs: "px-2 pr-6 h-6",
|
|
@@ -152,7 +152,7 @@
|
|
|
152
152
|
|
|
153
153
|
const itemBaseClass = $derived(
|
|
154
154
|
cx(
|
|
155
|
-
"w-full text-left px-4 py-2 transition-colors duration-[var(--transition-fast)] cursor-pointer",
|
|
155
|
+
"w-full text-left px-4 py-2 transition-colors duration-[var(--transition-fast)] cursor-pointer [@media(pointer:coarse)]:min-h-11",
|
|
156
156
|
TEXT[sz]
|
|
157
157
|
)
|
|
158
158
|
);
|