@eturnity/eturnity_reusable_components 8.16.9-EPDM-11600.9 → 8.16.9-EPDM-14690.5
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/package.json +1 -1
- package/src/TestChart.vue +229 -0
- package/src/assets/svgIcons/erase.svg +3 -2
- package/src/assets/theme.js +1 -1
- package/src/components/barchart/BottomFields.vue +125 -37
- package/src/components/barchart/composables/useAxisCalculations.js +1 -1
- package/src/components/barchart/composables/useChartData.js +1 -1
- package/src/components/barchart/composables/useTooltip.js +28 -3
- package/src/components/barchart/index.vue +54 -16
- package/src/components/barchart/styles/bottomFields.js +18 -4
- package/src/components/barchart/styles/chart.js +15 -12
- package/src/components/errorMessage/index.vue +1 -1
- package/src/components/infoCard/index.vue +18 -10
- package/src/components/infoCard/infoCard.spec.js +3 -3
- package/src/components/infoText/index.vue +36 -31
- package/src/components/inputs/inputNumber/InputNumber.stories.js +5 -5
- package/src/components/inputs/inputNumber/index.vue +73 -49
- package/src/components/pageSubtitle/index.vue +1 -7
- package/src/components/pageTitle/index.vue +3 -4
package/package.json
CHANGED
@@ -0,0 +1,229 @@
|
|
1
|
+
<template>
|
2
|
+
<div
|
3
|
+
style="
|
4
|
+
margin-top: 100px;
|
5
|
+
margin-left: 80px;
|
6
|
+
padding-bottom: 100px;
|
7
|
+
display: flex;
|
8
|
+
flex-direction: column;
|
9
|
+
"
|
10
|
+
>
|
11
|
+
<!-- Simple bar chart -->
|
12
|
+
<BarChart
|
13
|
+
:bar-width="60"
|
14
|
+
chart-controls-position="bottom"
|
15
|
+
:data="monthlyData"
|
16
|
+
height="400px"
|
17
|
+
:is-bottom-fields-shown="true"
|
18
|
+
:is-scrollable="false"
|
19
|
+
:is-selection-enabled="true"
|
20
|
+
:selection-size="3"
|
21
|
+
:value-formatter="valueFormatter"
|
22
|
+
width="700px"
|
23
|
+
@selection-change="handleSelectionChange"
|
24
|
+
/>
|
25
|
+
<br />
|
26
|
+
<br />
|
27
|
+
|
28
|
+
<!-- Stacked bar chart -->
|
29
|
+
<BarChart
|
30
|
+
:bar-width="60"
|
31
|
+
:data="monthLabels"
|
32
|
+
height="400px"
|
33
|
+
:is-bottom-fields-shown="true"
|
34
|
+
:is-legend-shown="true"
|
35
|
+
:legends-item-per-row="4"
|
36
|
+
:selected-split-button="selectedTimeFrame"
|
37
|
+
:series="tariffZones"
|
38
|
+
:show-percentage-on-tooltip="true"
|
39
|
+
:split-button-options="options"
|
40
|
+
:value-formatter="valueFormatter"
|
41
|
+
width="700px"
|
42
|
+
y-axis-title="Energy (kWh)"
|
43
|
+
@input-blur="handleInputBlur"
|
44
|
+
@select-split-button="handleSelectSplitButton"
|
45
|
+
/>
|
46
|
+
|
47
|
+
<!-- Stacked bar chart -->
|
48
|
+
<BarChart
|
49
|
+
:bar-width="60"
|
50
|
+
:data="monthLabels"
|
51
|
+
field-mode="percentage"
|
52
|
+
height="400px"
|
53
|
+
:is-bottom-fields-shown="true"
|
54
|
+
:is-legend-shown="false"
|
55
|
+
:legends-item-per-row="4"
|
56
|
+
:series="tariffZones"
|
57
|
+
:value-formatter="valueFormatter"
|
58
|
+
width="700px"
|
59
|
+
@input-blur="handleInputBlur"
|
60
|
+
@select-split-button="handleSelectSplitButton"
|
61
|
+
>
|
62
|
+
<!-- <template #tooltip="{ item, segment }">
|
63
|
+
<div style="display: flex; flex-direction: column">
|
64
|
+
{{ $c.log(item, segment) }}
|
65
|
+
<div>{{ item.label }}</div>
|
66
|
+
<div>{{ item.segments[0].value }} kWh</div>
|
67
|
+
</div>
|
68
|
+
</template> -->
|
69
|
+
</BarChart>
|
70
|
+
</div>
|
71
|
+
</template>
|
72
|
+
|
73
|
+
<script setup>
|
74
|
+
import { ref } from 'vue'
|
75
|
+
import BarChart from '@/components/barchart/index.vue'
|
76
|
+
|
77
|
+
const options = [
|
78
|
+
{ label: 'Day', value: 'day' },
|
79
|
+
{ label: 'Month', value: 'month' },
|
80
|
+
{ label: 'Year', value: 'year' },
|
81
|
+
]
|
82
|
+
|
83
|
+
const selectedTimeFrame = ref('day')
|
84
|
+
|
85
|
+
const handleSelectSplitButton = (value) => {
|
86
|
+
selectedTimeFrame.value = value
|
87
|
+
}
|
88
|
+
|
89
|
+
const monthlyData = [
|
90
|
+
{ label: 'Jan', value: 300 },
|
91
|
+
{ label: 'Feb', value: 600 },
|
92
|
+
{ label: 'Mar', value: 1000 },
|
93
|
+
{ label: 'Apr', value: 1200 },
|
94
|
+
{ label: 'May', value: 1400 },
|
95
|
+
{ label: 'Jun', value: 1810 },
|
96
|
+
{ label: 'Jul', value: 1400 },
|
97
|
+
{ label: 'Aug', value: 1200 },
|
98
|
+
{ label: 'Sep', value: 1000 },
|
99
|
+
// { label: 'Oct', value: 800 },
|
100
|
+
// { label: 'Nov', value: 600 },
|
101
|
+
// { label: 'Dec', value: 400 },
|
102
|
+
// { label: 'Jan', value: 300 },
|
103
|
+
// { label: 'Feb', value: 600 },
|
104
|
+
// { label: 'Mar', value: 1000 },
|
105
|
+
// { label: 'Apr', value: 1200 },
|
106
|
+
// { label: 'May', value: 1400 },
|
107
|
+
// { label: 'Jun', value: 1810 },
|
108
|
+
// { label: 'Jul', value: 1400 },
|
109
|
+
// { label: 'Aug', value: 1200 },
|
110
|
+
// { label: 'Sep', value: 1000 },
|
111
|
+
// { label: 'Oct', value: 800 },
|
112
|
+
// { label: 'Nov', value: 600 },
|
113
|
+
// { label: 'Dec', value: 400 },
|
114
|
+
|
115
|
+
// ... more months
|
116
|
+
]
|
117
|
+
|
118
|
+
const monthLabels = [
|
119
|
+
{ label: 'Jan' },
|
120
|
+
{ label: 'Feb' },
|
121
|
+
{ label: 'Mar' },
|
122
|
+
{ label: 'Apr' },
|
123
|
+
{ label: 'May' },
|
124
|
+
{ label: 'Jun' },
|
125
|
+
// ... more months
|
126
|
+
]
|
127
|
+
|
128
|
+
const tariffZones = ref([
|
129
|
+
{
|
130
|
+
name: 'Tariff Zone 1',
|
131
|
+
data: [
|
132
|
+
{ label: 'Jan', value: 200 },
|
133
|
+
{ label: 'Feb', value: 130 },
|
134
|
+
{ label: 'Mar', value: 220 },
|
135
|
+
{ label: 'Apr', value: 230 },
|
136
|
+
{ label: 'May', value: 200 },
|
137
|
+
{ label: 'Jun', value: 210 },
|
138
|
+
// ... more months
|
139
|
+
],
|
140
|
+
},
|
141
|
+
{
|
142
|
+
name: 'Tariff Zone 2',
|
143
|
+
data: [
|
144
|
+
{ label: 'Jan', value: 200 },
|
145
|
+
{ label: 'Feb', value: 100 },
|
146
|
+
{ label: 'Mar', value: 270 },
|
147
|
+
{ label: 'Apr', value: 180 },
|
148
|
+
{ label: 'May', value: 300 },
|
149
|
+
{ label: 'Jun', value: 250 },
|
150
|
+
// ... more months
|
151
|
+
],
|
152
|
+
},
|
153
|
+
{
|
154
|
+
name: 'Tariff Zone 3',
|
155
|
+
data: [
|
156
|
+
{ label: 'Jan', value: 200 },
|
157
|
+
{ label: 'Feb', value: 100 },
|
158
|
+
{ label: 'Mar', value: 210 },
|
159
|
+
{ label: 'Apr', value: 220 },
|
160
|
+
{ label: 'May', value: 300 },
|
161
|
+
{ label: 'Jun', value: 190 },
|
162
|
+
// ... more months
|
163
|
+
],
|
164
|
+
},
|
165
|
+
{
|
166
|
+
name: 'Tariff Zone 4',
|
167
|
+
data: [
|
168
|
+
{ label: 'Jan', value: 200 },
|
169
|
+
{ label: 'Feb', value: 100 },
|
170
|
+
{ label: 'Mar', value: 210 },
|
171
|
+
{ label: 'Apr', value: 220 },
|
172
|
+
{ label: 'May', value: 300 },
|
173
|
+
{ label: 'Jun', value: 190 },
|
174
|
+
// ... more months
|
175
|
+
],
|
176
|
+
},
|
177
|
+
{
|
178
|
+
name: 'Tariff Zone 5',
|
179
|
+
data: [
|
180
|
+
{ label: 'Jan', value: 200 },
|
181
|
+
{ label: 'Feb', value: 100 },
|
182
|
+
{ label: 'Mar', value: 210 },
|
183
|
+
{ label: 'Apr', value: 220 },
|
184
|
+
{ label: 'May', value: 300 },
|
185
|
+
{ label: 'Jun', value: 190 },
|
186
|
+
// ... more months
|
187
|
+
],
|
188
|
+
},
|
189
|
+
{
|
190
|
+
name: 'Tariff Zone 6',
|
191
|
+
data: [
|
192
|
+
{ label: 'Jan', value: 200 },
|
193
|
+
{ label: 'Feb', value: 100 },
|
194
|
+
{ label: 'Mar', value: 210 },
|
195
|
+
{ label: 'Apr', value: 220 },
|
196
|
+
{ label: 'May', value: 300 },
|
197
|
+
{ label: 'Jun', value: 190 },
|
198
|
+
// ... more months
|
199
|
+
],
|
200
|
+
},
|
201
|
+
// ... more tariff zones
|
202
|
+
])
|
203
|
+
|
204
|
+
const valueFormatter = (value) => {
|
205
|
+
return `${value} kWh`
|
206
|
+
}
|
207
|
+
|
208
|
+
const handleSelectionChange = (selectedBars) => {
|
209
|
+
console.log('selectedBars', selectedBars)
|
210
|
+
}
|
211
|
+
|
212
|
+
const handleInputBlur = (payload) => {
|
213
|
+
const newVal = [...tariffZones.value].map((zone) => {
|
214
|
+
if (zone.name === payload.seriesName) {
|
215
|
+
zone.data = zone.data.map((item) => {
|
216
|
+
if (item.label === payload.label) {
|
217
|
+
item.value = payload.value
|
218
|
+
}
|
219
|
+
return item
|
220
|
+
})
|
221
|
+
}
|
222
|
+
return zone
|
223
|
+
})
|
224
|
+
|
225
|
+
tariffZones.value = newVal
|
226
|
+
}
|
227
|
+
</script>
|
228
|
+
|
229
|
+
<style lang="scss" scoped></style>
|
@@ -1,3 +1,4 @@
|
|
1
|
-
<svg
|
2
|
-
|
1
|
+
<svg fill="none" height="16" viewbox="12 12 16 16" width="16" xmlns="http://www.w3.org/2000/svg">
|
2
|
+
<circle cx="20" cy="20" r="7"></circle>
|
3
|
+
<path d="M24.9592 15.0408C22.2382 12.3197 17.7618 12.3197 15.0408 15.0408C12.3197 17.7618 12.3197 22.2382 15.0408 24.9592C17.7618 27.6803 22.2382 27.6803 24.9592 24.9592C27.6803 22.2382 27.6803 17.8495 24.9592 15.0408ZM23.6426 22.5016L22.4138 23.7304L19.9561 21.2727L17.4984 23.7304L16.2696 22.5016L18.7273 20.0439L16.2696 17.5862L17.4984 16.3574L19.9561 18.815L22.4138 16.3574L23.6426 17.5862L21.185 20.0439L23.6426 22.5016Z" fill="#FF5656"></path>
|
3
4
|
</svg>
|
package/src/assets/theme.js
CHANGED
@@ -333,7 +333,7 @@ const theme = (() => {
|
|
333
333
|
borderColor: semanticColors.grey[300],
|
334
334
|
},
|
335
335
|
active: {
|
336
|
-
backgroundColor: semanticColors.
|
336
|
+
backgroundColor: semanticColors.blue[100],
|
337
337
|
textColor: semanticColors.purple[600],
|
338
338
|
borderColor: semanticColors.grey[600],
|
339
339
|
},
|
@@ -1,14 +1,14 @@
|
|
1
1
|
<template>
|
2
2
|
<Container :is-chart-controls-shown-in-bottom="isChartControlsShownInBottom">
|
3
3
|
<LabelsColumn :width="yAxisWidth">
|
4
|
-
<LabelRow v-for="series in
|
4
|
+
<LabelRow v-for="series in seriesData" :key="series.name">
|
5
5
|
{{ series.name }}
|
6
6
|
</LabelRow>
|
7
|
-
<TotalRow v-if="
|
8
|
-
{{ $gettext ? $gettext('Total (%)
|
7
|
+
<TotalRow v-if="seriesData.length && fieldMode === 'percentage'">
|
8
|
+
{{ $gettext ? `${$gettext('Total')} (%)` : 'Total (%)' }}
|
9
9
|
</TotalRow>
|
10
|
-
<TotalRow v-if="
|
11
|
-
{{ $gettext ? $gettext('Total (kWh)
|
10
|
+
<TotalRow v-if="seriesData.length">
|
11
|
+
{{ $gettext ? `${$gettext('Total')} (kWh)` : 'Total (kWh)' }}
|
12
12
|
</TotalRow>
|
13
13
|
</LabelsColumn>
|
14
14
|
|
@@ -18,27 +18,35 @@
|
|
18
18
|
>
|
19
19
|
<FieldsWrapper>
|
20
20
|
<!-- For stacked bar chart -->
|
21
|
-
<template v-if="
|
21
|
+
<template v-if="seriesData.length">
|
22
22
|
<InputRow
|
23
|
-
v-for="series in
|
23
|
+
v-for="series in seriesData"
|
24
24
|
:key="series.name"
|
25
25
|
:data-series-name="series.name"
|
26
26
|
>
|
27
27
|
<InputGroup
|
28
28
|
v-for="(item, index) in props.data"
|
29
|
+
:key="index"
|
29
30
|
:bar-width="barWidth"
|
30
31
|
:is-scrollable="isScrollable"
|
31
|
-
:key="index"
|
32
32
|
>
|
33
33
|
<InputNumber
|
34
34
|
:allow-negative="false"
|
35
|
+
:disabled="isInputsDisabled"
|
35
36
|
input-height="36px"
|
36
|
-
:
|
37
|
+
:is-info-border="
|
38
|
+
fieldMode === 'percentage'
|
39
|
+
? calculatePercentageTotal(item.label) !== 100
|
40
|
+
: false
|
41
|
+
"
|
37
42
|
:min-decimals="0"
|
43
|
+
:number-precision="fieldMode === 'percentage' ? 2 : 0"
|
38
44
|
text-align="center"
|
39
45
|
:unit-name="fieldMode === 'percentage' ? '%' : ''"
|
40
46
|
:value="getDisplayValue(series.data, item.label)"
|
41
|
-
@input-blur="
|
47
|
+
@input-blur="
|
48
|
+
handleInputBlur($event, series.name, item.label, series.data)
|
49
|
+
"
|
42
50
|
@input-focus="handleInputFocus(series.name, item.label)"
|
43
51
|
/>
|
44
52
|
</InputGroup>
|
@@ -47,16 +55,17 @@
|
|
47
55
|
<TotalInputRow v-if="fieldMode === 'percentage'">
|
48
56
|
<InputGroup
|
49
57
|
v-for="(item, index) in props.data"
|
58
|
+
:key="index"
|
50
59
|
:bar-width="barWidth"
|
51
60
|
:is-scrollable="isScrollable"
|
52
|
-
:key="index"
|
53
61
|
>
|
54
62
|
<InputNumber
|
55
63
|
:allow-negative="false"
|
64
|
+
:disabled="isInputsDisabled"
|
56
65
|
input-height="36px"
|
57
66
|
:is-read-only="true"
|
58
|
-
:number-precision="0"
|
59
67
|
:min-decimals="0"
|
68
|
+
:number-precision="fieldMode === 'percentage' ? 2 : 0"
|
60
69
|
text-align="center"
|
61
70
|
:unit-name="fieldMode === 'percentage' ? '%' : ''"
|
62
71
|
:value="calculatePercentageTotal(item.label)"
|
@@ -67,17 +76,23 @@
|
|
67
76
|
<TotalInputRow>
|
68
77
|
<InputGroup
|
69
78
|
v-for="(item, index) in props.data"
|
79
|
+
:key="index"
|
70
80
|
:bar-width="barWidth"
|
71
81
|
:is-scrollable="isScrollable"
|
72
|
-
:key="index"
|
73
82
|
>
|
74
83
|
<InputNumber
|
75
84
|
input-height="36px"
|
85
|
+
:is-border-error-only="true"
|
86
|
+
:is-info-border="
|
87
|
+
fieldMode === 'percentage'
|
88
|
+
? calculatePercentageTotal(item.label) !== 100
|
89
|
+
: false
|
90
|
+
"
|
76
91
|
:is-read-only="true"
|
77
|
-
:number-precision="2"
|
78
92
|
:min-decimals="0"
|
93
|
+
:number-precision="0"
|
79
94
|
text-align="center"
|
80
|
-
:value="
|
95
|
+
:value="calculateTotalValue(item.label)"
|
81
96
|
/>
|
82
97
|
</InputGroup>
|
83
98
|
</TotalInputRow>
|
@@ -88,17 +103,19 @@
|
|
88
103
|
<InputRow>
|
89
104
|
<InputGroup
|
90
105
|
v-for="(item, index) in props.data"
|
106
|
+
:key="index"
|
91
107
|
:bar-width="barWidth"
|
92
108
|
:is-scrollable="isScrollable"
|
93
|
-
:key="index"
|
94
109
|
>
|
95
110
|
<InputNumber
|
111
|
+
:allow-negative="false"
|
112
|
+
:disabled="isInputsDisabled"
|
96
113
|
input-height="36px"
|
97
114
|
:min-decimals="0"
|
98
|
-
:number-precision="
|
115
|
+
:number-precision="0"
|
99
116
|
text-align="center"
|
100
117
|
:value="item.value"
|
101
|
-
@input-blur="handleInputBlur($event, null, item.label)"
|
118
|
+
@input-blur="handleInputBlur($event, null, item.label, null)"
|
102
119
|
@input-focus="handleInputFocus(null, item.label)"
|
103
120
|
/>
|
104
121
|
</InputGroup>
|
@@ -107,11 +124,22 @@
|
|
107
124
|
</FieldsWrapper>
|
108
125
|
</FieldsContainer>
|
109
126
|
</Container>
|
127
|
+
<InfoCardContainer
|
128
|
+
v-if="hasAnySegmentNotTotatTo100Percent && fieldMode === 'percentage'"
|
129
|
+
:yAxisWidth="yAxisWidth"
|
130
|
+
>
|
131
|
+
<InfoCard align-items="center" type="info">
|
132
|
+
<InfoCardBody>
|
133
|
+
{{ $gettext('load_profile_not_add_up_to_100') }}
|
134
|
+
</InfoCardBody>
|
135
|
+
</InfoCard>
|
136
|
+
</InfoCardContainer>
|
110
137
|
</template>
|
111
138
|
|
112
139
|
<script setup>
|
113
|
-
import { ref } from 'vue'
|
140
|
+
import { ref, computed, watchEffect } from 'vue'
|
114
141
|
import InputNumber from '../inputs/inputNumber'
|
142
|
+
import InfoCard from '../infoCard'
|
115
143
|
|
116
144
|
import {
|
117
145
|
Container,
|
@@ -123,6 +151,8 @@
|
|
123
151
|
InputRow,
|
124
152
|
TotalInputRow,
|
125
153
|
InputGroup,
|
154
|
+
InfoCardContainer,
|
155
|
+
InfoCardBody,
|
126
156
|
} from './styles/bottomFields'
|
127
157
|
|
128
158
|
const props = defineProps({
|
@@ -159,6 +189,47 @@
|
|
159
189
|
default: 'absolute',
|
160
190
|
validator: (value) => ['absolute', 'percentage'].includes(value),
|
161
191
|
},
|
192
|
+
isInputsDisabled: {
|
193
|
+
type: Boolean,
|
194
|
+
default: false,
|
195
|
+
},
|
196
|
+
})
|
197
|
+
|
198
|
+
const seriesData = ref([])
|
199
|
+
|
200
|
+
watchEffect(() => {
|
201
|
+
let isNewSetOfSeries = false
|
202
|
+
const seriesDataCopy = [...seriesData.value]
|
203
|
+
if (
|
204
|
+
!seriesDataCopy.length ||
|
205
|
+
!props.series.length ||
|
206
|
+
seriesDataCopy.length !== props.series.length ||
|
207
|
+
!seriesDataCopy.some((item) => {
|
208
|
+
return props.series.map((s) => s.name).includes(item.name)
|
209
|
+
})
|
210
|
+
) {
|
211
|
+
isNewSetOfSeries = true
|
212
|
+
}
|
213
|
+
const currentSeriesData = !isNewSetOfSeries ? seriesDataCopy : []
|
214
|
+
const newSeriesData = []
|
215
|
+
|
216
|
+
props.series.forEach((item, itemIndex) => {
|
217
|
+
const data = item.data.map((d, dIndex) => ({
|
218
|
+
label: d.label,
|
219
|
+
value: d.value,
|
220
|
+
percentage: d.percentage,
|
221
|
+
originalValue: currentSeriesData.length
|
222
|
+
? currentSeriesData[itemIndex].data[dIndex].originalValue
|
223
|
+
: d.value,
|
224
|
+
}))
|
225
|
+
|
226
|
+
newSeriesData.push({
|
227
|
+
name: item.name,
|
228
|
+
data,
|
229
|
+
})
|
230
|
+
})
|
231
|
+
|
232
|
+
seriesData.value = [...newSeriesData]
|
162
233
|
})
|
163
234
|
|
164
235
|
const emit = defineEmits([
|
@@ -175,11 +246,13 @@
|
|
175
246
|
emit('input-focus', { seriesName, label })
|
176
247
|
}
|
177
248
|
|
178
|
-
const
|
179
|
-
|
249
|
+
const calculateTotalValue = (label) => {
|
250
|
+
const total = seriesData.value.reduce((sum, series) => {
|
180
251
|
const value = series.data.find((d) => d.label === label)?.value || 0
|
181
252
|
return sum + value
|
182
253
|
}, 0)
|
254
|
+
|
255
|
+
return Math.round(total)
|
183
256
|
}
|
184
257
|
|
185
258
|
const syncScroll = (scrollLeft) => {
|
@@ -190,34 +263,43 @@
|
|
190
263
|
container.scrollLeft = scrollLeft
|
191
264
|
}
|
192
265
|
}
|
193
|
-
|
266
|
+
|
267
|
+
const calculateTotalOriginalValue = (label) => {
|
268
|
+
return seriesData.value.reduce((sum, series) => {
|
269
|
+
const value =
|
270
|
+
series.data.find((d) => d.label === label)?.originalValue || 0
|
271
|
+
return sum + value
|
272
|
+
}, 0)
|
273
|
+
}
|
274
|
+
|
275
|
+
const getDisplayValue = (data, label, shouldRound = true) => {
|
194
276
|
if (props.fieldMode === 'absolute') {
|
195
|
-
return
|
277
|
+
return data.find((d) => d.label === label)?.value
|
196
278
|
}
|
197
279
|
|
198
|
-
|
199
|
-
const total = calculateTotal(label)
|
200
|
-
return total ? Number(((value / total) * 100).toFixed(0)) : 0
|
280
|
+
return data.find((d) => d.label === label)?.percentage
|
201
281
|
}
|
202
282
|
|
203
283
|
const calculatePercentageTotal = (label) => {
|
204
|
-
|
205
|
-
const
|
206
|
-
|
207
|
-
const percentage = total ? Number(((value / total) * 100).toFixed(0)) : 0
|
284
|
+
const percentageTotal = seriesData.value.reduce((sum, series) => {
|
285
|
+
const percentage =
|
286
|
+
series.data.find((d) => d.label === label)?.percentage || 0
|
208
287
|
return sum + percentage
|
209
288
|
}, 0)
|
289
|
+
|
290
|
+
return Math.round(percentageTotal)
|
210
291
|
}
|
211
292
|
|
212
|
-
const handleInputBlur = (_value, seriesName, label) => {
|
293
|
+
const handleInputBlur = (_value, seriesName, label, currentSeriesData) => {
|
213
294
|
let value = Number(_value)
|
214
295
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
296
|
+
const payload = seriesName
|
297
|
+
? {
|
298
|
+
seriesName,
|
299
|
+
label,
|
300
|
+
value,
|
301
|
+
}
|
302
|
+
: { label, value }
|
221
303
|
emit('input-blur', payload)
|
222
304
|
focusedInput.value = null
|
223
305
|
|
@@ -243,6 +325,12 @@
|
|
243
325
|
}
|
244
326
|
}
|
245
327
|
|
328
|
+
const hasAnySegmentNotTotatTo100Percent = computed(() => {
|
329
|
+
return props.data.some((d) => {
|
330
|
+
return calculatePercentageTotal(d.label) !== 100
|
331
|
+
})
|
332
|
+
})
|
333
|
+
|
246
334
|
const handleFieldsScroll = (event) => {
|
247
335
|
emit('sync-scroll', event.target.scrollLeft)
|
248
336
|
}
|
@@ -84,7 +84,7 @@ export function useAxisCalculations(props, maxValue) {
|
|
84
84
|
})
|
85
85
|
|
86
86
|
const yAxisWidth = computed(() => {
|
87
|
-
return !!props.yAxisTitle || props.isBottomFieldsShown ? '
|
87
|
+
return !!props.yAxisTitle || props.isBottomFieldsShown ? '80px' : '60px'
|
88
88
|
})
|
89
89
|
|
90
90
|
const isChartControlsShown = (position) => {
|
@@ -66,7 +66,7 @@ export function useChartData(props, paddedMaxValue) {
|
|
66
66
|
let accumulated = 0
|
67
67
|
return {
|
68
68
|
label: item.label,
|
69
|
-
segments: [...props.series].
|
69
|
+
segments: [...props.series].map((series, index) => {
|
70
70
|
const value =
|
71
71
|
series.data.find((d) => d.label === item.label)?.value || 0
|
72
72
|
accumulated += value
|
@@ -16,7 +16,21 @@ export function useTooltip(chartId, normalizedData) {
|
|
16
16
|
if (!showTooltipContent.value) {
|
17
17
|
showTooltipContent.value = true
|
18
18
|
}
|
19
|
-
if (isObjectEqual(item, tooltipData.value))
|
19
|
+
if (isObjectEqual(item, tooltipData.value)) {
|
20
|
+
return
|
21
|
+
}
|
22
|
+
|
23
|
+
const totalValue = item.segments.reduce((acc, segment) => {
|
24
|
+
return acc + segment.value
|
25
|
+
}, 0)
|
26
|
+
|
27
|
+
const segments = item.segments.map((segment) => {
|
28
|
+
let valuePercentage = (segment.value / totalValue) * 100
|
29
|
+
segment.valuePercentage = Math.round(valuePercentage)
|
30
|
+
|
31
|
+
return segment
|
32
|
+
})
|
33
|
+
item.segments = segments
|
20
34
|
|
21
35
|
tooltipData.value = { ...item }
|
22
36
|
|
@@ -41,16 +55,27 @@ export function useTooltip(chartId, normalizedData) {
|
|
41
55
|
|
42
56
|
isInputFocused.value = true
|
43
57
|
const barData = normalizedData.value.find((item) => item.label === label)
|
44
|
-
|
45
58
|
if (!barData) return
|
59
|
+
|
60
|
+
const totalValue = barData.segments.reduce((acc, segment) => {
|
61
|
+
return acc + segment.value
|
62
|
+
}, 0)
|
63
|
+
const segments = barData.segments.map((segment) => {
|
64
|
+
let valuePercentage = (segment.value / totalValue) * 100
|
65
|
+
segment.valuePercentage = Math.round(valuePercentage)
|
66
|
+
|
67
|
+
return segment
|
68
|
+
})
|
69
|
+
barData.segments = segments
|
46
70
|
focusedBarData.value = barData
|
71
|
+
|
47
72
|
const barElement = document.querySelector(
|
48
73
|
`.barchart-${chartId} .bar-group:nth-child(${
|
49
74
|
normalizedData.value.indexOf(barData) + 1
|
50
75
|
})`
|
51
76
|
)
|
52
|
-
|
53
77
|
if (!barElement) return
|
78
|
+
|
54
79
|
// Get the last bar segment, samee as hover behavior
|
55
80
|
const targetElement = barElement.querySelector('.bar-segment:last-child')
|
56
81
|
const rect = targetElement.getBoundingClientRect()
|
@@ -17,8 +17,8 @@
|
|
17
17
|
/>
|
18
18
|
</ChartControlsWrapper>
|
19
19
|
<GraphSection :height="height" :width="width">
|
20
|
-
<YAxis :width="yAxisWidth">
|
21
|
-
<YAxisTitleWrapper v-if="yAxisTitle">
|
20
|
+
<YAxis :height="height" :width="yAxisWidth">
|
21
|
+
<YAxisTitleWrapper v-if="yAxisTitle" :height="yAxisHeight">
|
22
22
|
{{ yAxisTitle }}
|
23
23
|
</YAxisTitleWrapper>
|
24
24
|
<YAxisRow
|
@@ -30,15 +30,15 @@
|
|
30
30
|
)
|
31
31
|
"
|
32
32
|
>
|
33
|
-
<YAxisLabel>{{ label }}</YAxisLabel>
|
33
|
+
<YAxisLabel>{{ getYAxisLabel(label) }}</YAxisLabel>
|
34
34
|
<YAxisLine :y-axis-width="yAxisWidth" />
|
35
35
|
</YAxisRow>
|
36
36
|
</YAxis>
|
37
37
|
|
38
38
|
<ScrollContainer
|
39
39
|
:class="`chart-scroll-container-${chartId}`"
|
40
|
-
:is-scrollable="isScrollable"
|
41
40
|
:height="height"
|
41
|
+
:is-scrollable="isScrollable"
|
42
42
|
@scroll="handleChartScroll"
|
43
43
|
>
|
44
44
|
<ChartContent
|
@@ -64,19 +64,19 @@
|
|
64
64
|
<BarsContainer>
|
65
65
|
<BarGroup
|
66
66
|
v-for="(item, index) in normalizedData"
|
67
|
+
:key="index"
|
67
68
|
:bar-width="barWidth"
|
68
69
|
class="bar-group"
|
69
70
|
:is-scrollable="isScrollable"
|
70
|
-
:key="index"
|
71
71
|
>
|
72
72
|
<BarWrapper>
|
73
73
|
<BarSegment
|
74
74
|
v-for="(segment, segIndex) in item.segments"
|
75
|
+
:key="segIndex"
|
75
76
|
class="bar-segment"
|
76
77
|
:gradient-from="getSegmentGradient(index, segment).from"
|
77
78
|
:gradient-to="getSegmentGradient(index, segment).to"
|
78
79
|
:height="`${segment.percentage}%`"
|
79
|
-
:key="segIndex"
|
80
80
|
:z-index="item.segments.length - segIndex"
|
81
81
|
@mouseenter="showTooltip(item, $event, series)"
|
82
82
|
@mouseleave="hideTooltip"
|
@@ -96,7 +96,7 @@
|
|
96
96
|
:left="tooltipStyle.left"
|
97
97
|
:top="tooltipStyle.top"
|
98
98
|
>
|
99
|
-
<slot :item="tooltipData" name="tooltip"
|
99
|
+
<slot :item="tooltipData" name="tooltip"></slot>
|
100
100
|
<TooltipTextWrapper v-if="!slots.tooltip && tooltipData">
|
101
101
|
<template v-if="!series.length">
|
102
102
|
<TooltipText font-weight="500">{{ tooltipData.label }}</TooltipText>
|
@@ -128,7 +128,11 @@
|
|
128
128
|
:gradient-to="segment.gradientTo"
|
129
129
|
/>
|
130
130
|
<TooltipText>
|
131
|
-
{{
|
131
|
+
{{
|
132
|
+
fieldMode === 'absolute' && showPercentageOnTooltip
|
133
|
+
? `${segment.valuePercentage}%`
|
134
|
+
: handleValueFormatter(segment.value)
|
135
|
+
}}
|
132
136
|
</TooltipText>
|
133
137
|
</TooltipRow>
|
134
138
|
</template>
|
@@ -159,6 +163,7 @@
|
|
159
163
|
:data="data"
|
160
164
|
:field-mode="fieldMode"
|
161
165
|
:is-chart-controls-shown-in-bottom="isChartControlsShown('bottom')"
|
166
|
+
:is-inputs-disabled="isLoading"
|
162
167
|
:is-scrollable="isScrollable"
|
163
168
|
:series="series"
|
164
169
|
:y-axis-width="yAxisWidth"
|
@@ -171,12 +176,13 @@
|
|
171
176
|
</template>
|
172
177
|
|
173
178
|
<script setup>
|
174
|
-
import { useSlots, computed } from 'vue'
|
179
|
+
import { useSlots, computed, ref } from 'vue'
|
175
180
|
|
176
181
|
import ChartControls from './ChartControls'
|
177
182
|
import BottomFields from './BottomFields'
|
178
183
|
import SelectionBox from './SelectionBox'
|
179
184
|
import Spinner from '../spinner'
|
185
|
+
import { numberToString } from '../../helpers/numberConverter'
|
180
186
|
|
181
187
|
import {
|
182
188
|
useTooltip,
|
@@ -246,10 +252,6 @@
|
|
246
252
|
type: String,
|
247
253
|
default: '',
|
248
254
|
},
|
249
|
-
valueFormatter: {
|
250
|
-
type: Function,
|
251
|
-
default: null,
|
252
|
-
},
|
253
255
|
isLegendShown: {
|
254
256
|
type: Boolean,
|
255
257
|
default: false,
|
@@ -296,6 +298,10 @@
|
|
296
298
|
type: Boolean,
|
297
299
|
default: false,
|
298
300
|
},
|
301
|
+
showPercentageOnTooltip: {
|
302
|
+
type: Boolean,
|
303
|
+
default: false,
|
304
|
+
},
|
299
305
|
})
|
300
306
|
|
301
307
|
const generateChartId = () =>
|
@@ -378,8 +384,40 @@
|
|
378
384
|
}
|
379
385
|
|
380
386
|
const handleValueFormatter = (value) => {
|
381
|
-
|
382
|
-
|
383
|
-
|
387
|
+
let formattedValue = value
|
388
|
+
if (value < 1000) {
|
389
|
+
formattedValue = numberToString({
|
390
|
+
value: formattedValue,
|
391
|
+
numberPrecision: 0,
|
392
|
+
minDecimals: 0,
|
393
|
+
})
|
394
|
+
} else if (value < 1000000) {
|
395
|
+
formattedValue = numberToString({
|
396
|
+
value: Number(formattedValue / 1000),
|
397
|
+
numberPrecision: 2,
|
398
|
+
minDecimals: 2,
|
399
|
+
})
|
400
|
+
} else {
|
401
|
+
formattedValue = numberToString({
|
402
|
+
value: Number(formattedValue / 1000000),
|
403
|
+
numberPrecision: 2,
|
404
|
+
minDecimals: 2,
|
405
|
+
})
|
406
|
+
}
|
407
|
+
if (value < 1000) {
|
408
|
+
return `${formattedValue} kWh`
|
409
|
+
} else if (value < 1000000) {
|
410
|
+
return `${formattedValue} MWh`
|
411
|
+
} else {
|
412
|
+
return `${formattedValue} GWh`
|
413
|
+
}
|
414
|
+
}
|
415
|
+
|
416
|
+
const getYAxisLabel = (label) => {
|
417
|
+
return numberToString({
|
418
|
+
value: label,
|
419
|
+
numberPrecision: 0,
|
420
|
+
minDecimals: 0,
|
421
|
+
})
|
384
422
|
}
|
385
423
|
</script>
|
@@ -17,18 +17,18 @@ export const LabelsColumn = styled('div', { width: String })`
|
|
17
17
|
|
18
18
|
export const LabelRow = styled.div`
|
19
19
|
height: 32px;
|
20
|
+
padding-top: 5px;
|
20
21
|
font-size: 12px;
|
21
22
|
font-weight: 500;
|
22
23
|
color: ${(props) => props.theme.semanticColors.teal[600]};
|
23
24
|
display: flex;
|
24
|
-
align-items:
|
25
|
+
align-items: center;
|
25
26
|
`
|
26
27
|
|
27
28
|
export const TotalRow = styled(LabelRow)``
|
28
29
|
|
29
30
|
export const FieldsContainer = styled.div`
|
30
31
|
flex: 1;
|
31
|
-
overflow-x: auto;
|
32
32
|
scrollbar-width: none;
|
33
33
|
|
34
34
|
&::-webkit-scrollbar {
|
@@ -59,8 +59,22 @@ export const InputGroup = styled('div', {
|
|
59
59
|
barWidth: Number,
|
60
60
|
isScrollable: Boolean,
|
61
61
|
})`
|
62
|
-
${(props) => (props.isScrollable ? 'min-width' : 'width')}
|
63
|
-
props.barWidth}px;
|
62
|
+
${(props) => (props.isScrollable ? 'min-width' : 'width')}: 70px;
|
64
63
|
display: flex;
|
65
64
|
justify-content: center;
|
65
|
+
position: relative;
|
66
|
+
|
67
|
+
input[readonly] {
|
68
|
+
border: 1px solid ${(props) => props.theme.colors.grey4} !important;
|
69
|
+
}
|
70
|
+
`
|
71
|
+
|
72
|
+
export const InfoCardContainer = styled('div', { yAxisWidth: String })`
|
73
|
+
margin-left: ${(props) => props.yAxisWidth};
|
74
|
+
padding: 12px;
|
75
|
+
margin-top: 12px;
|
76
|
+
`
|
77
|
+
|
78
|
+
export const InfoCardBody = styled.div`
|
79
|
+
padding: 8px 0;
|
66
80
|
`
|
@@ -16,9 +16,12 @@ export const GraphSection = styled('div', { width: String, height: String })`
|
|
16
16
|
display: flex;
|
17
17
|
`
|
18
18
|
|
19
|
-
export const YAxis = styled('div', { width: String })`
|
19
|
+
export const YAxis = styled('div', { width: String, height: String })`
|
20
20
|
width: ${(props) => props.width};
|
21
|
+
display: flex;
|
22
|
+
flex-direction: column;
|
21
23
|
position: relative;
|
24
|
+
height: ${(props) => props.height};
|
22
25
|
`
|
23
26
|
|
24
27
|
export const YAxisRow = styled('div', { percentage: Number })`
|
@@ -54,19 +57,18 @@ export const YAxisLine = styled('div', { yAxisWidth: String })`
|
|
54
57
|
transform: translateY(-50%);
|
55
58
|
`
|
56
59
|
|
57
|
-
export const YAxisTitleWrapper = styled('div')`
|
60
|
+
export const YAxisTitleWrapper = styled('div', { height: String })`
|
61
|
+
position: absolute;
|
62
|
+
left: -66px;
|
63
|
+
top: ${(props) => props.height};
|
64
|
+
transform: rotate(-90deg) translateX(50%);
|
65
|
+
transform-origin: right;
|
58
66
|
font-size: 12px;
|
59
|
-
|
60
|
-
color: ${(props) => props.theme.semanticColors.grey[700]};
|
61
|
-
white-space: nowrap;
|
62
|
-
height: 0;
|
63
|
-
width: 0;
|
67
|
+
color: ${(props) => props.theme.semanticColors.teal[600]};
|
64
68
|
display: flex;
|
65
|
-
align-items:
|
66
|
-
|
67
|
-
|
68
|
-
top: 50%;
|
69
|
-
transform: rotate(-90deg);
|
69
|
+
align-items: center;
|
70
|
+
white-space: nowrap;
|
71
|
+
font-family: ${(props) => props.theme.fonts.mainFont};
|
70
72
|
`
|
71
73
|
|
72
74
|
export const ScrollContainer = styled('div', {
|
@@ -125,6 +127,7 @@ export const BarWrapper = styled.div`
|
|
125
127
|
height: 100%;
|
126
128
|
width: 100%;
|
127
129
|
position: relative;
|
130
|
+
overflow: hidden;
|
128
131
|
`
|
129
132
|
|
130
133
|
export const BarSegment = styled('div', {
|
@@ -73,7 +73,12 @@
|
|
73
73
|
type: {
|
74
74
|
required: false,
|
75
75
|
type: String,
|
76
|
-
default: '
|
76
|
+
default: 'info_simple',
|
77
|
+
validator(value) {
|
78
|
+
return ['info_simple', 'warning', 'error_minor', 'info'].includes(
|
79
|
+
value
|
80
|
+
)
|
81
|
+
},
|
77
82
|
},
|
78
83
|
minWidth: {
|
79
84
|
required: false,
|
@@ -112,8 +117,11 @@
|
|
112
117
|
},
|
113
118
|
},
|
114
119
|
computed: {
|
115
|
-
|
120
|
+
isInfoSimple() {
|
116
121
|
// this property is used for tests
|
122
|
+
return this.type === 'info_simple'
|
123
|
+
},
|
124
|
+
isInfo() {
|
117
125
|
return this.type === 'info'
|
118
126
|
},
|
119
127
|
isWarning() {
|
@@ -123,11 +131,7 @@
|
|
123
131
|
return this.type === 'error_minor'
|
124
132
|
},
|
125
133
|
iconName() {
|
126
|
-
return this.type === 'warning'
|
127
|
-
? 'warning_triangle'
|
128
|
-
: this.isErrorMinor
|
129
|
-
? 'erase'
|
130
|
-
: 'info'
|
134
|
+
return this.type === 'warning' ? 'warning_triangle' : 'info'
|
131
135
|
},
|
132
136
|
presetStyles() {
|
133
137
|
// the types that doesn't have explicit border anyway have it transparent
|
@@ -146,11 +150,15 @@
|
|
146
150
|
stylesCollection.iconColor = theme.semanticColors.teal[800]
|
147
151
|
} else if (this.isErrorMinor) {
|
148
152
|
stylesCollection.borderStyle = 'dashed'
|
149
|
-
stylesCollection.borderColor = theme.colors.
|
150
|
-
stylesCollection.iconColor = theme.colors.
|
151
|
-
} else {
|
153
|
+
stylesCollection.borderColor = theme.colors.pureRed
|
154
|
+
stylesCollection.iconColor = theme.colors.pureRed
|
155
|
+
} else if (this.isInfoSimple) {
|
152
156
|
stylesCollection.borderStyle = 'dashed'
|
153
157
|
stylesCollection.borderColor = theme.colors.grey4
|
158
|
+
} else {
|
159
|
+
stylesCollection.color = theme.semanticColors.teal[800]
|
160
|
+
stylesCollection.backgroundColor = theme.semanticColors.blue[300]
|
161
|
+
stylesCollection.iconColor = theme.semanticColors.teal[800]
|
154
162
|
}
|
155
163
|
|
156
164
|
return stylesCollection
|
@@ -45,19 +45,19 @@ describe('RCInfoCard.vue', () => {
|
|
45
45
|
},
|
46
46
|
})
|
47
47
|
|
48
|
-
expect(wrapper.vm.
|
48
|
+
expect(wrapper.vm.isInfoSimple).toBe(true)
|
49
49
|
expect(wrapper.vm.isWarning).toBe(false)
|
50
50
|
expect(wrapper.vm.isErrorMinor).toBe(false)
|
51
51
|
|
52
52
|
await wrapper.setProps({ type: 'warning' })
|
53
53
|
|
54
|
-
expect(wrapper.vm.
|
54
|
+
expect(wrapper.vm.isInfoSimple).toBe(false)
|
55
55
|
expect(wrapper.vm.isWarning).toBe(true)
|
56
56
|
expect(wrapper.vm.isErrorMinor).toBe(false)
|
57
57
|
|
58
58
|
await wrapper.setProps({ type: 'error_minor' })
|
59
59
|
|
60
|
-
expect(wrapper.vm.
|
60
|
+
expect(wrapper.vm.isInfoSimple).toBe(false)
|
61
61
|
expect(wrapper.vm.isWarning).toBe(false)
|
62
62
|
expect(wrapper.vm.isErrorMinor).toBe(true)
|
63
63
|
})
|
@@ -15,37 +15,40 @@
|
|
15
15
|
:is-disabled="isDisabled"
|
16
16
|
:padding="padding"
|
17
17
|
>
|
18
|
-
<
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
18
|
+
<template v-if="!$slots.trigger">
|
19
|
+
<LabelWrapper
|
20
|
+
v-if="labelText && labelAlign === 'left'"
|
21
|
+
:color="iconColor || computedIconColor"
|
22
|
+
:size="labelSize"
|
23
|
+
>
|
24
|
+
{{ labelText }}
|
25
|
+
</LabelWrapper>
|
26
|
+
<Dot
|
27
|
+
v-if="type === 'dot'"
|
28
|
+
:color="dotColor"
|
29
|
+
data-test-id="infoText_dot"
|
30
|
+
/>
|
31
|
+
<IconComponent
|
32
|
+
v-else-if="!noIcon"
|
33
|
+
:color="iconColor || computedIconColor"
|
34
|
+
:cursor="isDisabled ? 'not-allowed' : 'pointer'"
|
35
|
+
:disabled="isDisabled"
|
36
|
+
:hovered-color="iconColor || computedIconColor"
|
37
|
+
:name="iconName"
|
38
|
+
:size="size"
|
39
|
+
/>
|
40
|
+
<LabelWrapper
|
41
|
+
v-if="labelText && labelAlign === 'right'"
|
42
|
+
:color="iconColor || computedIconColor"
|
43
|
+
:size="labelSize"
|
44
|
+
>
|
45
|
+
{{ labelText }}
|
46
|
+
</LabelWrapper>
|
47
|
+
</template>
|
48
|
+
<slot name="trigger"></slot>
|
46
49
|
</IconWrapper>
|
47
50
|
</div>
|
48
|
-
<Teleport v-if="isVisible" to="body">
|
51
|
+
<Teleport v-if="isVisible && !!text" to="body">
|
49
52
|
<TextWrapper data-test-id="info_text_wrapper" :style="wrapperStyle">
|
50
53
|
<TextOverlay
|
51
54
|
ref="infoBox"
|
@@ -227,7 +230,7 @@
|
|
227
230
|
},
|
228
231
|
infoPosition: {
|
229
232
|
required: false,
|
230
|
-
default:
|
233
|
+
default: null,
|
231
234
|
type: String,
|
232
235
|
},
|
233
236
|
maxWidth: {
|
@@ -363,7 +366,9 @@
|
|
363
366
|
{ position: 'left', space: spaceLeft },
|
364
367
|
].sort((a, b) => b.space - a.space)
|
365
368
|
|
366
|
-
const bestPosition =
|
369
|
+
const bestPosition = props.infoPosition
|
370
|
+
? props.infoPosition
|
371
|
+
: positions[0].position
|
367
372
|
|
368
373
|
let top, left, arrowPosition
|
369
374
|
|
@@ -3,15 +3,15 @@ import InputNumber from './index.vue'
|
|
3
3
|
export default {
|
4
4
|
title: 'InputNumber',
|
5
5
|
component: InputNumber,
|
6
|
+
// argTypes: {},
|
6
7
|
}
|
7
8
|
|
8
|
-
const Template = (args) => ({
|
9
|
+
const Template = (args, { argTypes }) => ({
|
9
10
|
// Components used in your story `template` are defined in the `components` object
|
10
11
|
components: { InputNumber },
|
11
|
-
setup()
|
12
|
-
|
13
|
-
|
14
|
-
template: `<InputNumber v-bind="args" />`,
|
12
|
+
// The story's `args` need to be mapped into the template through the `setup()` method
|
13
|
+
props: Object.keys(argTypes),
|
14
|
+
template: '<input-number v-bind="$props" />',
|
15
15
|
|
16
16
|
// import InputNumber from "@eturnity/eturnity_reusable_components/src/components/inputs/inputNumber"
|
17
17
|
// How to use:
|
@@ -30,44 +30,55 @@
|
|
30
30
|
/>
|
31
31
|
</LabelWrapper>
|
32
32
|
<InputWrapper>
|
33
|
-
<
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
33
|
+
<InfoText info-position="bottom" :text="inputInfoText">
|
34
|
+
<template #trigger>
|
35
|
+
<InputContainer
|
36
|
+
v-bind="$attrs"
|
37
|
+
ref="inputField1"
|
38
|
+
:align-items="alignItems"
|
39
|
+
:background-color="
|
40
|
+
colorMode === 'transparent' ? 'transparent' : backgroundColor
|
41
|
+
"
|
42
|
+
:border-color="
|
43
|
+
colorMode === 'transparent' && !borderColor
|
44
|
+
? 'white'
|
45
|
+
: borderColor
|
46
|
+
"
|
47
|
+
:color-mode="colorMode"
|
48
|
+
:data-id="inputDataId"
|
49
|
+
:data-qa-id="dataQaId"
|
50
|
+
:disabled="disabled"
|
51
|
+
:font-color="colorMode === 'transparent' ? 'white' : fontColor"
|
52
|
+
:font-size="fontSize"
|
53
|
+
:has-label-slot="hasLabelSlot"
|
54
|
+
:has-slot="hasSlot"
|
55
|
+
:has-unit="unitName && !!unitName.length"
|
56
|
+
:input-height="inputHeight"
|
57
|
+
:is-border-error-only="isBorderErrorOnly"
|
58
|
+
:is-disabled="disabled"
|
59
|
+
:is-error="isError"
|
60
|
+
:is-info-border="isInfoBorder"
|
61
|
+
:is-interactive="isInteractive"
|
62
|
+
:min-width="minWidth"
|
63
|
+
:no-border="noBorder"
|
64
|
+
:placeholder="displayedPlaceholder"
|
65
|
+
:read-only="isReadOnly"
|
66
|
+
:readonly="isReadOnly"
|
67
|
+
:show-arrow-controls="showArrowControls"
|
68
|
+
:show-linear-unit-name="showLinearUnitName"
|
69
|
+
:slot-size="slotSize"
|
70
|
+
:text-align="textAlign"
|
71
|
+
:value="formatWithCurrency(value)"
|
72
|
+
@blur="onInputBlur($event)"
|
73
|
+
@focus="focusInput()"
|
74
|
+
@input="onInput($event)"
|
75
|
+
@keydown.down="decrementValue"
|
76
|
+
@keydown.up="incrementValue"
|
77
|
+
@keyup.enter="onEnterPress"
|
78
|
+
/>
|
79
|
+
</template>
|
80
|
+
</InfoText>
|
81
|
+
|
71
82
|
<SlotContainer v-if="hasSlot" :is-error="isError" :slot-size="slotSize">
|
72
83
|
<slot></slot>
|
73
84
|
</SlotContainer>
|
@@ -79,7 +90,7 @@
|
|
79
90
|
>{{ unitName }}</UnitContainer
|
80
91
|
>
|
81
92
|
<IconWrapper
|
82
|
-
v-if="isError && !showLinearUnitName"
|
93
|
+
v-if="isError && !showLinearUnitName && !isBorderErrorOnly"
|
83
94
|
:margin-right="showSelect ? selectWidth : 0"
|
84
95
|
size="16px"
|
85
96
|
>
|
@@ -133,7 +144,9 @@
|
|
133
144
|
</ArrowButton>
|
134
145
|
</ArrowControls>
|
135
146
|
</InputWrapper>
|
136
|
-
<ErrorMessage v-if="isError && errorMessage">{{
|
147
|
+
<ErrorMessage v-if="isError && errorMessage">{{
|
148
|
+
errorMessage
|
149
|
+
}}</ErrorMessage>
|
137
150
|
</Container>
|
138
151
|
</template>
|
139
152
|
|
@@ -204,6 +217,8 @@
|
|
204
217
|
colorMode: String,
|
205
218
|
showArrowControls: Boolean,
|
206
219
|
readOnly: Boolean,
|
220
|
+
isBorderErrorOnly: Boolean,
|
221
|
+
isInfoBorder: Boolean,
|
207
222
|
}
|
208
223
|
|
209
224
|
const Container = styled('div', inputProps)`
|
@@ -216,7 +231,9 @@
|
|
216
231
|
|
217
232
|
const InputContainer = styled('input', inputProps)`
|
218
233
|
border: ${(props) =>
|
219
|
-
props.
|
234
|
+
props.isInfoBorder
|
235
|
+
? '1px solid ' + props.theme.semanticColors.blue[500]
|
236
|
+
: props.isError
|
220
237
|
? '1px solid ' + props.theme.colors.red
|
221
238
|
: props.noBorder
|
222
239
|
? 'none'
|
@@ -235,16 +252,17 @@
|
|
235
252
|
showLinearUnitName,
|
236
253
|
colorMode,
|
237
254
|
showArrowControls,
|
255
|
+
isBorderErrorOnly,
|
238
256
|
}) =>
|
239
257
|
showArrowControls
|
240
258
|
? '40px'
|
241
259
|
: colorMode === 'transparent'
|
242
260
|
? '0'
|
243
261
|
: slotSize
|
244
|
-
? isError && !showLinearUnitName
|
262
|
+
? isError && !showLinearUnitName && !isBorderErrorOnly
|
245
263
|
? 'calc(' + slotSize + ' + 24px)'
|
246
264
|
: 'calc(' + slotSize + ' + 10px)'
|
247
|
-
: isError && !showLinearUnitName
|
265
|
+
: isError && !showLinearUnitName && !isBorderErrorOnly
|
248
266
|
? '24px'
|
249
267
|
: '5px'};
|
250
268
|
border-radius: ${(props) =>
|
@@ -656,18 +674,12 @@
|
|
656
674
|
required: false,
|
657
675
|
default: '',
|
658
676
|
},
|
659
|
-
labelDataTestId: {
|
660
|
-
type: String,
|
661
|
-
required: false,
|
662
|
-
default: '',
|
663
|
-
},
|
664
677
|
inputDataId: {
|
665
678
|
type: String,
|
666
679
|
required: false,
|
667
680
|
default: '',
|
668
681
|
},
|
669
682
|
dataQaId: {
|
670
|
-
type: String,
|
671
683
|
required: false,
|
672
684
|
default: '',
|
673
685
|
},
|
@@ -703,6 +715,18 @@
|
|
703
715
|
type: Boolean,
|
704
716
|
default: false,
|
705
717
|
},
|
718
|
+
isBorderErrorOnly: {
|
719
|
+
type: Boolean,
|
720
|
+
default: false,
|
721
|
+
},
|
722
|
+
isInfoBorder: {
|
723
|
+
type: Boolean,
|
724
|
+
default: false,
|
725
|
+
},
|
726
|
+
inputInfoText: {
|
727
|
+
type: String,
|
728
|
+
default: '',
|
729
|
+
},
|
706
730
|
},
|
707
731
|
data() {
|
708
732
|
return {
|
@@ -5,8 +5,7 @@
|
|
5
5
|
:has-info-text="!!infoText"
|
6
6
|
:margin-bottom="marginBottom"
|
7
7
|
>
|
8
|
-
<span
|
9
|
-
<span v-else data-test-id="page_subtitle_text">
|
8
|
+
<span data-test-id="page_subtitle_text">
|
10
9
|
{{ text }}
|
11
10
|
</span>
|
12
11
|
<InfoText
|
@@ -59,11 +58,6 @@
|
|
59
58
|
required: true,
|
60
59
|
type: String,
|
61
60
|
},
|
62
|
-
containsHtml: {
|
63
|
-
required: false,
|
64
|
-
type: Boolean,
|
65
|
-
default: false,
|
66
|
-
},
|
67
61
|
color: {
|
68
62
|
required: false,
|
69
63
|
type: String,
|
@@ -1,8 +1,8 @@
|
|
1
1
|
<template>
|
2
2
|
<TitleWrap data-test-id="page_wrapper" :has-info-text="!!infoText">
|
3
3
|
<TitleText
|
4
|
-
data-test-id="page_title_text"
|
5
4
|
:color="color"
|
5
|
+
data-test-id="page_title_text"
|
6
6
|
:font-size="fontSize"
|
7
7
|
:uppercase="uppercase"
|
8
8
|
>
|
@@ -10,8 +10,8 @@
|
|
10
10
|
</TitleText>
|
11
11
|
<InfoText
|
12
12
|
v-if="!!infoText"
|
13
|
-
data-test-id="page_title_tooltip"
|
14
13
|
:align-arrow="infoAlign"
|
14
|
+
data-test-id="page_title_tooltip"
|
15
15
|
:text="infoText"
|
16
16
|
/>
|
17
17
|
</TitleWrap>
|
@@ -44,9 +44,8 @@
|
|
44
44
|
const titleAttrs = { color: String, fontSize: String, uppercase: Boolean }
|
45
45
|
const TitleText = styled('span', titleAttrs)`
|
46
46
|
color: ${(props) => (props.color ? props.color : props.theme.colors.black)};
|
47
|
-
font-weight:
|
47
|
+
font-weight: 500;
|
48
48
|
font-size: ${(props) => (props.fontSize ? props.fontSize : '20px')};
|
49
|
-
text-transform: ${(props) => (props.uppercase ? 'uppercase' : 'none')};
|
50
49
|
`
|
51
50
|
|
52
51
|
export default {
|