Skip to content

Commit f32dbb9

Browse files
authored
feat(components): add textarea input (#111)
1 parent ad35c57 commit f32dbb9

File tree

7 files changed

+124
-4
lines changed

7 files changed

+124
-4
lines changed

src/components/FormV2/__snapshots__/formv2.spec.ts.snap

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ exports[`PdapFormV2 > calls submit event with form values on valid submission 1`
3030
<input checked id="ice-cream" name="ice-cream" type="checkbox" value="true">
3131
<label for="ice-cream">Ice Cream</label>
3232
</div>
33+
<div class="pdap-input">
34+
<label for="notes">Notes?</label>
35+
<!--v-if-->
36+
<textarea id="notes" name="notes" placeholder="Notes" type="text"></textarea>
37+
</div>
3338
</form>
3439
`;
3540
@@ -63,6 +68,11 @@ exports[`PdapFormV2 > renders default error message when form has errors 1`] = `
6368
<input id="ice-cream" name="ice-cream" type="checkbox" value="false">
6469
<label for="ice-cream">Ice Cream</label>
6570
</div>
71+
<div class="pdap-input pdap-input-error">
72+
<label for="notes">Notes?</label>
73+
<div class="pdap-input-error-message">Notes are required</div>
74+
<textarea id="notes" name="notes" placeholder="Notes" type="text"></textarea>
75+
</div>
6676
</form>
6777
`;
6878
@@ -102,6 +112,11 @@ exports[`PdapFormV2 > renders error message when errorMessage prop is provided 1
102112
<input id="ice-cream" name="ice-cream" type="checkbox" value="false">
103113
<label for="ice-cream">Ice Cream</label>
104114
</div>
115+
<div class="pdap-input">
116+
<label for="notes">Notes?</label>
117+
<!--v-if-->
118+
<textarea id="notes" name="notes" placeholder="Notes" type="text"></textarea>
119+
</div>
105120
</form>
106121
`;
107122
@@ -135,5 +150,10 @@ exports[`PdapFormV2 > renders the form element 1`] = `
135150
<input id="ice-cream" name="ice-cream" type="checkbox" value="false">
136151
<label for="ice-cream">Ice Cream</label>
137152
</div>
153+
<div class="pdap-input">
154+
<label for="notes">Notes?</label>
155+
<!--v-if-->
156+
<textarea id="notes" name="notes" placeholder="Notes" type="text"></textarea>
157+
</div>
138158
</form>
139159
`;

src/components/FormV2/formv2.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import PdapFormV2 from './PdapFormV2.vue';
55
import InputCheckbox from '../InputCheckbox/PdapInputCheckbox.vue';
66
import InputText from '../InputText/PdapInputText.vue';
77
import InputPassword from '../InputPassword/PdapInputPassword.vue';
8+
import InputTextArea from '../InputTextArea/PdapInputTextArea.vue';
89

910
vi.mock('vue-router');
1011
vi.mock('vue', async () => {
@@ -46,6 +47,7 @@ const BASE_CONFIG = {
4647
email: '',
4748
password: '',
4849
'ice-cream': false,
50+
notes: '',
4951
},
5052
schema: [
5153
{
@@ -69,6 +71,12 @@ const BASE_CONFIG = {
6971
password: { value: true, message: 'Password is too weak' },
7072
},
7173
},
74+
{
75+
name: 'notes',
76+
validators: {
77+
required: { value: true, message: 'Notes are required' },
78+
},
79+
},
7280
],
7381
id: 'test',
7482
name: 'test',
@@ -101,6 +109,12 @@ const BASE_CONFIG = {
101109
name="ice-cream"
102110
label="Ice Cream"
103111
:defaultChecked="false"
112+
/>
113+
<InputTextArea
114+
id="notes"
115+
name="notes"
116+
label="Notes?"
117+
placeholder="Notes"
104118
/>
105119
`,
106120
},
@@ -109,6 +123,7 @@ const BASE_CONFIG = {
109123
InputCheckbox,
110124
InputText,
111125
InputPassword,
126+
InputTextArea,
112127
},
113128
},
114129
};
@@ -164,6 +179,7 @@ describe('PdapFormV2', () => {
164179
await form.find('input[name="email"]').setValue('john@example.com');
165180
await form.find('input[name="password"]').setValue('Password123!');
166181
await form.find('input[name="ice-cream"]').setChecked();
182+
await form.find('textarea[name="notes"]').setValue('This is a note');
167183

168184
await form.trigger('submit');
169185
await wrapper.vm.$forceUpdate();
@@ -175,6 +191,7 @@ describe('PdapFormV2', () => {
175191
email: 'john@example.com',
176192
password: 'Password123!',
177193
'ice-cream': true,
194+
notes: 'This is a note',
178195
},
179196
expect.any(Event)
180197
);
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<template>
2+
<div class="pdap-input" :class="{ ['pdap-input-error']: error }">
3+
<label v-if="$slots.label" :for="id"><slot name="label" /></label>
4+
<label v-else-if="label" :for="id">{{ label }}</label>
5+
<div v-if="$slots.error && error" class="pdap-input-error-message">
6+
<slot name="error" />
7+
</div>
8+
<div v-else-if="error" class="pdap-input-error-message">{{ error }}</div>
9+
10+
<textarea
11+
:id="id"
12+
:name="name"
13+
:placeholder="placeholder"
14+
:value="String(value)"
15+
v-bind="$attrs"
16+
type="text"
17+
@input="onInput"
18+
/>
19+
</div>
20+
</template>
21+
22+
<script setup lang="ts">
23+
import { computed, inject, useSlots } from 'vue';
24+
import { PdapInputTextAreaProps } from './types';
25+
import { PdapFormProvideV2 } from '../FormV2/types';
26+
import { provideKey } from '../FormV2/util';
27+
28+
const { label, name } = withDefaults(defineProps<PdapInputTextAreaProps>(), {
29+
placeholder: 'Enter text here',
30+
});
31+
const slots = useSlots();
32+
33+
if (!slots.label && !label)
34+
throw new Error(
35+
'All form inputs must have a label, passed as a slot or a prop'
36+
);
37+
38+
const { values, setValues, v$ } = inject<PdapFormProvideV2>(provideKey)!;
39+
40+
const error = computed(() => {
41+
return v$.value[name]?.$error ? v$.value[name]?.$errors?.[0]?.$message : '';
42+
});
43+
const value = computed(() => values.value[name] ?? '');
44+
45+
function onInput(e: Event) {
46+
setValues({ [name]: (e.target as unknown as HTMLInputElement).value });
47+
}
48+
</script>

src/components/InputTextArea/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as InputTextArea } from './PdapInputTextArea.vue';

src/components/InputTextArea/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export interface PdapInputTextAreaProps {
2+
id: string;
3+
label?: string;
4+
name: string;
5+
placeholder?: string;
6+
}

src/demo/pages/FormV2Demo.vue

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@
5252
</template>
5353
</InputSelect>
5454

55+
<PdapInputTextArea
56+
:id="INPUT_TEXT_AREA_NAME"
57+
:name="INPUT_TEXT_AREA_NAME"
58+
label="Any notes to share?"
59+
:rows="5"
60+
/>
61+
5562
<Button type="submit">Submit</Button>
5663
</FormV2>
5764
</main>
@@ -64,12 +71,14 @@ import { InputText } from '../../components/InputText';
6471
import { InputCheckbox } from '../../components/InputCheckbox';
6572
import { InputPassword } from '../../components/InputPassword';
6673
import { InputSelect } from '../../components/InputSelect';
74+
import PdapInputTextArea from '../../components/InputTextArea/PdapInputTextArea.vue';
6775
6876
const INPUT_CHECKBOX_NAME = 'ice-cream';
6977
const INPUT_TEXT_PLACEHOLDER = 'Paul';
7078
const INPUT_TEXT_NAME = 'first-name';
7179
const INPUT_PASSWORD_NAME = 'password';
7280
const INPUT_SELECT_NAME = 'flavors';
81+
const INPUT_TEXT_AREA_NAME = 'notes';
7382
7483
const ICE_CREAM_FLAVORS = [
7584
{
@@ -128,6 +137,15 @@ const SCHEMA = [
128137
},
129138
},
130139
},
140+
// {
141+
// name: INPUT_TEXT_AREA_NAME,
142+
// validators: {
143+
// required: {
144+
// message: 'Please add some notes.',
145+
// value: true,
146+
// },
147+
// },
148+
// },
131149
];
132150
</script>
133151

