@eturnity/eturnity_reusable_components 8.13.13-EPDM-6306.0 → 8.13.13-epic-shading.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eturnity/eturnity_reusable_components",
3
- "version": "8.13.13-EPDM-6306.0",
3
+ "version": "8.13.13-epic-shading.0",
4
4
  "files": [
5
5
  "dist",
6
6
  "src"
@@ -0,0 +1,3 @@
1
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M8 0.5C8.27614 0.5 8.5 0.723858 8.5 1V2.86667C8.5 3.14281 8.27614 3.36667 8 3.36667C7.72386 3.36667 7.5 3.14281 7.5 2.86667V1C7.5 0.723858 7.72386 0.5 8 0.5ZM0.5 8C0.5 7.72386 0.723858 7.5 1 7.5H2.86667C3.14281 7.5 3.36667 7.72386 3.36667 8C3.36667 8.27614 3.14281 8.5 2.86667 8.5H1C0.723858 8.5 0.5 8.27614 0.5 8ZM12.6333 8C12.6333 7.72386 12.8572 7.5 13.1333 7.5H15C15.2761 7.5 15.5 7.72386 15.5 8C15.5 8.27614 15.2761 8.5 15 8.5H13.1333C12.8572 8.5 12.6333 8.27614 12.6333 8ZM8.99987 10.8145C9.09475 11.0816 9.39061 11.2244 9.64095 11.0915C10.059 10.8696 10.4293 10.5644 10.728 10.1927C11.1343 9.6872 11.3922 9.0787 11.4728 8.43514C11.5535 7.79158 11.4537 7.13827 11.1847 6.54812C10.9156 5.95796 10.4879 5.45417 9.94915 5.09297C9.41045 4.73177 8.78197 4.52736 8.13385 4.50256C7.48573 4.47776 6.84347 4.63353 6.27873 4.9525C5.71399 5.27148 5.24899 5.7411 4.93563 6.30896C4.70526 6.72642 4.56349 7.1849 4.51696 7.65586C4.48909 7.93792 4.73355 8.15738 5.01665 8.14374C5.29975 8.1301 5.51274 7.8874 5.55771 7.60756C5.60274 7.32731 5.69588 7.05561 5.83426 6.80486C6.05573 6.40352 6.38437 6.07162 6.7835 5.84619C7.18262 5.62076 7.63654 5.51066 8.0946 5.52819C8.55265 5.54572 8.99683 5.69019 9.37756 5.94546C9.75829 6.20074 10.0606 6.55679 10.2507 6.97388C10.4409 7.39098 10.5114 7.8527 10.4544 8.30754C10.3974 8.76237 10.2152 9.19242 9.928 9.54971C9.74858 9.77293 9.5326 9.96227 9.29044 10.1103C9.04864 10.2582 8.90499 10.5474 8.99987 10.8145ZM5.17261 9.95833C5.36097 9.79137 5.64409 9.79046 5.83352 9.95621L8.82925 12.5775C8.93776 12.6724 9 12.8096 9 12.9538V14.5C9 14.7761 9.22386 15 9.5 15C9.77614 15 10 14.7761 10 14.5V12.9538C10 12.5212 9.81328 12.1097 9.48776 11.8249L6.49202 9.20363C5.92373 8.70638 5.0744 8.7091 4.5093 9.20998L1.50504 11.8728C1.18385 12.1575 1 12.5662 1 12.9954V14.5C1 14.7761 1.22386 15 1.5 15C1.77614 15 2 14.7761 2 14.5V12.9954C2 12.8523 2.06128 12.7161 2.16835 12.6212L5.17261 9.95833ZM3.40391 2.69668C3.20865 2.50142 2.89206 2.50142 2.6968 2.69668C2.50154 2.89194 2.50154 3.20852 2.6968 3.40379L4.01673 4.72372C4.212 4.91898 4.52858 4.91898 4.72384 4.72372C4.9191 4.52846 4.9191 4.21187 4.72384 4.01661L3.40391 2.69668ZM11.2764 4.01661C11.0811 4.21187 11.0811 4.52846 11.2764 4.72372C11.4716 4.91898 11.7882 4.91898 11.9835 4.72372L13.3034 3.40379C13.4987 3.20852 13.4987 2.89194 13.3034 2.69668C13.1081 2.50142 12.7916 2.50142 12.5963 2.69668L11.2764 4.01661ZM11.9835 11.2762C11.7882 11.081 11.4716 11.081 11.2764 11.2762C11.0811 11.4715 11.0811 11.7881 11.2764 11.9833L12.5963 13.3033C12.7916 13.4985 13.1081 13.4985 13.3034 13.3033C13.4987 13.108 13.4987 12.7914 13.3034 12.5962L11.9835 11.2762Z" fill="black"/>
3
+ </svg>
@@ -71,6 +71,7 @@ const theme = (() => {
71
71
  transparentWhite2: '#ffffff32',
72
72
  transparentWhite1: '#ffffff16',
73
73
  transparentBlack1: '#263238e6',
74
+ transparentBlack2: '#263238e5',
74
75
  transparentBlue1: '#20a4cae6',
75
76
  blueElectric: '#66dffa',
76
77
  eturnityGrey: '#263238',
@@ -0,0 +1,16 @@
1
+ const defaultProps = {
2
+ title: 'Sample Title',
3
+ infoText: 'Sample Info Text',
4
+ initialPosition: { top: '0px', left: '0px' },
5
+ minWidth: '284px',
6
+ maxWidth: '284px',
7
+ dragTargets: ['document'],
8
+ dragBounds: {},
9
+ sampleBody1:
10
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
11
+ sampleBody2:
12
+ 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.',
13
+ sampleFooter: 'Sample footer',
14
+ }
15
+
16
+ export default defaultProps
@@ -0,0 +1,99 @@
1
+ import { mount } from '@vue/test-utils'
2
+ import DraggableCard from '@/components/draggableCard'
3
+ import defaultProps from './defaultProps'
4
+
5
+ jest.mock('@/components/icon/iconCache.mjs', () => ({
6
+ // need to mock this due to how jest handles import.meta
7
+ fetchIcon: jest.fn(() => Promise.resolve('mocked-icon-url.svg')),
8
+ }))
9
+
10
+ describe('DraggableCard.vue', () => {
11
+ it('renders properly with required props', () => {
12
+ const wrapper = mount(DraggableCard, { props: defaultProps })
13
+ expect(
14
+ wrapper.find('[data-test-id="draggable_card_header"]').text()
15
+ ).toContain(defaultProps.title)
16
+
17
+ // Expect no footer rendered if not provided
18
+ const footerElement = wrapper.find('[data-test-id="draggable_card_footer"]')
19
+ expect(footerElement.exists()).toBe(false)
20
+ })
21
+
22
+ it('renders body slot content correctly', () => {
23
+ const wrapper = mount(DraggableCard, {
24
+ props: defaultProps,
25
+ slots: {
26
+ body: `
27
+ <div class="custom_body1">${defaultProps.sampleBody1}</div>
28
+ <div class="custom_body2">${defaultProps.sampleBody2}</div>
29
+ `,
30
+ },
31
+ })
32
+ expect(wrapper.find('.custom_body1').exists()).toBe(true)
33
+ expect(wrapper.text()).toContain(defaultProps.sampleBody1)
34
+ expect(wrapper.find('.custom_body2').exists()).toBe(true)
35
+ expect(wrapper.text()).toContain(defaultProps.sampleBody2)
36
+ })
37
+
38
+ it('renders footer slot content correctly', () => {
39
+ const wrapper = mount(DraggableCard, {
40
+ props: defaultProps,
41
+ slots: {
42
+ footer: `<div class="custom_footer">${defaultProps.sampleFooter}</div>`,
43
+ },
44
+ })
45
+ expect(
46
+ wrapper.find('[data-test-id="draggable_card_footer"]').exists()
47
+ ).toBe(true)
48
+ expect(wrapper.find('.custom_footer').exists()).toBe(true)
49
+ expect(wrapper.text()).toContain(defaultProps.sampleFooter)
50
+ })
51
+
52
+ it('emits "on-close" when close button is clicked', async () => {
53
+ const wrapper = mount(DraggableCard, { props: defaultProps })
54
+ await wrapper
55
+ .find('[data-test-id="draggable_card_close_button"]')
56
+ .trigger('click')
57
+ expect(wrapper.emitted('on-close')).toBeTruthy()
58
+ })
59
+
60
+ it('toggles collapse state when arrow icon is clicked', async () => {
61
+ const wrapper = mount(DraggableCard, {
62
+ props: { ...defaultProps, isCollapsible: true },
63
+ })
64
+ expect(wrapper.vm.isCollapsed).toBe(false)
65
+ await wrapper
66
+ .find('[data-test-id="draggable_card_collapse_button"]')
67
+ .trigger('click')
68
+ expect(wrapper.vm.isCollapsed).toBe(true)
69
+ })
70
+
71
+ it('handles drag start event', async () => {
72
+ const wrapper = mount(DraggableCard, { props: defaultProps })
73
+ await wrapper
74
+ .find('[data-test-id="draggable_card_drag_icon"]')
75
+ .trigger('mousedown', { clientX: 100, clientY: 100 })
76
+ expect(wrapper.vm.isDragging).toBe(true)
77
+ })
78
+
79
+ it('handles drag move event', async () => {
80
+ const wrapper = mount(DraggableCard, { props: defaultProps })
81
+ wrapper.vm.onDragStart(
82
+ { preventDefault: () => {}, clientX: 100, clientY: 100 },
83
+ false
84
+ )
85
+ wrapper.vm.onDrag({ preventDefault: () => {}, clientX: 120, clientY: 120 })
86
+ expect(wrapper.vm.eventCoordinates.x).toBe(120)
87
+ expect(wrapper.vm.eventCoordinates.y).toBe(120)
88
+ })
89
+
90
+ it('handles drag end event', async () => {
91
+ const wrapper = mount(DraggableCard, { props: defaultProps })
92
+ wrapper.vm.onDragStart(
93
+ { preventDefault: () => {}, clientX: 100, clientY: 100 },
94
+ false
95
+ )
96
+ wrapper.vm.onDragEnd()
97
+ expect(wrapper.vm.isDragging).toBe(false)
98
+ })
99
+ })
@@ -0,0 +1,79 @@
1
+ import defaultProps from './defaultProps'
2
+ import DraggableCard from './index.vue'
3
+ import styled from 'vue3-styled-components'
4
+ import theme from '@/assets/theme'
5
+
6
+ export default {
7
+ title: 'DraggableCard',
8
+ component: DraggableCard,
9
+ tags: ['autodocs'],
10
+ }
11
+
12
+ const TextContainer = styled.div`
13
+ font-family: ${theme.fonts.mainFont};
14
+ color: ${theme.colors.white};
15
+ font-weight: 400;
16
+ font-size: 14px;
17
+ line-height: 21px;
18
+ letter-spacing: 0%;
19
+ `
20
+
21
+ const CompleteTemplate = (args) => {
22
+ return {
23
+ components: { DraggableCard, TextContainer },
24
+ setup() {
25
+ return { args }
26
+ },
27
+ template: `
28
+ <DraggableCard v-bind="args">
29
+ <template #body>
30
+ <TextContainer>{{ args.sampleBody1 }}</TextContainer>
31
+ <TextContainer>{{ args.sampleBody2 }}</TextContainer>
32
+ </template>
33
+ <template #footer>
34
+ <TextContainer>{{ args.sampleFooter }}</TextContainer>
35
+ </template>
36
+ </DraggableCard>
37
+ `,
38
+ }
39
+ }
40
+
41
+ export const Default = CompleteTemplate.bind({})
42
+ Default.args = {
43
+ ...defaultProps,
44
+ }
45
+
46
+ export const NotCollapsible = CompleteTemplate.bind({})
47
+ NotCollapsible.args = {
48
+ ...defaultProps,
49
+ isCollapsible: false,
50
+ }
51
+
52
+ export const AdjustWidth = CompleteTemplate.bind({})
53
+ AdjustWidth.args = {
54
+ ...defaultProps,
55
+ minWidth: '100px',
56
+ maxWidth: '500px',
57
+ }
58
+
59
+ const NoFooterTemplate = (args) => {
60
+ return {
61
+ components: { DraggableCard, TextContainer },
62
+ setup() {
63
+ return { args }
64
+ },
65
+ template: `
66
+ <DraggableCard v-bind="args">
67
+ <template #body>
68
+ <TextContainer>{{ args.sampleBody1 }}</TextContainer>
69
+ <TextContainer>{{ args.sampleBody2 }}</TextContainer>
70
+ </template>
71
+ </DraggableCard>
72
+ `,
73
+ }
74
+ }
75
+
76
+ export const NoFooter = NoFooterTemplate.bind({})
77
+ NoFooter.args = {
78
+ ...defaultProps,
79
+ }
@@ -0,0 +1,354 @@
1
+ <template>
2
+ <CardContainer
3
+ data-test-id="draggable_card_container"
4
+ :initial-position="initialPosition"
5
+ :max-width="maxWidth"
6
+ :min-width="minWidth"
7
+ >
8
+ <HeaderContainer data-test-id="draggable_card_header">
9
+ <SubHeaderWrapper>
10
+ <LeftIconsContainer>
11
+ <DragHandleWrapper :class="{ dragging: isDragging }">
12
+ <RCIcon
13
+ :color="theme.colors.grey3"
14
+ data-test-id="draggable_card_drag_icon"
15
+ name="drag_icon"
16
+ size="14px"
17
+ :title="$gettext('drag_drop')"
18
+ @mousedown="(event) => onDragStart(event, false)"
19
+ @touchstart="
20
+ (event) => {
21
+ onDragStart(event, true)
22
+ }
23
+ "
24
+ />
25
+ </DragHandleWrapper>
26
+ <ArrowIconWrapper
27
+ v-if="isCollapsible"
28
+ data-test-id="draggable_card_collapse_button"
29
+ :is-collapsed="isCollapsed"
30
+ @click="toggleCollapse"
31
+ >
32
+ <CollapseArrowIcon />
33
+ </ArrowIconWrapper>
34
+ </LeftIconsContainer>
35
+ <TitleContainer :data-id="titleDataId">
36
+ <TextContainer>{{ title }}</TextContainer>
37
+ <InfoText v-if="infoText?.length" :text="infoText" />
38
+ </TitleContainer>
39
+ </SubHeaderWrapper>
40
+ <CloseButton
41
+ class="close"
42
+ data-test-id="draggable_card_close_button"
43
+ @click="$emit('on-close')"
44
+ />
45
+ </HeaderContainer>
46
+ <BodyContainer v-if="!isCollapsed" data-test-id="draggable_card_body">
47
+ <slot name="body"></slot>
48
+ </BodyContainer>
49
+ <FooterContainer v-if="$slots.footer" data-test-id="draggable_card_footer">
50
+ <slot name="footer"></slot>
51
+ </FooterContainer>
52
+ </CardContainer>
53
+ </template>
54
+
55
+ <script>
56
+ import styled from 'vue3-styled-components'
57
+ import theme from '../../assets/theme.js'
58
+ import RCIcon from '../icon'
59
+ import CloseButton from '../buttons/closeButton'
60
+ import InfoText from '../infoText'
61
+ import CollapseArrowIcon from '../../assets/icons/collapse_arrow_icon.svg'
62
+
63
+ const CardContainerAttr = {
64
+ initialPosition: Object,
65
+ minWidth: String,
66
+ maxWidth: String,
67
+ }
68
+ const CardContainer = styled('div', CardContainerAttr)`
69
+ position: absolute;
70
+ display: flex;
71
+ flex-direction: column;
72
+ border-radius: 4px;
73
+ min-width: ${(props) => props.minWidth};
74
+ max-width: ${(props) => props.maxWidth};
75
+ background: ${theme.colors.transparentBlack2};
76
+ z-index: 5;
77
+ ${(props) =>
78
+ props.initialPosition?.top && `top: ${props.initialPosition.top};`}
79
+ ${(props) =>
80
+ props.initialPosition?.right && `right: ${props.initialPosition.right};`}
81
+ ${(props) =>
82
+ props.initialPosition?.left && `left: ${props.initialPosition.left};`}
83
+ ${(props) =>
84
+ props.initialPosition?.bottom &&
85
+ `bottom: ${props.initialPosition.bottom};`}
86
+ `
87
+
88
+ const HeaderContainer = styled.div`
89
+ display: flex;
90
+ align-items: center;
91
+ justify-content: space-between;
92
+ padding: 8px;
93
+ `
94
+
95
+ const SubHeaderWrapper = styled.div`
96
+ display: flex;
97
+ min-width: 180px;
98
+ align-items: center;
99
+ justify-content: space-between;
100
+ height: fit-content;
101
+ margin-right: 14px;
102
+ `
103
+
104
+ const LeftIconsContainer = styled.div`
105
+ display: flex;
106
+ align-items: center;
107
+ gap: 4px;
108
+ margin-right: 14px;
109
+ `
110
+
111
+ const TitleContainer = styled.div`
112
+ display: flex;
113
+ align-items: center;
114
+ gap: 8px;
115
+ `
116
+
117
+ const TextContainer = styled.div`
118
+ font-family: ${theme.fonts.mainFont};
119
+ font-weight: 600;
120
+ font-size: 14px;
121
+ line-height: 19.6px;
122
+ letter-spacing: -1%;
123
+ color: ${theme.colors.white};
124
+ word-break: break-word;
125
+ overflow-wrap: break-word;
126
+ white-space: normal;
127
+ `
128
+
129
+ const DragHandleWrapper = styled.div`
130
+ display: grid;
131
+ align-items: center;
132
+ justify-items: center;
133
+ width: 26px;
134
+ height: 26px;
135
+ cursor: grab;
136
+ &.dragging {
137
+ cursor: grabbing;
138
+ }
139
+ `
140
+
141
+ const collapsedAttrs = {
142
+ isCollapsed: Boolean,
143
+ }
144
+ const ArrowIconWrapper = styled('div', collapsedAttrs)`
145
+ display: flex;
146
+ align-items: center;
147
+ justify-content: center;
148
+ width: 8px;
149
+ height: 26px;
150
+ cursor: pointer;
151
+ transition: transform 0.3s ease;
152
+ path {
153
+ fill: ${theme.colors.white};
154
+ }
155
+
156
+ ${(props) => props.isCollapsed && 'transform: rotate(-180deg);'}
157
+ `
158
+
159
+ const BodyContainer = styled.div`
160
+ display: flex;
161
+ flex-direction: column;
162
+ gap: 16px;
163
+ padding-top: 8px;
164
+ padding-right: 16px;
165
+ padding-bottom: 8px;
166
+ padding-left: 16px;
167
+ word-break: break-word;
168
+ overflow-wrap: break-word;
169
+ white-space: normal;
170
+ `
171
+
172
+ const FooterContainer = styled.div`
173
+ display: flex;
174
+ border-radius: 4px;
175
+ align-items: center;
176
+ justify-content: space-between;
177
+ padding: 8px;
178
+ background: ${theme.colors.eturnityGrey};
179
+ word-break: break-word;
180
+ overflow-wrap: break-word;
181
+ white-space: normal;
182
+ `
183
+
184
+ export default {
185
+ name: 'DraggableCard',
186
+ components: {
187
+ CardContainer,
188
+ HeaderContainer,
189
+ SubHeaderWrapper,
190
+ LeftIconsContainer,
191
+ TextContainer,
192
+ DragHandleWrapper,
193
+ ArrowIconWrapper,
194
+ CollapseArrowIcon,
195
+ RCIcon,
196
+ CloseButton,
197
+ InfoText,
198
+ TitleContainer,
199
+ BodyContainer,
200
+ FooterContainer,
201
+ },
202
+ props: {
203
+ minWidth: {
204
+ required: true,
205
+ type: String,
206
+ },
207
+ maxWidth: {
208
+ required: true,
209
+ type: String,
210
+ },
211
+ initialPosition: {
212
+ required: true,
213
+ type: Object,
214
+ },
215
+ title: {
216
+ required: true,
217
+ type: String,
218
+ },
219
+ titleDataId: {
220
+ required: false,
221
+ type: String,
222
+ default: '',
223
+ },
224
+ isCollapsible: {
225
+ required: false,
226
+ type: Boolean,
227
+ default: true,
228
+ },
229
+ infoText: {
230
+ required: false,
231
+ type: String,
232
+ default: '',
233
+ },
234
+ dragTargets: {
235
+ required: false,
236
+ type: Array,
237
+ default: () => ['document'],
238
+ },
239
+ dragBounds: {
240
+ required: false,
241
+ type: Object,
242
+ default: () => {},
243
+ },
244
+ },
245
+ emits: ['on-close'],
246
+ data() {
247
+ return {
248
+ isCollapsed: false,
249
+ isDragging: false,
250
+ isTouchStart: false,
251
+ eventCoordinates: {
252
+ x: 0,
253
+ y: 0,
254
+ },
255
+ }
256
+ },
257
+ computed: {
258
+ dragBoundsEnabled() {
259
+ const minPosition = this.dragBounds?.min
260
+ const maxPosition = this.dragBounds?.max
261
+ return (
262
+ minPosition?.top &&
263
+ minPosition?.left &&
264
+ maxPosition?.top &&
265
+ maxPosition?.left
266
+ )
267
+ },
268
+ theme() {
269
+ return theme
270
+ },
271
+ },
272
+ beforeUnmount() {
273
+ this.removeEvents()
274
+ },
275
+ methods: {
276
+ toggleCollapse() {
277
+ this.isCollapsed = !this.isCollapsed
278
+ },
279
+ onDragStart(e, isTouchStart) {
280
+ e.preventDefault()
281
+ this.isDragging = true
282
+ this.isTouchStart = isTouchStart
283
+ this.eventCoordinates.x = isTouchStart
284
+ ? e.touches[0].clientX
285
+ : e.clientX
286
+ this.eventCoordinates.y = isTouchStart
287
+ ? e.touches[0].clientY
288
+ : e.clientY
289
+ this.dragTargets.forEach((id) => {
290
+ const target =
291
+ id === 'document' ? document : document.getElementById(id)
292
+ if (target && target.addEventListener) {
293
+ target.addEventListener(
294
+ isTouchStart ? 'touchend' : 'mouseup',
295
+ this.onDragEnd
296
+ )
297
+ target.addEventListener(
298
+ isTouchStart ? 'touchmove' : 'mousemove',
299
+ this.onDrag
300
+ )
301
+ }
302
+ })
303
+ document.addEventListener(
304
+ isTouchStart ? 'touchend' : 'mouseup',
305
+ this.onDragEnd
306
+ )
307
+ },
308
+ onDrag(e) {
309
+ e.preventDefault()
310
+ const eventX = this.isTouchStart ? e.touches[0].clientX : e.clientX
311
+ const eventY = this.isTouchStart ? e.touches[0].clientY : e.clientY
312
+ const deltaX = this.eventCoordinates.x - eventX
313
+ const deltaY = this.eventCoordinates.y - eventY
314
+ this.eventCoordinates.x = eventX
315
+ this.eventCoordinates.y = eventY
316
+ const element = this.$el
317
+ let positionY = element.offsetTop - deltaY
318
+ let positionX = element.offsetLeft - deltaX
319
+ if (this.dragBoundsEnabled) {
320
+ const minPosition = this.dragBounds.min
321
+ const maxPosition = this.dragBounds.max
322
+ positionY = Math.min(
323
+ Math.max(positionY, minPosition.top),
324
+ maxPosition.top
325
+ )
326
+ positionX = Math.min(
327
+ Math.max(positionX, minPosition.left),
328
+ maxPosition.left
329
+ )
330
+ }
331
+ element.style.top = positionY + 'px'
332
+ element.style.left = positionX + 'px'
333
+ },
334
+ onDragEnd() {
335
+ this.isDragging = false
336
+ this.removeEvents()
337
+ },
338
+ removeEvents() {
339
+ this.dragTargets.forEach((id) => {
340
+ const target =
341
+ id === 'document' ? document : document.getElementById(id)
342
+ if (target && target.removeEventListener) {
343
+ target.removeEventListener('mouseup', this.onDragEnd)
344
+ target.removeEventListener('touchend', this.onDragEnd)
345
+ target.removeEventListener('mousemove', this.onDrag)
346
+ target.removeEventListener('touchmove', this.onDrag)
347
+ }
348
+ })
349
+ document.removeEventListener('mouseup', this.onDragEnd)
350
+ document.removeEventListener('touchend', this.onDragEnd)
351
+ },
352
+ },
353
+ }
354
+ </script>
@@ -44,7 +44,7 @@
44
44
  import styled from 'vue3-styled-components'
45
45
 
46
46
  const ComponentWrapper = styled.div`
47
- min-height: 18px;
47
+ min-height: 16px;
48
48
  `
49
49
 
50
50
  const CheckWrapper = styled('div', { hasLabel: Boolean })`
@@ -179,7 +179,7 @@
179
179
  font-size: 13px;
180
180
  display: grid;
181
181
  align-items: center;
182
- min-height: 18px;
182
+ min-height: 16px;
183
183
  color: ${(props) =>
184
184
  props.isDisabled ? props.theme.colors.grey2 : 'unset'};
185
185
  `
@@ -60,7 +60,7 @@
60
60
  :show-linear-unit-name="showLinearUnitName"
61
61
  :slot-size="slotSize"
62
62
  :text-align="textAlign"
63
- :value="formattedValue"
63
+ :value="formatWithCurrency(value)"
64
64
  @blur="onInputBlur($event)"
65
65
  @focus="focusInput()"
66
66
  @input="onInput($event)"
@@ -74,7 +74,7 @@
74
74
 
75
75
  <UnitContainer
76
76
  v-if="unitName && showLinearUnitName && !hasSlot"
77
- :has-length="hasLength"
77
+ :has-length="!!textInput.length"
78
78
  :is-error="isError"
79
79
  >{{ unitName }}</UnitContainer
80
80
  >
@@ -91,7 +91,7 @@
91
91
  :disabled="isSelectDisabled"
92
92
  :select-width="`${selectWidth}px`"
93
93
  :show-border="false"
94
- @input-change="handleSelectChange"
94
+ @input-change="$emit('select-change', $event)"
95
95
  >
96
96
  <template #selector>
97
97
  <SelectText>{{ getSelectValue }}</SelectText>
@@ -449,18 +449,8 @@
449
449
  background-color: ${({ theme }) => theme.colors.grey4};
450
450
  `
451
451
 
452
- const EVENT_TYPES = {
453
- INPUT_FOCUS: 'input-focus',
454
- INPUT_CHANGE: 'input-change',
455
- INPUT_BLUR: 'input-blur',
456
- PRESS_ENTER: 'on-enter-click',
457
- INPUT_DRAG: 'on-input-drag',
458
- SELECT_CHANGE: 'select-change',
459
- }
460
-
461
452
  export default {
462
453
  name: 'InputNumber',
463
- emits: [...Object.values(EVENT_TYPES)],
464
454
  components: {
465
455
  Container,
466
456
  InputContainer,
@@ -699,10 +689,9 @@
699
689
  },
700
690
  data() {
701
691
  return {
692
+ textInput: '',
702
693
  isFocused: false,
703
694
  warningIcon: warningIcon,
704
- inputValue: null,
705
- enteredValue: null,
706
695
  }
707
696
  },
708
697
  computed: {
@@ -725,14 +714,6 @@
725
714
 
726
715
  return item ? item.label : '-'
727
716
  },
728
- formattedValue() {
729
- return this.isFocused
730
- ? this.enteredValue
731
- : this.formatWithCurrency(this.value)
732
- },
733
- hasLength() {
734
- return this.formattedValue !== null && this.formattedValue.length > 0
735
- },
736
717
  },
737
718
  watch: {
738
719
  focus(value) {
@@ -743,19 +724,30 @@
743
724
  clearInput: function (value) {
744
725
  if (value) {
745
726
  // If the value is typed, then we should clear the textInput on Continue
746
- this.inputValue = ''
747
- this.enteredValue = ''
727
+ this.textInput = ''
748
728
  }
749
729
  },
750
- value: {
751
- immediate: true,
752
- handler(val) {
753
- if (this.value !== this.inputValue && !Number.isNaN(this.value)) {
754
- this.inputValue = this.value
755
- this.enteredValue = this.value
756
- }
757
- },
758
- },
730
+ },
731
+ created() {
732
+ if (this.value) {
733
+ this.textInput = numberToString({
734
+ value: this.value,
735
+ numberPrecision: this.numberPrecision,
736
+ minDecimals: this.minDecimals,
737
+ })
738
+ } else if (this.defaultNumber !== null) {
739
+ this.textInput = numberToString({
740
+ value: this.defaultNumber,
741
+ numberPrecision: this.numberPrecision,
742
+ minDecimals: this.minDecimals,
743
+ })
744
+ } else if (this.minNumber !== null) {
745
+ this.textInput = numberToString({
746
+ value: this.minNumber,
747
+ numberPrecision: this.numberPrecision,
748
+ minDecimals: this.minDecimals,
749
+ })
750
+ }
759
751
  },
760
752
  mounted() {
761
753
  if (this.focus) {
@@ -794,28 +786,29 @@
794
786
  }
795
787
  },
796
788
  onEnterPress() {
797
- this.$emit(EVENT_TYPES.PRESS_ENTER)
789
+ this.$emit('on-enter-click')
798
790
  this.$refs.inputField1.$el.blur()
799
791
  },
800
- onChangeHandler(value) {
801
- if (isNaN(value) || value === '') {
802
- value = this.defaultNumber
792
+ onChangeHandler(event) {
793
+ if (isNaN(event) || event === '') {
794
+ event = this.defaultNumber
803
795
  ? this.defaultNumber
804
796
  : this.minNumber || this.minNumber === 0
805
797
  ? this.minNumber
806
- : value
798
+ : event
807
799
  }
808
800
  if (!this.allowNegative) {
809
- value = Math.abs(value)
801
+ event = Math.abs(event)
810
802
  }
811
- value = parseFloat(value)
803
+ event = parseFloat(event)
812
804
  // Need to return an integer rather than a string
813
- return parseFloat(value)
805
+ this.$emit('input-change', event)
814
806
  },
815
- onEvaluateCode(value) {
807
+ onEvaluateCode(event) {
816
808
  // function to perform math on the code
817
809
  // filter the string in case of any malicious content
818
- let filtered = value.replace('(auto)', '').replace(/[^-()\d/*+.,]/g, '')
810
+ const val = event.target.value
811
+ let filtered = val.replace('(auto)', '').replace(/[^-()\d/*+.,]/g, '')
819
812
  filtered = filtered.split(/([-+*/()])/)
820
813
  let formatted = filtered.map((item) => {
821
814
  if (
@@ -873,29 +866,48 @@
873
866
  return array
874
867
  },
875
868
  onInput(event) {
876
- this.enteredValue = event.target.value
877
- if (!this.isFocused || this.enteredValue === this.inputValue) {
869
+ if (!this.isFocused) {
878
870
  return
879
871
  }
872
+ if (event.target.value === '') {
873
+ this.$emit('on-input', '')
874
+ }
880
875
  let evaluatedVal
881
876
  try {
882
- evaluatedVal = this.onEvaluateCode(String(this.enteredValue))
877
+ evaluatedVal = this.onEvaluateCode(event)
883
878
  } finally {
884
- this.inputValue = this.onChangeHandler(evaluatedVal)
885
-
886
- if (this.isFocused && typeof this.enteredValue !== 'number') {
887
- this.$emit(EVENT_TYPES.INPUT_CHANGE, this.inputValue)
879
+ if (evaluatedVal && this.value != evaluatedVal) {
880
+ this.$emit('on-input', evaluatedVal)
888
881
  }
889
882
  }
890
883
  this.textInput = evaluatedVal
891
884
  },
892
885
  onInputBlur(e) {
893
886
  this.isFocused = false
894
- this.enteredValue = this.inputValue
895
- this.$emit(
896
- EVENT_TYPES.INPUT_BLUR,
897
- this.onEvaluateCode(String(this.inputValue))
898
- )
887
+ let value = e.target.value
888
+ let evaluatedInput = this.onEvaluateCode(e)
889
+ this.onChangeHandler(evaluatedInput ? evaluatedInput : value)
890
+ if ((evaluatedInput && value.length) || this.minNumber !== null) {
891
+ this.textInput = numberToString({
892
+ value:
893
+ evaluatedInput && value.length
894
+ ? evaluatedInput
895
+ : this.defaultNumber
896
+ ? this.defaultNumber
897
+ : this.minNumber,
898
+ numberPrecision: this.numberPrecision,
899
+ minDecimals: this.minDecimals,
900
+ })
901
+ }
902
+ let adjustedMinValue =
903
+ evaluatedInput && evaluatedInput.length
904
+ ? evaluatedInput
905
+ : this.defaultNumber
906
+ ? this.defaultNumber
907
+ : this.minNumber || this.minNumber === 0
908
+ ? this.minNumber
909
+ : ''
910
+ this.$emit('input-blur', adjustedMinValue)
899
911
  },
900
912
  focusInput() {
901
913
  if (this.disabled) {
@@ -905,7 +917,7 @@
905
917
  this.$nextTick(() => {
906
918
  this.$refs.inputField1.$el.select()
907
919
  })
908
- this.$emit(EVENT_TYPES.INPUT_FOCUS, this.inputValue)
920
+ this.$emit('input-focus')
909
921
  },
910
922
  blurInput() {
911
923
  if (this.disabled) {
@@ -925,7 +937,7 @@
925
937
  : this.minNumber || this.minNumber === 0
926
938
  ? this.minNumber
927
939
  : ''
928
- if (adjustedMinValue || adjustedMinValue === 0) {
940
+ if ((adjustedMinValue || adjustedMinValue === 0) && !this.isFocused) {
929
941
  let input = this.numberToStringEnabled
930
942
  ? numberToString({
931
943
  value: adjustedMinValue,
@@ -938,8 +950,6 @@
938
950
  return input + ' ' + unit
939
951
  } else if (!adjustedMinValue && adjustedMinValue !== 0) {
940
952
  return ''
941
- } else if (this.isFocused) {
942
- return value
943
953
  } else {
944
954
  return this.numberToStringEnabled
945
955
  ? numberToString({
@@ -960,7 +970,14 @@
960
970
  e.preventDefault()
961
971
  let value = parseFloat(this.value || 0)
962
972
  value += parseFloat(this.interactionStep) * parseInt(e.movementX)
963
- this.$emit(EVENT_TYPES.INPUT_DRAG, this.onChangeHandler(value))
973
+ this.$emit('on-input-drag', value)
974
+
975
+ this.textInput = numberToString({
976
+ value: value && value.length ? value : this.minNumber,
977
+ numberPrecision: this.numberPrecision,
978
+ minDecimals: this.minDecimals,
979
+ })
980
+ //this.value=value
964
981
  },
965
982
  stopInteract(e) {
966
983
  e.preventDefault()
@@ -968,9 +985,6 @@
968
985
  window.removeEventListener('mouseup', this.stopInteract, false)
969
986
  this.blurInput()
970
987
  },
971
- handleSelectChange(value) {
972
- this.$emit(EVENT_TYPES.SELECT_CHANGE, value)
973
- },
974
988
  },
975
989
  }
976
990
  </script>
@@ -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 = !Number.isNaN(parseFloat(value)) ? parseFloat(value) : 0
97
+ value = parseFloat(value)
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: