✨(react) add generic Field component
This component will wrap most of form components in order to provide them a generic state attribute along with texts below them.
This commit is contained in:
5
.changeset/clean-ladybugs-visit.md
Normal file
5
.changeset/clean-ladybugs-visit.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@openfun/cunningham-react": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Add Field component
|
||||||
30
packages/react/src/components/Forms/Field/index.scss
Normal file
30
packages/react/src/components/Forms/Field/index.scss
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
.c__field {
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: var(--c--components--forms-field--width);
|
||||||
|
color: var(--c--components--forms-field--color);
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
&__footer {
|
||||||
|
font-size: var(--c--components--forms-field--font-size);
|
||||||
|
padding: 0.25rem calc(1rem + 2px) 0 calc(1rem + 2px);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__text, &__text-right {
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--error {
|
||||||
|
color: var(--c--theme--colors--danger-500);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--success {
|
||||||
|
color: var(--c--theme--colors--success-600)
|
||||||
|
}
|
||||||
|
|
||||||
|
&--full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
27
packages/react/src/components/Forms/Field/index.stories.mdx
Normal file
27
packages/react/src/components/Forms/Field/index.stories.mdx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { Canvas, Meta, Story, Source, ArgsTable } from '@storybook/addon-docs';
|
||||||
|
import { Field } from "./index";
|
||||||
|
|
||||||
|
<Meta title="Components/Forms/Field/Doc" component={Field}/>
|
||||||
|
|
||||||
|
export const Template = (args) => <Field {...args} />;
|
||||||
|
|
||||||
|
# Field
|
||||||
|
|
||||||
|
The Field component is used to wrap a form input. As a design system consumer you are
|
||||||
|
not supposed to directly use it, unless you need to create custom inputs.
|
||||||
|
|
||||||
|
**But, as most of Cunningham's components are wrapped inside this component, you may need to customize**
|
||||||
|
the default width, the generics texts below inputs for example. This documentation is here to show you the
|
||||||
|
available design token to do so.
|
||||||
|
|
||||||
|
## Design tokens
|
||||||
|
|
||||||
|
| Token | Description |
|
||||||
|
|--------------- |----------------------------- |
|
||||||
|
| width | Default width of inputs ( default is 292px ) |
|
||||||
|
| font-size | Font size of texts below inputs |
|
||||||
|
| color | Font color of texts below inputs |
|
||||||
|
|
||||||
|
## Props
|
||||||
|
|
||||||
|
<ArgsTable of={Field} />
|
||||||
34
packages/react/src/components/Forms/Field/index.stories.tsx
Normal file
34
packages/react/src/components/Forms/Field/index.stories.tsx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { ComponentMeta, ComponentStory } from "@storybook/react";
|
||||||
|
import React from "react";
|
||||||
|
import { Field } from "components/Forms/Field/index";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: "Components/Forms/Field",
|
||||||
|
component: Field,
|
||||||
|
} as ComponentMeta<typeof Field>;
|
||||||
|
|
||||||
|
const Template: ComponentStory<typeof Field> = (args) => (
|
||||||
|
<Field {...args}>
|
||||||
|
<strong>Any children</strong>
|
||||||
|
</Field>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const Default = Template.bind({});
|
||||||
|
Default.args = {
|
||||||
|
text: "This is an optional text",
|
||||||
|
rightText: "Right text",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Success = Template.bind({});
|
||||||
|
Success.args = {
|
||||||
|
state: "success",
|
||||||
|
text: "This is an optional success message",
|
||||||
|
rightText: "Right text",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Error = Template.bind({});
|
||||||
|
Error.args = {
|
||||||
|
state: "error",
|
||||||
|
text: "This is an optional error message",
|
||||||
|
rightText: "Right text",
|
||||||
|
};
|
||||||
37
packages/react/src/components/Forms/Field/index.tsx
Normal file
37
packages/react/src/components/Forms/Field/index.tsx
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import React, { PropsWithChildren } from "react";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
|
export type FieldState = "success" | "error" | "default";
|
||||||
|
|
||||||
|
export type FieldProps = {
|
||||||
|
state?: FieldState | undefined;
|
||||||
|
text?: string | undefined;
|
||||||
|
rightText?: string | undefined;
|
||||||
|
fullWidth?: boolean | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = FieldProps & PropsWithChildren;
|
||||||
|
|
||||||
|
export const Field = ({
|
||||||
|
children,
|
||||||
|
state = "default",
|
||||||
|
text,
|
||||||
|
rightText,
|
||||||
|
fullWidth,
|
||||||
|
}: Props) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames("c__field", "c__field--" + state, {
|
||||||
|
"c__field--full-width": fullWidth,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
{(text || rightText) && (
|
||||||
|
<div className="c__field__footer">
|
||||||
|
<span className="c__field__text">{text}</span>
|
||||||
|
<span className="c__field__text__right">{rightText}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
7
packages/react/src/components/Forms/Field/tokens.ts
Normal file
7
packages/react/src/components/Forms/Field/tokens.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { DefaultTokens } from "@openfun/cunningham-tokens";
|
||||||
|
|
||||||
|
export const tokens = (defaults: DefaultTokens) => ({
|
||||||
|
width: "292px",
|
||||||
|
"font-size": defaults.theme.font.sizes.s,
|
||||||
|
color: defaults.theme.colors["greyscale-600"],
|
||||||
|
});
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
@import './components/Accessibility';
|
@import './components/Accessibility';
|
||||||
@import './components/Button';
|
@import './components/Button';
|
||||||
@import './components/DataGrid';
|
@import './components/DataGrid';
|
||||||
|
@import './components/Forms/Field';
|
||||||
@import './components/Forms/Input';
|
@import './components/Forms/Input';
|
||||||
@import './components/Loader';
|
@import './components/Loader';
|
||||||
@import './components/Pagination';
|
@import './components/Pagination';
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import "./index.scss";
|
|||||||
export * from "./components/Button";
|
export * from "./components/Button";
|
||||||
export * from "./components/DataGrid";
|
export * from "./components/DataGrid";
|
||||||
export * from "./components/DataGrid/SimpleDataGrid";
|
export * from "./components/DataGrid/SimpleDataGrid";
|
||||||
|
export * from "./components/Forms/Field";
|
||||||
export * from "./components/Loader";
|
export * from "./components/Loader";
|
||||||
export * from "./components/Pagination";
|
export * from "./components/Pagination";
|
||||||
export * from "./components/Provider";
|
export * from "./components/Provider";
|
||||||
|
|||||||
Reference in New Issue
Block a user