@energysage/es-ds-components 3.1.6 → 3.2.0
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/components/es-file-input.vue +24 -2
- package/components/es-progress.vue +98 -22
- package/package.json +2 -2
- package/utils/omit.ts +4 -0
|
@@ -48,6 +48,15 @@ const props = defineProps({
|
|
|
48
48
|
default: false,
|
|
49
49
|
required: false,
|
|
50
50
|
},
|
|
51
|
+
/**
|
|
52
|
+
* When true, allows multiple file selection. When false, restricts to single file selection.
|
|
53
|
+
* Defaults to true to maintain backward compatibility.
|
|
54
|
+
*/
|
|
55
|
+
multiple: {
|
|
56
|
+
type: Boolean,
|
|
57
|
+
default: true,
|
|
58
|
+
required: false,
|
|
59
|
+
},
|
|
51
60
|
});
|
|
52
61
|
|
|
53
62
|
let currentFiles: Array<File> = [];
|
|
@@ -204,6 +213,13 @@ async function verifyFiles(files: Array<File>) {
|
|
|
204
213
|
// @ts-expect-error basically we're filtering out the non-Files here
|
|
205
214
|
newValidFiles = newValidFiles.filter((file) => file && file.status === 'fulfilled').map((file) => file.value);
|
|
206
215
|
|
|
216
|
+
// If multiple is false, only keep the first file
|
|
217
|
+
if (!props.multiple && newValidFiles.length > 0) {
|
|
218
|
+
newValidFiles = [newValidFiles[0]];
|
|
219
|
+
// Clear existing files when single mode is enabled
|
|
220
|
+
currentFiles = [];
|
|
221
|
+
}
|
|
222
|
+
|
|
207
223
|
// If the new file with name already exists in the current files
|
|
208
224
|
// Don't upload the new file and display an error
|
|
209
225
|
const duplicateFiles = newValidFiles.filter(({ name }) => currentFiles.some((file) => file.name === name));
|
|
@@ -211,7 +227,13 @@ async function verifyFiles(files: Array<File>) {
|
|
|
211
227
|
|
|
212
228
|
// For new files with unused names, add them to files
|
|
213
229
|
newValidFiles = newValidFiles.filter(({ name }) => !currentFiles.some((file) => file.name === name));
|
|
214
|
-
|
|
230
|
+
|
|
231
|
+
// In single file mode, replace existing files instead of adding to them
|
|
232
|
+
if (!props.multiple && newValidFiles.length > 0) {
|
|
233
|
+
currentFiles = newValidFiles;
|
|
234
|
+
} else {
|
|
235
|
+
currentFiles = [...currentFiles, ...newValidFiles];
|
|
236
|
+
}
|
|
215
237
|
|
|
216
238
|
if (newValidFiles.length > 0) {
|
|
217
239
|
emit('readyToUpload', newValidFiles);
|
|
@@ -328,7 +350,7 @@ const openFilePicker = () => {
|
|
|
328
350
|
type="file"
|
|
329
351
|
:accept="fileTypes.join(', ')"
|
|
330
352
|
style="display: none"
|
|
331
|
-
multiple
|
|
353
|
+
:multiple="multiple"
|
|
332
354
|
@change="onFileChanged($event)" />
|
|
333
355
|
</div>
|
|
334
356
|
</template>
|
|
@@ -1,36 +1,112 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import ProgressBar from 'primevue/progressbar';
|
|
3
3
|
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
4
|
+
const BASE_FONT_SIZE = 16;
|
|
5
|
+
const DEFAULT_BAR_HEIGHT = 2;
|
|
6
|
+
const DEFAULT_BORDER_WIDTH = 0.5;
|
|
7
|
+
const DEFAULT_CIRCLE_GLOW_SIZE = 4;
|
|
8
|
+
const DEFAULT_INSET_SHADOW_SIZE = 0.5;
|
|
9
|
+
const DIFF_CIRCLE_SIZE_FROM_BAR_HEIGHT_IN_PX = 4;
|
|
10
|
+
const DEFAULT_CIRCLE_DIMENSION = DEFAULT_BAR_HEIGHT + DIFF_CIRCLE_SIZE_FROM_BAR_HEIGHT_IN_PX;
|
|
11
|
+
|
|
12
|
+
interface Props {
|
|
13
|
+
formatter?: Function;
|
|
14
|
+
height?: string;
|
|
15
|
+
showCircle?: boolean;
|
|
16
|
+
showValue?: boolean;
|
|
17
|
+
value: number;
|
|
18
|
+
valueClass?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
22
|
+
formatter: (val: number) => `${val}%`,
|
|
23
|
+
height: '0.125rem',
|
|
24
|
+
showCircle: true,
|
|
25
|
+
showValue: false,
|
|
26
|
+
valueClass: '',
|
|
17
27
|
});
|
|
28
|
+
|
|
18
29
|
const progressBarPt = {
|
|
19
30
|
value: {
|
|
20
|
-
class:
|
|
31
|
+
class: [
|
|
32
|
+
'EsProgressValue progress-bar overflow-visible position-relative rounded-sm',
|
|
33
|
+
{
|
|
34
|
+
'progress-bar--with-circle': props.showCircle,
|
|
35
|
+
},
|
|
36
|
+
],
|
|
21
37
|
style: {
|
|
22
38
|
height: props.height,
|
|
23
|
-
borderRadius: props.value === 100 ? '0' : '0 0.125rem 0.125rem 0',
|
|
24
39
|
},
|
|
25
40
|
},
|
|
26
41
|
};
|
|
42
|
+
|
|
43
|
+
const barHeight = computed(() => {
|
|
44
|
+
let barHeight = DEFAULT_BAR_HEIGHT;
|
|
45
|
+
|
|
46
|
+
if (props.height.indexOf('rem') === props.height.length - 3) {
|
|
47
|
+
barHeight = parseFloat(props.height.replace('rem', '')) * BASE_FONT_SIZE;
|
|
48
|
+
} else if (props.height.indexOf('px') === props.height.length - 2) {
|
|
49
|
+
barHeight = parseInt(props.height.replace('px', ''), 10);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return barHeight;
|
|
53
|
+
});
|
|
54
|
+
const circleDimension = computed(
|
|
55
|
+
() => barHeight.value + (DIFF_CIRCLE_SIZE_FROM_BAR_HEIGHT_IN_PX * barHeight.value) / DEFAULT_BAR_HEIGHT,
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const circleDimensionPx = computed(() => `${circleDimension.value}px`);
|
|
59
|
+
const circleRightPx = computed(() => `${circleDimension.value * -0.5}px`);
|
|
60
|
+
const circleBorderWidthPx = computed(
|
|
61
|
+
() => `${(DEFAULT_BORDER_WIDTH * circleDimension.value) / DEFAULT_CIRCLE_DIMENSION}px`,
|
|
62
|
+
);
|
|
63
|
+
const circleGlowSizePx = computed(
|
|
64
|
+
() => `${(DEFAULT_CIRCLE_GLOW_SIZE * circleDimension.value) / DEFAULT_CIRCLE_DIMENSION}px`,
|
|
65
|
+
);
|
|
66
|
+
const circleInsetShadowSizePx = computed(
|
|
67
|
+
() => `${(DEFAULT_INSET_SHADOW_SIZE * circleDimension.value) / DEFAULT_CIRCLE_DIMENSION}px`,
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const verticalContainerPaddingPx = computed(() =>
|
|
71
|
+
props.showCircle ? `${(circleDimension.value - barHeight.value) / 2}px` : '0',
|
|
72
|
+
);
|
|
27
73
|
</script>
|
|
74
|
+
|
|
28
75
|
<template>
|
|
29
|
-
<
|
|
30
|
-
class="
|
|
31
|
-
:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
76
|
+
<div
|
|
77
|
+
class="es-progress"
|
|
78
|
+
:class="$attrs.class">
|
|
79
|
+
<progress-bar
|
|
80
|
+
class="bg-gray-200 rounded-sm"
|
|
81
|
+
:pt="progressBarPt"
|
|
82
|
+
:show-value="false"
|
|
83
|
+
:value="value"
|
|
84
|
+
v-bind="omit('class', $attrs)">
|
|
85
|
+
</progress-bar>
|
|
86
|
+
<div
|
|
87
|
+
v-if="showValue"
|
|
88
|
+
class="font-size-75 mt-25 text-right"
|
|
89
|
+
:class="valueClass">
|
|
90
|
+
{{ formatter(value) }}
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
36
93
|
</template>
|
|
94
|
+
|
|
95
|
+
<style lang="scss" scoped>
|
|
96
|
+
@use '@energysage/es-ds-styles/scss/variables' as variables;
|
|
97
|
+
|
|
98
|
+
.es-progress {
|
|
99
|
+
padding-bottom: v-bind(verticalContainerPaddingPx);
|
|
100
|
+
padding-top: v-bind(verticalContainerPaddingPx);
|
|
101
|
+
|
|
102
|
+
:deep(.progress-bar--with-circle::after) {
|
|
103
|
+
border: v-bind(circleBorderWidthPx) solid variables.$warm-orange;
|
|
104
|
+
box-shadow:
|
|
105
|
+
0 0 v-bind(circleInsetShadowSizePx) v-bind(circleInsetShadowSizePx) variables.$warm-orange inset,
|
|
106
|
+
0 0 v-bind(circleGlowSizePx) 0 variables.$warm-orange;
|
|
107
|
+
height: v-bind(circleDimensionPx);
|
|
108
|
+
right: v-bind(circleRightPx);
|
|
109
|
+
width: v-bind(circleDimensionPx);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
</style>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@energysage/es-ds-components",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "An EnergySage Vue component library",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"author": "EnergySage",
|
|
18
18
|
"license": "MIT",
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@energysage/es-ds-styles": "^3.
|
|
20
|
+
"@energysage/es-ds-styles": "^3.2.0",
|
|
21
21
|
"@nuxt/eslint": "^1.0.1",
|
|
22
22
|
"@nuxtjs/google-fonts": "^3.2.0",
|
|
23
23
|
"@vuelidate/core": "^2.0.3",
|
package/utils/omit.ts
ADDED