@dcrackel/hematournamentui 1.0.707 → 1.0.709
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/AGENTS.md +118 -118
- package/README.md +132 -106
- package/dist/HemaTournamentUI-lib.es.js +7111 -7006
- package/dist/HemaTournamentUI-lib.umd.js +27 -27
- package/dist/hematournamentui-tailwind.css +198 -412
- package/package.json +10 -10
- package/src/index.js +2 -0
- package/src/mocks/getDEBouts-42Fencers.js +4 -4
- package/src/mocks/getDEBouts-TableOf128.js +37 -0
- package/src/mocks/getDEBouts-TableOf64.js +35 -0
- package/src/stories/Atoms/Input/BaseInput.test.js +97 -85
- package/src/stories/Atoms/Input/BaseInput.vue +149 -150
- package/src/stories/Molecules/Indicators/MissingHemaRatingsId/MissingHemaRatingsId.stories.js +23 -0
- package/src/stories/Molecules/Indicators/MissingHemaRatingsId/MissingHemaRatingsId.vue +35 -0
- package/src/stories/Molecules/Modals/DirectorModal/DirectorModal.test.js +18 -0
- package/src/stories/Molecules/Modals/DirectorModal/DirectorModal.vue +3 -2
- package/src/stories/Molecules/Modals/EditBoutModal/EditBoutModal.vue +1 -1
- package/src/stories/Organisms/Cards/BracketDirectorAssignmentCard/BracketDirectorAssignmentCard.stories.js +33 -0
- package/src/stories/Organisms/Cards/BracketDirectorAssignmentCard/BracketDirectorAssignmentCard.test.js +45 -0
- package/src/stories/Organisms/Cards/BracketDirectorAssignmentCard/BracketDirectorAssignmentCard.vue +103 -0
- package/src/stories/Organisms/Cards/FencerCard/FencerCard.vue +298 -278
- package/src/stories/Organisms/Cards/TableauBoutCard/TableauBoutCard.stories.js +60 -98
- package/src/stories/Organisms/Cards/TableauBoutCard/TableauBoutCard.test.js +103 -4
- package/src/stories/Organisms/Cards/TableauBoutCard/TableauBoutCard.vue +256 -215
- package/src/stories/Organisms/Cards/TableauFencerCard/TableauFencerCard.stories.js +69 -92
- package/src/stories/Organisms/Cards/TableauFencerCard/TableauFencerCard.vue +80 -128
- package/src/stories/Organisms/Cards/WaitlistFencerCard/WaitlistFencerCard.vue +14 -4
- package/src/stories/Organisms/ComplexInputs/ImageCropper/ImageCropper.stories.js +31 -20
- package/src/stories/Organisms/ComplexInputs/ImageCropper/ImageCropper.test.js +109 -0
- package/src/stories/Organisms/ComplexInputs/ImageCropper/ImageCropper.vue +192 -133
- package/src/stories/Organisms/Containers/Tableau/Tableau.stories.js +2 -2
- package/src/stories/Organisms/Containers/Tableau/Tableau.test.js +131 -3
- package/src/stories/Organisms/Containers/Tableau/Tableau.vue +287 -89
- package/src/stories/Organisms/Containers/Tableau/components/BracketDirectorAssignmentPanel.test.js +29 -0
- package/src/stories/Organisms/Containers/Tableau/components/BracketDirectorAssignmentPanel.vue +46 -0
- package/src/stories/Organisms/Containers/Tableau/components/TableauSvgOverlay.test.js +21 -0
- package/src/stories/Organisms/Containers/Tableau/components/TableauSvgOverlay.vue +39 -0
- package/src/stories/Organisms/Containers/Tableau/layout/TableauLayoutEngine.js +145 -0
- package/src/stories/Organisms/Containers/Tableau/layout/TableauLayoutEngine.test.js +64 -0
- package/src/stories/Organisms/Containers/Tableau/plannedAssignments.js +57 -0
- package/src/stories/Organisms/Containers/Tableau/plannedAssignments.test.js +65 -0
- package/src/stories/Organisms/Containers/TableauColumn/TableauColumn.vue +31 -29
- package/src/stories/Templates/EventManagement/Bracket/Bracket.stories.js +146 -18
- package/src/stories/Templates/EventManagement/Bracket/Bracket.test.js +52 -2
- package/src/stories/Templates/EventManagement/Bracket/Bracket.vue +53 -17
- package/src/stories/Templates/EventManagement/Bracket/BracketPlannedSuggestions.js +39 -0
- package/src/stories/Templates/EventManagement/Bracket/BracketStoryHarness.js +39 -0
- package/src/stories/Templates/EventManagement/Bracket/BracketStoryHarness.test.js +79 -0
- package/src/stories/Templates/PersonManagement/Admin/Administration/Administration.stories.js +14 -0
- package/src/stories/Templates/PersonManagement/Admin/Administration/Administration.test.js +39 -0
- package/src/stories/Templates/PersonManagement/Admin/Administration/Administration.vue +13 -3
- package/src/stories/Templates/PersonManagement/Basic/BasicEdit.vue +170 -172
- package/src/stories/Templates/PersonManagement/PersonManagement.stories.js +156 -103
- package/src/stories/Templates/PersonManagement/PersonManagement.test.js +329 -0
- package/src/stories/Templates/PersonManagement/PersonManagement.vue +329 -213
- package/src/stories/Templates/PersonManagement/PersonManagementDraft.js +42 -0
- package/src/stories/Util/Validations/PersonManagementValidations.js +45 -29
- package/src/stories/Organisms/Cards/TableauBoutCard/SpacingConfig.js +0 -111
- package/src/stories/Organisms/Containers/TableauLines/SpacingConfig.js +0 -162
- package/src/stories/Organisms/Containers/TableauLines/TableauLines.stories.js +0 -21
- package/src/stories/Organisms/Containers/TableauLines/TableauLines.vue +0 -78
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dcrackel/hematournamentui",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.709",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/HemaTournamentUI-lib.umd.js",
|
|
7
7
|
"module": "dist/HemaTournamentUI-lib.es.js",
|
|
@@ -58,18 +58,18 @@
|
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@babel/eslint-parser": "^7.28.6",
|
|
61
|
-
"@chromatic-com/storybook": "^5.
|
|
61
|
+
"@chromatic-com/storybook": "^5.5.1",
|
|
62
62
|
"@eslint/eslintrc": "^3.3.5",
|
|
63
|
-
"@storybook/addon-docs": "^10.
|
|
64
|
-
"@storybook/addon-links": "^10.
|
|
65
|
-
"@storybook/react": "^10.
|
|
66
|
-
"@storybook/vue3-vite": "^10.
|
|
63
|
+
"@storybook/addon-docs": "^10.6.2",
|
|
64
|
+
"@storybook/addon-links": "^10.6.2",
|
|
65
|
+
"@storybook/react": "^10.6.2",
|
|
66
|
+
"@storybook/vue3-vite": "^10.6.2",
|
|
67
67
|
"@tailwindcss/cli": "^4.3.0",
|
|
68
68
|
"@tailwindcss/postcss": "^4.3.0",
|
|
69
69
|
"@typescript-eslint/eslint-plugin": "^8.59.3",
|
|
70
70
|
"@typescript-eslint/parser": "^8.59.3",
|
|
71
71
|
"@vitejs/plugin-vue": "^6.0.7",
|
|
72
|
-
"@vitest/coverage-v8": "^4.1.
|
|
72
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
73
73
|
"@vue/test-utils": "^2.4.10",
|
|
74
74
|
"@vuepic/vue-datepicker": "^12.1.0",
|
|
75
75
|
"autoprefixer": "^10.5.0",
|
|
@@ -77,17 +77,17 @@
|
|
|
77
77
|
"eslint": "^9.9.0",
|
|
78
78
|
"eslint-plugin-jest": "^29.15.2",
|
|
79
79
|
"eslint-plugin-prettier": "^5.5.5",
|
|
80
|
-
"eslint-plugin-storybook": "^10.
|
|
80
|
+
"eslint-plugin-storybook": "^10.6.2",
|
|
81
81
|
"eslint-plugin-vue": "^10.9.1",
|
|
82
82
|
"happy-dom": "^20.9.0",
|
|
83
83
|
"patch-package": "^8.0.1",
|
|
84
84
|
"postcss": "^8.5.14",
|
|
85
85
|
"prettier": "^3.9.6",
|
|
86
|
-
"storybook": "^10.
|
|
86
|
+
"storybook": "^10.6.2",
|
|
87
87
|
"storybook-vue3-router": "^7.0.0",
|
|
88
88
|
"tailwindcss": "^4.3.0",
|
|
89
89
|
"vite": "^8.0.13",
|
|
90
|
-
"vitest": "^4.1.
|
|
90
|
+
"vitest": "^4.1.11",
|
|
91
91
|
"vue-eslint-parser": "^10.4.0"
|
|
92
92
|
},
|
|
93
93
|
"overrides": {
|
package/src/index.js
CHANGED
|
@@ -17,6 +17,8 @@ export { default as DatePicker } from './stories/Organisms/ComplexInputs/DatePic
|
|
|
17
17
|
export { default as DropDownMenu } from './stories/Organisms/ComplexInputs/DropDown/DropDownMenu.vue';
|
|
18
18
|
export { default as GridContainer } from './stories/Organisms/Grids/GridContainer.vue';
|
|
19
19
|
export { default as PoolGrid } from './stories/Organisms/Containers/PoolGrid/PoolGrid.vue';
|
|
20
|
+
export { default as BracketDirectorAssignmentCard } from './stories/Organisms/Cards/BracketDirectorAssignmentCard/BracketDirectorAssignmentCard.vue';
|
|
21
|
+
export { default as BracketDirectorAssignmentPanel } from './stories/Organisms/Containers/Tableau/components/BracketDirectorAssignmentPanel.vue';
|
|
20
22
|
export { default as ImageCropper } from './stories/Organisms/ComplexInputs/ImageCropper/ImageCropper.vue';
|
|
21
23
|
export { default as TextBoxEditor } from './stories/Organisms/ComplexInputs/TextBoxEditor/TextBoxEditor.vue';
|
|
22
24
|
export { default as EditEventWizard } from './stories/Organisms/Wizards/EditEventWizard/EditEventWizard.vue';
|
|
@@ -3150,7 +3150,7 @@ const getDEWithBouts42Fencers = {
|
|
|
3150
3150
|
TimeLeft: 0,
|
|
3151
3151
|
CurrentPass: 0,
|
|
3152
3152
|
MaxPasses: 0,
|
|
3153
|
-
RoundLabel: '
|
|
3153
|
+
RoundLabel: 'Table of 8',
|
|
3154
3154
|
DEBoutId: 57,
|
|
3155
3155
|
DENextBoutId: 61,
|
|
3156
3156
|
LoserNextBoutId: null,
|
|
@@ -3201,7 +3201,7 @@ const getDEWithBouts42Fencers = {
|
|
|
3201
3201
|
TimeLeft: 0,
|
|
3202
3202
|
CurrentPass: 0,
|
|
3203
3203
|
MaxPasses: 0,
|
|
3204
|
-
RoundLabel: '
|
|
3204
|
+
RoundLabel: 'Table of 8',
|
|
3205
3205
|
DEBoutId: 58,
|
|
3206
3206
|
DENextBoutId: 61,
|
|
3207
3207
|
LoserNextBoutId: null,
|
|
@@ -3252,7 +3252,7 @@ const getDEWithBouts42Fencers = {
|
|
|
3252
3252
|
TimeLeft: 0,
|
|
3253
3253
|
CurrentPass: 0,
|
|
3254
3254
|
MaxPasses: 0,
|
|
3255
|
-
RoundLabel: '
|
|
3255
|
+
RoundLabel: 'Table of 8',
|
|
3256
3256
|
DEBoutId: 59,
|
|
3257
3257
|
DENextBoutId: 62,
|
|
3258
3258
|
LoserNextBoutId: null,
|
|
@@ -3303,7 +3303,7 @@ const getDEWithBouts42Fencers = {
|
|
|
3303
3303
|
TimeLeft: 0,
|
|
3304
3304
|
CurrentPass: 0,
|
|
3305
3305
|
MaxPasses: 0,
|
|
3306
|
-
RoundLabel: '
|
|
3306
|
+
RoundLabel: 'Table of 8',
|
|
3307
3307
|
DEBoutId: 60,
|
|
3308
3308
|
DENextBoutId: 62,
|
|
3309
3309
|
LoserNextBoutId: null,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import historicalSixtySevenFencerBracket from './getDEBouts-67Fencers.js';
|
|
2
|
+
|
|
3
|
+
const roundLabelRules = [
|
|
4
|
+
{ matches: boutId => boutId >= 1 && boutId <= 64, label: 'Table of 128' },
|
|
5
|
+
{ matches: boutId => boutId >= 65 && boutId <= 96, label: 'Table of 64' },
|
|
6
|
+
{ matches: boutId => boutId >= 97 && boutId <= 112, label: 'Table of 32' },
|
|
7
|
+
{ matches: boutId => boutId >= 113 && boutId <= 120, label: 'Table of 16' },
|
|
8
|
+
{ matches: boutId => boutId >= 121 && boutId <= 124, label: 'Table of 8' },
|
|
9
|
+
{ matches: boutId => boutId >= 125 && boutId <= 126, label: 'Semifinal' },
|
|
10
|
+
{ matches: boutId => boutId === 127, label: 'Final' }
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
const getCurrentRoundLabel = bout => {
|
|
14
|
+
const boutId = Number(bout.DEBoutId);
|
|
15
|
+
return roundLabelRules.find(rule => rule.matches(boutId))?.label || bout.RoundLabel;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const normalizeTableOf128Bout = bout => ({
|
|
19
|
+
...bout,
|
|
20
|
+
RoundLabel: getCurrentRoundLabel(bout)
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const [historicalPool, ...otherPools] = historicalSixtySevenFencerBracket.pools;
|
|
24
|
+
|
|
25
|
+
const getDEBoutsTableOf128 = {
|
|
26
|
+
...historicalSixtySevenFencerBracket,
|
|
27
|
+
message: 'Current Table of 128 fixture retrieved',
|
|
28
|
+
pools: [
|
|
29
|
+
{
|
|
30
|
+
...historicalPool,
|
|
31
|
+
Bouts: historicalPool.Bouts.map(normalizeTableOf128Bout)
|
|
32
|
+
},
|
|
33
|
+
...otherPools
|
|
34
|
+
]
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export default getDEBoutsTableOf128;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import historicalSixtySevenFencerBracket from './getDEBouts-67Fencers.js';
|
|
2
|
+
|
|
3
|
+
const FIRST_TABLE_OF_64_BOUT_ID = 65;
|
|
4
|
+
|
|
5
|
+
const roundLabelRules = [
|
|
6
|
+
{ matches: boutId => boutId >= 65 && boutId <= 96, label: 'Table of 64' },
|
|
7
|
+
{ matches: boutId => boutId >= 97 && boutId <= 112, label: 'Table of 32' },
|
|
8
|
+
{ matches: boutId => boutId >= 113 && boutId <= 120, label: 'Table of 16' },
|
|
9
|
+
{ matches: boutId => boutId >= 121 && boutId <= 124, label: 'Table of 8' },
|
|
10
|
+
{ matches: boutId => boutId >= 125 && boutId <= 126, label: 'Semifinal' },
|
|
11
|
+
{ matches: boutId => boutId === 127, label: 'Final' }
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
const isTableOf64Bout = bout => Number(bout.DEBoutId) >= FIRST_TABLE_OF_64_BOUT_ID;
|
|
15
|
+
|
|
16
|
+
const getCurrentRoundLabel = bout => {
|
|
17
|
+
const boutId = Number(bout.DEBoutId);
|
|
18
|
+
return roundLabelRules.find(rule => rule.matches(boutId))?.label || bout.RoundLabel;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const normalizeTableOf64Bout = bout => ({
|
|
22
|
+
...bout,
|
|
23
|
+
RoundLabel: getCurrentRoundLabel(bout)
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const [historicalPool, ...otherPools] = historicalSixtySevenFencerBracket.pools;
|
|
27
|
+
const tableOf64Bouts = historicalPool.Bouts.filter(isTableOf64Bout).map(normalizeTableOf64Bout);
|
|
28
|
+
|
|
29
|
+
const getDEBoutsTableOf64 = {
|
|
30
|
+
...historicalSixtySevenFencerBracket,
|
|
31
|
+
message: 'Current Table of 64 fixture retrieved',
|
|
32
|
+
pools: [{ ...historicalPool, Bouts: tableOf64Bouts }, ...otherPools]
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export default getDEBoutsTableOf64;
|
|
@@ -1,85 +1,97 @@
|
|
|
1
|
-
import BaseInput from './BaseInput.vue';
|
|
2
|
-
import { mount } from '@vue/test-utils';
|
|
3
|
-
import { describe, expect, test, it } from 'vitest';
|
|
4
|
-
|
|
5
|
-
describe('BaseInput.vue', () => {
|
|
6
|
-
it('renders with default props', () => {
|
|
7
|
-
const wrapper = mount(BaseInput);
|
|
8
|
-
const inputElement = wrapper.find('input');
|
|
9
|
-
|
|
10
|
-
expect(inputElement.attributes('placeholder')).toBe('');
|
|
11
|
-
expect(wrapper.vm.internalValue).toBe('');
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it('initializes with the correct value prop', () => {
|
|
15
|
-
const initialValue = 'Hello, World!';
|
|
16
|
-
const wrapper = mount(BaseInput, {
|
|
17
|
-
props: {
|
|
18
|
-
value: initialValue
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
expect(wrapper.vm.internalValue).toBe(initialValue);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('updates internalValue when value prop changes', async () => {
|
|
26
|
-
const wrapper = mount(BaseInput);
|
|
27
|
-
await wrapper.setProps({ value: 'New Value' });
|
|
28
|
-
|
|
29
|
-
expect(wrapper.vm.internalValue).toBe('New Value');
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('emits
|
|
33
|
-
const wrapper = mount(BaseInput);
|
|
34
|
-
const inputElement = wrapper.find('input');
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
expect(inputElement.classes()).toContain('
|
|
54
|
-
expect(inputElement.classes()).toContain('
|
|
55
|
-
expect(inputElement.classes()).toContain('
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
});
|
|
1
|
+
import BaseInput from './BaseInput.vue';
|
|
2
|
+
import { mount } from '@vue/test-utils';
|
|
3
|
+
import { describe, expect, test, it } from 'vitest';
|
|
4
|
+
|
|
5
|
+
describe('BaseInput.vue', () => {
|
|
6
|
+
it('renders with default props', () => {
|
|
7
|
+
const wrapper = mount(BaseInput);
|
|
8
|
+
const inputElement = wrapper.find('input');
|
|
9
|
+
|
|
10
|
+
expect(inputElement.attributes('placeholder')).toBe('');
|
|
11
|
+
expect(wrapper.vm.internalValue).toBe('');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('initializes with the correct value prop', () => {
|
|
15
|
+
const initialValue = 'Hello, World!';
|
|
16
|
+
const wrapper = mount(BaseInput, {
|
|
17
|
+
props: {
|
|
18
|
+
value: initialValue
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
expect(wrapper.vm.internalValue).toBe(initialValue);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('updates internalValue when value prop changes', async () => {
|
|
26
|
+
const wrapper = mount(BaseInput);
|
|
27
|
+
await wrapper.setProps({ value: 'New Value' });
|
|
28
|
+
|
|
29
|
+
expect(wrapper.vm.internalValue).toBe('New Value');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('emits the latest value synchronously before the next action', () => {
|
|
33
|
+
const wrapper = mount(BaseInput);
|
|
34
|
+
const inputElement = wrapper.find('input');
|
|
35
|
+
|
|
36
|
+
inputElement.element.value = 'Test Input';
|
|
37
|
+
inputElement.element.dispatchEvent(new Event('input', { bubbles: true }));
|
|
38
|
+
expect(wrapper.emitted('update:value')).toEqual([['Test Input']]);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('applies input border styles when addBorder is enabled', () => {
|
|
42
|
+
const wrapper = mount(BaseInput, {
|
|
43
|
+
props: {
|
|
44
|
+
addBorder: true,
|
|
45
|
+
invalid: false
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
const inputElement = wrapper.find('input');
|
|
49
|
+
expect(inputElement.classes()).toContain('border');
|
|
50
|
+
expect(inputElement.classes()).toContain('rounded-lg');
|
|
51
|
+
expect(inputElement.classes()).toContain('text-quinary');
|
|
52
|
+
expect(inputElement.classes()).toContain('text-sm');
|
|
53
|
+
expect(inputElement.classes()).toContain('p-2');
|
|
54
|
+
expect(inputElement.classes()).toContain('w-full');
|
|
55
|
+
expect(inputElement.classes()).toContain('border-dropdownSelect');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('applies border-alarm class when invalid is true', () => {
|
|
59
|
+
const wrapper = mount(BaseInput, {
|
|
60
|
+
props: {
|
|
61
|
+
addBorder: true,
|
|
62
|
+
invalid: true
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
const inputElement = wrapper.find('input');
|
|
66
|
+
expect(inputElement.classes()).toContain('border-alarm');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('does not apply border-alarm class when invalid is false', () => {
|
|
70
|
+
const wrapper = mount(BaseInput, {
|
|
71
|
+
props: {
|
|
72
|
+
addBorder: true,
|
|
73
|
+
invalid: false
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
const inputElement = wrapper.find('input');
|
|
77
|
+
expect(inputElement.classes()).not.toContain('border-alarm');
|
|
78
|
+
expect(inputElement.classes()).toContain('border-dropdownSelect');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('delivers a cleared value before the input is unmounted', () => {
|
|
82
|
+
const wrapper = mount(BaseInput, { props: { value: '123', inputType: 'number' } });
|
|
83
|
+
const input = wrapper.find('input');
|
|
84
|
+
input.element.value = '';
|
|
85
|
+
input.element.dispatchEvent(new Event('input', { bubbles: true }));
|
|
86
|
+
expect(wrapper.emitted('update:value')).toEqual([['']]);
|
|
87
|
+
wrapper.unmount();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('does not emit edits while disabled', () => {
|
|
91
|
+
const wrapper = mount(BaseInput, { props: { disabled: true, value: 'original' } });
|
|
92
|
+
const input = wrapper.find('input');
|
|
93
|
+
input.element.value = 'changed';
|
|
94
|
+
input.element.dispatchEvent(new Event('input', { bubbles: true }));
|
|
95
|
+
expect(wrapper.emitted('update:value')).toBeUndefined();
|
|
96
|
+
});
|
|
97
|
+
});
|
|
@@ -1,150 +1,149 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div :class="iconName ? '' : ''">
|
|
3
|
-
<input
|
|
4
|
-
ref="input"
|
|
5
|
-
|
|
6
|
-
:class="baseClasses"
|
|
7
|
-
:placeholder="placeholder"
|
|
8
|
-
:type="inputType"
|
|
9
|
-
:disabled="disabled"
|
|
10
|
-
|
|
11
|
-
@
|
|
12
|
-
@
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
</
|
|
16
|
-
|
|
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
|
-
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
};
|
|
95
|
-
},
|
|
96
|
-
computed: {
|
|
97
|
-
baseClasses() {
|
|
98
|
-
let classes = 'appearance-none focus:outline-none w-full text-sm rounded-lg text-quinary';
|
|
99
|
-
if (this.addBorder) {
|
|
100
|
-
classes += this.invalid ? ' border border-alarm p-2' : ' border border-dropdownSelect p-2';
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (this.centerInput) classes += ' text-center';
|
|
104
|
-
|
|
105
|
-
classes += sizeClasses[this.size] || '';
|
|
106
|
-
|
|
107
|
-
return classes;
|
|
108
|
-
}
|
|
109
|
-
},
|
|
110
|
-
watch: {
|
|
111
|
-
value(newValue) {
|
|
112
|
-
this.internalValue = newValue;
|
|
113
|
-
}
|
|
114
|
-
},
|
|
115
|
-
methods: {
|
|
116
|
-
onInput(event) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="iconName ? '' : ''">
|
|
3
|
+
<input
|
|
4
|
+
ref="input"
|
|
5
|
+
:value="internalValue"
|
|
6
|
+
:class="baseClasses"
|
|
7
|
+
:placeholder="placeholder"
|
|
8
|
+
:type="inputType"
|
|
9
|
+
:disabled="disabled"
|
|
10
|
+
:aria-invalid="invalid"
|
|
11
|
+
@input="onInput"
|
|
12
|
+
@focus="onFocus"
|
|
13
|
+
@blur="onBlur"
|
|
14
|
+
/>
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script>
|
|
19
|
+
const sizeClasses = {
|
|
20
|
+
xs: ' text-xs',
|
|
21
|
+
sm: ' text-sm',
|
|
22
|
+
md: ' text-md',
|
|
23
|
+
lg: ' text-lg',
|
|
24
|
+
xl: ' text-xl',
|
|
25
|
+
'2xl': ' text-2xl',
|
|
26
|
+
'3xl': ' text-3xl',
|
|
27
|
+
'4xl': ' text-4xl',
|
|
28
|
+
'5xl': ' text-5xl'
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export default {
|
|
32
|
+
name: 'BaseInput',
|
|
33
|
+
emits: ['update:value'],
|
|
34
|
+
props: {
|
|
35
|
+
placeholder: {
|
|
36
|
+
type: [String, Number],
|
|
37
|
+
default: ''
|
|
38
|
+
},
|
|
39
|
+
value: {
|
|
40
|
+
type: [String, Number],
|
|
41
|
+
default: ''
|
|
42
|
+
},
|
|
43
|
+
inputType: {
|
|
44
|
+
type: String,
|
|
45
|
+
default: 'text'
|
|
46
|
+
},
|
|
47
|
+
invalid: {
|
|
48
|
+
type: Boolean,
|
|
49
|
+
default: false
|
|
50
|
+
},
|
|
51
|
+
addBorder: {
|
|
52
|
+
type: Boolean,
|
|
53
|
+
default: false
|
|
54
|
+
},
|
|
55
|
+
iconName: {
|
|
56
|
+
type: String,
|
|
57
|
+
default: ''
|
|
58
|
+
},
|
|
59
|
+
disabled: {
|
|
60
|
+
type: Boolean,
|
|
61
|
+
default: false
|
|
62
|
+
},
|
|
63
|
+
iconStyle: {
|
|
64
|
+
type: String,
|
|
65
|
+
default: 'fa-solid',
|
|
66
|
+
validator: value => ['fa-solid', 'fa-regular', 'fa-light', 'fa-thing'].includes(value)
|
|
67
|
+
},
|
|
68
|
+
size: {
|
|
69
|
+
type: String,
|
|
70
|
+
default: 'sm',
|
|
71
|
+
validator: value => ['', ' ', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl'].includes(value)
|
|
72
|
+
},
|
|
73
|
+
centerInput: {
|
|
74
|
+
type: Boolean,
|
|
75
|
+
default: false
|
|
76
|
+
},
|
|
77
|
+
iconColor: {
|
|
78
|
+
type: String,
|
|
79
|
+
default: 'primary',
|
|
80
|
+
validator: value =>
|
|
81
|
+
['neutral', 'primary', 'secondary', 'tertiary', 'quaternary', 'quinary', 'bright', 'white', 'alarm'].includes(
|
|
82
|
+
value
|
|
83
|
+
)
|
|
84
|
+
},
|
|
85
|
+
allowPercent: {
|
|
86
|
+
type: Boolean,
|
|
87
|
+
default: false
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
data() {
|
|
91
|
+
return {
|
|
92
|
+
internalValue: this.value,
|
|
93
|
+
currentPlaceholder: this.placeholder
|
|
94
|
+
};
|
|
95
|
+
},
|
|
96
|
+
computed: {
|
|
97
|
+
baseClasses() {
|
|
98
|
+
let classes = 'appearance-none focus:outline-none w-full text-sm rounded-lg text-quinary';
|
|
99
|
+
if (this.addBorder) {
|
|
100
|
+
classes += this.invalid ? ' border border-alarm p-2' : ' border border-dropdownSelect p-2';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (this.centerInput) classes += ' text-center';
|
|
104
|
+
|
|
105
|
+
classes += sizeClasses[this.size] || '';
|
|
106
|
+
|
|
107
|
+
return classes;
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
watch: {
|
|
111
|
+
value(newValue) {
|
|
112
|
+
this.internalValue = newValue;
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
methods: {
|
|
116
|
+
onInput(event) {
|
|
117
|
+
if (this.disabled) return;
|
|
118
|
+
const input = event.target;
|
|
119
|
+
let sanitizedValue = input.value;
|
|
120
|
+
|
|
121
|
+
if (this.inputType === 'number') {
|
|
122
|
+
sanitizedValue = sanitizedValue.replace(/\D/g, '');
|
|
123
|
+
}
|
|
124
|
+
if (this.inputType === 'text') {
|
|
125
|
+
this.allowPercent
|
|
126
|
+
? (sanitizedValue = sanitizedValue.replace(/[\\'"=*<>|#$^(){}\[\]]/g, ''))
|
|
127
|
+
: (sanitizedValue = sanitizedValue.replace(/[\\'"=*<>|#$%^(){}\[\]]/g, ''));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
this.internalValue = sanitizedValue;
|
|
131
|
+
input.value = sanitizedValue;
|
|
132
|
+
this.$emit('update:value', sanitizedValue);
|
|
133
|
+
},
|
|
134
|
+
onFocus() {
|
|
135
|
+
this.currentPlaceholder = '';
|
|
136
|
+
},
|
|
137
|
+
onBlur() {
|
|
138
|
+
if (!this.internalValue) {
|
|
139
|
+
this.currentPlaceholder = this.placeholder;
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
focus() {
|
|
143
|
+
if (this.$refs.input) {
|
|
144
|
+
this.$refs.input.focus();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
</script>
|