svelte-comp 1.3.3 → 1.3.6
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/LICENSE.md +21 -21
- package/README.md +101 -100
- package/dist/App.svelte +507 -507
- package/dist/Container.svelte +59 -59
- package/dist/app.css +234 -235
- package/dist/app.d.ts +10 -0
- package/dist/lib/Accordion.svelte +155 -155
- package/dist/lib/Badge.svelte +44 -44
- package/dist/lib/Button.svelte +185 -170
- package/dist/lib/Calendar.svelte +384 -384
- package/dist/lib/Card.svelte +103 -103
- package/dist/lib/Carousel.svelte +293 -293
- package/dist/lib/Carousel.svelte.d.ts +1 -1
- package/dist/lib/CheckBox.svelte +210 -210
- package/dist/lib/CodeView.svelte +308 -307
- package/dist/lib/ColorPicker.svelte +159 -159
- package/dist/lib/ContextMenu.svelte +328 -322
- package/dist/lib/DatePicker.svelte +246 -246
- package/dist/lib/Dialog.svelte +233 -233
- package/dist/lib/Field.svelte +299 -299
- package/dist/lib/FilePicker.svelte +295 -240
- package/dist/lib/FilePicker.svelte.d.ts +6 -1
- package/dist/lib/Form.svelte +438 -438
- package/dist/lib/Hamburger.svelte +217 -217
- package/dist/lib/InstallPWA.svelte +94 -94
- package/dist/lib/Menu.svelte +623 -623
- package/dist/lib/NoticeBase.svelte +140 -140
- package/dist/lib/PaginatedCard.svelte +73 -73
- package/dist/lib/Pagination.svelte +119 -119
- package/dist/lib/PrimaryColorSelect.svelte +111 -111
- package/dist/lib/ProgressBar.svelte +141 -141
- package/dist/lib/ProgressCircle.svelte +190 -190
- package/dist/lib/Radio.svelte +189 -189
- package/dist/lib/SearchInput.svelte +104 -104
- package/dist/lib/Select.svelte +524 -524
- package/dist/lib/Slider.svelte +253 -253
- package/dist/lib/Splitter.svelte +159 -150
- package/dist/lib/Switch.svelte +168 -167
- package/dist/lib/Table.svelte +299 -299
- package/dist/lib/Tabs.svelte +213 -213
- package/dist/lib/ThemeToggle.svelte +128 -127
- package/dist/lib/TimePicker.svelte +312 -312
- package/dist/lib/TimePickerNew.svelte +634 -0
- package/dist/lib/TimePickerNew.svelte.d.ts +49 -0
- package/dist/lib/Toast.svelte +123 -123
- package/dist/lib/Tooltip.svelte +110 -110
- package/dist/lib/Topbar.svelte +107 -107
- 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 +234 -232
- package/dist/utils/index.js +15 -4
- package/package.json +52 -52
package/dist/lib/CheckBox.svelte
CHANGED
|
@@ -1,210 +1,210 @@
|
|
|
1
|
-
<!-- src/lib/CheckBox.svelte -->
|
|
2
|
-
<script lang="ts">
|
|
3
|
-
/**
|
|
4
|
-
* @component CheckBox
|
|
5
|
-
* @description Accessible custom checkbox with `indeterminate` support.
|
|
6
|
-
*
|
|
7
|
-
* @prop label {string} - Text label shown next to the checkbox
|
|
8
|
-
*
|
|
9
|
-
* @prop sz {SizeKey} - Size option
|
|
10
|
-
* @options xs|sm|md|lg|xl
|
|
11
|
-
* @default md
|
|
12
|
-
*
|
|
13
|
-
* @prop variant {ComponentVariant} - Visual style preset
|
|
14
|
-
* @options default|neutral
|
|
15
|
-
* @default default
|
|
16
|
-
*
|
|
17
|
-
* @prop indeterminate {boolean} - Enables the mixed state
|
|
18
|
-
* @default false
|
|
19
|
-
*
|
|
20
|
-
* @prop checked {boolean} - Controlled checked state (bindable)
|
|
21
|
-
* @default false
|
|
22
|
-
*
|
|
23
|
-
* @prop onChange {(checked: boolean) => void} - Fired when the checkbox toggles
|
|
24
|
-
*
|
|
25
|
-
* @prop class {string} - Extra classes applied to the root container
|
|
26
|
-
* @default ""
|
|
27
|
-
*
|
|
28
|
-
* @prop invalid {boolean} - Marks the field invalid and sets `aria-invalid`
|
|
29
|
-
* @default false
|
|
30
|
-
*
|
|
31
|
-
* @prop describedBy {string} - ID of helper or error text for accessibility
|
|
32
|
-
*
|
|
33
|
-
* @note Fully bindable via `bind:checked`; `onChange` receives the final boolean.
|
|
34
|
-
* @note `indeterminate` is applied to the underlying input and reported as `aria-checked="mixed"`.
|
|
35
|
-
* @note Clicking the custom box while `indeterminate` clears it and sets `checked=true`.
|
|
36
|
-
* @note `invalid` maps to `aria-invalid`; `describedBy` maps to `aria-describedby`.
|
|
37
|
-
* @note SVG check and dash are inline; colors adapt per `variant` (`neutral` uses border color).
|
|
38
|
-
* @note Sizes scale the control box (`xs → xl`).
|
|
39
|
-
*/
|
|
40
|
-
import type { HTMLInputAttributes } from "svelte/elements";
|
|
41
|
-
import { type SizeKey, type ComponentVariant, TEXT } from "./types";
|
|
42
|
-
import { cx, uid } from "../utils";
|
|
43
|
-
|
|
44
|
-
type Props = HTMLInputAttributes & {
|
|
45
|
-
label?: string;
|
|
46
|
-
sz?: SizeKey;
|
|
47
|
-
variant?: ComponentVariant;
|
|
48
|
-
indeterminate?: boolean;
|
|
49
|
-
checked?: boolean;
|
|
50
|
-
onChange?: (checked: boolean) => void;
|
|
51
|
-
class?: string;
|
|
52
|
-
invalid?: boolean;
|
|
53
|
-
describedBy?: string;
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
let {
|
|
57
|
-
label,
|
|
58
|
-
sz = "md",
|
|
59
|
-
variant = "default",
|
|
60
|
-
indeterminate = false,
|
|
61
|
-
checked = $bindable(false),
|
|
62
|
-
onChange,
|
|
63
|
-
class: externalClass = "",
|
|
64
|
-
invalid = false,
|
|
65
|
-
describedBy,
|
|
66
|
-
...rest
|
|
67
|
-
}: Props = $props();
|
|
68
|
-
|
|
69
|
-
const inputId = $derived(rest.id ?? uid("chk-"));
|
|
70
|
-
|
|
71
|
-
const sizeClasses = {
|
|
72
|
-
xs: "w-3 h-3",
|
|
73
|
-
sm: "w-3.5 h-3.5",
|
|
74
|
-
md: "w-4 h-4",
|
|
75
|
-
lg: "w-[18px] h-[18px]",
|
|
76
|
-
xl: "w-5 h-5",
|
|
77
|
-
} as const;
|
|
78
|
-
|
|
79
|
-
const gapBySize: Record<SizeKey, string> = {
|
|
80
|
-
xs: "gap-1.5",
|
|
81
|
-
sm: "gap-2",
|
|
82
|
-
md: "gap-2.5",
|
|
83
|
-
lg: "gap-3",
|
|
84
|
-
xl: "gap-3.5",
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const variants = $derived(
|
|
88
|
-
variant === "neutral"
|
|
89
|
-
? {
|
|
90
|
-
checked: "bg-transparent border-[var(--border-color-strong)]",
|
|
91
|
-
unchecked: "bg-transparent border-[var(--border-color-default)]",
|
|
92
|
-
mixed: "bg-transparent border-[var(--border-color-strong)]",
|
|
93
|
-
}
|
|
94
|
-
: {
|
|
95
|
-
checked:
|
|
96
|
-
"bg-[var(--color-bg-primary)] border-[var(--color-bg-primary)]",
|
|
97
|
-
unchecked:
|
|
98
|
-
"bg-[var(--color-bg-surface)] border-[var(--border-color-default)]",
|
|
99
|
-
mixed:
|
|
100
|
-
"bg-[var(--color-bg-secondary)] border-[var(--border-color-default)]",
|
|
101
|
-
}
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
const boxBase =
|
|
105
|
-
"rounded-[var(--radius-sm)] border border-solid cursor-pointer transition-all duration-[var(--transition-fast)] ease-[var(--timing-default)] flex items-center justify-center";
|
|
106
|
-
|
|
107
|
-
const focusFromPeer =
|
|
108
|
-
"peer-focus-visible:ring-2 peer-focus-visible:ring-[var(--border-color-focus)] peer-focus-visible:border-[var(--border-color-focus)]";
|
|
109
|
-
|
|
110
|
-
const state = $derived(
|
|
111
|
-
indeterminate ? "mixed" : checked ? "checked" : "unchecked"
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
const strokeColor = $derived(
|
|
115
|
-
variant === "neutral"
|
|
116
|
-
? state === "checked" || state === "mixed"
|
|
117
|
-
? "var(--border-color-strong)"
|
|
118
|
-
: "var(--border-color-default)"
|
|
119
|
-
: "
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
const rootClass = $derived(
|
|
123
|
-
cx(
|
|
124
|
-
"inline-flex items-center cursor-pointer select-none",
|
|
125
|
-
gapBySize[sz],
|
|
126
|
-
externalClass
|
|
127
|
-
)
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
const checkboxClass = $derived(
|
|
131
|
-
cx(
|
|
132
|
-
boxBase,
|
|
133
|
-
focusFromPeer,
|
|
134
|
-
sizeClasses[sz],
|
|
135
|
-
state === "checked" && variants.checked,
|
|
136
|
-
state === "mixed" && variants.mixed,
|
|
137
|
-
state === "unchecked" && variants.unchecked,
|
|
138
|
-
"peer-disabled:opacity-[var(--opacity-disabled)] peer-disabled:cursor-not-allowed"
|
|
139
|
-
)
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
const labelClass = $derived(
|
|
143
|
-
cx(
|
|
144
|
-
TEXT[sz],
|
|
145
|
-
"[color:var(--color-text-muted)] font-medium peer-disabled:cursor-not-allowed"
|
|
146
|
-
)
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
function handleClick(e: MouseEvent) {
|
|
150
|
-
if (indeterminate) {
|
|
151
|
-
e.preventDefault();
|
|
152
|
-
checked = true;
|
|
153
|
-
indeterminate = false;
|
|
154
|
-
onChange?.(true);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
</script>
|
|
158
|
-
|
|
159
|
-
<label class={rootClass} for={inputId}>
|
|
160
|
-
<input
|
|
161
|
-
id={inputId}
|
|
162
|
-
type="checkbox"
|
|
163
|
-
bind:checked
|
|
164
|
-
{...rest}
|
|
165
|
-
class="sr-only peer"
|
|
166
|
-
aria-checked={indeterminate ? "mixed" : checked}
|
|
167
|
-
aria-invalid={invalid || undefined}
|
|
168
|
-
aria-describedby={describedBy}
|
|
169
|
-
onchange={() => {
|
|
170
|
-
if (indeterminate) indeterminate = false;
|
|
171
|
-
onChange?.(checked);
|
|
172
|
-
}}
|
|
173
|
-
/>
|
|
174
|
-
|
|
175
|
-
<span
|
|
176
|
-
data-state={state}
|
|
177
|
-
class={checkboxClass}
|
|
178
|
-
onclick={handleClick}
|
|
179
|
-
aria-hidden="true"
|
|
180
|
-
>
|
|
181
|
-
{#if indeterminate}
|
|
182
|
-
<svg
|
|
183
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
184
|
-
viewBox="0 0 24 24"
|
|
185
|
-
fill="none"
|
|
186
|
-
stroke={strokeColor}
|
|
187
|
-
stroke-width="3"
|
|
188
|
-
stroke-linecap="round"
|
|
189
|
-
>
|
|
190
|
-
<line x1="4" y1="12" x2="20" y2="12" />
|
|
191
|
-
</svg>
|
|
192
|
-
{:else if checked}
|
|
193
|
-
<svg
|
|
194
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
195
|
-
viewBox="0 0 24 24"
|
|
196
|
-
fill="none"
|
|
197
|
-
stroke={strokeColor}
|
|
198
|
-
stroke-width="3"
|
|
199
|
-
stroke-linecap="round"
|
|
200
|
-
stroke-linejoin="round"
|
|
201
|
-
>
|
|
202
|
-
<polyline points="20 6 9 17 4 12" />
|
|
203
|
-
</svg>
|
|
204
|
-
{/if}
|
|
205
|
-
</span>
|
|
206
|
-
|
|
207
|
-
{#if label}
|
|
208
|
-
<span class={labelClass}>{label}</span>
|
|
209
|
-
{/if}
|
|
210
|
-
</label>
|
|
1
|
+
<!-- src/lib/CheckBox.svelte -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
/**
|
|
4
|
+
* @component CheckBox
|
|
5
|
+
* @description Accessible custom checkbox with `indeterminate` support.
|
|
6
|
+
*
|
|
7
|
+
* @prop label {string} - Text label shown next to the checkbox
|
|
8
|
+
*
|
|
9
|
+
* @prop sz {SizeKey} - Size option
|
|
10
|
+
* @options xs|sm|md|lg|xl
|
|
11
|
+
* @default md
|
|
12
|
+
*
|
|
13
|
+
* @prop variant {ComponentVariant} - Visual style preset
|
|
14
|
+
* @options default|neutral
|
|
15
|
+
* @default default
|
|
16
|
+
*
|
|
17
|
+
* @prop indeterminate {boolean} - Enables the mixed state
|
|
18
|
+
* @default false
|
|
19
|
+
*
|
|
20
|
+
* @prop checked {boolean} - Controlled checked state (bindable)
|
|
21
|
+
* @default false
|
|
22
|
+
*
|
|
23
|
+
* @prop onChange {(checked: boolean) => void} - Fired when the checkbox toggles
|
|
24
|
+
*
|
|
25
|
+
* @prop class {string} - Extra classes applied to the root container
|
|
26
|
+
* @default ""
|
|
27
|
+
*
|
|
28
|
+
* @prop invalid {boolean} - Marks the field invalid and sets `aria-invalid`
|
|
29
|
+
* @default false
|
|
30
|
+
*
|
|
31
|
+
* @prop describedBy {string} - ID of helper or error text for accessibility
|
|
32
|
+
*
|
|
33
|
+
* @note Fully bindable via `bind:checked`; `onChange` receives the final boolean.
|
|
34
|
+
* @note `indeterminate` is applied to the underlying input and reported as `aria-checked="mixed"`.
|
|
35
|
+
* @note Clicking the custom box while `indeterminate` clears it and sets `checked=true`.
|
|
36
|
+
* @note `invalid` maps to `aria-invalid`; `describedBy` maps to `aria-describedby`.
|
|
37
|
+
* @note SVG check and dash are inline; colors adapt per `variant` (`neutral` uses border color).
|
|
38
|
+
* @note Sizes scale the control box (`xs → xl`).
|
|
39
|
+
*/
|
|
40
|
+
import type { HTMLInputAttributes } from "svelte/elements";
|
|
41
|
+
import { type SizeKey, type ComponentVariant, TEXT } from "./types";
|
|
42
|
+
import { cx, uid } from "../utils";
|
|
43
|
+
|
|
44
|
+
type Props = HTMLInputAttributes & {
|
|
45
|
+
label?: string;
|
|
46
|
+
sz?: SizeKey;
|
|
47
|
+
variant?: ComponentVariant;
|
|
48
|
+
indeterminate?: boolean;
|
|
49
|
+
checked?: boolean;
|
|
50
|
+
onChange?: (checked: boolean) => void;
|
|
51
|
+
class?: string;
|
|
52
|
+
invalid?: boolean;
|
|
53
|
+
describedBy?: string;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
let {
|
|
57
|
+
label,
|
|
58
|
+
sz = "md",
|
|
59
|
+
variant = "default",
|
|
60
|
+
indeterminate = false,
|
|
61
|
+
checked = $bindable(false),
|
|
62
|
+
onChange,
|
|
63
|
+
class: externalClass = "",
|
|
64
|
+
invalid = false,
|
|
65
|
+
describedBy,
|
|
66
|
+
...rest
|
|
67
|
+
}: Props = $props();
|
|
68
|
+
|
|
69
|
+
const inputId = $derived(rest.id ?? uid("chk-"));
|
|
70
|
+
|
|
71
|
+
const sizeClasses = {
|
|
72
|
+
xs: "w-3 h-3",
|
|
73
|
+
sm: "w-3.5 h-3.5",
|
|
74
|
+
md: "w-4 h-4",
|
|
75
|
+
lg: "w-[18px] h-[18px]",
|
|
76
|
+
xl: "w-5 h-5",
|
|
77
|
+
} as const;
|
|
78
|
+
|
|
79
|
+
const gapBySize: Record<SizeKey, string> = {
|
|
80
|
+
xs: "gap-1.5",
|
|
81
|
+
sm: "gap-2",
|
|
82
|
+
md: "gap-2.5",
|
|
83
|
+
lg: "gap-3",
|
|
84
|
+
xl: "gap-3.5",
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const variants = $derived(
|
|
88
|
+
variant === "neutral"
|
|
89
|
+
? {
|
|
90
|
+
checked: "bg-transparent border-[var(--border-color-strong)]",
|
|
91
|
+
unchecked: "bg-transparent border-[var(--border-color-default)]",
|
|
92
|
+
mixed: "bg-transparent border-[var(--border-color-strong)]",
|
|
93
|
+
}
|
|
94
|
+
: {
|
|
95
|
+
checked:
|
|
96
|
+
"bg-[var(--color-bg-primary)] border-[var(--color-bg-primary)]",
|
|
97
|
+
unchecked:
|
|
98
|
+
"bg-[var(--color-bg-surface)] border-[var(--border-color-default)]",
|
|
99
|
+
mixed:
|
|
100
|
+
"bg-[var(--color-bg-secondary)] border-[var(--border-color-default)]",
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const boxBase =
|
|
105
|
+
"rounded-[var(--radius-sm)] border border-solid cursor-pointer transition-all duration-[var(--transition-fast)] ease-[var(--timing-default)] flex items-center justify-center";
|
|
106
|
+
|
|
107
|
+
const focusFromPeer =
|
|
108
|
+
"peer-focus-visible:ring-2 peer-focus-visible:ring-[var(--border-color-focus)] peer-focus-visible:border-[var(--border-color-focus)]";
|
|
109
|
+
|
|
110
|
+
const state = $derived(
|
|
111
|
+
indeterminate ? "mixed" : checked ? "checked" : "unchecked"
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const strokeColor = $derived(
|
|
115
|
+
variant === "neutral"
|
|
116
|
+
? state === "checked" || state === "mixed"
|
|
117
|
+
? "var(--border-color-strong)"
|
|
118
|
+
: "var(--border-color-default)"
|
|
119
|
+
: "var(--color-text-inverse,#fff)"
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
const rootClass = $derived(
|
|
123
|
+
cx(
|
|
124
|
+
"inline-flex items-center cursor-pointer select-none [@media(pointer:coarse)]:min-h-11",
|
|
125
|
+
gapBySize[sz],
|
|
126
|
+
externalClass
|
|
127
|
+
)
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
const checkboxClass = $derived(
|
|
131
|
+
cx(
|
|
132
|
+
boxBase,
|
|
133
|
+
focusFromPeer,
|
|
134
|
+
sizeClasses[sz],
|
|
135
|
+
state === "checked" && variants.checked,
|
|
136
|
+
state === "mixed" && variants.mixed,
|
|
137
|
+
state === "unchecked" && variants.unchecked,
|
|
138
|
+
"peer-disabled:opacity-[var(--opacity-disabled)] peer-disabled:cursor-not-allowed"
|
|
139
|
+
)
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
const labelClass = $derived(
|
|
143
|
+
cx(
|
|
144
|
+
TEXT[sz],
|
|
145
|
+
"[color:var(--color-text-muted)] font-medium peer-disabled:cursor-not-allowed"
|
|
146
|
+
)
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
function handleClick(e: MouseEvent) {
|
|
150
|
+
if (indeterminate) {
|
|
151
|
+
e.preventDefault();
|
|
152
|
+
checked = true;
|
|
153
|
+
indeterminate = false;
|
|
154
|
+
onChange?.(true);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
</script>
|
|
158
|
+
|
|
159
|
+
<label class={rootClass} for={inputId}>
|
|
160
|
+
<input
|
|
161
|
+
id={inputId}
|
|
162
|
+
type="checkbox"
|
|
163
|
+
bind:checked
|
|
164
|
+
{...rest}
|
|
165
|
+
class="sr-only peer"
|
|
166
|
+
aria-checked={indeterminate ? "mixed" : checked}
|
|
167
|
+
aria-invalid={invalid || undefined}
|
|
168
|
+
aria-describedby={describedBy}
|
|
169
|
+
onchange={() => {
|
|
170
|
+
if (indeterminate) indeterminate = false;
|
|
171
|
+
onChange?.(checked);
|
|
172
|
+
}}
|
|
173
|
+
/>
|
|
174
|
+
|
|
175
|
+
<span
|
|
176
|
+
data-state={state}
|
|
177
|
+
class={checkboxClass}
|
|
178
|
+
onclick={handleClick}
|
|
179
|
+
aria-hidden="true"
|
|
180
|
+
>
|
|
181
|
+
{#if indeterminate}
|
|
182
|
+
<svg
|
|
183
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
184
|
+
viewBox="0 0 24 24"
|
|
185
|
+
fill="none"
|
|
186
|
+
stroke={strokeColor}
|
|
187
|
+
stroke-width="3"
|
|
188
|
+
stroke-linecap="round"
|
|
189
|
+
>
|
|
190
|
+
<line x1="4" y1="12" x2="20" y2="12" />
|
|
191
|
+
</svg>
|
|
192
|
+
{:else if checked}
|
|
193
|
+
<svg
|
|
194
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
195
|
+
viewBox="0 0 24 24"
|
|
196
|
+
fill="none"
|
|
197
|
+
stroke={strokeColor}
|
|
198
|
+
stroke-width="3"
|
|
199
|
+
stroke-linecap="round"
|
|
200
|
+
stroke-linejoin="round"
|
|
201
|
+
>
|
|
202
|
+
<polyline points="20 6 9 17 4 12" />
|
|
203
|
+
</svg>
|
|
204
|
+
{/if}
|
|
205
|
+
</span>
|
|
206
|
+
|
|
207
|
+
{#if label}
|
|
208
|
+
<span class={labelClass}>{label}</span>
|
|
209
|
+
{/if}
|
|
210
|
+
</label>
|