src/styles/components.css

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,22 @@
4141
@apply h-[max-content] gap-1 leading-normal mb-3 w-full flex flex-col;
4242
}
4343

44-
.pdap-input input {
44+
.pdap-input input,
45+
.pdap-input textarea {
4546
@apply dark:bg-neutral-950 border border-neutral-500 border-solid px-3 py-2 text-[rgba(0,0,0)];
4647
}
4748

48-
.pdap-input input::placeholder {
49+
.pdap-input input::placeholder,
50+
.pdap-input textarea::placeholder{
4951
@apply text-neutral-600 text-lg;
5052
}
5153

5254
.pdap-input input:focus,
5355
.pdap-input input:focus-within,
54-
.pdap-input input:focus-visible {
56+
.pdap-input input:focus-visible,
57+
.pdap-input textarea:focus,
58+
.pdap-input textarea:focus-within,
59+
.pdap-input textarea:focus-visible {
5560
@apply border-2 border-blue-light border-solid outline-none;
5661
}
5762

@@ -69,7 +74,8 @@
6974
}
7075

7176
.pdap-input-error input,
72-
.pdap-input-error div[role="combobox"] {
77+
.pdap-input-error div[role="combobox"],
78+
.pdap-input-error textarea {
7379
@apply border-red-800 dark:border-red-300;
7480
}
7581

@@ -106,4 +112,8 @@
106112
@apply cursor-pointer;
107113
}
108114

115+
/* Text area */
116+
.pdap-input textarea {
117+
@apply text-lg;
118+
}
109119
}

0 commit comments

Comments
 (0)