@eturnity/eturnity_reusable_components 7.32.1 → 7.33.1

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/.eslintrc.js CHANGED
@@ -152,6 +152,8 @@ module.exports = {
152
152
  'no-multi-spaces': 'warn',
153
153
  'no-mixed-spaces-and-tabs': 'warn',
154
154
  'no-redeclare': 'warn',
155
+ 'vue/no-reserved-component-names': 'warn',
156
+ 'vue/no-deprecated-destroyed-lifecycle': 'warn',
155
157
  'no-prototype-builtins': 'warn',
156
158
  'no-unsafe-finally': 'warn',
157
159
  'max-len': [
package/babel.config.js CHANGED
@@ -1,5 +1,7 @@
1
1
  module.exports = {
2
- presets: [
3
- '@vue/cli-plugin-babel/preset'
4
- ]
2
+ presets: ['@vue/cli-plugin-babel/preset', '@babel/preset-env'],
3
+ plugins: [
4
+ '@babel/plugin-syntax-import-meta',
5
+ '@babel/plugin-transform-runtime',
6
+ ],
5
7
  }
package/jest.config.js ADDED
@@ -0,0 +1,19 @@
1
+ module.exports = {
2
+ transform: {
3
+ '^.+\\.vue$': 'vue-jest',
4
+ '^.+\\.js$': 'babel-jest',
5
+ },
6
+ moduleFileExtensions: ['js', 'json', 'vue'],
7
+ transformIgnorePatterns: ['<rootDir>/node_modules/'],
8
+ testMatch: ['**/src/**/*.spec.js'],
9
+ collectCoverageFrom: [
10
+ 'src/**/*.{js,vue}',
11
+ '!src/main.js',
12
+ '!src/router/index.js',
13
+ '!**/node_modules/**',
14
+ ],
15
+ moduleNameMapper: {
16
+ '^@/(.*)$': '<rootDir>/src/$1',
17
+ '^@/components/icon/iconCache$': '<rootDir>/tests/__mocks__/iconCache.js',
18
+ },
19
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eturnity/eturnity_reusable_components",
3
- "version": "7.32.1",
3
+ "version": "7.33.1",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "dev": "vue-cli-service serve",
@@ -8,7 +8,9 @@
8
8
  "lint": "vue-cli-service lint",
9
9
  "storybook": "start-storybook -p 6006",
10
10
  "build-storybook": "build-storybook",
11
- "prettier": "prettier --write 'src/**/*.{js,vue}'"
11
+ "prettier": "prettier --write 'src/**/*.{js,vue}'",
12
+ "test": "jest",
13
+ "prepublishOnly": "npm run test"
12
14
  },
13
15
  "dependencies": {
14
16
  "@storybook/vue3": "7.0.18",
@@ -19,19 +21,53 @@
19
21
  "html-loader": "0.5.5",
20
22
  "postcss": "8.4.25",
21
23
  "vue": "3.3.4",
24
+ "vue-router": "^4.4.2",
22
25
  "vue3-styled-components": "1.2.1",
23
26
  "vuedraggable": "4.1.0"
24
27
  },
25
28
  "devDependencies": {
26
- "babel-eslint": "10.1.0",
29
+ "@babel/core": "^7.25.2",
30
+ "@babel/plugin-syntax-import-meta": "^7.10.4",
31
+ "@babel/preset-env": "^7.25.3",
32
+ "@types/node": "^22.1.0",
33
+ "@vue/cli-plugin-babel": "^5.0.8",
27
34
  "@vue/cli-plugin-eslint": "5.0.8",
28
- "@vue/cli-service": "5.0.8",
35
+ "@vue/cli-service": "^5.0.8",
29
36
  "@vue/compiler-sfc": "3.3.4",
37
+ "@vue/test-utils": "^2.4.6",
38
+ "babel-eslint": "10.1.0",
39
+ "babel-jest": "^26.6.3",
30
40
  "eslint": "8.0.1",
31
41
  "eslint-config-prettier": "8.8.0",
32
42
  "eslint-plugin-prettier": "4.2.1",
33
43
  "eslint-plugin-vue": "9.14.1",
34
- "prettier": "2.8.4"
44
+ "jest": "^26.6.3",
45
+ "prettier": "2.8.4",
46
+ "vue-jest": "^5.0.0-alpha.10"
47
+ },
48
+ "jest": {
49
+ "preset": "@vue/cli-plugin-unit-jest",
50
+ "transform": {
51
+ "^.+\\.vue$": "vue-jest",
52
+ "^.+\\.js$": "babel-jest"
53
+ },
54
+ "moduleFileExtensions": [
55
+ "js",
56
+ "json",
57
+ "vue"
58
+ ],
59
+ "transformIgnorePatterns": [
60
+ "<rootDir>/node_modules/"
61
+ ],
62
+ "testMatch": [
63
+ "**/tests/unit/**/*.spec.js"
64
+ ],
65
+ "collectCoverageFrom": [
66
+ "src/**/*.{js,vue}",
67
+ "!src/main.js",
68
+ "!src/router/index.js",
69
+ "!**/node_modules/**"
70
+ ]
35
71
  },
36
72
  "browserslist": [
37
73
  "> 1%",
package/src/App.vue CHANGED
@@ -1,99 +1,19 @@
1
1
  <template>
2
2
  <ThemeProvider :style="{ height: '100%' }" :theme="getTheme()">
3
- <PageContainer>
4
- <br />
5
- <InputNumber
6
- background-color="transparent"
7
- border-color="eturnityGrey"
8
- input-height="34px"
9
- input-width="420px"
10
- :interaction-step="1"
11
- :is-interactive="true"
12
- :min-number="0"
13
- :number-precision="0"
14
- text-align="left"
15
- unit-name="mm"
16
- :value="value"
17
- @input-blur="blurHandler"
18
- @input-change="changeHandler"
19
- @input-focus="focusHandler"
20
- @on-input="inputHandler"
21
- >
22
- <template #label>
23
- <div>Interactive Label 1</div>
24
- </template>
25
- </InputNumber>
26
-
27
- <hr />
28
-
29
- <InputNumber
30
- background-color="transparent"
31
- border-color="eturnityGrey"
32
- input-height="34px"
33
- input-width="420px"
34
- :interaction-step="1"
35
- :is-interactive="true"
36
- :min-number="0"
37
- :number-precision="0"
38
- text-align="left"
39
- unit-name="mm"
40
- :value="value"
41
- @input-blur="blurHandler"
42
- @input-change="changeHandler"
43
- @input-focus="focusHandler"
44
- @on-input="inputHandler"
45
- >
46
- <template #label>
47
- <div>Interactive Label 2</div>
48
- </template>
49
- </InputNumber>
50
-
51
- <hr />
52
- <button @click="value = 42">Click to set at 42</button>
53
- </PageContainer>
3
+ <RouterView />
54
4
  </ThemeProvider>
55
5
  </template>
56
6
 
57
7
  <script>
58
8
  import { ThemeProvider } from 'vue3-styled-components'
59
9
  import theme from './assets/theme'
60
- import styled from 'vue3-styled-components'
61
- import InputNumber from '@/components/inputs/inputNumber'
62
-
63
- const PageContainer = styled.div`
64
- padding: 40px;
65
- `
66
10
 
67
11
  export default {
68
12
  name: 'App',
69
13
  components: {
70
14
  ThemeProvider,
71
- PageContainer,
72
- InputNumber,
73
- },
74
- data() {
75
- return {
76
- value: 42,
77
- }
78
15
  },
79
- computed: {},
80
16
  methods: {
81
- blurHandler(e) {
82
- console.log('blur', e)
83
- },
84
- changeHandler(e) {
85
- console.log('change', e)
86
- },
87
- focusHandler(e) {
88
- console.log('focus', e)
89
- },
90
- inputHandler(e) {
91
- console.log('input', e)
92
- //this.value = e
93
- setTimeout(() => {
94
- this.value = e
95
- }, 1000)
96
- },
97
17
  getTheme() {
98
18
  return theme
99
19
  },
package/src/Test.vue ADDED
@@ -0,0 +1,102 @@
1
+ <template>
2
+ <PageContainer>
3
+ <br />
4
+ <InputNumber
5
+ background-color="transparent"
6
+ border-color="eturnityGrey"
7
+ input-height="34px"
8
+ input-width="420px"
9
+ :interaction-step="1"
10
+ :is-interactive="true"
11
+ :min-number="0"
12
+ :number-precision="0"
13
+ text-align="left"
14
+ unit-name="mm"
15
+ :value="value"
16
+ @input-blur="blurHandler"
17
+ @input-change="changeHandler"
18
+ @input-focus="focusHandler"
19
+ @on-input="inputHandler"
20
+ >
21
+ <template #label>
22
+ <div>Interactive Label 1</div>
23
+ </template>
24
+ </InputNumber>
25
+
26
+ <hr />
27
+
28
+ <InputNumber
29
+ background-color="transparent"
30
+ border-color="eturnityGrey"
31
+ input-height="34px"
32
+ input-width="420px"
33
+ :interaction-step="1"
34
+ :is-interactive="true"
35
+ :min-number="0"
36
+ :number-precision="0"
37
+ text-align="left"
38
+ unit-name="mm"
39
+ :value="value"
40
+ @input-blur="blurHandler"
41
+ @input-change="changeHandler"
42
+ @input-focus="focusHandler"
43
+ @on-input="inputHandler"
44
+ >
45
+ <template #label>
46
+ <div>Interactive Label 2</div>
47
+ </template>
48
+ </InputNumber>
49
+
50
+ <hr />
51
+ <button @click="value = 42">Click to set at 42</button>
52
+ </PageContainer>
53
+ </template>
54
+
55
+ <script>
56
+ import styled from 'vue3-styled-components'
57
+ import InputNumber from '@/components/inputs/inputNumber'
58
+
59
+ const PageContainer = styled.div`
60
+ padding: 40px;
61
+ `
62
+
63
+ export default {
64
+ name: 'App',
65
+ components: {
66
+ PageContainer,
67
+ InputNumber,
68
+ },
69
+ data() {
70
+ return {
71
+ value: 42,
72
+ }
73
+ },
74
+ computed: {},
75
+ methods: {
76
+ blurHandler(e) {
77
+ console.log('blur', e)
78
+ },
79
+ changeHandler(e) {
80
+ console.log('change', e)
81
+ },
82
+ focusHandler(e) {
83
+ console.log('focus', e)
84
+ },
85
+ inputHandler(e) {
86
+ console.log('input', e)
87
+ //this.value = e
88
+ setTimeout(() => {
89
+ this.value = e
90
+ }, 1000)
91
+ },
92
+ },
93
+ }
94
+ </script>
95
+
96
+ <style>
97
+ html,
98
+ body {
99
+ height: 100%;
100
+ margin: 0;
101
+ }
102
+ </style>
@@ -0,0 +1 @@
1
+ export const fetchIcon = jest.fn(() => Promise.resolve('mocked-icon-url.svg'))
@@ -0,0 +1,12 @@
1
+ export function convertHexToRGB(hex) {
2
+ // Remove the '#' if it's included in the input
3
+ hex = hex.replace(/^#/, '')
4
+
5
+ // Parse the hex values into separate R, G, and B values
6
+ const red = parseInt(hex.substring(0, 2), 16)
7
+ const green = parseInt(hex.substring(2, 4), 16)
8
+ const blue = parseInt(hex.substring(4, 6), 16)
9
+
10
+ // Return the RGB values as a string
11
+ return `rgb(${red}, ${green}, ${blue})`
12
+ }
@@ -72,7 +72,12 @@
72
72
  </IconWrapper>
73
73
  <SelectWrapper v-if="showSelect">
74
74
  <Divider />
75
+ <<<<<<< HEAD
76
+ <RCSelect
77
+ =======
75
78
  <Select
79
+ :disabled="isSelectDisabled"
80
+ >>>>>>> f7f274d10df532971e44249a355b2a458d105e1c
76
81
  :select-width="`${selectWidth}px`"
77
82
  :show-border="false"
78
83
  @input-change="$emit('select-change', $event)"
@@ -81,15 +86,15 @@
81
86
  <SelectText>{{ getSelectValue }}</SelectText>
82
87
  </template>
83
88
  <template #dropdown>
84
- <Option
89
+ <RCOption
85
90
  v-for="item in selectOptions"
86
91
  :key="item.value"
87
92
  :value="item.value"
88
93
  >
89
94
  {{ item.label }}
90
- </Option>
95
+ </RCOption>
91
96
  </template>
92
- </Select>
97
+ </RCSelect>
93
98
  </SelectWrapper>
94
99
  </InputWrapper>
95
100
  <ErrorMessage v-if="isError">{{ errorMessage }}</ErrorMessage>
@@ -132,8 +137,8 @@
132
137
  } from '../../../helpers/numberConverter'
133
138
  import InfoText from '../../infoText'
134
139
  import ErrorMessage from '../../errorMessage'
135
- import Select from '../select'
136
- import Option from '../select/option'
140
+ import RCSelect from '../select'
141
+ import RCOption from '../select/option'
137
142
  import warningIcon from '../../../assets/icons/error_icon.png'
138
143
  import Icon from '../../icon'
139
144
 
@@ -353,8 +358,8 @@
353
358
  Icon,
354
359
  SlotContainer,
355
360
  IconWrapper,
356
- Select,
357
- Option,
361
+ RCSelect,
362
+ RCOption,
358
363
  SelectWrapper,
359
364
  SelectText,
360
365
  Divider,
@@ -511,6 +516,10 @@
511
516
  type: [String, Number],
512
517
  default: null,
513
518
  },
519
+ isSelectDisabled: {
520
+ type: Boolean,
521
+ default: false,
522
+ },
514
523
  },
515
524
  data() {
516
525
  return {
@@ -13,7 +13,7 @@
13
13
  <LabelWrapper
14
14
  v-if="label"
15
15
  :data-id="labelDataId"
16
- :info-text-message="!!infoTextMessage"
16
+ :info-text-message="!!infoTextMessage || !!$slots.infoText"
17
17
  >
18
18
  <InputLabel
19
19
  :font-color="
@@ -181,6 +181,7 @@
181
181
  import Icon from '../../icon'
182
182
  import InputText from '../inputText'
183
183
  import DraggableInputHandle from '../../draggableInputHandle'
184
+ import { debounce } from '../../../utils'
184
185
 
185
186
  const CARET_WIDTH = '30px'
186
187
  const BORDER_WIDTH = '1px'
@@ -733,9 +734,9 @@
733
734
  this.blur()
734
735
  this.$emit('input-change', e)
735
736
  },
736
- optionHovered(e) {
737
+ optionHovered: debounce(function (e) {
737
738
  this.hoveredValue = e
738
- },
739
+ }, 300),
739
740
  mouseEnterHandler() {
740
741
  if (this.hoverDropdown) {
741
742
  this.focus()
@@ -2,15 +2,21 @@
2
2
  <Container>
3
3
  <FlexWrapper
4
4
  :data-id="dataId"
5
+ data-test-id="page_wrapper"
5
6
  :disabled="disabled"
6
7
  :size="size"
7
8
  @click="onToggleChange"
8
9
  >
9
10
  <LabelContainer
10
11
  v-if="label && labelAlign === 'left'"
12
+ data-test-id="label_left_container"
11
13
  :has-info-message="!!infoTextMessage"
12
14
  >
13
- <LabelText :font-color="fontColor" :size="size">
15
+ <LabelText
16
+ data-test-id="label_left_text"
17
+ :font-color="fontColor"
18
+ :size="size"
19
+ >
14
20
  {{ label }}
15
21
  </LabelText>
16
22
  <InfoText v-if="infoTextMessage" :text="infoTextMessage" />
@@ -18,6 +24,7 @@
18
24
  <ToggleWrapper
19
25
  :background-color="backgroundColor"
20
26
  :checked="isChecked"
27
+ data-test-id="toggle_wrapper"
21
28
  :disabled="disabled"
22
29
  :is-checked="isChecked"
23
30
  role="checkbox"
@@ -27,10 +34,12 @@
27
34
  >
28
35
  <ToggleBackground
29
36
  :background-color="backgroundColor"
37
+ data-test-id="toggle_background"
30
38
  :disabled="disabled"
31
39
  :is-checked="isChecked"
32
40
  />
33
41
  <ToggleDot
42
+ data-test-id="toggle_dot"
34
43
  :disabled="disabled"
35
44
  :is-checked="isChecked"
36
45
  :size="size"
@@ -39,12 +48,22 @@
39
48
  </ToggleWrapper>
40
49
  <LabelContainer
41
50
  v-if="label && labelAlign === 'right'"
51
+ data-test-id="label_right_container"
42
52
  :has-info-message="!!infoTextMessage"
43
53
  >
44
- <LabelText :font-color="fontColor" :size="size">
54
+ <LabelText
55
+ data-test-id="label_left_text"
56
+ :font-color="fontColor"
57
+ :size="size"
58
+ >
45
59
  {{ label }}
46
60
  </LabelText>
47
- <InfoText v-if="infoTextMessage" :text="infoTextMessage" @click.stop />
61
+ <InfoText
62
+ v-if="infoTextMessage"
63
+ data-test-id="info_text"
64
+ :text="infoTextMessage"
65
+ @click.stop
66
+ />
48
67
  </LabelContainer>
49
68
  </FlexWrapper>
50
69
  </Container>
@@ -239,34 +258,47 @@
239
258
  label: {
240
259
  required: false,
241
260
  default: '',
261
+ type: String,
242
262
  },
243
263
  isChecked: {
244
264
  required: true,
245
265
  default: false,
266
+ type: Boolean,
246
267
  },
247
268
  toggleColor: {
248
269
  required: false,
270
+ default: '',
271
+ type: String,
249
272
  },
250
273
  backgroundColor: {
251
274
  required: false,
275
+ default: '',
276
+ type: String,
252
277
  },
253
278
  size: {
254
279
  required: false,
255
280
  default: 'small',
281
+ type: String,
256
282
  },
257
283
  labelAlign: {
258
284
  required: false,
259
285
  default: 'right',
286
+ type: String,
260
287
  },
261
288
  fontColor: {
262
289
  required: false,
290
+ default: '',
291
+ type: String,
263
292
  },
264
293
  disabled: {
265
294
  required: false,
266
295
  default: false,
296
+ type: Boolean,
267
297
  },
268
298
  infoTextMessage: {
269
299
  required: false,
300
+ default: '',
301
+ type: String,
270
302
  },
271
303
  dataId: {
272
304
  type: String,
@@ -0,0 +1,102 @@
1
+ /* eslint-disable */
2
+ import { mount } from '@vue/test-utils'
3
+ import RCToggle from '@/components/inputs/toggle'
4
+ import theme from '@/assets/theme'
5
+
6
+ jest.mock('@/components/icon/iconCache', () => ({
7
+ // need to mock this due to how jest handles import.meta
8
+ fetchIcon: jest.fn(() => Promise.resolve('mocked-icon-url.svg')),
9
+ }))
10
+
11
+ describe('RCToggle.vue', () => {
12
+ it('checkbox is rendered and emits correct payload on change', async () => {
13
+ const wrapper = mount(RCToggle, {
14
+ props: { isChecked: true, label: 'Test label', disabled: false },
15
+ global: {
16
+ provide: {
17
+ theme,
18
+ },
19
+ },
20
+ })
21
+ const toggleWrapper = wrapper.find('[data-test-id="toggle_wrapper"]')
22
+
23
+ // check that the element exists
24
+ expect(toggleWrapper.exists()).toBe(true)
25
+ expect(toggleWrapper.attributes('checked')).toBe('true')
26
+
27
+ // Log attributes to see what is rendered (commented out just for reference)
28
+ // console.log('attributes', toggleWrapper.attributes())
29
+ // console.log('All of the Toggles' attributes', wrapper.vm)
30
+
31
+ // Test the label
32
+ expect(wrapper.text()).toContain('Test label')
33
+
34
+ // Test the click
35
+ const pageWrapper = wrapper.find('[data-test-id="page_wrapper"]')
36
+ await pageWrapper.trigger('click')
37
+ expect(wrapper.emitted('on-toggle-change')).toBeTruthy()
38
+ const emittedEvent = wrapper.emitted('on-toggle-change')
39
+ // To inspect emitted events:
40
+ // console.log('Emitted events', wrapper.emitted())
41
+ expect(emittedEvent).toHaveLength(1) // Check if the event was emitted exactly once
42
+ // Check the payload of the event
43
+ expect(emittedEvent[0]).toEqual([false])
44
+ }),
45
+ it('checkbox disabled does not emit anything', async () => {
46
+ const wrapper = mount(RCToggle, {
47
+ props: { isChecked: false, disabled: true },
48
+ global: {
49
+ provide: {
50
+ theme,
51
+ },
52
+ },
53
+ })
54
+ const toggleWrapper = wrapper.find('[data-test-id="toggle_wrapper"]')
55
+ expect(toggleWrapper.attributes('checked')).toBe('false')
56
+
57
+ // Test the click
58
+ const pageWrapper = wrapper.find('[data-test-id="page_wrapper"]')
59
+ await pageWrapper.trigger('click')
60
+
61
+ // Inspect emitted events
62
+ const emittedEvents = wrapper.emitted('on-toggle-change')
63
+
64
+ // Verify that no events were emitted
65
+ expect(emittedEvents).toBeUndefined() // No event should be emitted
66
+ }),
67
+ it('should toggle back and forth on multiple clicks', async () => {
68
+ const wrapper = mount(RCToggle, {
69
+ props: { isChecked: false, disabled: false },
70
+ global: {
71
+ provide: {
72
+ theme,
73
+ },
74
+ },
75
+ })
76
+ const toggleWrapper = wrapper.find('[data-test-id="toggle_wrapper"]')
77
+ // Initial state
78
+ expect(toggleWrapper.attributes('checked')).toBe('false')
79
+
80
+ // Trigger click and check events
81
+ const pageWrapper = wrapper.find('[data-test-id="page_wrapper"]')
82
+ await pageWrapper.trigger('click')
83
+ let emittedEvent = wrapper.emitted('on-toggle-change')
84
+ expect(emittedEvent).toBeTruthy() // Ensure that the event was emitted
85
+ expect(emittedEvent).toHaveLength(1) // Ensure that only one event was emitted
86
+ expect(emittedEvent[0]).toEqual([true]) // Check the payload of the first click
87
+ await wrapper.setProps({ isChecked: true }) // manually update the props
88
+
89
+ // Trigger click again and check events
90
+ await pageWrapper.trigger('click')
91
+ emittedEvent = wrapper.emitted('on-toggle-change')
92
+ expect(emittedEvent).toHaveLength(2) // Ensure that the event count has increased
93
+ expect(emittedEvent[1]).toEqual([false]) // Check the payload of the second click
94
+ await wrapper.setProps({ isChecked: false }) // manually update the props
95
+
96
+ // Trigger click again and check events
97
+ await pageWrapper.trigger('click')
98
+ emittedEvent = wrapper.emitted('on-toggle-change')
99
+ expect(emittedEvent).toHaveLength(3) // Ensure that the event count has increased
100
+ expect(emittedEvent[2]).toEqual([true]) // Check the payload of the third click
101
+ })
102
+ })
package/src/main.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import App from './App.vue'
2
2
  import { createApp } from 'vue'
3
+ import router from './router/dynamicRoutes'
3
4
 
4
5
  const app = createApp(App)
5
-
6
+ app.use(router)
6
7
  app.mount('#app')
@@ -0,0 +1,23 @@
1
+ import { createRouter, createWebHistory } from 'vue-router'
2
+ import Test from '@/Test.vue'
3
+ import Toggle from '@/components/inputs/toggle/index.vue'
4
+
5
+ const routes = [
6
+ {
7
+ path: '/',
8
+ name: 'Test',
9
+ component: Test,
10
+ },
11
+ {
12
+ path: '/toggle',
13
+ name: 'Toggle',
14
+ component: Toggle,
15
+ },
16
+ ]
17
+
18
+ const router = createRouter({
19
+ history: createWebHistory(),
20
+ routes,
21
+ })
22
+
23
+ export default router
@@ -0,0 +1,12 @@
1
+ export function debounce(fn, wait) {
2
+ let timer
3
+ return function (...args) {
4
+ if (timer) {
5
+ clearTimeout(timer)
6
+ }
7
+ const context = this
8
+ timer = setTimeout(() => {
9
+ fn.apply(context, args)
10
+ }, wait)
11
+ }
12
+ }