svelte-comp 1.0.7 → 1.0.9
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 +6 -4
- package/dist/lib/ProgressCircle.svelte +191 -0
- package/dist/lib/ProgressCircle.svelte.d.ts +39 -0
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/index.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -45,10 +45,10 @@ Add to `src/app.css`:
|
|
|
45
45
|
|
|
46
46
|
## 📁 Components included
|
|
47
47
|
|
|
48
|
-
Accordion • Button • Card • Carousel • CheckBox • CodeView • ColorPicker
|
|
49
|
-
DatePicker • Dialog • Field • FilePicker • Form • Hamburger • Menu
|
|
50
|
-
PaginatedCard • Pagination • ProgressBar •
|
|
51
|
-
Splitter • Switch • Tabs • Table • ThemeToggle • TimePicker
|
|
48
|
+
Accordion • Button • Card • Carousel • CheckBox • CodeView • ColorPicker •
|
|
49
|
+
DatePicker • Dialog • Field • FilePicker • Form • Hamburger • Menu •
|
|
50
|
+
PaginatedCard • Pagination • ProgressBar • ProgressCircle • Radio • Select
|
|
51
|
+
• Slider • Splitter • Switch • Tabs • Table • ThemeToggle • TimePicker
|
|
52
52
|
Toast • Tooltip
|
|
53
53
|
|
|
54
54
|
Full component list in repository.
|
|
@@ -88,3 +88,5 @@ MIT License
|
|
|
88
88
|
## 🔗 Links
|
|
89
89
|
|
|
90
90
|
GitHub: [https://github.com/MaestroFusion360/svelte-comp](https://github.com/MaestroFusion360/svelte-comp)
|
|
91
|
+
|
|
92
|
+
Demo: [https://maestrofusion360.github.io/svelte-comp/](https://maestrofusion360.github.io/svelte-comp/)
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
<!-- src/lib/ProgressCircle.svelte -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
/**
|
|
4
|
+
* @component ProgressCircle
|
|
5
|
+
* @description Circular progress indicator for visualizing completion or load state (0-100). Supports indeterminate mode.
|
|
6
|
+
* @prop value {number} - Current progress value
|
|
7
|
+
* @default 0
|
|
8
|
+
* @prop indeterminate {boolean} - Enables spinning infinite mode
|
|
9
|
+
* @default false
|
|
10
|
+
* @prop size {number} - Diameter in px
|
|
11
|
+
* @default 48
|
|
12
|
+
* @prop stroke {number} - Stroke width in px
|
|
13
|
+
* @default 4
|
|
14
|
+
* @prop variant {ComponentVariant} - Color/style variant
|
|
15
|
+
* @options default|neutral|success|warning|error
|
|
16
|
+
* @default default
|
|
17
|
+
* @prop label {string} - Optional text shown in center
|
|
18
|
+
* @default ""
|
|
19
|
+
* @prop max {number} - Max progress value for normalization
|
|
20
|
+
* @default 100
|
|
21
|
+
* @prop class {string} - Extra wrapper classes
|
|
22
|
+
* @default ""
|
|
23
|
+
* @note Clamps value between 0-max
|
|
24
|
+
* @note Uses SVG stroke-dashoffset animation
|
|
25
|
+
* @note Accessible role=progressbar with aria-valuenow
|
|
26
|
+
* @note Works in both determinate/indeterminate modes
|
|
27
|
+
*/
|
|
28
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
29
|
+
import { type SizeKey, type ComponentVariant, TEXT } from "./types";
|
|
30
|
+
import { cx, clamp } from "../utils";
|
|
31
|
+
|
|
32
|
+
type Props = HTMLAttributes<HTMLDivElement> & {
|
|
33
|
+
value?: number;
|
|
34
|
+
indeterminate?: boolean;
|
|
35
|
+
sz?: SizeKey;
|
|
36
|
+
variant?: ComponentVariant;
|
|
37
|
+
class?: string;
|
|
38
|
+
label?: string;
|
|
39
|
+
disabled?: boolean;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
let {
|
|
43
|
+
value = 0,
|
|
44
|
+
indeterminate = false,
|
|
45
|
+
sz = "md",
|
|
46
|
+
variant = "default",
|
|
47
|
+
class: externalClass = "",
|
|
48
|
+
label = "",
|
|
49
|
+
disabled = false,
|
|
50
|
+
...rest
|
|
51
|
+
}: Props = $props();
|
|
52
|
+
|
|
53
|
+
const sizes: Record<SizeKey, { diameter: number; stroke: number }> = {
|
|
54
|
+
xs: { diameter: 40, stroke: 4 },
|
|
55
|
+
sm: { diameter: 48, stroke: 5 },
|
|
56
|
+
md: { diameter: 56, stroke: 6 },
|
|
57
|
+
lg: { diameter: 64, stroke: 7 },
|
|
58
|
+
xl: { diameter: 72, stroke: 8 },
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const pctValue = $derived(clamp(value, 0, 100));
|
|
62
|
+
const pctText = $derived(Math.round(pctValue));
|
|
63
|
+
|
|
64
|
+
const geometry = $derived(sizes[sz]);
|
|
65
|
+
const center = $derived(geometry.diameter / 2);
|
|
66
|
+
const radius = $derived(center - geometry.stroke / 2);
|
|
67
|
+
const circumference = $derived(2 * Math.PI * radius);
|
|
68
|
+
|
|
69
|
+
const dashOffset = $derived(((100 - pctValue) / 100) * circumference);
|
|
70
|
+
const dashArray = $derived(`${circumference} ${circumference}`);
|
|
71
|
+
const indeterminateDash = $derived(`${circumference * 0.3} ${circumference}`);
|
|
72
|
+
|
|
73
|
+
const strokeColor = $derived(
|
|
74
|
+
variant === "neutral"
|
|
75
|
+
? "stroke-[var(--color-bg-secondary)]"
|
|
76
|
+
: "stroke-[var(--color-bg-primary)]"
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const rootClass = $derived(
|
|
80
|
+
cx(
|
|
81
|
+
"inline-flex flex-col items-center gap-1 data-[disabled=true]:opacity-[var(--opacity-disabled)] data-[disabled=true]:cursor-not-allowed",
|
|
82
|
+
externalClass
|
|
83
|
+
)
|
|
84
|
+
);
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<div
|
|
88
|
+
class={rootClass}
|
|
89
|
+
role="progressbar"
|
|
90
|
+
aria-valuemin="0"
|
|
91
|
+
aria-valuemax="100"
|
|
92
|
+
aria-valuenow={indeterminate ? undefined : pctText}
|
|
93
|
+
data-disabled={disabled ? "true" : undefined}
|
|
94
|
+
{...rest}
|
|
95
|
+
>
|
|
96
|
+
{#if label}
|
|
97
|
+
<span class="text-[var(--color-text-muted)] select-none {TEXT[sz]}">
|
|
98
|
+
{label}
|
|
99
|
+
</span>
|
|
100
|
+
{/if}
|
|
101
|
+
|
|
102
|
+
<div
|
|
103
|
+
class="relative inline-flex items-center justify-center"
|
|
104
|
+
style={`width:${geometry.diameter}px;height:${geometry.diameter}px;`}
|
|
105
|
+
>
|
|
106
|
+
<svg
|
|
107
|
+
class="pc-svg"
|
|
108
|
+
viewBox={`0 0 ${geometry.diameter} ${geometry.diameter}`}
|
|
109
|
+
role="presentation"
|
|
110
|
+
aria-hidden="true"
|
|
111
|
+
>
|
|
112
|
+
<g class="pc-rot">
|
|
113
|
+
<circle
|
|
114
|
+
class="pc-track"
|
|
115
|
+
cx={center}
|
|
116
|
+
cy={center}
|
|
117
|
+
r={radius}
|
|
118
|
+
stroke-width={geometry.stroke}
|
|
119
|
+
></circle>
|
|
120
|
+
|
|
121
|
+
{#if indeterminate}
|
|
122
|
+
<circle
|
|
123
|
+
class={cx("pc-bar pc-indet", strokeColor)}
|
|
124
|
+
cx={center}
|
|
125
|
+
cy={center}
|
|
126
|
+
r={radius}
|
|
127
|
+
stroke-width={geometry.stroke}
|
|
128
|
+
stroke-dasharray={indeterminateDash}
|
|
129
|
+
></circle>
|
|
130
|
+
{:else}
|
|
131
|
+
<circle
|
|
132
|
+
class={cx("pc-bar", strokeColor)}
|
|
133
|
+
cx={center}
|
|
134
|
+
cy={center}
|
|
135
|
+
r={radius}
|
|
136
|
+
stroke-width={geometry.stroke}
|
|
137
|
+
stroke-dasharray={dashArray}
|
|
138
|
+
stroke-dashoffset={dashOffset}
|
|
139
|
+
></circle>
|
|
140
|
+
{/if}
|
|
141
|
+
</g>
|
|
142
|
+
</svg>
|
|
143
|
+
|
|
144
|
+
{#if !indeterminate}
|
|
145
|
+
<div
|
|
146
|
+
class="absolute inset-0 flex items-center justify-center text-[var(--color-text-muted)] font-medium select-none {TEXT[
|
|
147
|
+
sz
|
|
148
|
+
]}"
|
|
149
|
+
>
|
|
150
|
+
{pctText}%
|
|
151
|
+
</div>
|
|
152
|
+
{/if}
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
|
|
156
|
+
<style>
|
|
157
|
+
.pc-svg {
|
|
158
|
+
width: 100%;
|
|
159
|
+
height: 100%;
|
|
160
|
+
}
|
|
161
|
+
.pc-rot {
|
|
162
|
+
transform: rotate(-90deg);
|
|
163
|
+
transform-origin: center;
|
|
164
|
+
}
|
|
165
|
+
.pc-track {
|
|
166
|
+
fill: none;
|
|
167
|
+
stroke: var(--border-color-default);
|
|
168
|
+
}
|
|
169
|
+
.pc-bar {
|
|
170
|
+
fill: none;
|
|
171
|
+
stroke-linecap: round;
|
|
172
|
+
transition:
|
|
173
|
+
stroke-dashoffset 0.25s ease,
|
|
174
|
+
stroke 0.2s ease;
|
|
175
|
+
transform-origin: center;
|
|
176
|
+
}
|
|
177
|
+
.pc-indet {
|
|
178
|
+
animation: pc-spin 1.2s linear infinite;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
:global {
|
|
182
|
+
@keyframes pc-spin {
|
|
183
|
+
0% {
|
|
184
|
+
transform: rotate(0deg);
|
|
185
|
+
}
|
|
186
|
+
100% {
|
|
187
|
+
transform: rotate(360deg);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
</style>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @component ProgressCircle
|
|
3
|
+
* @description Circular progress indicator for visualizing completion or load state (0-100). Supports indeterminate mode.
|
|
4
|
+
* @prop value {number} - Current progress value
|
|
5
|
+
* @default 0
|
|
6
|
+
* @prop indeterminate {boolean} - Enables spinning infinite mode
|
|
7
|
+
* @default false
|
|
8
|
+
* @prop size {number} - Diameter in px
|
|
9
|
+
* @default 48
|
|
10
|
+
* @prop stroke {number} - Stroke width in px
|
|
11
|
+
* @default 4
|
|
12
|
+
* @prop variant {ComponentVariant} - Color/style variant
|
|
13
|
+
* @options default|neutral|success|warning|error
|
|
14
|
+
* @default default
|
|
15
|
+
* @prop label {string} - Optional text shown in center
|
|
16
|
+
* @default ""
|
|
17
|
+
* @prop max {number} - Max progress value for normalization
|
|
18
|
+
* @default 100
|
|
19
|
+
* @prop class {string} - Extra wrapper classes
|
|
20
|
+
* @default ""
|
|
21
|
+
* @note Clamps value between 0-max
|
|
22
|
+
* @note Uses SVG stroke-dashoffset animation
|
|
23
|
+
* @note Accessible role=progressbar with aria-valuenow
|
|
24
|
+
* @note Works in both determinate/indeterminate modes
|
|
25
|
+
*/
|
|
26
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
27
|
+
import { type SizeKey, type ComponentVariant } from "./types";
|
|
28
|
+
type Props = HTMLAttributes<HTMLDivElement> & {
|
|
29
|
+
value?: number;
|
|
30
|
+
indeterminate?: boolean;
|
|
31
|
+
sz?: SizeKey;
|
|
32
|
+
variant?: ComponentVariant;
|
|
33
|
+
class?: string;
|
|
34
|
+
label?: string;
|
|
35
|
+
disabled?: boolean;
|
|
36
|
+
};
|
|
37
|
+
declare const ProgressCircle: import("svelte").Component<Props, {}, "">;
|
|
38
|
+
type ProgressCircle = ReturnType<typeof ProgressCircle>;
|
|
39
|
+
export default ProgressCircle;
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export { default as Menu } from "./Menu.svelte";
|
|
|
15
15
|
export { default as PaginatedCard } from "./PaginatedCard.svelte";
|
|
16
16
|
export { default as Pagination } from "./Pagination.svelte";
|
|
17
17
|
export { default as ProgressBar } from "./ProgressBar.svelte";
|
|
18
|
+
export { default as ProgressCircle } from "./ProgressCircle.svelte";
|
|
18
19
|
export { default as Radio } from "./Radio.svelte";
|
|
19
20
|
export { default as Select } from "./Select.svelte";
|
|
20
21
|
export { default as Slider } from "./Slider.svelte";
|
package/dist/lib/index.js
CHANGED
|
@@ -16,6 +16,7 @@ export { default as Menu } from "./Menu.svelte";
|
|
|
16
16
|
export { default as PaginatedCard } from "./PaginatedCard.svelte";
|
|
17
17
|
export { default as Pagination } from "./Pagination.svelte";
|
|
18
18
|
export { default as ProgressBar } from "./ProgressBar.svelte";
|
|
19
|
+
export { default as ProgressCircle } from "./ProgressCircle.svelte";
|
|
19
20
|
export { default as Radio } from "./Radio.svelte";
|
|
20
21
|
export { default as Select } from "./Select.svelte";
|
|
21
22
|
export { default as Slider } from "./Slider.svelte";
|
package/package.json
CHANGED