Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(components): checkbox input updates #70

Merged
merged 4 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,12 @@ export default {
value: 999
},
},
{
id: 'ice-cream',
name: 'iceCream',
label: 'Do you like ice cream?',
type: 'checkbox',
defaultChecked: true,
}
]
}
Expand Down
27 changes: 17 additions & 10 deletions src/components/Form/PdapForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,14 @@
"
:value="values[field.name]"
@change="updateForm(field.name, $event)"
@input="updateForm(field.name, $event)"
/>
<slot />
</form>
</template>

<script setup lang="ts">
// Globals
import { computed, reactive, ref, watchEffect } from 'vue';
import { computed, ref, watchEffect } from 'vue';
import { useVuelidate } from '@vuelidate/core';

// Components
Expand Down Expand Up @@ -63,7 +62,7 @@ const data = computed(() =>
})
);

let values = reactive<Record<string, string>>(
const values = ref<Record<string, string>>(
data.value.reduce((acc, input) => {
switch (input.type) {
case PdapInputTypes.CHECKBOX:
Expand Down Expand Up @@ -101,8 +100,15 @@ export type VuelidateInstance = typeof v$.value;
const errorMessage = ref(props.error);

// Handlers
function updateForm(fieldName: string, value: string) {
values[fieldName] = value;
function updateForm(fieldName: string, event: Event) {
const target = event.target as HTMLInputElement;
const update =
target.type === PdapInputTypes.CHECKBOX &&
typeof target.checked === 'boolean'
? target.checked.toString()
: target.value;

values.value[fieldName] = update;
change();
}

Expand Down Expand Up @@ -133,24 +139,25 @@ watchEffect(() => {
});

function change() {
emit('change', { ...values });
emit('change', { ...values.value });
}

async function submit(event: Event) {
// Check form submission
const isValidSubmission = await v$.value.$validate();
if (isValidSubmission) {
// Emit submit event (spread to new object to create new object, this allows us to reset `values` without messing with the data returned)
emit('submit', { ...values });
emit('submit', { ...values.value });
// Reset vuelidate and form
v$.value.$reset();
const form = <HTMLFormElement>event.target;
form.reset();

// Wipe values state ('' for text inputs, as-was for everything else)
values = Object.entries(values).reduce((acc, [key, value]) => {
return { ...acc, [key]: ['true', 'false'].includes(value) ? value : '' };
// Wipe values state
values.value = Object.entries(values).reduce((acc, [key]) => {
return { ...acc, [key]: '' };
}, {});

return;
}
}
Expand Down
70 changes: 18 additions & 52 deletions src/components/Form/__snapshots__/form.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,32 @@
exports[`Form component > Renders component in form error state 1`] = `
<form class="pdap-form" id="test" name="test">
<div class="pdap-form-error-message">This form is incorrect</div>
<div class="pdap-grid-container pdap-input">
<!-- Text -->
<input id="test-1" name="testOne" placeholder="Enter a value here" type="text"><!-- Password -->
<!--v-if-->
<div class="pdap-input pdap-input-text">
<input id="test-1" name="testOne" placeholder="Enter a value here" type="text">
<!--v-if-->
<label class="pdap-input-label" for="test-1">First test input</label>
</div>
<div class="pdap-grid-container pdap-input">
<!-- Text -->
<input id="test-email" name="email" placeholder="Email" type="text"><!-- Password -->
<!--v-if-->
<div class="pdap-input pdap-input-text">
<input id="test-email" name="email" placeholder="Email" type="text">
<!--v-if-->
<label class="pdap-input-label" for="test-email">Email test input</label>
</div>
<div class="pdap-grid-container pdap-input">
<!-- Text -->
<!--v-if-->
<!-- Password -->
<div class="pdap-input pdap-input-password">
<input id="test-password" name="password" placeholder="Password" type="password">
<!--v-if-->
<label class="pdap-input-label" for="test-password">Password test input</label>
</div>
<div class="pdap-grid-container pdap-input">
<!-- Text -->
<input id="test-2" name="testTwo" placeholder="Enter another value here" type="text"><!-- Password -->
<!--v-if-->
<div class="pdap-input pdap-input-text">
<input id="test-2" name="testTwo" placeholder="Enter another value here" type="text">
<!--v-if-->
<label class="pdap-input-label" for="test-2">Second test input</label>
</div>
<div class="pdap-grid-container pdap-input">
<!-- Text -->
<!--v-if-->
<!-- Password -->
<!-- Checkbox -->
<div class="pdap-input pdap-input-checkbox pdap-input-checkbox-checked">
<input checked class="pdap-input-checkbox" id="checkbox-default-checked" name="checkboxDefaultChecked" type="checkbox" value="true">
<!--v-if-->
<label class="pdap-input-label" for="checkbox-default-checked">Keep this box checked?</label>
</div>
<div class="pdap-grid-container pdap-input">
<!-- Text -->
<!--v-if-->
<!-- Password -->
<!-- Checkbox -->
<div class="pdap-input pdap-input-checkbox">
<input class="pdap-input-checkbox" id="checkbox-default-unchecked" name="checkboxDefaultUnchecked" type="checkbox" value="false">
<!--v-if-->
<label class="pdap-input-label" for="checkbox-default-unchecked">Check this box?</label>
Expand All @@ -57,49 +40,32 @@ exports[`Form component > Renders component in form error state 1`] = `
exports[`Form component > Renders component in static state 1`] = `
<form class="pdap-form" id="test" name="test">
<!--v-if-->
<div class="pdap-grid-container pdap-input">
<!-- Text -->
<input id="test-1" name="testOne" placeholder="Enter a value here" type="text"><!-- Password -->
<!--v-if-->
<div class="pdap-input pdap-input-text">
<input id="test-1" name="testOne" placeholder="Enter a value here" type="text">
<!--v-if-->
<label class="pdap-input-label" for="test-1">First test input</label>
</div>
<div class="pdap-grid-container pdap-input">
<!-- Text -->
<input id="test-email" name="email" placeholder="Email" type="text"><!-- Password -->
<!--v-if-->
<div class="pdap-input pdap-input-text">
<input id="test-email" name="email" placeholder="Email" type="text">
<!--v-if-->
<label class="pdap-input-label" for="test-email">Email test input</label>
</div>
<div class="pdap-grid-container pdap-input">
<!-- Text -->
<!--v-if-->
<!-- Password -->
<div class="pdap-input pdap-input-password">
<input id="test-password" name="password" placeholder="Password" type="password">
<!--v-if-->
<label class="pdap-input-label" for="test-password">Password test input</label>
</div>
<div class="pdap-grid-container pdap-input">
<!-- Text -->
<input id="test-2" name="testTwo" placeholder="Enter another value here" type="text"><!-- Password -->
<!--v-if-->
<div class="pdap-input pdap-input-text">
<input id="test-2" name="testTwo" placeholder="Enter another value here" type="text">
<!--v-if-->
<label class="pdap-input-label" for="test-2">Second test input</label>
</div>
<div class="pdap-grid-container pdap-input">
<!-- Text -->
<!--v-if-->
<!-- Password -->
<!-- Checkbox -->
<div class="pdap-input pdap-input-checkbox pdap-input-checkbox-checked">
<input checked class="pdap-input-checkbox" id="checkbox-default-checked" name="checkboxDefaultChecked" type="checkbox" value="true">
<!--v-if-->
<label class="pdap-input-label" for="checkbox-default-checked">Keep this box checked?</label>
</div>
<div class="pdap-grid-container pdap-input">
<!-- Text -->
<!--v-if-->
<!-- Password -->
<!-- Checkbox -->
<div class="pdap-input pdap-input-checkbox">
<input class="pdap-input-checkbox" id="checkbox-default-unchecked" name="checkboxDefaultUnchecked" type="checkbox" value="false">
<!--v-if-->
<label class="pdap-input-label" for="checkbox-default-unchecked">Check this box?</label>
Expand Down
4 changes: 2 additions & 2 deletions src/components/Form/form.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,10 @@ describe('Form component', () => {
);
expect(
(inputCheckboxDefaultChecked.element as HTMLInputElement).value
).toBe('false');
).toBe('true');
expect(
(inputCheckboxDefaultUnchecked.element as HTMLInputElement).value
).toBe('true');
).toBe('false');
});

test('Submits with correct values', async () => {
Expand Down
7 changes: 3 additions & 4 deletions src/components/Form/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PdapInputBaseProps } from '../Input/types';
import { PdapInputProps } from '../Input/types';

export type PdapLengthRules = 'maxLength' | 'minLength';

Expand All @@ -21,10 +21,9 @@ export interface PdapFormValidators {
password: PdapFormValidator<boolean>;
}

export interface PdapFormInputProps
extends Exclude<PdapInputBaseProps, 'error'> {
export type PdapFormInputProps = PdapInputProps & {
validators?: Partial<PdapFormValidators>;
}
};
export type PdapFormSchema = PdapFormInputProps[];
export type PdapFormData = Record<string, unknown>;

Expand Down
27 changes: 27 additions & 0 deletions src/components/Input/Checkbox/InputCheckbox.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<template>
<input
:id="id"
:name="name"
:checked="value === 'true' ?? undefined"
:value="value"
class="pdap-input-checkbox"
type="checkbox"
v-bind="$attrs"
@change="change"
/>
</template>

<script setup lang="ts">
import { PdapInputCheckboxProps } from '../types';

defineProps<PdapInputCheckboxProps>();

// Emits
const emit = defineEmits<{
(event: 'change', val: Event): void;
}>();

const change = (event: Event) => {
emit('change', event);
};
</script>
95 changes: 35 additions & 60 deletions src/components/Input/PdapInput.vue
Original file line number Diff line number Diff line change
@@ -1,46 +1,22 @@
<template>
<div
:class="{
'pdap-grid-container': true,
'pdap-input': true,
[`pdap-input-${type}`]: true,
[`pdap-input-${type}-checked`]:
type === PdapInputTypes.CHECKBOX && value === 'true',
'pdap-input-error': Number(error?.length) >= 1,
}"
>
<!-- Text -->
<input
v-if="type === PdapInputTypes.TEXT"
:id="id"
type="text"
:name="name"
:placeholder="placeholder"
:value="value"
v-bind="$attrs"
@input="input"
<PdapInputCheckbox
v-if="type === PdapInputTypes.CHECKBOX"
class="pdap-input-checkbox"
v-bind="{ ...$attrs, ...(props as PdapInputCheckboxProps) }"
/>

<!-- Password -->
<input
v-if="type === PdapInputTypes.PASSWORD"
:id="id"
type="password"
:name="name"
:placeholder="placeholder"
:value="value"
v-bind="$attrs"
@input="input"
/>

<!-- Checkbox -->
<input
v-else-if="type === PdapInputTypes.CHECKBOX"
:id="id"
class="pdap-input-checkbox"
:name="name"
:checked="checked"
type="checkbox"
:value="value"
v-bind="$attrs"
@change="change"
<PdapInputText
v-else
v-bind="{ ...$attrs, ...($props as PdapInputTextProps) }"
/>

<div v-if="error" :id="errorMessageId" class="pdap-input-error-message">
Expand All @@ -52,27 +28,17 @@
</template>

<script setup lang="ts">
import { computed, ref } from 'vue';
import { PdapInputBaseProps, PdapInputTypes } from './types';

const props = withDefaults(defineProps<PdapInputBaseProps>(), {});

// Emits
const emit = defineEmits<{
(event: 'change', val: string): void;
(event: 'input', val: string): void;
}>();

const change = () => {
checked.value = !checked.value;
emit('change', checked.value.toString());
};

const input = (event: Event) => {
emit('input', (<HTMLInputElement>event.target).value);
};

const checked = ref(props.defaultChecked);
import { computed } from 'vue';
import {
PdapInputProps,
PdapInputTypes,
PdapInputCheckboxProps,
PdapInputTextProps,
} from './types';
import PdapInputText from './Text/InputText.vue';
import PdapInputCheckbox from './Checkbox/InputCheckbox.vue';

const props = withDefaults(defineProps<PdapInputProps>(), {});

const errorMessageId = computed(() => `pdap-${props.name}-input-error`);
</script>
Expand All @@ -86,10 +52,6 @@ const errorMessageId = computed(() => `pdap-${props.name}-input-error`);
@apply h-[max-content] gap-4 leading-normal mb-3 w-full flex flex-col;
}

.pdap-grid-container.pdap-input {
@apply p-0 gap-0;
}

.pdap-input input {
@apply dark:bg-neutral-950 border border-neutral-500 border-solid px-3 py-2 text-[rgba(0,0,0)];
}
Expand Down Expand Up @@ -134,12 +96,25 @@ const errorMessageId = computed(() => `pdap-${props.name}-input-error`);
}

/* Input - checkbox */
.pdap-input-checkbox {
@apply border-2 border-transparent items-center gap-4 flex-row py-1 px-2 w-auto;
}

.pdap-input-checkbox-checked {
@apply border-2 border-brand-gold border-solid rounded-md;
}

.pdap-input input[type='checkbox'] {
@apply h-6 w-6 accent-brand-gold;
}

.pdap-input input[type='checkbox'] ~ label {
@apply pl-0;
@apply pl-0 w-full max-w-full;
}

.pdap-input input[type='checkbox'],
.pdap-input input[type='checkbox'] ~ label {
@apply cursor-pointer;
}
}
</style>