@makolabs/ripple 0.0.1-dev.17 → 0.0.1-dev.18
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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { cn } from '../../helper/cls.js';
|
|
3
3
|
import { Color, Size } from '../../variants.js';
|
|
4
|
-
import type { ProgressProps } from '../../index.js';
|
|
4
|
+
import type { ProgressProps, ProgressSegment, VariantColors } from '../../index.js';
|
|
5
5
|
|
|
6
6
|
let {
|
|
7
7
|
value,
|
|
@@ -10,19 +10,55 @@
|
|
|
10
10
|
color = Color.PRIMARY,
|
|
11
11
|
showLabel = true,
|
|
12
12
|
labelPosition = 'right',
|
|
13
|
+
segments = undefined,
|
|
14
|
+
showValues = false,
|
|
15
|
+
showLabels = false,
|
|
13
16
|
class: className = '',
|
|
14
17
|
labelClass = '',
|
|
15
18
|
barClass = ''
|
|
16
19
|
}: ProgressProps = $props();
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
// Function composition for better readability and maintainability
|
|
22
|
+
function calculatePercentage(val: number, maximum: number): number {
|
|
23
|
+
return Math.min(Math.round((val / maximum) * 100), 100);
|
|
24
|
+
}
|
|
19
25
|
|
|
26
|
+
function getColorClass(color: VariantColors): string {
|
|
27
|
+
const colorMap = {
|
|
28
|
+
[Color.PRIMARY]: 'bg-primary-600',
|
|
29
|
+
[Color.SECONDARY]: 'bg-secondary-600',
|
|
30
|
+
[Color.SUCCESS]: 'bg-success-600',
|
|
31
|
+
[Color.DANGER]: 'bg-danger-600',
|
|
32
|
+
[Color.WARNING]: 'bg-warning-600',
|
|
33
|
+
[Color.INFO]: 'bg-info-600',
|
|
34
|
+
[Color.DEFAULT]: 'bg-gray-600'
|
|
35
|
+
};
|
|
36
|
+
return colorMap[color] || colorMap[Color.PRIMARY];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getSizeTextClass(size: string): string {
|
|
40
|
+
if (size === Size.XS || size === Size.SM) return 'text-xs';
|
|
41
|
+
if (size === Size.BASE) return 'text-sm';
|
|
42
|
+
return 'text-base'; // For Size.LG, Size.XL
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Derived values
|
|
46
|
+
const percentage = $derived(segments ? 100 : calculatePercentage(value, max));
|
|
47
|
+
const segmentPercentages = $derived(
|
|
48
|
+
segments?.map(segment => ({
|
|
49
|
+
...segment,
|
|
50
|
+
percentage: calculatePercentage(segment.value, max)
|
|
51
|
+
})) || []
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
// Class compositions
|
|
20
55
|
const containerClass = $derived(
|
|
21
56
|
cn(
|
|
22
|
-
'relative
|
|
57
|
+
'relative',
|
|
23
58
|
{
|
|
24
|
-
'flex
|
|
25
|
-
'flex-
|
|
59
|
+
'flex items-center': !segments,
|
|
60
|
+
'flex-col gap-1': !segments && (labelPosition === 'top' || labelPosition === 'bottom'),
|
|
61
|
+
'flex-row gap-3': !segments && labelPosition === 'right'
|
|
26
62
|
},
|
|
27
63
|
className
|
|
28
64
|
)
|
|
@@ -35,23 +71,16 @@
|
|
|
35
71
|
'h-2.5': size === Size.BASE,
|
|
36
72
|
'h-3': size === Size.LG,
|
|
37
73
|
'h-4': size === Size.XL,
|
|
38
|
-
'order-2': labelPosition === 'top',
|
|
39
|
-
'order-1': labelPosition === 'bottom'
|
|
74
|
+
'order-2': !segments && labelPosition === 'top',
|
|
75
|
+
'order-1': !segments && labelPosition === 'bottom',
|
|
76
|
+
'flex overflow-hidden': segments
|
|
40
77
|
})
|
|
41
78
|
);
|
|
42
79
|
|
|
43
80
|
const fillClass = $derived(
|
|
44
81
|
cn(
|
|
45
82
|
'h-full rounded-full transition-all',
|
|
46
|
-
|
|
47
|
-
'bg-primary-600': color === Color.PRIMARY,
|
|
48
|
-
'bg-secondary-600': color === Color.SECONDARY,
|
|
49
|
-
'bg-success-600': color === Color.SUCCESS,
|
|
50
|
-
'bg-danger-600': color === Color.DANGER,
|
|
51
|
-
'bg-warning-600': color === Color.WARNING,
|
|
52
|
-
'bg-info-600': color === Color.INFO,
|
|
53
|
-
'bg-gray-600': color === Color.DEFAULT
|
|
54
|
-
},
|
|
83
|
+
segments ? '' : getColorClass(color),
|
|
55
84
|
barClass
|
|
56
85
|
)
|
|
57
86
|
);
|
|
@@ -59,12 +88,11 @@
|
|
|
59
88
|
const labelTextClass = $derived(
|
|
60
89
|
cn(
|
|
61
90
|
'text-gray-500',
|
|
91
|
+
getSizeTextClass(size),
|
|
62
92
|
{
|
|
63
|
-
'
|
|
64
|
-
'
|
|
65
|
-
'
|
|
66
|
-
'order-1': labelPosition === 'top',
|
|
67
|
-
'order-2': labelPosition === 'bottom'
|
|
93
|
+
'order-1': !segments && labelPosition === 'top',
|
|
94
|
+
'order-2': !segments && labelPosition === 'bottom',
|
|
95
|
+
'mt-1': segments
|
|
68
96
|
},
|
|
69
97
|
labelClass
|
|
70
98
|
)
|
|
@@ -79,9 +107,39 @@
|
|
|
79
107
|
aria-valuemin="0"
|
|
80
108
|
aria-valuemax="100"
|
|
81
109
|
>
|
|
82
|
-
|
|
110
|
+
{#if segments}
|
|
111
|
+
{#each segmentPercentages as segment}
|
|
112
|
+
{#if segment.percentage > 0}
|
|
113
|
+
<div
|
|
114
|
+
class={cn(getColorClass(segment.color), barClass)}
|
|
115
|
+
style="width: {segment.percentage}%"
|
|
116
|
+
title={segment.label || `${segment.value} (${segment.percentage}%)`}
|
|
117
|
+
></div>
|
|
118
|
+
{/if}
|
|
119
|
+
{/each}
|
|
120
|
+
{:else}
|
|
121
|
+
<div class={fillClass} style="width: {percentage}%"></div>
|
|
122
|
+
{/if}
|
|
83
123
|
</div>
|
|
84
|
-
|
|
124
|
+
|
|
125
|
+
{#if segments && (showLabels || showValues)}
|
|
126
|
+
<div class="flex justify-between mt-1">
|
|
127
|
+
{#each segmentPercentages as segment}
|
|
128
|
+
{#if segment.percentage > 0}
|
|
129
|
+
<div class={labelTextClass}>
|
|
130
|
+
{#if showLabels && segment.label}
|
|
131
|
+
{segment.label}
|
|
132
|
+
{/if}
|
|
133
|
+
{#if showValues}
|
|
134
|
+
{#if showLabels && segment.label} ({/if}
|
|
135
|
+
{segment.percentage}%
|
|
136
|
+
{#if showLabels && segment.label}){/if}
|
|
137
|
+
{/if}
|
|
138
|
+
</div>
|
|
139
|
+
{/if}
|
|
140
|
+
{/each}
|
|
141
|
+
</div>
|
|
142
|
+
{:else if showLabel}
|
|
85
143
|
<span class={labelTextClass}>{percentage}%</span>
|
|
86
144
|
{/if}
|
|
87
145
|
</div>
|
package/dist/index.d.ts
CHANGED
|
@@ -700,34 +700,26 @@ export interface SliderProps {
|
|
|
700
700
|
notation?: NotationType;
|
|
701
701
|
};
|
|
702
702
|
}
|
|
703
|
-
export type ProgressProps = {
|
|
704
|
-
value: number;
|
|
705
|
-
max?: number;
|
|
706
|
-
size?: VariantSizes;
|
|
707
|
-
color?: VariantColors;
|
|
708
|
-
showLabel?: boolean;
|
|
709
|
-
labelPosition?: 'top' | 'bottom' | 'right';
|
|
710
|
-
class?: string;
|
|
711
|
-
labelClass?: string;
|
|
712
|
-
barClass?: string;
|
|
713
|
-
};
|
|
714
703
|
export type ProgressSegment = {
|
|
715
704
|
value: number;
|
|
716
705
|
color: VariantColors;
|
|
717
706
|
label?: string;
|
|
718
707
|
};
|
|
719
|
-
export type
|
|
720
|
-
|
|
708
|
+
export type ProgressProps = {
|
|
709
|
+
value: number;
|
|
721
710
|
max?: number;
|
|
722
711
|
size?: VariantSizes;
|
|
712
|
+
color?: VariantColors;
|
|
713
|
+
showLabel?: boolean;
|
|
714
|
+
labelPosition?: 'top' | 'bottom' | 'right';
|
|
715
|
+
segments?: ProgressSegment[];
|
|
723
716
|
showLabels?: boolean;
|
|
724
717
|
showValues?: boolean;
|
|
725
|
-
class?:
|
|
726
|
-
barClass?: string;
|
|
718
|
+
class?: ClassValue;
|
|
727
719
|
labelClass?: string;
|
|
720
|
+
barClass?: string;
|
|
728
721
|
};
|
|
729
722
|
export { default as Progress } from './elements/progress/Progress.svelte';
|
|
730
|
-
export { default as DividedProgress } from './elements/progress/DividedProgress.svelte';
|
|
731
723
|
export interface TimelineItem {
|
|
732
724
|
title: string;
|
|
733
725
|
time: Date | string;
|
package/dist/index.js
CHANGED
|
@@ -62,5 +62,4 @@ export { default as DateRange } from './forms/DateRange.svelte';
|
|
|
62
62
|
export { default as Tags } from './forms/Tags.svelte';
|
|
63
63
|
export { default as RadioPill } from './forms/RadioPill.svelte';
|
|
64
64
|
export { default as Progress } from './elements/progress/Progress.svelte';
|
|
65
|
-
export { default as DividedProgress } from './elements/progress/DividedProgress.svelte';
|
|
66
65
|
export { default as Timeline } from './elements/timeline/Timeline.svelte';
|
package/package.json
CHANGED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { cn } from '../../helper/cls.js';
|
|
3
|
-
import { Color, Size } from '../../variants.js';
|
|
4
|
-
import type { DividedProgressProps, ProgressSegment, VariantColors } from '../../index.js';
|
|
5
|
-
|
|
6
|
-
let {
|
|
7
|
-
segments,
|
|
8
|
-
max = 100,
|
|
9
|
-
size = Size.BASE,
|
|
10
|
-
showLabels = false,
|
|
11
|
-
showValues = true,
|
|
12
|
-
class: className = '',
|
|
13
|
-
barClass = '',
|
|
14
|
-
labelClass = ''
|
|
15
|
-
}: DividedProgressProps = $props();
|
|
16
|
-
|
|
17
|
-
// Calculate derived values
|
|
18
|
-
const totalValue = $derived(calculateTotalValue(segments));
|
|
19
|
-
const segmentPercentages = $derived(calculateSegmentPercentages(segments, max));
|
|
20
|
-
|
|
21
|
-
// Function composition - each function has a single responsibility
|
|
22
|
-
function calculateTotalValue(segments: ProgressSegment[]): number {
|
|
23
|
-
return segments.reduce((sum, segment) => sum + segment.value, 0);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function calculatePercentage(value: number, max: number): number {
|
|
27
|
-
return Math.min(Math.round((value / max) * 100), 100);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function calculateSegmentPercentages(segments: ProgressSegment[], max: number) {
|
|
31
|
-
return segments.map(segment => ({
|
|
32
|
-
...segment,
|
|
33
|
-
percentage: calculatePercentage(segment.value, max)
|
|
34
|
-
}));
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Class compositions
|
|
38
|
-
const containerClass = $derived(cn('relative w-full', className));
|
|
39
|
-
|
|
40
|
-
const progressClass = $derived(
|
|
41
|
-
cn('w-full rounded-full bg-gray-200 flex overflow-hidden', {
|
|
42
|
-
'h-1.5': size === Size.XS,
|
|
43
|
-
'h-2': size === Size.SM,
|
|
44
|
-
'h-2.5': size === Size.BASE,
|
|
45
|
-
'h-3': size === Size.LG,
|
|
46
|
-
'h-4': size === Size.XL
|
|
47
|
-
})
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
function getColorClass(color: VariantColors): string {
|
|
51
|
-
const colorMap = {
|
|
52
|
-
[Color.PRIMARY]: 'bg-primary-600',
|
|
53
|
-
[Color.SECONDARY]: 'bg-secondary-600',
|
|
54
|
-
[Color.SUCCESS]: 'bg-success-600',
|
|
55
|
-
[Color.DANGER]: 'bg-danger-600',
|
|
56
|
-
[Color.WARNING]: 'bg-warning-600',
|
|
57
|
-
[Color.INFO]: 'bg-info-600',
|
|
58
|
-
[Color.DEFAULT]: 'bg-gray-600'
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
return colorMap[color] || 'bg-primary-600';
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function getSizeTextClass(size: string): string {
|
|
65
|
-
if (size === Size.XS || size === Size.SM) return 'text-xs';
|
|
66
|
-
if (size === Size.BASE) return 'text-sm';
|
|
67
|
-
return 'text-base'; // For Size.LG, Size.XL, and any other sizes
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const labelTextClass = $derived(
|
|
71
|
-
cn('text-gray-500 mt-1', getSizeTextClass(size), labelClass)
|
|
72
|
-
);
|
|
73
|
-
</script>
|
|
74
|
-
|
|
75
|
-
<div class={containerClass}>
|
|
76
|
-
<div
|
|
77
|
-
class={progressClass}
|
|
78
|
-
role="progressbar"
|
|
79
|
-
aria-valuenow={totalValue}
|
|
80
|
-
aria-valuemin="0"
|
|
81
|
-
aria-valuemax={max}
|
|
82
|
-
>
|
|
83
|
-
{#each segmentPercentages as segment}
|
|
84
|
-
{#if segment.percentage > 0}
|
|
85
|
-
<div
|
|
86
|
-
class={cn(getColorClass(segment.color), barClass)}
|
|
87
|
-
style="width: {segment.percentage}%"
|
|
88
|
-
title={segment.label || `${segment.value} (${segment.percentage}%)`}
|
|
89
|
-
></div>
|
|
90
|
-
{/if}
|
|
91
|
-
{/each}
|
|
92
|
-
</div>
|
|
93
|
-
|
|
94
|
-
{#if showLabels || showValues}
|
|
95
|
-
<div class="flex justify-between mt-1">
|
|
96
|
-
{#each segmentPercentages as segment}
|
|
97
|
-
{#if segment.percentage > 0}
|
|
98
|
-
<div class={labelTextClass}>
|
|
99
|
-
{#if showLabels && segment.label}
|
|
100
|
-
{segment.label}
|
|
101
|
-
{/if}
|
|
102
|
-
{#if showValues}
|
|
103
|
-
{#if showLabels && segment.label} ({/if}
|
|
104
|
-
{segment.percentage}%
|
|
105
|
-
{#if showLabels && segment.label}){/if}
|
|
106
|
-
{/if}
|
|
107
|
-
</div>
|
|
108
|
-
{/if}
|
|
109
|
-
{/each}
|
|
110
|
-
</div>
|
|
111
|
-
{/if}
|
|
112
|
-
</div>
|