Skip to content

Commit 93eb69c

Browse files
committed
feat: base of refactor mask
1 parent 5d960ca commit 93eb69c

32 files changed

+931
-100
lines changed

.eslintrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ module.exports = {
2222
}],
2323
'no-param-reassign': 'off',
2424
'max-len': ['error', {
25-
code: 120,
25+
code: 140,
2626
tabWidth: 2,
2727
ignoreUrls: true,
2828
}],

configs/storybook/helper.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable no-useless-escape */
22
/* eslint-disable no-restricted-syntax */
33
import dedent from 'ts-dedent';
4-
import { paramCase } from 'param-case';
4+
import { paramCase } from 'change-case';
55

66
const templateSourceCode = (
77
templateSource,

configs/storybook/preview.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { app } from '@storybook/vue3';
22
import { CoreUIPlugin } from '@plugins/core-ui-plugin';
3+
import { MaskPlugin } from '@plugins/mask-plugin';
34
import { transformSource, tokenFiles } from './helper';
45
import '@styles/index.scss';
56

7+
app.use(MaskPlugin);
68
app.use(CoreUIPlugin);
79

810
export const parameters = {

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@
3232
}
3333
},
3434
"dependencies": {
35+
"change-case": "^4.1.2",
3536
"flush-promises": "^1.0.2",
36-
"mask-imp": "^1.0.8"
37+
"maska": "^1.5.0",
38+
"validate": "^5.2.0"
3739
},
3840
"peerDependencies": {
3941
"vue": "^3.2.26"
@@ -73,7 +75,6 @@
7375
"file-loader": "^6.2.0",
7476
"html-webpack-plugin": "^5.5.0",
7577
"jest": "^27.4.5",
76-
"param-case": "^3.0.4",
7778
"sass": "^1.46.0",
7879
"sass-loader": "^12.4.0",
7980
"semantic-release": "^18.0.1",

src/components/atoms/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ export * from './loading';
1616
export * from './checkbox';
1717
export * from './radio';
1818
export * from './menu';
19+
export * from './text-field';

src/components/atoms/menu/menu-item.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ const handleClick = () => {
5858
align-items: center;
5959
transition: background-color 0.25s;
6060
background-color: var(--h-menu-item-background-color);
61+
white-space: nowrap;
6162
6263
&:hover {
6364
--h-menu-item-background-color: var(--h-menu-item-background-color--hover);

src/components/atoms/select/select.stories.mdx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import HSelect from './select.vue';
2020
template: `
2121
<div style="height: 40vh;">
2222
<h-select
23+
label="Exemplo"
2324
v-model="selected"
2425
:options="['example1', 'Example 1']"
2526
/>
@@ -90,6 +91,23 @@ import HSelect from './select.vue';
9091
</Story>
9192
</Canvas>
9293

94+
### HelperText:
95+
96+
<Canvas>
97+
<Story name="HelperText">
98+
{{
99+
components: { HSelect },
100+
template: `
101+
<div>
102+
<h-select helper-text="Helper text" :options="['yes', 'no']" />
103+
<h-select helper-text="Invalid" invalid :options="['yes', 'no']" />
104+
</div>
105+
`,
106+
}}
107+
</Story>
108+
</Canvas>
109+
110+
93111
### placeholder:
94112

95113
<Canvas>
@@ -132,7 +150,9 @@ import HSelect from './select.vue';
132150
<div>
133151
<h-select placeholder="default" behavior="default" />
134152
<p />
135-
<h-select placeholder="block" behavior="block" />
153+
<h-select invalid />
154+
<p />
155+
<h-select placeholder="block" block />
136156
</div>
137157
`,
138158
}}

src/components/atoms/select/select.vue

Lines changed: 154 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,24 @@
22
<div
33
:class="{
44
'h-select': true,
5+
[`h-select--behavior-invalid`]: state.internalInvalid,
56
[`h-select--behavior-block`]: block,
6-
[`h-select--behavior-has-value`]: hasValue,
7-
[`h-select--size-${size}`]: size,
7+
[`h-select--behavior-has-value`]: state.hasValue,
88
}"
99
>
10+
<label
11+
v-if="label"
12+
class="h-select__label"
13+
>
14+
{{ label }}
15+
</label>
16+
1017
<select
1118
class="h-select__field"
1219
v-bind="$attrs"
13-
:value="internalValue"
14-
@change.stop="handlerChange($event?.target?.value)"
20+
:value="state.internalValue"
21+
:name="state.name"
22+
@change.stop="handlerChange"
1523
>
1624
<option
1725
v-if="placeholder"
@@ -28,11 +36,23 @@
2836
v-for="(option, index) in options"
2937
:key="option.value || index"
3038
class="h-select__field-option"
31-
:value="option.value || option"
39+
:value="getOption(option, 'value')"
3240
>
33-
{{ option.text || option }}
41+
{{ getOption(option, 'text') }}
3442
</option>
3543
</select>
44+
45+
<h-text
46+
v-if="helperTextActive"
47+
class="h-select__helper-text"
48+
size="extra-small"
49+
weight="medium"
50+
emphasis="high"
51+
>
52+
<template v-if="state.helperTextVisible">
53+
{{ state.internalTextValue }}
54+
</template>
55+
</h-text>
3656
</div>
3757
</template>
3858

