Skip to content

Commit

Permalink
✨ - feat: add form component
Browse files Browse the repository at this point in the history
  • Loading branch information
svenvandescheur committed Feb 19, 2024
1 parent 791a94e commit 011e9e3
Show file tree
Hide file tree
Showing 27 changed files with 739 additions and 11 deletions.
9 changes: 9 additions & 0 deletions src/components/button/button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@
transform: translateY(var(--mykn-button-offset));
width: var(--mykn-button-width);

&[disabled] {
--mykn-button-color-background: var(
--mykn-button-color-background-mute,
#ccc
) !important;
--mykn-button-offset: 0 !important;
pointer-events: none;
}

&--bold {
--mykn-button-font-weight: var(--typography-font-weight-bold);
}
Expand Down
7 changes: 7 additions & 0 deletions src/components/form/errormessage/errormessage.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.mykn-errormessage {
color: var(--page-color-danger);
font-family: var(--typography-font-family-body);
font-size: var(--typography-font-size-body-s);
font-weight: var(--typography-font-weight-bold);
line-height: var(--typography-line-height-body-s);
}
17 changes: 17 additions & 0 deletions src/components/form/errormessage/errormessage.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { Meta, StoryObj } from "@storybook/react";

import { ErrorMessage } from "./errormessage";

const meta = {
title: "Form/ErrorMessage",
component: ErrorMessage,
} satisfies Meta<typeof ErrorMessage>;

export default meta;
type Story = StoryObj<typeof meta>;

export const ErrorMessageComponent: Story = {
args: {
children: "The quick brown fox jumps over the lazy dog.",
},
};
20 changes: 20 additions & 0 deletions src/components/form/errormessage/errormessage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from "react";

import "./errormessage.scss";

export type ErrorMessageProps = React.ComponentProps<"span">;

/**
* ErrorMessage component
* @param children
* @param props
* @constructor
*/
export const ErrorMessage: React.FC<ErrorMessageProps> = ({
children,
...props
}) => (
<span className="mykn-errormessage" role={"alert"} {...props}>
{children}
</span>
);
1 change: 1 addition & 0 deletions src/components/form/errormessage/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./errormessage";
5 changes: 5 additions & 0 deletions src/components/form/form/form.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.mykn-form {
display: flex;
flex-direction: column;
gap: var(--spacing-v-l);
}
122 changes: 122 additions & 0 deletions src/components/form/form/form.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import type { Meta, StoryObj } from "@storybook/react";
import { userEvent, within } from "@storybook/test";
import { Formik } from "formik";
import React from "react";

import { formatMessage } from "../../../lib/i18n/formatmessage";
import { Form } from "./form";

const meta = {
title: "Form/Form",
component: Form,
} satisfies Meta<typeof Form>;

export default meta;
type Story = StoryObj<typeof meta>;

export const FormComponent: Story = {
args: {
debug: true,
fields: [
{ label: "First name", name: "first_name" },
{ label: "Last name", name: "last_name" },
{
label: "Select school year",
name: "school_year",
options: [
{ label: "Freshman" },
{ label: "Sophomore" },
{ label: "Junior" },
{ label: "Senior" },
{ label: "Graduate" },
],
},
{ label: "Address", name: "address" },
{ label: "Address (addition)", name: "address" },
],
validate: (values, fields) => {
const entries = Object.entries(values);
const emtpyEntries = entries.filter(([, value]) => !value);
const mappedEntries = emtpyEntries.map(([name]) => [
name,
formatMessage('Field "{name}" is required', {
name: (
fields?.find((f) => f.name === name)?.label || name
).toLowerCase(),
}),
]);
return Object.fromEntries(mappedEntries);
},
validateOnChange: true,
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const firstName = canvas.getByLabelText("First name");
const lastName = canvas.getByLabelText("Last name");
const schoolYear = canvas.getByLabelText("Select school year");
const address = canvas.getByLabelText("Address");
const address_addition = canvas.getByLabelText("Address (addition)");

await userEvent.clear(firstName);
await userEvent.type(firstName, "John", { delay: 10 });

await userEvent.clear(lastName);
await userEvent.type(lastName, "Doe", { delay: 10 });

await userEvent.click(schoolYear, { delay: 10 });
const junior = await canvas.findByText("Junior");
await userEvent.click(junior, { delay: 10 });

await userEvent.clear(address);
await userEvent.type(address, "Keizersgracht 117", { delay: 10 });

await userEvent.clear(address_addition);
await userEvent.type(address_addition, "2", { delay: 10 });
},
};

export const usageWithFormik: Story = {
...FormComponent,
args: {
...FormComponent.args,
fields: [
{ label: "First name", name: "first_name" },
{ label: "Last name", name: "last_name" },
{
label: "Select school year",
name: "school_year",
options: [
{ label: "Freshman" },
{ label: "Sophomore" },
{ label: "Junior" },
{ label: "Senior" },
{ label: "Graduate" },
],
},
{ label: "Address", name: "address[0]" },
{ label: "Address (addition)", name: "address[1]" },
],
},
render: (args) => {
return (
<Formik
initialValues={{}}
onSubmit={(data) => console.log(data)}
validate={(values) =>
args.validate && args.validate(values, args.fields)
}
validateOnChange={args.validateOnChange}
>
{({ errors, values, handleChange }) => (
<Form
debug={args.debug}
errors={errors}
fields={args.fields}
values={values}
onChange={handleChange}
></Form>
)}
</Formik>
);
},
};
Loading

0 comments on commit 011e9e3

Please sign in to comment.