Skip to content
New issue

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

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

Already on GitHub? # to your account

feat: form v2 and inputs v2 #105

Merged
merged 3 commits into from
Oct 8, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion commitlint.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export default {
extends: ['@commitlint/config-conventional'],
rules: {
'footer-max-length': [2, 'never']
'footer-max-length': [0]
}
};
3 changes: 3 additions & 0 deletions src/components/Form/PdapForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ async function submit(e: Event) {
* The `Form` component is powerful. All you need to do is pass a few props, and the component will generate inputs and render them in the UI, complete with customizable form validation and both form-level and input-level error states.
*
*
* @deprecated use FormV2 with the PdapInputCheckbox, ...Text, and ...Password components instead
*
*
* ## Props
* @prop {string | undefined | null} error Error state. Only a non-falsy string results in a form-level error being displayed
* @prop {string} id Passed through to the `form` element as its `id`
Expand Down
99 changes: 99 additions & 0 deletions src/components/FormV2/PdapFormV2.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<template>
<form :id="id" :name="name" class="pdap-form" @submit.prevent="submit">
<slot v-if="$slots.error" name="error" />
<div
v-else-if="typeof errorMessage === 'string'"
class="pdap-form-error-message"
>
{{ errorMessage }}
</div>

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

// Types
import { PdapFormPropsV2 } from './types';
import { provideKey, makeRules } from './util';

// Props
const { defaultValues, error, schema } = withDefaults(
defineProps<PdapFormPropsV2>(),
{
error: null,
}
);

// Emits
const emit = defineEmits(['submit']);

// Constants
const errorMessage = ref(error);
const values = ref(defaultValues ?? {});
const rules = makeRules(schema);
const v$ = useVuelidate(rules, values, { $autoDirty: false, $lazy: true });

// Provide
provide(provideKey, {
setValues,
values,
rules,
v$,
});

// Expose
defineExpose({
setValues,
});

// Helpers
function setValues(val: Partial<typeof values.value>) {
values.value = { ...values.value, ...val };
}
function resetForm() {
v$.value.$reset();
values.value = Object.entries(values.value).reduce((acc, [key]) => {
return {
...acc,
[key]:
typeof values.value[key] === 'string'
? ''
: Boolean(defaultValues?.[key]),
};
}, {});
}
async function submit(e: 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.value }, e);

resetForm();
}
}

// Effects
// Effect - Updates form error state based on input error state and/or props
watchEffect(() => {
if (error) errorMessage.value = error;
else if (errorMessage.value && v$.value.$errors.length === 0)
errorMessage.value = null;
else if (!errorMessage.value && v$.value.$errors.length > 0)
errorMessage.value = 'Please update this form to correct the errors';
});
</script>

<style>
@tailwind components;

@layer components {
.pdap-form-error-message {
@apply items-center justify-start basis-full flex-shrink flex bg-red-300 text-red-800 mb-3 p-2 text-sm;
}
}
</style>
139 changes: 139 additions & 0 deletions src/components/FormV2/__snapshots__/formv2.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`PdapFormV2 > calls submit event with form values on valid submission 1`] = `
<form class="pdap-form" id="test" name="test">
<!--v-if-->
<div class="pdap-input">
<!--v-if-->
<input id="name" name="name" placeholder="Name" type="text">
<label for="name">Name</label>
</div>
<div class="pdap-input">
<!--v-if-->
<input id="email" name="email" placeholder="Email" type="text">
<label for="email">Email</label>
</div>
<div class="pdap-input pdap-input-password">
<!--v-if-->
<div class="pdap-input-password-wrapper">
<input id="password" name="password" placeholder="Password" type="password">
<button aria-label="Show text" class="pdap-input-password-toggle" type="button">
<svg aria-hidden="true" class="svg-inline--fa fa-eye" data-icon="eye" data-prefix="fas" focusable="false" role="img" viewBox="0 0 576 512" xmlns="http://www.w3.org/2000/svg">
<path class="" d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM144 256a144 144 0 1 1 288 0 144 144 0 1 1 -288 0zm144-64c0 35.3-28.7 64-64 64c-7.1 0-13.9-1.2-20.3-3.3c-5.5-1.8-11.9 1.6-11.7 7.4c.3 6.9 1.3 13.8 3.2 20.7c13.7 51.2 66.4 81.6 117.6 67.9s81.6-66.4 67.9-117.6c-11.1-41.5-47.8-69.4-88.6-71.1c-5.8-.2-9.2 6.1-7.4 11.7c2.1 6.4 3.3 13.2 3.3 20.3z" fill="currentColor" />
</svg>
</button>
</div>
<label for="password">Password</label>
</div>
<div class="pdap-input pdap-input-checkbox">
<!--v-if-->
<input checked id="ice-cream" name="ice-cream" type="checkbox" value="true">
<label for="ice-cream">Ice Cream</label>
</div>
</form>
`;

