svelte-comp 1.3.3 → 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 +540 -540
- package/dist/app.css +2 -3
- package/dist/app.d.ts +10 -0
- package/dist/lib/Accordion.svelte +14 -14
- package/dist/lib/Button.svelte +23 -8
- 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/ContextMenu.svelte +19 -13
- package/dist/lib/Dialog.svelte +3 -3
- package/dist/lib/Field.svelte +1 -1
- package/dist/lib/FilePicker.svelte +66 -11
- package/dist/lib/FilePicker.svelte.d.ts +6 -1
- package/dist/lib/Hamburger.svelte +12 -12
- package/dist/lib/Menu.svelte +18 -18
- package/dist/lib/NoticeBase.svelte +5 -5
- 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/TimePickerNew.svelte +634 -0
- package/dist/lib/TimePickerNew.svelte.d.ts +49 -0
- package/dist/lib/Tooltip.svelte +7 -7
- package/dist/lib/Topbar.svelte +6 -6
- 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 +1 -0
- package/dist/lib/index.js +1 -0
- package/dist/lib/lang.d.ts +4 -0
- package/dist/lib/lang.js +4 -0
- package/dist/styles.css +2 -0
- package/dist/utils/index.js +15 -4
- package/package.json +12 -12
package/dist/app.css
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
/* src/app.css */
|
|
2
|
-
|
|
3
2
|
@import "tailwindcss";
|
|
4
3
|
|
|
5
|
-
/* src/styles.css */
|
|
6
|
-
@import "tailwindcss";
|
|
7
4
|
@custom-variant dark (&:where(.dark, .dark *));
|
|
8
5
|
|
|
9
6
|
@theme {
|
|
@@ -15,6 +12,7 @@
|
|
|
15
12
|
--color-text-warning: oklch(95% 0.05 90deg);
|
|
16
13
|
--color-text-link: oklch(35% 0.3 250deg);
|
|
17
14
|
--color-text-red: oklch(50% 0.25 30deg);
|
|
15
|
+
--color-text-inverse: oklch(100% 0 0deg);
|
|
18
16
|
|
|
19
17
|
/* COLORS — BG */
|
|
20
18
|
--color-bg-page: oklch(98% 0 0deg);
|
|
@@ -108,6 +106,7 @@
|
|
|
108
106
|
--color-text-warning: oklch(95% 0.05 90deg);
|
|
109
107
|
--color-text-link: oklch(65% 0.3 250deg);
|
|
110
108
|
--color-text-red: oklch(50% 0.25 30deg);
|
|
109
|
+
--color-text-inverse: oklch(100% 0 0deg);
|
|
111
110
|
|
|
112
111
|
/* COLORS — BG */
|
|
113
112
|
--color-bg-page: oklch(15% 0 0deg);
|
package/dist/app.d.ts
ADDED
|
@@ -51,22 +51,22 @@
|
|
|
51
51
|
}: Props = $props();
|
|
52
52
|
|
|
53
53
|
const base =
|
|
54
|
-
"w-full border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] shadow-
|
|
54
|
+
"w-full border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] shadow-[0_1px_2px_var(--shadow-color)]";
|
|
55
55
|
|
|
56
56
|
const sizes: Record<SizeKey, string> = {
|
|
57
|
-
xs: "rounded-[var(--radius-md)]
|
|
58
|
-
sm: "rounded-[var(--radius-md)]
|
|
59
|
-
md: "rounded-[var(--radius-lg)]
|
|
60
|
-
lg: "rounded-[var(--radius-lg)]
|
|
61
|
-
xl: "rounded-[var(--radius-xl)]
|
|
57
|
+
xs: cx("rounded-[var(--radius-md)]", TEXT.xs),
|
|
58
|
+
sm: cx("rounded-[var(--radius-md)]", TEXT.sm),
|
|
59
|
+
md: cx("rounded-[var(--radius-lg)]", TEXT.md),
|
|
60
|
+
lg: cx("rounded-[var(--radius-lg)]", TEXT.lg),
|
|
61
|
+
xl: cx("rounded-[var(--radius-xl)]", TEXT.xl),
|
|
62
62
|
};
|
|
63
63
|
|
|
64
64
|
const contentSize: Record<SizeKey, string> = {
|
|
65
|
-
xs: "px-
|
|
66
|
-
sm: "px-
|
|
67
|
-
md: "px-
|
|
68
|
-
lg: "px-
|
|
69
|
-
xl: "px-
|
|
65
|
+
xs: "px-[var(--spacing-md)] pb-[var(--spacing-md)] mt-[var(--spacing-xs)]",
|
|
66
|
+
sm: "px-[calc(var(--spacing-md)+var(--spacing-xs))] pb-[calc(var(--spacing-md)+var(--spacing-xs))] mt-[var(--spacing-sm)]",
|
|
67
|
+
md: "px-[calc(var(--spacing-md)+var(--spacing-sm))] pb-[calc(var(--spacing-md)+var(--spacing-sm))] mt-[calc(var(--spacing-sm)+var(--spacing-xs))]",
|
|
68
|
+
lg: "px-[var(--spacing-xl)] pb-[var(--spacing-xl)] mt-[var(--spacing-md)]",
|
|
69
|
+
xl: "px-[calc(var(--spacing-xl)+var(--spacing-sm))] pb-[calc(var(--spacing-xl)+var(--spacing-sm))] mt-[calc(var(--spacing-md)+var(--spacing-xs))]",
|
|
70
70
|
};
|
|
71
71
|
|
|
72
72
|
const iconSize: Record<SizeKey, string> = {
|
|
@@ -110,14 +110,14 @@
|
|
|
110
110
|
<h3>
|
|
111
111
|
<button
|
|
112
112
|
type="button"
|
|
113
|
-
class="flex w-full items-center justify-between gap-
|
|
113
|
+
class="flex w-full items-center justify-between gap-[calc(var(--spacing-sm)+var(--spacing-xs))] p-[var(--spacing-sm)] text-left font-medium text-[var(--color-text-default)] bg-transparent transition-colors hover:bg-[var(--color-bg-hover)] active:bg-[var(--color-bg-active)] focus:outline-none focus:ring-2 focus:ring-[var(--border-color-focus)] focus:ring-inset"
|
|
114
114
|
aria-expanded={isOpen(i)}
|
|
115
115
|
onclick={() => toggle(i)}
|
|
116
116
|
>
|
|
117
117
|
<span>{item.title}</span>
|
|
118
118
|
<svg
|
|
119
119
|
class={cx(
|
|
120
|
-
"shrink-0 transition-transform duration-
|
|
120
|
+
"shrink-0 transition-transform duration-[var(--transition-fast)] text-[var(--color-text-muted)]",
|
|
121
121
|
iconClass
|
|
122
122
|
)}
|
|
123
123
|
class:rotate-180={isOpen(i)}
|
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
</h3>
|
|
136
136
|
|
|
137
137
|
<div
|
|
138
|
-
class="grid overflow-hidden transition-[grid-template-rows] duration-
|
|
138
|
+
class="grid overflow-hidden transition-[grid-template-rows] duration-[var(--transition-fast)]"
|
|
139
139
|
class:grid-rows-[1fr]={isOpen(i)}
|
|
140
140
|
class:grid-rows-[0fr]={!isOpen(i)}
|
|
141
141
|
>
|
package/dist/lib/Button.svelte
CHANGED
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
relative inline-flex items-center justify-center gap-2 rounded-[var(--radius-md)] border font-medium
|
|
71
71
|
transition-all duration-[var(--transition-fast)] ease-[var(--timing-default)] whitespace-nowrap select-none
|
|
72
72
|
focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--border-color-focus)]
|
|
73
|
+
[@media(pointer:coarse)]:min-h-11 [@media(pointer:coarse)]:min-w-11
|
|
73
74
|
disabled:opacity-[var(--opacity-disabled)]
|
|
74
75
|
disabled:cursor-not-allowed
|
|
75
76
|
disabled:brightness-100
|
|
@@ -87,20 +88,20 @@
|
|
|
87
88
|
|
|
88
89
|
const variants: Record<ButtonVariant, string> = {
|
|
89
90
|
primary:
|
|
90
|
-
"bg-[var(--color-bg-primary)] text-
|
|
91
|
+
"bg-[var(--color-bg-primary)] text-[var(--color-text-inverse,#fff)] border-[var(--border-color-primary)] hover:brightness-110 active:scale-95",
|
|
91
92
|
secondary:
|
|
92
93
|
"bg-[var(--color-bg-secondary)] [color:var(--color-text-default)] border-[var(--border-color-default)] hover:bg-[var(--color-bg-hover)] active:scale-95",
|
|
93
|
-
pill: "bg-[var(--color-bg-primary)] text-
|
|
94
|
+
pill: "bg-[var(--color-bg-primary)] text-[var(--color-text-inverse,#fff)] border-[var(--border-color-primary)] rounded-full hover:brightness-110 active:scale-95",
|
|
94
95
|
danger:
|
|
95
|
-
"bg-[var(--color-bg-danger)] text-
|
|
96
|
+
"bg-[var(--color-bg-danger)] text-[var(--color-text-inverse,#fff)] border-[var(--color-bg-danger)] hover:brightness-110 active:scale-95",
|
|
96
97
|
success:
|
|
97
|
-
"bg-[var(--color-bg-success)] text-
|
|
98
|
+
"bg-[var(--color-bg-success)] text-[var(--color-text-inverse,#fff)] border-[var(--color-bg-success)] hover:brightness-110 active:scale-95",
|
|
98
99
|
warning:
|
|
99
|
-
"bg-[var(--color-bg-warning)] text-
|
|
100
|
+
"bg-[var(--color-bg-warning)] text-[var(--color-text-inverse,#fff)] border-[var(--color-bg-warning)] hover:brightness-110 active:scale-95",
|
|
100
101
|
ghost:
|
|
101
102
|
"bg-transparent [color:var(--color-text-default)] border-transparent hover:bg-[var(--color-bg-hover)] active:bg-[var(--color-bg-active)] active:scale-95",
|
|
102
103
|
link: "bg-transparent underline border-transparent [color:var(--color-text-link)] hover:brightness-110 active:scale-95 transition-transform ",
|
|
103
|
-
info: "bg-[var(--color-bg-secondary)] text-
|
|
104
|
+
info: "bg-[var(--color-bg-secondary)] text-[var(--color-text-inverse,#fff)] border-[var(--border-color-default)] hover:bg-[var(--color-bg-hover)] active:scale-95",
|
|
104
105
|
};
|
|
105
106
|
|
|
106
107
|
const buttonClass = $derived(
|
|
@@ -132,15 +133,29 @@
|
|
|
132
133
|
|
|
133
134
|
function navigateToLink() {
|
|
134
135
|
if (!link || typeof window === "undefined") return;
|
|
136
|
+
const safeLink = getSafeLink(link);
|
|
137
|
+
if (!safeLink) return;
|
|
135
138
|
|
|
136
139
|
const restAttrs = rest as Record<string, unknown>;
|
|
137
140
|
const target =
|
|
138
141
|
typeof restAttrs.target === "string" ? restAttrs.target : undefined;
|
|
139
142
|
|
|
140
143
|
if (target === "_blank") {
|
|
141
|
-
window.open(
|
|
144
|
+
window.open(safeLink, "_blank", "noopener,noreferrer");
|
|
142
145
|
} else {
|
|
143
|
-
window.location.assign(
|
|
146
|
+
window.location.assign(safeLink);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function getSafeLink(value: string) {
|
|
151
|
+
try {
|
|
152
|
+
const url = new URL(value, window.location.href);
|
|
153
|
+
if (!["http:", "https:", "mailto:", "tel:"].includes(url.protocol)) {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
return value;
|
|
157
|
+
} catch {
|
|
158
|
+
return null;
|
|
144
159
|
}
|
|
145
160
|
}
|
|
146
161
|
</script>
|
package/dist/lib/Card.svelte
CHANGED
|
@@ -53,16 +53,16 @@
|
|
|
53
53
|
}: Props = $props();
|
|
54
54
|
|
|
55
55
|
const paddingSizes: Record<SizeKey, string> = {
|
|
56
|
-
xs: "px-
|
|
57
|
-
sm: "px-
|
|
58
|
-
md: "px-
|
|
59
|
-
lg: "px-
|
|
60
|
-
xl: "px-
|
|
56
|
+
xs: "px-[calc(var(--spacing-sm)+var(--spacing-xs))] py-[var(--spacing-sm)]",
|
|
57
|
+
sm: "px-[var(--spacing-md)] py-[var(--spacing-sm)]",
|
|
58
|
+
md: "px-[calc(var(--spacing-md)+var(--spacing-xs))] py-[calc(var(--spacing-sm)+var(--spacing-xs))]",
|
|
59
|
+
lg: "px-[calc(var(--spacing-md)+var(--spacing-sm))] py-[var(--spacing-md)]",
|
|
60
|
+
xl: "px-[calc(var(--spacing-md)+var(--spacing-sm)+var(--spacing-xs))] py-[calc(var(--spacing-md)+var(--spacing-xs))]",
|
|
61
61
|
};
|
|
62
62
|
|
|
63
63
|
const cardClass = $derived(
|
|
64
64
|
cx(
|
|
65
|
-
"bg-[var(--color-bg-surface)] border border-[var(--border-color-default)] rounded-xl shadow-
|
|
65
|
+
"bg-[var(--color-bg-surface)] border border-[var(--border-color-default)] rounded-[var(--radius-xl)] shadow-[0_1px_2px_var(--shadow-color)] overflow-hidden",
|
|
66
66
|
TEXT[sz],
|
|
67
67
|
"flex flex-col",
|
|
68
68
|
externalClass
|
package/dist/lib/Carousel.svelte
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
*/
|
|
35
35
|
import Card from "./Card.svelte";
|
|
36
36
|
import type { HTMLAttributes } from "svelte/elements";
|
|
37
|
-
import type
|
|
37
|
+
import { TEXT, type SizeKey, type CarouselItem } from "./types";
|
|
38
38
|
import { cx } from "../utils";
|
|
39
39
|
|
|
40
40
|
type Props = HTMLAttributes<HTMLDivElement> & {
|
|
@@ -66,19 +66,19 @@
|
|
|
66
66
|
"relative w-full overflow-hidden rounded-[var(--radius-lg)] bg-[var(--color-bg-surface)]";
|
|
67
67
|
|
|
68
68
|
const sizes: Record<SizeKey, string> = {
|
|
69
|
-
xs: "rounded-[var(--radius-md)]
|
|
70
|
-
sm: "rounded-[var(--radius-md)]
|
|
71
|
-
md: "rounded-[var(--radius-lg)]
|
|
72
|
-
lg: "rounded-[var(--radius-lg)]
|
|
73
|
-
xl: "rounded-[var(--radius-xl)]
|
|
69
|
+
xs: cx("rounded-[var(--radius-md)]", TEXT.xs),
|
|
70
|
+
sm: cx("rounded-[var(--radius-md)]", TEXT.sm),
|
|
71
|
+
md: cx("rounded-[var(--radius-lg)]", TEXT.md),
|
|
72
|
+
lg: cx("rounded-[var(--radius-lg)]", TEXT.lg),
|
|
73
|
+
xl: cx("rounded-[var(--radius-xl)]", TEXT.xl),
|
|
74
74
|
};
|
|
75
75
|
|
|
76
76
|
const contentSize: Record<SizeKey, string> = {
|
|
77
|
-
xs: "p-
|
|
78
|
-
sm: "p-
|
|
79
|
-
md: "p-
|
|
80
|
-
lg: "p-
|
|
81
|
-
xl: "p-
|
|
77
|
+
xs: "p-[calc(var(--spacing-sm)+var(--spacing-xs))] gap-[var(--spacing-sm)]",
|
|
78
|
+
sm: "p-[var(--spacing-md)] gap-[calc(var(--spacing-sm)+var(--spacing-xs)/2)]",
|
|
79
|
+
md: "p-[calc(var(--spacing-md)+var(--spacing-xs))] gap-[calc(var(--spacing-sm)+var(--spacing-xs))]",
|
|
80
|
+
lg: "p-[calc(var(--spacing-md)+var(--spacing-sm))] gap-[var(--spacing-md)]",
|
|
81
|
+
xl: "p-[var(--spacing-xl)] gap-[calc(var(--spacing-md)+var(--spacing-xs))]",
|
|
82
82
|
};
|
|
83
83
|
|
|
84
84
|
const arrowSize: Record<SizeKey, string> = {
|
|
@@ -123,14 +123,14 @@
|
|
|
123
123
|
const arrowClass = $derived(
|
|
124
124
|
cx(
|
|
125
125
|
arrowSize[sz],
|
|
126
|
-
"rounded-full bg-[var(--color-bg-surface)] shadow-
|
|
126
|
+
"rounded-full bg-[var(--color-bg-surface)] shadow-[0_8px_16px_var(--shadow-color)] flex items-center justify-center [color:var(--color-text-default)] hover:bg-[var(--color-bg-hover)] transition-colors focus-visible:ring-2 focus-visible:ring-[var(--border-color-focus)] focus:outline-none"
|
|
127
127
|
)
|
|
128
128
|
);
|
|
129
129
|
|
|
130
130
|
const dotClass = $derived(
|
|
131
131
|
cx(
|
|
132
132
|
dotSize[sz],
|
|
133
|
-
"rounded-full transition-all duration-
|
|
133
|
+
"rounded-full transition-all duration-[var(--transition-fast)] focus-visible:ring-2 focus-visible:ring-[var(--border-color-focus)] focus:outline-none"
|
|
134
134
|
)
|
|
135
135
|
);
|
|
136
136
|
|
|
@@ -156,7 +156,7 @@
|
|
|
156
156
|
|
|
157
157
|
$effect(() => {
|
|
158
158
|
if (autoplay && hasItems && items.length > 1) {
|
|
159
|
-
autoplayTimer = setInterval(next, interval);
|
|
159
|
+
autoplayTimer = setInterval(next, Math.max(1000, interval));
|
|
160
160
|
}
|
|
161
161
|
return () => {
|
|
162
162
|
if (autoplayTimer) {
|
|
@@ -203,7 +203,7 @@
|
|
|
203
203
|
{/snippet}
|
|
204
204
|
|
|
205
205
|
<div
|
|
206
|
-
class="transition-opacity duration-
|
|
206
|
+
class="transition-opacity duration-[var(--transition-normal)] ease-in-out"
|
|
207
207
|
class:opacity-100={i === current}
|
|
208
208
|
class:opacity-0={i !== current}
|
|
209
209
|
class:block={i === current}
|
|
@@ -275,7 +275,7 @@
|
|
|
275
275
|
</div>
|
|
276
276
|
|
|
277
277
|
{#if showDots && hasItems && items.length > 1}
|
|
278
|
-
<div class="flex justify-center gap-
|
|
278
|
+
<div class="flex justify-center gap-[var(--spacing-sm)] p-[var(--spacing-md)]">
|
|
279
279
|
{#each items as item, i (item.id ?? i)}
|
|
280
280
|
<button
|
|
281
281
|
type="button"
|
package/dist/lib/CheckBox.svelte
CHANGED
|
@@ -116,12 +116,12 @@
|
|
|
116
116
|
? state === "checked" || state === "mixed"
|
|
117
117
|
? "var(--border-color-strong)"
|
|
118
118
|
: "var(--border-color-default)"
|
|
119
|
-
: "
|
|
119
|
+
: "var(--color-text-inverse,#fff)"
|
|
120
120
|
);
|
|
121
121
|
|
|
122
122
|
const rootClass = $derived(
|
|
123
123
|
cx(
|
|
124
|
-
"inline-flex items-center cursor-pointer select-none",
|
|
124
|
+
"inline-flex items-center cursor-pointer select-none [@media(pointer:coarse)]:min-h-11",
|
|
125
125
|
gapBySize[sz],
|
|
126
126
|
externalClass
|
|
127
127
|
)
|
package/dist/lib/CodeView.svelte
CHANGED
|
@@ -139,6 +139,7 @@
|
|
|
139
139
|
});
|
|
140
140
|
|
|
141
141
|
async function copyToClipboard() {
|
|
142
|
+
if (typeof navigator === "undefined" || !navigator.clipboard) return;
|
|
142
143
|
await navigator.clipboard.writeText(code);
|
|
143
144
|
copied = true;
|
|
144
145
|
setTimeout(() => (copied = false), 1200);
|
|
@@ -155,7 +156,7 @@
|
|
|
155
156
|
{#if title}
|
|
156
157
|
<div
|
|
157
158
|
class={cx(
|
|
158
|
-
|
|
159
|
+
"px-[calc(var(--spacing-sm)+var(--spacing-xs))] py-[var(--spacing-xs)] bg-[var(--color-bg-muted)] font-semibold uppercase flex items-center justify-between",
|
|
159
160
|
TEXT[sz]
|
|
160
161
|
)}
|
|
161
162
|
>
|
|
@@ -165,7 +166,7 @@
|
|
|
165
166
|
<button
|
|
166
167
|
onclick={copyToClipboard}
|
|
167
168
|
class={cx(
|
|
168
|
-
"px-
|
|
169
|
+
"px-[calc(var(--spacing-sm)+var(--spacing-xs))] py-[calc(var(--spacing-xs)/2)] [font-size:var(--text-xs)] rounded-[var(--radius-sm)] bg-[var(--color-primary)] text-[var(--color-text-inverse,#fff)] hover:opacity-[var(--opacity-hover)]",
|
|
169
170
|
"transition focus-visible:ring-2 focus-visible:ring-[var(--border-color-focus)] focus:outline-none"
|
|
170
171
|
)}
|
|
171
172
|
class:!bg-green-600={copied}
|
|
@@ -187,7 +188,7 @@
|
|
|
187
188
|
<div
|
|
188
189
|
bind:this={gutterEl}
|
|
189
190
|
class={cx(
|
|
190
|
-
"select-none px-
|
|
191
|
+
"select-none px-[calc(var(--spacing-sm)+var(--spacing-xs))] py-[calc(var(--spacing-sm)+var(--spacing-xs))] border-r border-[var(--border-color-default)]",
|
|
191
192
|
"text-[var(--color-text-muted)] text-right overflow-hidden",
|
|
192
193
|
"cv-gutter bg-[var(--color-bg-surface)] tabular-nums h-full min-h-0"
|
|
193
194
|
)}
|
|
@@ -232,8 +233,8 @@
|
|
|
232
233
|
<style>
|
|
233
234
|
.cv-layer {
|
|
234
235
|
position: absolute;
|
|
235
|
-
padding:
|
|
236
|
-
white-space: pre;
|
|
236
|
+
padding: calc(var(--spacing-sm) + var(--spacing-xs));
|
|
237
|
+
white-space: var(--code-white-space, pre);
|
|
237
238
|
box-sizing: border-box;
|
|
238
239
|
font: inherit;
|
|
239
240
|
line-height: inherit;
|
|
@@ -120,25 +120,31 @@
|
|
|
120
120
|
const doCut = () => (onCut(), close());
|
|
121
121
|
const doPaste = () => (onPaste(), close());
|
|
122
122
|
const doDelete = () => (onDelete(), close());
|
|
123
|
+
|
|
124
|
+
const menuPanelClass =
|
|
125
|
+
"fixed bg-[var(--color-bg-surface)] border border-[var(--border-color-default)] rounded-[var(--radius-md)] min-w-[160px] max-w-[260px] py-[var(--spacing-xs)] z-[9999] box-border text-[var(--text-sm)] shadow-[0_2px_4px_var(--shadow-color)] font-[var(--font-sans)] text-[var(--color-text-default)] m-0 scale-90 origin-top-left";
|
|
126
|
+
const itemClass =
|
|
127
|
+
"w-full flex items-center justify-between bg-transparent border-0 text-[var(--color-text-default)] px-[calc(var(--spacing-sm)+var(--spacing-xs))] py-[var(--spacing-sm)] m-0 font-inherit cursor-pointer rounded-[var(--radius-sm)] whitespace-nowrap leading-[var(--line-height-normal)] gap-[calc(var(--spacing-sm)+var(--spacing-xs))] outline-none shadow-none relative hover:bg-[var(--color-bg-hover)] hover:text-[var(--color-text-default)] active:bg-[color-mix(in_srgb,var(--color-primary)_12%,var(--color-bg-hover)_88%)] active:text-[var(--color-text-default)] transition-colors duration-[var(--transition-fast)]";
|
|
128
|
+
const itemContentClass = "flex items-center gap-[calc(var(--spacing-sm)+var(--spacing-xs)/2)]";
|
|
123
129
|
</script>
|
|
124
130
|
|
|
125
131
|
{#if visible}
|
|
126
132
|
<div
|
|
127
133
|
id="ctx-menu"
|
|
128
|
-
class=
|
|
134
|
+
class={menuPanelClass}
|
|
129
135
|
style="top: {y}px; left: {x}px;"
|
|
130
136
|
role="menu"
|
|
131
137
|
tabindex="-1"
|
|
132
138
|
>
|
|
133
139
|
<button
|
|
134
|
-
class=
|
|
140
|
+
class={itemClass}
|
|
135
141
|
onclick={(e) => {
|
|
136
142
|
e.stopPropagation();
|
|
137
143
|
doUndo();
|
|
138
144
|
}}
|
|
139
145
|
title={L.hotkeys.undo}
|
|
140
146
|
>
|
|
141
|
-
<div class=
|
|
147
|
+
<div class={itemContentClass}>
|
|
142
148
|
<svg
|
|
143
149
|
xmlns="http://www.w3.org/2000/svg"
|
|
144
150
|
width="24"
|
|
@@ -161,14 +167,14 @@
|
|
|
161
167
|
</button>
|
|
162
168
|
|
|
163
169
|
<button
|
|
164
|
-
class=
|
|
170
|
+
class={itemClass}
|
|
165
171
|
onclick={(e) => {
|
|
166
172
|
e.stopPropagation();
|
|
167
173
|
doRedo();
|
|
168
174
|
}}
|
|
169
175
|
title={L.hotkeys.redo}
|
|
170
176
|
>
|
|
171
|
-
<div class=
|
|
177
|
+
<div class={itemContentClass}>
|
|
172
178
|
<svg
|
|
173
179
|
xmlns="http://www.w3.org/2000/svg"
|
|
174
180
|
width="24"
|
|
@@ -191,14 +197,14 @@
|
|
|
191
197
|
</button>
|
|
192
198
|
|
|
193
199
|
<button
|
|
194
|
-
class=
|
|
200
|
+
class={itemClass}
|
|
195
201
|
onclick={(e) => {
|
|
196
202
|
e.stopPropagation();
|
|
197
203
|
doCopy();
|
|
198
204
|
}}
|
|
199
205
|
title={L.hotkeys.copy}
|
|
200
206
|
>
|
|
201
|
-
<div class=
|
|
207
|
+
<div class={itemContentClass}>
|
|
202
208
|
<svg
|
|
203
209
|
xmlns="http://www.w3.org/2000/svg"
|
|
204
210
|
width="24"
|
|
@@ -221,14 +227,14 @@
|
|
|
221
227
|
</button>
|
|
222
228
|
|
|
223
229
|
<button
|
|
224
|
-
class=
|
|
230
|
+
class={itemClass}
|
|
225
231
|
onclick={(e) => {
|
|
226
232
|
e.stopPropagation();
|
|
227
233
|
doCut();
|
|
228
234
|
}}
|
|
229
235
|
title={L.hotkeys.cut}
|
|
230
236
|
>
|
|
231
|
-
<div class=
|
|
237
|
+
<div class={itemContentClass}>
|
|
232
238
|
<svg
|
|
233
239
|
xmlns="http://www.w3.org/2000/svg"
|
|
234
240
|
width="24"
|
|
@@ -254,14 +260,14 @@
|
|
|
254
260
|
</button>
|
|
255
261
|
|
|
256
262
|
<button
|
|
257
|
-
class=
|
|
263
|
+
class={itemClass}
|
|
258
264
|
onclick={(e) => {
|
|
259
265
|
e.stopPropagation();
|
|
260
266
|
doPaste();
|
|
261
267
|
}}
|
|
262
268
|
title={L.hotkeys.paste}
|
|
263
269
|
>
|
|
264
|
-
<div class=
|
|
270
|
+
<div class={itemContentClass}>
|
|
265
271
|
<svg
|
|
266
272
|
xmlns="http://www.w3.org/2000/svg"
|
|
267
273
|
width="24"
|
|
@@ -287,14 +293,14 @@
|
|
|
287
293
|
</button>
|
|
288
294
|
|
|
289
295
|
<button
|
|
290
|
-
class=
|
|
296
|
+
class={itemClass}
|
|
291
297
|
onclick={(e) => {
|
|
292
298
|
e.stopPropagation();
|
|
293
299
|
doDelete();
|
|
294
300
|
}}
|
|
295
301
|
title={L.hotkeys.delete}
|
|
296
302
|
>
|
|
297
|
-
<div class=
|
|
303
|
+
<div class={itemContentClass}>
|
|
298
304
|
<svg
|
|
299
305
|
xmlns="http://www.w3.org/2000/svg"
|
|
300
306
|
width="24"
|
package/dist/lib/Dialog.svelte
CHANGED
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
const panelBase =
|
|
101
|
-
"fusion-dialog bg-[var(--color-bg-surface)] rounded-[var(--radius-lg)] shadow-
|
|
101
|
+
"fusion-dialog bg-[var(--color-bg-surface)] rounded-[var(--radius-lg)] shadow-[0_8px_24px_var(--shadow-color)] min-w-0 max-w-[min(100%,28rem)] max-h-[calc(100svh-var(--spacing-lg)*2)] overflow-auto w-full border border-[var(--border-color-default)]";
|
|
102
102
|
|
|
103
103
|
const paddingBySize: Record<SizeKey, string> = {
|
|
104
104
|
xs: "p-[var(--spacing-sm)]",
|
|
@@ -164,7 +164,7 @@
|
|
|
164
164
|
{#if open}
|
|
165
165
|
{#if modal}
|
|
166
166
|
<div
|
|
167
|
-
class="fixed inset-0 z-[var(--z-modal)] bg-oklch(0_0_0/var(--opacity-overlay)) flex items-center justify-center p-
|
|
167
|
+
class="fixed inset-0 z-[var(--z-modal)] bg-[oklch(0_0_0/var(--opacity-overlay))] flex items-center justify-center p-[var(--spacing-md)]"
|
|
168
168
|
role="presentation"
|
|
169
169
|
tabindex="-1"
|
|
170
170
|
onkeydown={handleKeydown}
|
|
@@ -195,7 +195,7 @@
|
|
|
195
195
|
</div>
|
|
196
196
|
{:else}
|
|
197
197
|
<div
|
|
198
|
-
class="fixed top-
|
|
198
|
+
class="fixed top-[var(--spacing-md)] right-[var(--spacing-md)] z-[var(--z-modal)] max-w-[calc(100vw-var(--spacing-md)*2)]"
|
|
199
199
|
role="dialog"
|
|
200
200
|
aria-modal="false"
|
|
201
201
|
aria-label={title}
|
package/dist/lib/Field.svelte
CHANGED
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
}: Props = $props();
|
|
87
87
|
|
|
88
88
|
const base =
|
|
89
|
-
"w-full outline-none 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)] disabled:opacity-[var(--opacity-disabled)] disabled:cursor-not-allowed";
|
|
89
|
+
"w-full outline-none 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)] disabled:opacity-[var(--opacity-disabled)] disabled:cursor-not-allowed [@media(pointer:coarse)]:min-h-11";
|
|
90
90
|
|
|
91
91
|
const sizes: Record<SizeKey, string> = {
|
|
92
92
|
xs: "px-2 h-6",
|
|
@@ -18,6 +18,10 @@
|
|
|
18
18
|
* @prop clearable {boolean} - Shows a clear button to reset selection
|
|
19
19
|
* @default true
|
|
20
20
|
*
|
|
21
|
+
* @prop maxBytes {number} - Maximum allowed file size in bytes
|
|
22
|
+
*
|
|
23
|
+
* @prop onError {(error: string) => void} - Fired when selected files are rejected
|
|
24
|
+
*
|
|
21
25
|
* @prop placeholder {string} - Placeholder text for the drop zone
|
|
22
26
|
*
|
|
23
27
|
* @prop value {FileList | null} - Controlled selected files (bindable)
|
|
@@ -30,7 +34,7 @@
|
|
|
30
34
|
*
|
|
31
35
|
* @note The entire area is clickable and supports drag-and-drop.
|
|
32
36
|
* @note After a selection, the underlying input resets its value, so choosing the same file twice still triggers updates.
|
|
33
|
-
* @note `accept`
|
|
37
|
+
* @note `accept` and `maxBytes` are enforced for both input and dropped files.
|
|
34
38
|
* @note When `clearable=true`, the user can clear selected files and the callback receives `null`.
|
|
35
39
|
* @note When `disabled=true`, clicks, drag events, focus, and keyboard input are blocked.
|
|
36
40
|
*/
|
|
@@ -47,6 +51,7 @@
|
|
|
47
51
|
clearable?: boolean;
|
|
48
52
|
placeholder?: string;
|
|
49
53
|
value?: FileList | null;
|
|
54
|
+
maxBytes?: number;
|
|
50
55
|
onFilesSelected?: (files: FileList | null) => void;
|
|
51
56
|
onError?: (error: string) => void;
|
|
52
57
|
class?: string;
|
|
@@ -60,7 +65,9 @@
|
|
|
60
65
|
clearable = true,
|
|
61
66
|
placeholder,
|
|
62
67
|
value = $bindable<FileList | null>(null),
|
|
68
|
+
maxBytes = Number.POSITIVE_INFINITY,
|
|
63
69
|
onFilesSelected,
|
|
70
|
+
onError,
|
|
64
71
|
class: externalClass = "",
|
|
65
72
|
...rest
|
|
66
73
|
}: Props = $props();
|
|
@@ -97,11 +104,7 @@
|
|
|
97
104
|
|
|
98
105
|
function handleFileChange(event: Event) {
|
|
99
106
|
const target = event.target as HTMLInputElement;
|
|
100
|
-
|
|
101
|
-
value = files;
|
|
102
|
-
if (files && files.length > 0) {
|
|
103
|
-
onFilesSelected?.(files);
|
|
104
|
-
}
|
|
107
|
+
selectFiles(target.files);
|
|
105
108
|
if (inputEl) {
|
|
106
109
|
inputEl.value = "";
|
|
107
110
|
}
|
|
@@ -111,11 +114,7 @@
|
|
|
111
114
|
event.preventDefault();
|
|
112
115
|
isDragOver = false;
|
|
113
116
|
if (disabled) return;
|
|
114
|
-
|
|
115
|
-
value = files || null;
|
|
116
|
-
if (files && files.length > 0) {
|
|
117
|
-
onFilesSelected?.(files);
|
|
118
|
-
}
|
|
117
|
+
selectFiles(event.dataTransfer?.files ?? null);
|
|
119
118
|
if (inputEl) {
|
|
120
119
|
inputEl.value = "";
|
|
121
120
|
}
|
|
@@ -153,6 +152,62 @@
|
|
|
153
152
|
}
|
|
154
153
|
onFilesSelected?.(null);
|
|
155
154
|
}
|
|
155
|
+
|
|
156
|
+
function selectFiles(files: FileList | null) {
|
|
157
|
+
const acceptedFiles = filterFiles(files);
|
|
158
|
+
value = acceptedFiles;
|
|
159
|
+
if (acceptedFiles && acceptedFiles.length > 0) {
|
|
160
|
+
onFilesSelected?.(acceptedFiles);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function filterFiles(files: FileList | null) {
|
|
165
|
+
if (!files || files.length === 0) return null;
|
|
166
|
+
|
|
167
|
+
const selected = Array.from(files);
|
|
168
|
+
const accepted = selected.filter(isAllowedFile);
|
|
169
|
+
|
|
170
|
+
if (accepted.length !== selected.length) {
|
|
171
|
+
onError?.("Some files were rejected by type or size constraints.");
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (accepted.length === 0) return null;
|
|
175
|
+
if (accepted.length === selected.length) return files;
|
|
176
|
+
|
|
177
|
+
return toFileList(accepted);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function isAllowedFile(file: File) {
|
|
181
|
+
if (Number.isFinite(maxBytes) && file.size > maxBytes) return false;
|
|
182
|
+
return matchesAccept(file, accept);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function matchesAccept(file: File, acceptValue: string) {
|
|
186
|
+
const rules = acceptValue
|
|
187
|
+
.split(",")
|
|
188
|
+
.map((rule) => rule.trim().toLowerCase())
|
|
189
|
+
.filter(Boolean);
|
|
190
|
+
|
|
191
|
+
if (rules.length === 0 || rules.includes("*/*")) return true;
|
|
192
|
+
|
|
193
|
+
const fileName = file.name.toLowerCase();
|
|
194
|
+
const fileType = file.type.toLowerCase();
|
|
195
|
+
|
|
196
|
+
return rules.some((rule) => {
|
|
197
|
+
if (rule.startsWith(".")) return fileName.endsWith(rule);
|
|
198
|
+
if (rule.endsWith("/*")) return fileType.startsWith(rule.slice(0, -1));
|
|
199
|
+
return fileType === rule;
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function toFileList(files: File[]) {
|
|
204
|
+
if (typeof DataTransfer === "undefined") return null;
|
|
205
|
+
const transfer = new DataTransfer();
|
|
206
|
+
for (const file of files) {
|
|
207
|
+
transfer.items.add(file);
|
|
208
|
+
}
|
|
209
|
+
return transfer.files;
|
|
210
|
+
}
|
|
156
211
|
</script>
|
|
157
212
|
|
|
158
213
|
<div class={pickerClass} {...rest}>
|
|
@@ -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)
|
|
@@ -28,7 +32,7 @@
|
|
|
28
32
|
*
|
|
29
33
|
* @note The entire area is clickable and supports drag-and-drop.
|
|
30
34
|
* @note After a selection, the underlying input resets its value, so choosing the same file twice still triggers updates.
|
|
31
|
-
* @note `accept`
|
|
35
|
+
* @note `accept` and `maxBytes` are enforced for both input and dropped files.
|
|
32
36
|
* @note When `clearable=true`, the user can clear selected files and the callback receives `null`.
|
|
33
37
|
* @note When `disabled=true`, clicks, drag events, focus, and keyboard input are blocked.
|
|
34
38
|
*/
|
|
@@ -41,6 +45,7 @@ type Props = HTMLAttributes<HTMLDivElement> & {
|
|
|
41
45
|
clearable?: boolean;
|
|
42
46
|
placeholder?: string;
|
|
43
47
|
value?: FileList | null;
|
|
48
|
+
maxBytes?: number;
|
|
44
49
|
onFilesSelected?: (files: FileList | null) => void;
|
|
45
50
|
onError?: (error: string) => void;
|
|
46
51
|
class?: string;
|