@eturnity/eturnity_reusable_components 7.45.5-qa-elisee-7.48.0 → 7.45.5-qa-16-11.13
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/components/icon/index.vue +3 -13
- package/src/components/inputs/inputNumber/index.vue +58 -76
- package/src/components/inputs/select/index.vue +57 -5
- package/src/components/modals/modal/index.vue +27 -27
- package/src/helpers/numberConverter.js +1 -1
- package/src/components/icon/icon.spec.js +0 -66
package/package.json
CHANGED
@@ -1,24 +1,14 @@
|
|
1
1
|
<template>
|
2
|
-
<Wrapper
|
3
|
-
:cursor="cursor"
|
4
|
-
data-test-id="icon_wrapper"
|
5
|
-
:disabled="disabled"
|
6
|
-
:size="size"
|
7
|
-
>
|
2
|
+
<Wrapper :cursor="cursor" :disabled="disabled" :size="size">
|
8
3
|
<IconImage
|
9
4
|
:animation="animation"
|
10
5
|
:background-color="backgroundColor"
|
11
6
|
:color="color"
|
12
|
-
data-test-id="icon_image"
|
13
7
|
:hovered-color="hoveredColor"
|
14
8
|
>
|
15
|
-
<i
|
9
|
+
<i v-html="icon.html"></i>
|
16
10
|
</IconImage>
|
17
|
-
<StrikedLine
|
18
|
-
v-if="isStriked"
|
19
|
-
:color="color"
|
20
|
-
data-test-id="icon_striked_line"
|
21
|
-
/>
|
11
|
+
<StrikedLine v-if="isStriked" :color="color" />
|
22
12
|
</Wrapper>
|
23
13
|
</template>
|
24
14
|
|
@@ -47,7 +47,7 @@
|
|
47
47
|
:show-linear-unit-name="showLinearUnitName"
|
48
48
|
:slot-size="slotSize"
|
49
49
|
:text-align="textAlign"
|
50
|
-
:value="
|
50
|
+
:value="formattedValue"
|
51
51
|
@blur="onInputBlur($event)"
|
52
52
|
@focus="focusInput()"
|
53
53
|
@input="onInput($event)"
|
@@ -59,7 +59,7 @@
|
|
59
59
|
|
60
60
|
<UnitContainer
|
61
61
|
v-if="unitName && showLinearUnitName && !hasSlot"
|
62
|
-
:has-length="
|
62
|
+
:has-length="hasLength"
|
63
63
|
:is-error="isError"
|
64
64
|
>{{ unitName }}</UnitContainer
|
65
65
|
>
|
@@ -339,8 +339,17 @@
|
|
339
339
|
background-color: ${({ theme }) => theme.colors.grey4};
|
340
340
|
`
|
341
341
|
|
342
|
+
const EVENT_TYPES = {
|
343
|
+
INPUT_FOCUS: 'input-focus',
|
344
|
+
INPUT_CHANGE: 'input-change',
|
345
|
+
INPUT_BLUR: 'input-blur',
|
346
|
+
PRESS_ENTER: 'on-enter-click',
|
347
|
+
INPUT_DRAG: 'on-input-drag',
|
348
|
+
}
|
349
|
+
|
342
350
|
export default {
|
343
351
|
name: 'InputNumber',
|
352
|
+
emits: [...Object.values(EVENT_TYPES)],
|
344
353
|
components: {
|
345
354
|
Container,
|
346
355
|
InputContainer,
|
@@ -519,9 +528,10 @@
|
|
519
528
|
},
|
520
529
|
data() {
|
521
530
|
return {
|
522
|
-
textInput: '',
|
523
531
|
isFocused: false,
|
524
532
|
warningIcon: warningIcon,
|
533
|
+
inputValue: null,
|
534
|
+
enteredValue: null,
|
525
535
|
}
|
526
536
|
},
|
527
537
|
computed: {
|
@@ -544,6 +554,14 @@
|
|
544
554
|
|
545
555
|
return item ? item.label : '-'
|
546
556
|
},
|
557
|
+
formattedValue() {
|
558
|
+
return this.formatWithCurrency(
|
559
|
+
this.isFocused ? this.enteredValue : this.inputValue
|
560
|
+
)
|
561
|
+
},
|
562
|
+
hasLength() {
|
563
|
+
return this.formattedValue !== null && this.formattedValue.length > 0
|
564
|
+
},
|
547
565
|
},
|
548
566
|
watch: {
|
549
567
|
focus(value) {
|
@@ -554,30 +572,19 @@
|
|
554
572
|
clearInput: function (value) {
|
555
573
|
if (value) {
|
556
574
|
// If the value is typed, then we should clear the textInput on Continue
|
557
|
-
this.
|
575
|
+
this.inputValue = ''
|
576
|
+
this.enteredValue = ''
|
558
577
|
}
|
559
578
|
},
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
}
|
568
|
-
}
|
569
|
-
this.textInput = numberToString({
|
570
|
-
value: this.defaultNumber,
|
571
|
-
numberPrecision: this.numberPrecision,
|
572
|
-
minDecimals: this.minDecimals,
|
573
|
-
})
|
574
|
-
} else if (this.minNumber !== null) {
|
575
|
-
this.textInput = numberToString({
|
576
|
-
value: this.minNumber,
|
577
|
-
numberPrecision: this.numberPrecision,
|
578
|
-
minDecimals: this.minDecimals,
|
579
|
-
})
|
580
|
-
}
|
579
|
+
value: {
|
580
|
+
immediate: true,
|
581
|
+
handler(val) {
|
582
|
+
if (this.value !== this.inputValue && !Number.isNaN(this.value)) {
|
583
|
+
this.inputValue = this.value
|
584
|
+
this.enteredValue = this.value
|
585
|
+
}
|
586
|
+
},
|
587
|
+
},
|
581
588
|
},
|
582
589
|
mounted() {
|
583
590
|
if (this.focus) {
|
@@ -586,29 +593,28 @@
|
|
586
593
|
},
|
587
594
|
methods: {
|
588
595
|
onEnterPress() {
|
589
|
-
this.$emit(
|
596
|
+
this.$emit(EVENT_TYPES.PRESS_ENTER)
|
590
597
|
this.$refs.inputField1.$el.blur()
|
591
598
|
},
|
592
|
-
onChangeHandler(
|
593
|
-
if (isNaN(
|
594
|
-
|
599
|
+
onChangeHandler(value) {
|
600
|
+
if (isNaN(value) || value === '') {
|
601
|
+
value = this.defaultNumber
|
595
602
|
? this.defaultNumber
|
596
603
|
: this.minNumber || this.minNumber === 0
|
597
604
|
? this.minNumber
|
598
|
-
:
|
605
|
+
: value
|
599
606
|
}
|
600
607
|
if (!this.allowNegative) {
|
601
|
-
|
608
|
+
value = Math.abs(value)
|
602
609
|
}
|
603
|
-
|
610
|
+
value = parseFloat(value)
|
604
611
|
// Need to return an integer rather than a string
|
605
|
-
|
612
|
+
return parseFloat(value)
|
606
613
|
},
|
607
|
-
onEvaluateCode(
|
614
|
+
onEvaluateCode(value) {
|
608
615
|
// function to perform math on the code
|
609
616
|
// filter the string in case of any malicious content
|
610
|
-
|
611
|
-
let filtered = val.replace('(auto)', '').replace(/[^-()\d/*+.,]/g, '')
|
617
|
+
let filtered = value.replace('(auto)', '').replace(/[^-()\d/*+.,]/g, '')
|
612
618
|
filtered = filtered.split(/([-+*/()])/)
|
613
619
|
let formatted = filtered.map((item) => {
|
614
620
|
if (
|
@@ -666,47 +672,28 @@
|
|
666
672
|
return array
|
667
673
|
},
|
668
674
|
onInput(event) {
|
669
|
-
|
675
|
+
this.enteredValue = event.target.value
|
676
|
+
if (!this.isFocused || this.enteredValue === this.inputValue) {
|
670
677
|
return
|
671
678
|
}
|
672
|
-
if (event.target.value === '') {
|
673
|
-
this.$emit('on-input', '')
|
674
|
-
}
|
675
679
|
let evaluatedVal
|
676
680
|
try {
|
677
|
-
evaluatedVal = this.onEvaluateCode(
|
681
|
+
evaluatedVal = this.onEvaluateCode(String(this.enteredValue))
|
678
682
|
} finally {
|
679
|
-
|
680
|
-
|
683
|
+
this.inputValue = this.onChangeHandler(evaluatedVal)
|
684
|
+
|
685
|
+
if (this.isFocused && typeof this.enteredValue !== 'number') {
|
686
|
+
this.$emit(EVENT_TYPES.INPUT_CHANGE, this.inputValue)
|
681
687
|
}
|
682
688
|
}
|
683
689
|
},
|
684
690
|
onInputBlur(e) {
|
685
691
|
this.isFocused = false
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
value:
|
692
|
-
evaluatedInput && value.length
|
693
|
-
? evaluatedInput
|
694
|
-
: this.defaultNumber
|
695
|
-
? this.defaultNumber
|
696
|
-
: this.minNumber,
|
697
|
-
numberPrecision: this.numberPrecision,
|
698
|
-
minDecimals: this.minDecimals,
|
699
|
-
})
|
700
|
-
}
|
701
|
-
let adjustedMinValue =
|
702
|
-
evaluatedInput && evaluatedInput.length
|
703
|
-
? evaluatedInput
|
704
|
-
: this.defaultNumber
|
705
|
-
? this.defaultNumber
|
706
|
-
: this.minNumber || this.minNumber === 0
|
707
|
-
? this.minNumber
|
708
|
-
: ''
|
709
|
-
this.$emit('input-blur', adjustedMinValue)
|
692
|
+
this.enteredValue = this.inputValue
|
693
|
+
this.$emit(
|
694
|
+
EVENT_TYPES.INPUT_BLUR,
|
695
|
+
this.onEvaluateCode(String(this.inputValue))
|
696
|
+
)
|
710
697
|
},
|
711
698
|
focusInput() {
|
712
699
|
if (this.disabled) {
|
@@ -716,7 +703,7 @@
|
|
716
703
|
this.$nextTick(() => {
|
717
704
|
this.$refs.inputField1.$el.select()
|
718
705
|
})
|
719
|
-
this.$emit(
|
706
|
+
this.$emit(EVENT_TYPES.INPUT_FOCUS)
|
720
707
|
},
|
721
708
|
blurInput() {
|
722
709
|
if (this.disabled) {
|
@@ -749,6 +736,8 @@
|
|
749
736
|
return input + ' ' + unit
|
750
737
|
} else if (!adjustedMinValue && adjustedMinValue !== 0) {
|
751
738
|
return ''
|
739
|
+
} else if (this.isFocused && this.numberPrecision > 0) {
|
740
|
+
return value
|
752
741
|
} else {
|
753
742
|
return this.numberToStringEnabled
|
754
743
|
? numberToString({
|
@@ -769,14 +758,7 @@
|
|
769
758
|
e.preventDefault()
|
770
759
|
let value = parseFloat(this.value || 0)
|
771
760
|
value += parseFloat(this.interactionStep) * parseInt(e.movementX)
|
772
|
-
this.$emit(
|
773
|
-
|
774
|
-
this.textInput = numberToString({
|
775
|
-
value: value && value.length ? value : this.minNumber,
|
776
|
-
numberPrecision: this.numberPrecision,
|
777
|
-
minDecimals: this.minDecimals,
|
778
|
-
})
|
779
|
-
//this.value=value
|
761
|
+
this.$emit(EVENT_TYPES.INPUT_DRAG, this.onChangeHandler(value))
|
780
762
|
},
|
781
763
|
stopInteract(e) {
|
782
764
|
e.preventDefault()
|
@@ -120,6 +120,11 @@
|
|
120
120
|
<SelectDropdown
|
121
121
|
v-show="isSelectDropdownShown"
|
122
122
|
ref="dropdown"
|
123
|
+
:style="{
|
124
|
+
transform: `translate(${dropdownPosition?.left}px, ${
|
125
|
+
noRelative ? 'auto' : `${dropdownPosition?.top}px`
|
126
|
+
})`,
|
127
|
+
}"
|
123
128
|
:bg-color="
|
124
129
|
dropdownBgColor || colorMode == 'dark' ? 'black' : 'white'
|
125
130
|
"
|
@@ -344,9 +349,8 @@
|
|
344
349
|
box-sizing: border-box;
|
345
350
|
z-index: ${(props) => (props.isActive ? '2' : '99999')};
|
346
351
|
position: absolute;
|
347
|
-
top:
|
348
|
-
|
349
|
-
left: ${(props) => props.dropdownPosition?.left}px;
|
352
|
+
top: 0px;
|
353
|
+
left: 0px;
|
350
354
|
border: ${BORDER_WIDTH} solid ${(props) => props.theme.colors.grey4};
|
351
355
|
border-radius: 4px;
|
352
356
|
display: flex;
|
@@ -606,6 +610,10 @@
|
|
606
610
|
},
|
607
611
|
dropdownWidth: null,
|
608
612
|
hoveredValue: null,
|
613
|
+
isDisplayedAtBottom: true,
|
614
|
+
selectTopPosition: 0,
|
615
|
+
selectAndDropdownDistance: 0,
|
616
|
+
animationFrameId: null,
|
609
617
|
}
|
610
618
|
},
|
611
619
|
computed: {
|
@@ -676,8 +684,13 @@
|
|
676
684
|
}, 10)
|
677
685
|
await this.$nextTick()
|
678
686
|
this.handleSetDropdownOffet()
|
687
|
+
this.calculateSelectTopPosition()
|
679
688
|
} else {
|
680
689
|
this.dropdownPosition.left = null
|
690
|
+
if (this.animationFrameId) {
|
691
|
+
cancelAnimationFrame(this.animationFrameId)
|
692
|
+
this.animationFrameId = null
|
693
|
+
}
|
681
694
|
setTimeout(() => {
|
682
695
|
this.isClickOutsideActive = false
|
683
696
|
}, 10)
|
@@ -690,11 +703,27 @@
|
|
690
703
|
})
|
691
704
|
}
|
692
705
|
},
|
706
|
+
isSelectDropdownShown(isShown) {
|
707
|
+
if (!isShown) return
|
708
|
+
|
709
|
+
// Need to wait for 1ms to make sure the dropdown menu is shown in the DOM
|
710
|
+
// before getting the distance between the select and the dropdown menu
|
711
|
+
setTimeout(() => {
|
712
|
+
this.getDistanceBetweenSelectAndDropdownMenu()
|
713
|
+
}, 100)
|
714
|
+
},
|
715
|
+
selectTopPosition() {
|
716
|
+
this.dropdownPosition.top =
|
717
|
+
this.selectTopPosition +
|
718
|
+
this.$refs.select.$el.clientHeight +
|
719
|
+
this.selectAndDropdownDistance
|
720
|
+
},
|
693
721
|
},
|
694
722
|
mounted() {
|
695
723
|
this.observeDropdownHeight()
|
696
724
|
this.observeSelectWidth()
|
697
725
|
window.addEventListener('resize', this.handleSetDropdownOffet)
|
726
|
+
document.body.addEventListener('scroll', this.calculateSelectTopPosition)
|
698
727
|
},
|
699
728
|
beforeMount() {
|
700
729
|
this.selectedValue = this.value
|
@@ -703,6 +732,10 @@
|
|
703
732
|
window.removeEventListener('resize', this.handleSetDropdownOffet)
|
704
733
|
if (this.dropdownResizeObserver) this.dropdownResizeObserver.disconnect()
|
705
734
|
if (this.selectResizeObserver) this.selectResizeObserver.disconnect()
|
735
|
+
document.body.removeEventListener(
|
736
|
+
'scroll',
|
737
|
+
this.calculateSelectTopPosition
|
738
|
+
)
|
706
739
|
},
|
707
740
|
unmounted() {
|
708
741
|
document.removeEventListener('click', this.clickOutside)
|
@@ -808,11 +841,11 @@
|
|
808
841
|
return
|
809
842
|
}
|
810
843
|
await this.$nextTick()
|
811
|
-
|
844
|
+
this.isDisplayedAtBottom = await this.generateDropdownPosition()
|
812
845
|
// If the dropdown menu is going to be displayed at the bottom,
|
813
846
|
// we need reverify its position after a dom update (nextTick)
|
814
847
|
await this.$nextTick()
|
815
|
-
if (isDisplayedAtBottom) this.generateDropdownPosition()
|
848
|
+
if (this.isDisplayedAtBottom) this.generateDropdownPosition()
|
816
849
|
},
|
817
850
|
async generateDropdownPosition() {
|
818
851
|
const isDropdownNotCompletelyVisible =
|
@@ -905,6 +938,25 @@
|
|
905
938
|
}
|
906
939
|
}
|
907
940
|
},
|
941
|
+
getDistanceBetweenSelectAndDropdownMenu() {
|
942
|
+
const wholeSelectTopPosition =
|
943
|
+
this.selectTopPosition + this.$refs.select.$el.clientHeight
|
944
|
+
this.selectAndDropdownDistance =
|
945
|
+
this.dropdownPosition.top - wholeSelectTopPosition
|
946
|
+
},
|
947
|
+
calculateSelectTopPosition() {
|
948
|
+
const selectRef = this.$refs.select
|
949
|
+
if (selectRef) {
|
950
|
+
const currentTopPosition =
|
951
|
+
selectRef.$el.getBoundingClientRect().top + window.scrollY
|
952
|
+
if (this.selectTopPosition !== currentTopPosition) {
|
953
|
+
this.selectTopPosition = currentTopPosition
|
954
|
+
}
|
955
|
+
}
|
956
|
+
this.animationFrameId = requestAnimationFrame(
|
957
|
+
this.calculateSelectTopPosition
|
958
|
+
)
|
959
|
+
},
|
908
960
|
},
|
909
961
|
}
|
910
962
|
</script>
|
@@ -35,37 +35,37 @@
|
|
35
35
|
visibility: ${(props) => (props.visible ? 'inherit' : 'hidden')};
|
36
36
|
`
|
37
37
|
|
38
|
-
const pageAttrs = {
|
38
|
+
const pageAttrs = { backdrop: String, position: String }
|
39
39
|
const PageWrapper = styled('div', pageAttrs)`
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
40
|
+
position: ${(props) => props.position}
|
41
|
+
display: grid;
|
42
|
+
top: 0;
|
43
|
+
left: 0;
|
44
|
+
width: 100%;
|
45
|
+
height: 100%;
|
46
|
+
background-color: ${(props) =>
|
47
|
+
props.backdrop == 'dark'
|
48
|
+
? 'rgba(0, 0, 0, 0.4)'
|
49
|
+
: 'rgba(255, 255, 255, 0.9)'};
|
50
|
+
z-index: 99999;
|
51
|
+
overflow: auto;
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
53
|
+
&.visible {
|
54
|
+
visibility: visible;
|
55
|
+
opacity: 1;
|
56
|
+
transition: visibility 0s linear 0s, opacity 300ms;
|
57
|
+
}
|
58
58
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
59
|
+
&.hidden {
|
60
|
+
visibility: hidden;
|
61
|
+
opacity: 0;
|
62
|
+
transition: visibility 0s linear 300ms, opacity 300ms;
|
63
|
+
}
|
64
64
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
`
|
65
|
+
@media (max-width: 425px) {
|
66
|
+
background: white;
|
67
|
+
}
|
68
|
+
`
|
69
69
|
|
70
70
|
const ModalContainer = styled.div`
|
71
71
|
align-self: center;
|
@@ -94,7 +94,7 @@ export const stringToNumber = ({
|
|
94
94
|
|
95
95
|
export const numberToString = ({ value, numberPrecision, minDecimals }) => {
|
96
96
|
const minimumRounding = minDecimals ? minDecimals : 0
|
97
|
-
value = parseFloat(value)
|
97
|
+
value = !Number.isNaN(parseFloat(value)) ? parseFloat(value) : 0
|
98
98
|
return value.toLocaleString(langForLocaleString(), {
|
99
99
|
minimumFractionDigits: minimumRounding, // removing this for now. Why do we need this to be a minimum amount?
|
100
100
|
maximumFractionDigits:
|
@@ -1,66 +0,0 @@
|
|
1
|
-
import { mount } from '@vue/test-utils'
|
2
|
-
import RCIcon from '@/components/icon'
|
3
|
-
import theme from '@/assets/theme'
|
4
|
-
import 'jest-styled-components'
|
5
|
-
jest.mock('@/components/icon/iconCache.mjs', () => ({
|
6
|
-
fetchIcon: jest.fn(() => Promise.resolve('mocked-icon-url.svg')),
|
7
|
-
}))
|
8
|
-
|
9
|
-
describe('RCIcon.vue', () => {
|
10
|
-
it('renders icon with default props', async () => {
|
11
|
-
const wrapper = mount(RCIcon, {
|
12
|
-
props: { name: 'House' },
|
13
|
-
global: {
|
14
|
-
provide: {
|
15
|
-
theme,
|
16
|
-
},
|
17
|
-
},
|
18
|
-
})
|
19
|
-
|
20
|
-
const iconWrapper = wrapper.find('[data-test-id="icon_wrapper"]')
|
21
|
-
const iconImage = wrapper.find('[data-test-id="icon_image"]')
|
22
|
-
|
23
|
-
expect(iconWrapper.exists()).toBe(true)
|
24
|
-
expect(iconImage.exists()).toBe(true)
|
25
|
-
expect(wrapper.props('size')).toBe('30px')
|
26
|
-
})
|
27
|
-
|
28
|
-
it('renders striked line when isStriked is true', async () => {
|
29
|
-
const wrapper = mount(RCIcon, {
|
30
|
-
props: {
|
31
|
-
name: 'House',
|
32
|
-
isStriked: true,
|
33
|
-
color: 'red',
|
34
|
-
},
|
35
|
-
global: {
|
36
|
-
provide: {
|
37
|
-
theme,
|
38
|
-
},
|
39
|
-
},
|
40
|
-
})
|
41
|
-
|
42
|
-
const strikedLine = wrapper.find('[data-test-id="icon_striked_line"]')
|
43
|
-
expect(strikedLine.exists()).toBe(true)
|
44
|
-
})
|
45
|
-
|
46
|
-
it('applies correct styling based on props', async () => {
|
47
|
-
const wrapper = mount(RCIcon, {
|
48
|
-
props: {
|
49
|
-
name: 'House',
|
50
|
-
size: '60px',
|
51
|
-
color: 'red',
|
52
|
-
hoveredColor: 'blue',
|
53
|
-
backgroundColor: 'yellow',
|
54
|
-
},
|
55
|
-
global: {
|
56
|
-
provide: {
|
57
|
-
theme,
|
58
|
-
},
|
59
|
-
},
|
60
|
-
})
|
61
|
-
|
62
|
-
const iconImage = wrapper.find('[data-test-id="icon_image"]')
|
63
|
-
expect(iconImage.exists()).toBe(true)
|
64
|
-
// Add assertions for styling if needed
|
65
|
-
})
|
66
|
-
})
|