exports[`PdapFormV2 > renders default error message when form has errors 1`] = `
<form class="pdap-form" id="test" name="test">
<div class="pdap-form-error-message">Please update this form to correct the errors</div>
<div class="pdap-input pdap-input-error">
<div class="pdap-input-error-message">Value is required</div>
<input id="name" name="name" placeholder="Name" type="text">
<label for="name">Name</label>
</div>
<div class="pdap-input pdap-input-error">
<div class="pdap-input-error-message">Value is required</div>
<input id="email" name="email" placeholder="Email" type="text">
<label for="email">Email</label>
</div>
<div class="pdap-input pdap-input-password">
<!--v-if-->
<div class="pdap-input-password-wrapper">
<input id="password" name="password" placeholder="Password" type="password">
<button aria-label="Show text" class="pdap-input-password-toggle" type="button">
<svg aria-hidden="true" class="svg-inline--fa fa-eye" data-icon="eye" data-prefix="fas" focusable="false" role="img" viewBox="0 0 576 512" xmlns="http://www.w3.org/2000/svg">
<path class="" d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM144 256a144 144 0 1 1 288 0 144 144 0 1 1 -288 0zm144-64c0 35.3-28.7 64-64 64c-7.1 0-13.9-1.2-20.3-3.3c-5.5-1.8-11.9 1.6-11.7 7.4c.3 6.9 1.3 13.8 3.2 20.7c13.7 51.2 66.4 81.6 117.6 67.9s81.6-66.4 67.9-117.6c-11.1-41.5-47.8-69.4-88.6-71.1c-5.8-.2-9.2 6.1-7.4 11.7c2.1 6.4 3.3 13.2 3.3 20.3z" fill="currentColor" />
</svg>
</button>
</div>
<label for="password">Password</label>
</div>
<div class="pdap-input pdap-input-checkbox">
<!--v-if-->
<input id="ice-cream" name="ice-cream" type="checkbox" value="false">
<label for="ice-cream">Ice Cream</label>
</div>
</form>
`;

exports[`PdapFormV2 > renders error message slot when provided 1`] = `
<form class="pdap-form" id="test" name="test">
<div>Custom Error Message</div>
</form>
`;

exports[`PdapFormV2 > renders error message when errorMessage prop is provided 1`] = `
<form class="pdap-form" id="test" name="test">
<div class="pdap-form-error-message">Form Error</div>
<div class="pdap-input">
<!--v-if-->
<input id="name" name="name" placeholder="Name" type="text">
<label for="name">Name</label>
</div>
<div class="pdap-input">
<!--v-if-->
<input id="email" name="email" placeholder="Email" type="text">
<label for="email">Email</label>
</div>
<div class="pdap-input pdap-input-password">
<!--v-if-->
<div class="pdap-input-password-wrapper">
<input id="password" name="password" placeholder="Password" type="password">
<button aria-label="Show text" class="pdap-input-password-toggle" type="button">
<svg aria-hidden="true" class="svg-inline--fa fa-eye" data-icon="eye" data-prefix="fas" focusable="false" role="img" viewBox="0 0 576 512" xmlns="http://www.w3.org/2000/svg">
<path class="" d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM144 256a144 144 0 1 1 288 0 144 144 0 1 1 -288 0zm144-64c0 35.3-28.7 64-64 64c-7.1 0-13.9-1.2-20.3-3.3c-5.5-1.8-11.9 1.6-11.7 7.4c.3 6.9 1.3 13.8 3.2 20.7c13.7 51.2 66.4 81.6 117.6 67.9s81.6-66.4 67.9-117.6c-11.1-41.5-47.8-69.4-88.6-71.1c-5.8-.2-9.2 6.1-7.4 11.7c2.1 6.4 3.3 13.2 3.3 20.3z" fill="currentColor" />
</svg>
</button>
</div>
<label for="password">Password</label>
</div>
<div class="pdap-input pdap-input-checkbox">
<!--v-if-->
<input id="ice-cream" name="ice-cream" type="checkbox" value="false">
<label for="ice-cream">Ice Cream</label>
</div>
</form>
`;

exports[`PdapFormV2 > renders the form element 1`] = `
<form class="pdap-form" id="test" name="test">
<!--v-if-->
<div class="pdap-input">
<!--v-if-->
<input id="name" name="name" placeholder="Name" type="text">
<label for="name">Name</label>
</div>
<div class="pdap-input">
<!--v-if-->
<input id="email" name="email" placeholder="Email" type="text">
<label for="email">Email</label>
</div>
<div class="pdap-input pdap-input-password">
<!--v-if-->
<div class="pdap-input-password-wrapper">
<input id="password" name="password" placeholder="Password" type="password">
<button aria-label="Show text" class="pdap-input-password-toggle" type="button">
<svg aria-hidden="true" class="svg-inline--fa fa-eye" data-icon="eye" data-prefix="fas" focusable="false" role="img" viewBox="0 0 576 512" xmlns="http://www.w3.org/2000/svg">
<path class="" d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM144 256a144 144 0 1 1 288 0 144 144 0 1 1 -288 0zm144-64c0 35.3-28.7 64-64 64c-7.1 0-13.9-1.2-20.3-3.3c-5.5-1.8-11.9 1.6-11.7 7.4c.3 6.9 1.3 13.8 3.2 20.7c13.7 51.2 66.4 81.6 117.6 67.9s81.6-66.4 67.9-117.6c-11.1-41.5-47.8-69.4-88.6-71.1c-5.8-.2-9.2 6.1-7.4 11.7c2.1 6.4 3.3 13.2 3.3 20.3z" fill="currentColor" />
</svg>
</button>
</div>
<label for="password">Password</label>
</div>
<div class="pdap-input pdap-input-checkbox">
<!--v-if-->
<input id="ice-cream" name="ice-cream" type="checkbox" value="false">
<label for="ice-cream">Ice Cream</label>
</div>
</form>
`;
Loading
Loading