@@ -41,11 +61,30 @@ import { shouldBeOneOf } from '@utils/validations';
4161
import {
4262
selectSizes,
4363
} from '@assets/constants';
64+
import { HFormKey } from '@components/molecules/form';
65+
import {
66+
computed,
67+
reactive,
68+
ref,
69+
onMounted,
70+
watch,
71+
inject,
72+
toRef,
73+
} from 'vue';
74+
import { Validate } from '@utils/validations/validate';
4475
4576
export default {
4677
name: 'HSelect',
4778
inheritAttrs: false,
4879
props: {
80+
label: {
81+
type: String,
82+
default: null,
83+
},
84+
name: {
85+
type: String,
86+
default: null,
87+
},
4988
block: {
5089
type: Boolean,
5190
default: false,
@@ -73,82 +112,133 @@ export default {
73112
type: [Object, String],
74113
default: null,
75114
},
76-
},
77-
emits: ['input', 'change', 'select', 'update:modelValue'],
78-
computed: {
79-
internalValue() {
80-
return this.value || this.modelValue;
115+
invalid: {
116+
type: Boolean,
117+
default: false,
118+
},
119+
helperTextActive: {
120+
type: Boolean,
121+
default: true,
81122
},
82-
hasValue() {
83-
return Boolean(this.internalValue);
123+
helperText: {
124+
type: String,
125+
default: null,
84126
},
85-
},
86-
methods: {
87-
handlerChange(value) {
88-
this.$emit('input', value);
89-
this.$emit('change', value);
90-
this.$emit('select', value);
91-
this.$emit('update:modelValue', value);
127+
rules: {
128+
type: Object,
129+
default: null,
92130
},
93131
},
132+
emits: ['input', 'change', 'select', 'update:modelValue'],
133+
setup($props, { emit: $emit }) {
134+
const HForm = inject(HFormKey, undefined);
135+
136+
const state = reactive({
137+
internalValue: computed(() => $props.value || $props.modelValue),
138+
hasValue: computed(() => Boolean(state.internalValue)),
139+
validationMessages: null,
140+
validationActive: true,
141+
helperTextVisible: computed(() => $props.helperText || state.invalid),
142+
invalid: computed(() => Boolean(state.validationActive && state.validationMessages?.length)),
143+
internalTextValue: computed(() => state.validationMessages?.[0]?.message || $props.helperText),
144+
internalInvalid: computed(() => $props.invalid || state.invalid),
145+
name: computed(() => $props.name || $props.label || 'Campo'),
146+
currentValidation: computed(() => ({
147+
name: state.name,
148+
value: state.internalValue,
149+
tag: 'select',
150+
type: 'simple',
151+
messages: state.validationMessages,
152+
})),
153+
});
154+
155+
const checkValidation = (validationActive) => {
156+
if (!$props.rules) return;
157+
state.validationActive = Boolean(validationActive);
158+
state.validationMessages = Validate(state.internalValue, $props.rules);
159+
};
160+
161+
const getOption = (option, key) => (Object.prototype.hasOwnProperty.call(option, key)
162+
? option[key]
163+
: option);
164+
165+
const handlerChange = ($event) => {
166+
const value = $event?.target?.value;
167+
console.log(value);
168+
$emit('input', value);
169+
$emit('change', value);
170+
$emit('select', value);
171+
$emit('update:modelValue', value);
172+
};
173+
174+
const currentValidation = toRef(state, 'currentValidation');
175+
176+
watch(() => state.internalValue, () => checkValidation(true));
177+
178+
onMounted(() => {
179+
if ($props.rules) checkValidation($props?.rules?.startValidating);
180+
if (HForm) HForm.registerField(currentValidation);
181+
});
182+
183+
return {
184+
state,
185+
handlerChange,
186+
getOption,
187+
};
188+
},
94189
};
95190
</script>
96191
97192
<style lang="scss">
98193
:root {
99-
--h-select--border-color: var(--color-theme-primary);
100-
--h-select--border-radius: var(--border-radius-normal);
101-
--h-select--border-style: solid;
102-
--h-select--border-width: var(--size-base-micro);
194+
--h-select__field--border-color: var(--color-theme-primary);
195+
--h-select__field--border-radius: var(--border-radius-normal);
196+
--h-select__field--border-style: solid;
197+
--h-select__field--border-width: var(--size-base-micro);
103198
--h-select__field--color: var(--color-theme-primary);
104199
--h-select__field--background-color: var(--color-theme-white);
200+
201+
--h-select-width: 250px;
202+
203+
--h-select__label-font-weight: 500;
204+
--h-select__label-margin-bottom: var(--size-base-small);
205+
--h-select__field--height: 44px;
206+
207+
--h-select__helper-text-color: var(--color-theme-grey);
208+
--h-select__helper-text-color--invalid: var(--color-theme-danger);
209+
--h-select__helper-text-height: var(--size-base-medium);
105210
}
106211
107212
.h-select {
108-
border-color: var(--h-select--border-color);
109-
border-radius: var(--h-select--border-radius);
110-
border-style: var(--h-select--border-style);
111-
border-width: var(--h-select--border-width);
112-
113-
display: inline-flex;
213+
display: inline-block;
114214
font-family: 'Red Hat Text', sans-serif;
115215
height: fit-content;
116216
position: relative;
117-
width: 303px;
118-
119-
&--size {
120-
&-small {
121-
& > .h-select__field {
122-
min-height: var(--size-base-extra-large);
123-
font-size: var(--size-scalable-micro);
124-
}
125-
}
126-
&-medium {
127-
& > .h-select__field {
128-
min-height: var(--size-base-jumbo);
129-
font-size: var(--size-scalable-extra-small);
130-
}
131-
}
132-
}
217+
width: var(--h-select-width);
133218
134219
&--behavior {
135220
&-block {
136221
width: 100%;
137222
}
138223
&-has-value {
139-
--h-select__field--background-color: var(--color-blue-grey-scale-100);
224+
--h-select__field--background-color: var(--color-blue-grey-scale-050);
225+
}
226+
&-invalid {
227+
--h-select__field--border-color: var(--color-pink-scale-alpha-400);
228+
--h-select__helper-text-color: var(--h-select__helper-text-color--invalid);
140229
}
141230
}
142231
143232
&__field {
233+
border-color: var(--h-select__field--border-color);
234+
border-radius: var(--h-select__field--border-radius);
235+
border-style: var(--h-select__field--border-style);
236+
border-width: var(--h-select__field--border-width);
144237
background-color: var(--h-select__field--background-color);
145-
border-radius: var(--border-radius-normal);
146-
border: none;
147238
color: var(--h-select__field--color);
148-
flex: 1;
149239
font-family: 'Red Hat Text', sans-serif;
150240
font-weight: 500;
151-
height: 100%;
241+
height: var(--h-select__field--height);
152242
left: 0;
153243
padding-left: var(--size-base-medium);
154244
padding-right: var(--size-base-medium);
@@ -158,10 +248,23 @@ export default {
158248
}
159249
}
160250
251+
.h-select__label {
252+
font-weight: var(--h-select__label-font-weight);
253+
margin-bottom: var(--h-select__label-margin-bottom);
254+
display: inline-block;
255+
}
256+
161257
.h-select__field--placeholder {
162258
color: var(--color-blue-grey-scale-300);
163259
font-weight: 500;
164260
font-style: italic;
165261
}
166262
263+
.h-select__helper-text {
264+
--h-text--color: var(--h-select__helper-text-color);
265+
margin-top: var(--size-base-extra-small);
266+
padding-left: var(--size-base-small);
267+
padding-right: var(--size-base-small);
268+
min-height: var(--h-select__helper-text-height);
269+
}
167270
</style>
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
import TextField from './text-field.vue';
1+
import HTextField from './text-field.vue';
22

3-
export { TextField };
3+
export { HTextField };

0 commit comments

Comments
 (0)