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
|
@@ -1,111 +1,111 @@
|
|
|
1
|
-
<!-- src/lib/PrimaryColorSelect.svelte -->
|
|
2
|
-
<script lang="ts">
|
|
3
|
-
/**
|
|
4
|
-
* @component PrimaryColorSelect
|
|
5
|
-
* @description Theme primary-color selector built on top of Select. Provides a fixed palette,
|
|
6
|
-
* handles persistence, and updates the global <html> attribute.
|
|
7
|
-
*
|
|
8
|
-
* @prop sz {SizeKey} - Sizing preset passed directly to Select
|
|
9
|
-
* @options xs|sm|md|lg|xl
|
|
10
|
-
* @default sm
|
|
11
|
-
*
|
|
12
|
-
* @prop label {string} - Custom label text. Falls back to localized copy when omitted.
|
|
13
|
-
*
|
|
14
|
-
* @prop class {string} - Extra classes forwarded to the underlying Select component
|
|
15
|
-
* @default ""
|
|
16
|
-
*
|
|
17
|
-
* @note The palette is predefined internally (`{ value, label, swatch }`).
|
|
18
|
-
* @note Selected value is stored in localStorage under "primary".
|
|
19
|
-
* @note The `html` element receives `data-primary="{value}"` for theme styling.
|
|
20
|
-
* @note Uses the same onChange contract as Select and forwards palette options as-is.
|
|
21
|
-
*/
|
|
22
|
-
import Select from "./Select.svelte";
|
|
23
|
-
import type { PrimaryKey, PaletteOption, SizeKey } from "./types";
|
|
24
|
-
import { getComponentText, getLangContext, getLangKey } from "./lang-context";
|
|
25
|
-
|
|
26
|
-
type Props = {
|
|
27
|
-
sz?: SizeKey;
|
|
28
|
-
label?: string;
|
|
29
|
-
class?: string;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
let { sz = "sm", label, class: externalClass = "" }: Props = $props();
|
|
33
|
-
|
|
34
|
-
const langCtx = getLangContext();
|
|
35
|
-
const langKey = $derived(getLangKey(langCtx));
|
|
36
|
-
const L = $derived(getComponentText("primaryColorSelect", langKey));
|
|
37
|
-
|
|
38
|
-
const labelFinal = $derived(label ?? L.text);
|
|
39
|
-
|
|
40
|
-
const palette: PaletteOption[] = [
|
|
41
|
-
{
|
|
42
|
-
value: "default",
|
|
43
|
-
label: "Indigo",
|
|
44
|
-
swatch: "oklch(62.3% 0.214 259.8deg)",
|
|
45
|
-
},
|
|
46
|
-
{ value: "cyan", label: "Cyan", swatch: "oklch(71.5% 0.143 215.221)" },
|
|
47
|
-
{ value: "red", label: "Red", swatch: "oklch(58% 0.24 30deg)" },
|
|
48
|
-
{ value: "green", label: "Green", swatch: "oklch(65% 0.22 140deg)" },
|
|
49
|
-
{ value: "yellow", label: "Yellow", swatch: "oklch(75% 0.18 90deg)" },
|
|
50
|
-
{ value: "pink", label: "Pink", swatch: "oklch(70% 0.25 350deg)" },
|
|
51
|
-
{ value: "orange", label: "Orange", swatch: "oklch(72% 0.22 60deg)" },
|
|
52
|
-
{ value: "purple", label: "Purple", swatch: "oklch(55% 0.22 290deg)" },
|
|
53
|
-
];
|
|
54
|
-
|
|
55
|
-
const paletteMap = palette.reduce<Record<PrimaryKey, PaletteOption>>(
|
|
56
|
-
(acc, option) => {
|
|
57
|
-
acc[option.value] = option;
|
|
58
|
-
return acc;
|
|
59
|
-
},
|
|
60
|
-
{} as Record<PrimaryKey, PaletteOption>
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
let selected = $state<PrimaryKey>("default");
|
|
64
|
-
let mounted = $state(false);
|
|
65
|
-
|
|
66
|
-
function isPrimaryKey(value: unknown): value is PrimaryKey {
|
|
67
|
-
return typeof value === "string" && value in paletteMap;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
$effect(() => {
|
|
71
|
-
if (!mounted) {
|
|
72
|
-
try {
|
|
73
|
-
if (typeof window !== "undefined") {
|
|
74
|
-
const saved = localStorage.getItem("primary");
|
|
75
|
-
if (isPrimaryKey(saved)) {
|
|
76
|
-
selected = saved;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
} catch {
|
|
80
|
-
// ignore unavailable storage/environment
|
|
81
|
-
}
|
|
82
|
-
mounted = true;
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
$effect(() => {
|
|
87
|
-
if (mounted) {
|
|
88
|
-
try {
|
|
89
|
-
if (typeof document !== "undefined") {
|
|
90
|
-
document.documentElement.setAttribute("data-primary", selected);
|
|
91
|
-
}
|
|
92
|
-
if (typeof window !== "undefined") {
|
|
93
|
-
localStorage.setItem("primary", selected);
|
|
94
|
-
}
|
|
95
|
-
} catch {
|
|
96
|
-
// ignore unavailable storage/environment
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
</script>
|
|
101
|
-
|
|
102
|
-
<Select
|
|
103
|
-
{sz}
|
|
104
|
-
label={labelFinal}
|
|
105
|
-
options={palette}
|
|
106
|
-
value={selected}
|
|
107
|
-
onChange={(v) => {
|
|
108
|
-
if (isPrimaryKey(v)) selected = v;
|
|
109
|
-
}}
|
|
110
|
-
class={externalClass}
|
|
111
|
-
/>
|
|
1
|
+
<!-- src/lib/PrimaryColorSelect.svelte -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
/**
|
|
4
|
+
* @component PrimaryColorSelect
|
|
5
|
+
* @description Theme primary-color selector built on top of Select. Provides a fixed palette,
|
|
6
|
+
* handles persistence, and updates the global <html> attribute.
|
|
7
|
+
*
|
|
8
|
+
* @prop sz {SizeKey} - Sizing preset passed directly to Select
|
|
9
|
+
* @options xs|sm|md|lg|xl
|
|
10
|
+
* @default sm
|
|
11
|
+
*
|
|
12
|
+
* @prop label {string} - Custom label text. Falls back to localized copy when omitted.
|
|
13
|
+
*
|
|
14
|
+
* @prop class {string} - Extra classes forwarded to the underlying Select component
|
|
15
|
+
* @default ""
|
|
16
|
+
*
|
|
17
|
+
* @note The palette is predefined internally (`{ value, label, swatch }`).
|
|
18
|
+
* @note Selected value is stored in localStorage under "primary".
|
|
19
|
+
* @note The `html` element receives `data-primary="{value}"` for theme styling.
|
|
20
|
+
* @note Uses the same onChange contract as Select and forwards palette options as-is.
|
|
21
|
+
*/
|
|
22
|
+
import Select from "./Select.svelte";
|
|
23
|
+
import type { PrimaryKey, PaletteOption, SizeKey } from "./types";
|
|
24
|
+
import { getComponentText, getLangContext, getLangKey } from "./lang-context";
|
|
25
|
+
|
|
26
|
+
type Props = {
|
|
27
|
+
sz?: SizeKey;
|
|
28
|
+
label?: string;
|
|
29
|
+
class?: string;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
let { sz = "sm", label, class: externalClass = "" }: Props = $props();
|
|
33
|
+
|
|
34
|
+
const langCtx = getLangContext();
|
|
35
|
+
const langKey = $derived(getLangKey(langCtx));
|
|
36
|
+
const L = $derived(getComponentText("primaryColorSelect", langKey));
|
|
37
|
+
|
|
38
|
+
const labelFinal = $derived(label ?? L.text);
|
|
39
|
+
|
|
40
|
+
const palette: PaletteOption[] = [
|
|
41
|
+
{
|
|
42
|
+
value: "default",
|
|
43
|
+
label: "Indigo",
|
|
44
|
+
swatch: "oklch(62.3% 0.214 259.8deg)",
|
|
45
|
+
},
|
|
46
|
+
{ value: "cyan", label: "Cyan", swatch: "oklch(71.5% 0.143 215.221)" },
|
|
47
|
+
{ value: "red", label: "Red", swatch: "oklch(58% 0.24 30deg)" },
|
|
48
|
+
{ value: "green", label: "Green", swatch: "oklch(65% 0.22 140deg)" },
|
|
49
|
+
{ value: "yellow", label: "Yellow", swatch: "oklch(75% 0.18 90deg)" },
|
|
50
|
+
{ value: "pink", label: "Pink", swatch: "oklch(70% 0.25 350deg)" },
|
|
51
|
+
{ value: "orange", label: "Orange", swatch: "oklch(72% 0.22 60deg)" },
|
|
52
|
+
{ value: "purple", label: "Purple", swatch: "oklch(55% 0.22 290deg)" },
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
const paletteMap = palette.reduce<Record<PrimaryKey, PaletteOption>>(
|
|
56
|
+
(acc, option) => {
|
|
57
|
+
acc[option.value] = option;
|
|
58
|
+
return acc;
|
|
59
|
+
},
|
|
60
|
+
{} as Record<PrimaryKey, PaletteOption>
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
let selected = $state<PrimaryKey>("default");
|
|
64
|
+
let mounted = $state(false);
|
|
65
|
+
|
|
66
|
+
function isPrimaryKey(value: unknown): value is PrimaryKey {
|
|
67
|
+
return typeof value === "string" && value in paletteMap;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
$effect(() => {
|
|
71
|
+
if (!mounted) {
|
|
72
|
+
try {
|
|
73
|
+
if (typeof window !== "undefined") {
|
|
74
|
+
const saved = localStorage.getItem("primary");
|
|
75
|
+
if (isPrimaryKey(saved)) {
|
|
76
|
+
selected = saved;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
} catch {
|
|
80
|
+
// ignore unavailable storage/environment
|
|
81
|
+
}
|
|
82
|
+
mounted = true;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
$effect(() => {
|
|
87
|
+
if (mounted) {
|
|
88
|
+
try {
|
|
89
|
+
if (typeof document !== "undefined") {
|
|
90
|
+
document.documentElement.setAttribute("data-primary", selected);
|
|
91
|
+
}
|
|
92
|
+
if (typeof window !== "undefined") {
|
|
93
|
+
localStorage.setItem("primary", selected);
|
|
94
|
+
}
|
|
95
|
+
} catch {
|
|
96
|
+
// ignore unavailable storage/environment
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
</script>
|
|
101
|
+
|
|
102
|
+
<Select
|
|
103
|
+
{sz}
|
|
104
|
+
label={labelFinal}
|
|
105
|
+
options={palette}
|
|
106
|
+
value={selected}
|
|
107
|
+
onChange={(v) => {
|
|
108
|
+
if (isPrimaryKey(v)) selected = v;
|
|
109
|
+
}}
|
|
110
|
+
class={externalClass}
|
|
111
|
+
/>
|
|
@@ -1,141 +1,141 @@
|
|
|
1
|
-
<!-- src/lib/ProgressBar.svelte -->
|
|
2
|
-
<script lang="ts">
|
|
3
|
-
/**
|
|
4
|
-
* @component ProgressBar
|
|
5
|
-
* @description A simple and accessible progress bar component that visually represents task completion.
|
|
6
|
-
*
|
|
7
|
-
* @prop value {number} - Current progress value from 0 to 100
|
|
8
|
-
* @default 0
|
|
9
|
-
*
|
|
10
|
-
* @prop indeterminate {boolean} - Enables the animated indeterminate state
|
|
11
|
-
* @default false
|
|
12
|
-
*
|
|
13
|
-
* @prop sz {SizeKey} - Controls the bar height
|
|
14
|
-
* @options xs|sm|md|lg|xl
|
|
15
|
-
* @default md
|
|
16
|
-
*
|
|
17
|
-
* @prop variant {ComponentVariant} - Visual style of the progress bar
|
|
18
|
-
* @options default|neutral
|
|
19
|
-
* @default default
|
|
20
|
-
*
|
|
21
|
-
* @prop class {string} - Additional CSS classes for the wrapper element
|
|
22
|
-
* @default ""
|
|
23
|
-
*
|
|
24
|
-
* @prop label {string} - Optional text label displayed above the bar
|
|
25
|
-
* @default ""
|
|
26
|
-
*
|
|
27
|
-
* @prop disabled {boolean} - Applies a muted inactive visual style
|
|
28
|
-
* @default false
|
|
29
|
-
*
|
|
30
|
-
* @note Indeterminate animation for unknown progress.
|
|
31
|
-
* @note Auto-clamping between 0 and 100.
|
|
32
|
-
* @note Adaptive height based on size.
|
|
33
|
-
* @note Theming support via CSS variables.
|
|
34
|
-
* @note Fully accessible with proper `aria` roles.
|
|
35
|
-
* @note No invalid ARIA attributes.
|
|
36
|
-
*/
|
|
37
|
-
import type { HTMLAttributes } from "svelte/elements";
|
|
38
|
-
import { type SizeKey, type ComponentVariant, TEXT } from "./types";
|
|
39
|
-
import { cx, clamp } from "../utils";
|
|
40
|
-
|
|
41
|
-
type Props = HTMLAttributes<HTMLDivElement> & {
|
|
42
|
-
value?: number;
|
|
43
|
-
indeterminate?: boolean;
|
|
44
|
-
sz?: SizeKey;
|
|
45
|
-
variant?: ComponentVariant;
|
|
46
|
-
class?: string;
|
|
47
|
-
label?: string;
|
|
48
|
-
disabled?: boolean;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
let {
|
|
52
|
-
value = 0,
|
|
53
|
-
indeterminate = false,
|
|
54
|
-
sz = "md",
|
|
55
|
-
variant = "default",
|
|
56
|
-
class: externalClass = "",
|
|
57
|
-
label = "",
|
|
58
|
-
disabled = false,
|
|
59
|
-
...rest
|
|
60
|
-
}: Props = $props();
|
|
61
|
-
|
|
62
|
-
const pct = $derived(`${clamp(value, 0, 100)}%`);
|
|
63
|
-
|
|
64
|
-
const sizeTrack = $derived(
|
|
65
|
-
{
|
|
66
|
-
xs: "h-[4px]",
|
|
67
|
-
sm: "h-[5px]",
|
|
68
|
-
md: "h-[6px]",
|
|
69
|
-
lg: "h-[7px]",
|
|
70
|
-
xl: "h-[8px]",
|
|
71
|
-
}[sz]
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
const bar = $derived(
|
|
75
|
-
variant === "neutral"
|
|
76
|
-
? "bg-[var(--color-bg-secondary)]"
|
|
77
|
-
: "bg-[var(--color-bg-primary)]"
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
const rootClass = $derived(
|
|
81
|
-
cx(
|
|
82
|
-
"relative flex flex-col gap-1 w-full data-[disabled=true]:opacity-[var(--opacity-disabled)] data-[disabled=true]:cursor-not-allowed",
|
|
83
|
-
externalClass
|
|
84
|
-
)
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
const trackClass = $derived(
|
|
88
|
-
cx(
|
|
89
|
-
"absolute top-1/2 -translate-y-1/2 w-full bg-[var(--border-color-default)] rounded overflow-hidden",
|
|
90
|
-
sizeTrack
|
|
91
|
-
)
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
const barClass = $derived(cx("h-full", bar));
|
|
95
|
-
</script>
|
|
96
|
-
|
|
97
|
-
<div
|
|
98
|
-
class={rootClass}
|
|
99
|
-
role="progressbar"
|
|
100
|
-
aria-valuemin="0"
|
|
101
|
-
aria-valuemax="100"
|
|
102
|
-
aria-valuenow={indeterminate ? undefined : Math.round(clamp(value, 0, 100))}
|
|
103
|
-
data-disabled={disabled ? "true" : undefined}
|
|
104
|
-
{...rest}
|
|
105
|
-
>
|
|
106
|
-
{#if label}
|
|
107
|
-
<span class={cx("text-[var(--color-text-muted)] select-none", TEXT[sz])}>
|
|
108
|
-
{label}
|
|
109
|
-
</span>
|
|
110
|
-
{/if}
|
|
111
|
-
|
|
112
|
-
<div class="relative w-full h-10">
|
|
113
|
-
<div class={trackClass}>
|
|
114
|
-
{#if indeterminate}
|
|
115
|
-
<div class={cx(barClass, "pb-indet")}></div>
|
|
116
|
-
{:else}
|
|
117
|
-
<div
|
|
118
|
-
class={cx(barClass, "transition-[width]")}
|
|
119
|
-
style={`width:${pct}`}
|
|
120
|
-
></div>
|
|
121
|
-
{/if}
|
|
122
|
-
</div>
|
|
123
|
-
</div>
|
|
124
|
-
</div>
|
|
125
|
-
|
|
126
|
-
<style>
|
|
127
|
-
:global {
|
|
128
|
-
@keyframes pb-indeterminate {
|
|
129
|
-
0% {
|
|
130
|
-
transform: translateX(-100%);
|
|
131
|
-
}
|
|
132
|
-
100% {
|
|
133
|
-
transform: translateX(250%);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
.pb-indet {
|
|
138
|
-
width: 40%;
|
|
139
|
-
animation: pb-indeterminate 2s linear infinite;
|
|
140
|
-
}
|
|
141
|
-
</style>
|
|
1
|
+
<!-- src/lib/ProgressBar.svelte -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
/**
|
|
4
|
+
* @component ProgressBar
|
|
5
|
+
* @description A simple and accessible progress bar component that visually represents task completion.
|
|
6
|
+
*
|
|
7
|
+
* @prop value {number} - Current progress value from 0 to 100
|
|
8
|
+
* @default 0
|
|
9
|
+
*
|
|
10
|
+
* @prop indeterminate {boolean} - Enables the animated indeterminate state
|
|
11
|
+
* @default false
|
|
12
|
+
*
|
|
13
|
+
* @prop sz {SizeKey} - Controls the bar height
|
|
14
|
+
* @options xs|sm|md|lg|xl
|
|
15
|
+
* @default md
|
|
16
|
+
*
|
|
17
|
+
* @prop variant {ComponentVariant} - Visual style of the progress bar
|
|
18
|
+
* @options default|neutral
|
|
19
|
+
* @default default
|
|
20
|
+
*
|
|
21
|
+
* @prop class {string} - Additional CSS classes for the wrapper element
|
|
22
|
+
* @default ""
|
|
23
|
+
*
|
|
24
|
+
* @prop label {string} - Optional text label displayed above the bar
|
|
25
|
+
* @default ""
|
|
26
|
+
*
|
|
27
|
+
* @prop disabled {boolean} - Applies a muted inactive visual style
|
|
28
|
+
* @default false
|
|
29
|
+
*
|
|
30
|
+
* @note Indeterminate animation for unknown progress.
|
|
31
|
+
* @note Auto-clamping between 0 and 100.
|
|
32
|
+
* @note Adaptive height based on size.
|
|
33
|
+
* @note Theming support via CSS variables.
|
|
34
|
+
* @note Fully accessible with proper `aria` roles.
|
|
35
|
+
* @note No invalid ARIA attributes.
|
|
36
|
+
*/
|
|
37
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
38
|
+
import { type SizeKey, type ComponentVariant, TEXT } from "./types";
|
|
39
|
+
import { cx, clamp } from "../utils";
|
|
40
|
+
|
|
41
|
+
type Props = HTMLAttributes<HTMLDivElement> & {
|
|
42
|
+
value?: number;
|
|
43
|
+
indeterminate?: boolean;
|
|
44
|
+
sz?: SizeKey;
|
|
45
|
+
variant?: ComponentVariant;
|
|
46
|
+
class?: string;
|
|
47
|
+
label?: string;
|
|
48
|
+
disabled?: boolean;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
let {
|
|
52
|
+
value = 0,
|
|
53
|
+
indeterminate = false,
|
|
54
|
+
sz = "md",
|
|
55
|
+
variant = "default",
|
|
56
|
+
class: externalClass = "",
|
|
57
|
+
label = "",
|
|
58
|
+
disabled = false,
|
|
59
|
+
...rest
|
|
60
|
+
}: Props = $props();
|
|
61
|
+
|
|
62
|
+
const pct = $derived(`${clamp(value, 0, 100)}%`);
|
|
63
|
+
|
|
64
|
+
const sizeTrack = $derived(
|
|
65
|
+
{
|
|
66
|
+
xs: "h-[4px]",
|
|
67
|
+
sm: "h-[5px]",
|
|
68
|
+
md: "h-[6px]",
|
|
69
|
+
lg: "h-[7px]",
|
|
70
|
+
xl: "h-[8px]",
|
|
71
|
+
}[sz]
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const bar = $derived(
|
|
75
|
+
variant === "neutral"
|
|
76
|
+
? "bg-[var(--color-bg-secondary)]"
|
|
77
|
+
: "bg-[var(--color-bg-primary)]"
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
const rootClass = $derived(
|
|
81
|
+
cx(
|
|
82
|
+
"relative flex flex-col gap-1 w-full data-[disabled=true]:opacity-[var(--opacity-disabled)] data-[disabled=true]:cursor-not-allowed",
|
|
83
|
+
externalClass
|
|
84
|
+
)
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const trackClass = $derived(
|
|
88
|
+
cx(
|
|
89
|
+
"absolute top-1/2 -translate-y-1/2 w-full bg-[var(--border-color-default)] rounded overflow-hidden",
|
|
90
|
+
sizeTrack
|
|
91
|
+
)
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const barClass = $derived(cx("h-full", bar));
|
|
95
|
+
</script>
|
|
96
|
+
|
|
97
|
+
<div
|
|
98
|
+
class={rootClass}
|
|
99
|
+
role="progressbar"
|
|
100
|
+
aria-valuemin="0"
|
|
101
|
+
aria-valuemax="100"
|
|
102
|
+
aria-valuenow={indeterminate ? undefined : Math.round(clamp(value, 0, 100))}
|
|
103
|
+
data-disabled={disabled ? "true" : undefined}
|
|
104
|
+
{...rest}
|
|
105
|
+
>
|
|
106
|
+
{#if label}
|
|
107
|
+
<span class={cx("text-[var(--color-text-muted)] select-none", TEXT[sz])}>
|
|
108
|
+
{label}
|
|
109
|
+
</span>
|
|
110
|
+
{/if}
|
|
111
|
+
|
|
112
|
+
<div class="relative w-full h-10">
|
|
113
|
+
<div class={trackClass}>
|
|
114
|
+
{#if indeterminate}
|
|
115
|
+
<div class={cx(barClass, "pb-indet")}></div>
|
|
116
|
+
{:else}
|
|
117
|
+
<div
|
|
118
|
+
class={cx(barClass, "transition-[width]")}
|
|
119
|
+
style={`width:${pct}`}
|
|
120
|
+
></div>
|
|
121
|
+
{/if}
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<style>
|
|
127
|
+
:global {
|
|
128
|
+
@keyframes pb-indeterminate {
|
|
129
|
+
0% {
|
|
130
|
+
transform: translateX(-100%);
|
|
131
|
+
}
|
|
132
|
+
100% {
|
|
133
|
+
transform: translateX(250%);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
.pb-indet {
|
|
138
|
+
width: 40%;
|
|
139
|
+
animation: pb-indeterminate 2s linear infinite;
|
|
140
|
+
}
|
|
141
|
+
</style>
|