✨(react) add Checkbox component
Implement Checkbox input based on designed sketches.
This commit is contained in:
5
.changeset/quick-singers-poke.md
Normal file
5
.changeset/quick-singers-poke.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@openfun/cunningham-react": minor
|
||||
---
|
||||
|
||||
add Checkbox component
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M17.5685 6.34318L9.8751 14.0366L7.07184 11.2333C6.84127 11.0106 6.53245 10.8874 6.21191 10.8902C5.89137 10.893 5.58474 11.0215 5.35807 11.2482C5.1314 11.4749 5.00283 11.7815 5.00005 12.102C4.99726 12.4226 5.12048 12.7314 5.34318 12.962L9.01077 16.6296C9.24003 16.8587 9.55093 16.9875 9.8751 16.9875C10.1993 16.9875 10.5102 16.8587 10.7394 16.6296L19.2972 8.07184C19.5198 7.84127 19.6431 7.53245 19.6403 7.21191C19.6375 6.89136 19.5089 6.58474 19.2823 6.35807C19.0556 6.1314 18.749 6.00283 18.4284 6.00005C18.1079 5.99726 17.7991 6.12048 17.5685 6.34318Z" fill="#419A14"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 688 B |
125
packages/react/src/components/Forms/Checkbox/index.scss
Normal file
125
packages/react/src/components/Forms/Checkbox/index.scss
Normal file
@@ -0,0 +1,125 @@
|
||||
.c__checkbox__group {
|
||||
|
||||
&__list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.c__field__footer {
|
||||
padding: 0.25rem 0 0 calc(2rem);
|
||||
}
|
||||
}
|
||||
|
||||
.c__checkbox {
|
||||
display: inline-flex;
|
||||
$padding: 0.25rem;
|
||||
padding: $padding;
|
||||
border-radius: 2px;
|
||||
box-sizing: border-box;
|
||||
border-style: solid;
|
||||
border-color: transparent;
|
||||
// To automatically align the checkbox to the left side.
|
||||
margin-left: -1 * $padding;
|
||||
|
||||
&:hover, &:focus-within {
|
||||
background-color: var(--c--theme--colors--greyscale-200);
|
||||
}
|
||||
|
||||
&:focus-within {
|
||||
outline: 0;
|
||||
border-color: var(--c--theme--colors--primary-600);
|
||||
}
|
||||
|
||||
&__container {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
color: var(--c--components--forms-checkbox--color);
|
||||
}
|
||||
|
||||
.c__field__footer {
|
||||
padding: 0.25rem 0 0 calc(2rem);
|
||||
}
|
||||
|
||||
&__wrapper {
|
||||
position: relative;
|
||||
$clipPathShow: inset(0 0 0 0);
|
||||
$clipPathHide: inset(0 100% 0 0);
|
||||
|
||||
input {
|
||||
appearance: none;
|
||||
margin: 0;
|
||||
background-color: white;
|
||||
width: var(--c--components--forms-checkbox--size);
|
||||
height: var(--c--components--forms-checkbox--size);
|
||||
border: 1.5px solid var(--c--components--forms-checkbox--border-color);
|
||||
border-radius: var(--c--components--forms-checkbox--border-radius);
|
||||
display: block;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:not(:checked) {
|
||||
~ .checkmark {
|
||||
clip-path: $clipPathHide;
|
||||
}
|
||||
~ .indeterminate {
|
||||
clip-path: $clipPathHide;
|
||||
}
|
||||
}
|
||||
|
||||
&:checked {
|
||||
~ .checkmark {
|
||||
clip-path: $clipPathShow;
|
||||
}
|
||||
~ .indeterminate {
|
||||
clip-path: $clipPathHide;
|
||||
}
|
||||
}
|
||||
|
||||
&:indeterminate {
|
||||
~ .indeterminate {
|
||||
clip-path: $clipPathShow;
|
||||
}
|
||||
~ .checkmark {
|
||||
clip-path: $clipPathHide;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
clip-path: $clipPathHide;
|
||||
transition: var(--c--theme--transitions--duration) var(--c--theme--transitions--ease-out);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
color: var(--c--components--forms-checkbox--accent-color);
|
||||
}
|
||||
}
|
||||
|
||||
&__label {
|
||||
font-size: var(--c--components--forms-checkbox--font-size);
|
||||
font-weight: var(--c--components--forms-checkbox--font-weight);
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
border-color: transparent;
|
||||
color: var(--c--theme--colors--greyscale-600);
|
||||
|
||||
svg {
|
||||
color: var(--c--theme--colors--greyscale-400);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.c__checkbox__label {
|
||||
color: var(--c--theme--colors--greyscale-600);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
109
packages/react/src/components/Forms/Checkbox/index.spec.tsx
Normal file
109
packages/react/src/components/Forms/Checkbox/index.spec.tsx
Normal file
@@ -0,0 +1,109 @@
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { Checkbox, CheckboxGroup } from "components/Forms/Checkbox/index";
|
||||
|
||||
describe("<Checkbox/>", () => {
|
||||
it("renders and can be checked", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<Checkbox label="Agree" />);
|
||||
const input: HTMLInputElement = screen.getByRole("checkbox", {
|
||||
name: "Agree",
|
||||
});
|
||||
expect(input.checked).toEqual(false);
|
||||
await user.click(input);
|
||||
expect(input.checked).toEqual(true);
|
||||
});
|
||||
it("renders with default value and can be unchecked", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<Checkbox label="Agree" checked={true} />);
|
||||
const input: HTMLInputElement = screen.getByRole("checkbox", {
|
||||
name: "Agree",
|
||||
});
|
||||
expect(input.checked).toEqual(true);
|
||||
await user.click(input);
|
||||
expect(input.checked).toEqual(false);
|
||||
});
|
||||
it("renders with indeterminate state", async () => {
|
||||
render(<Checkbox label="Agree" indeterminate={true} />);
|
||||
expect(document.querySelector("svg.indeterminate")).toBeInTheDocument();
|
||||
});
|
||||
it("renders disabled", async () => {
|
||||
render(<Checkbox label="Agree" disabled={true} />);
|
||||
expect(screen.getByRole("checkbox", { name: "Agree" })).toBeDisabled();
|
||||
// Click and expect the checkbox does not get checked
|
||||
const user = userEvent.setup();
|
||||
const input: HTMLInputElement = screen.getByRole("checkbox", {
|
||||
name: "Agree",
|
||||
});
|
||||
expect(input.checked).toEqual(false);
|
||||
await user.click(input);
|
||||
expect(input.checked).toEqual(false);
|
||||
});
|
||||
it("renders with text", async () => {
|
||||
render(<Checkbox label="Agree" text="Text" />);
|
||||
expect(screen.getByText("Text")).toBeInTheDocument();
|
||||
});
|
||||
it("renders with state=success", async () => {
|
||||
render(<Checkbox label="Agree" state="success" text="Success text" />);
|
||||
expect(screen.getByText("Success text")).toBeInTheDocument();
|
||||
expect(
|
||||
document.querySelector(".c__field.c__field--success")
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
it("renders with state=error", async () => {
|
||||
render(<Checkbox label="Agree" state="error" text="Error text" />);
|
||||
expect(screen.getByText("Error text")).toBeInTheDocument();
|
||||
expect(
|
||||
document.querySelector(".c__field.c__field--error")
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders with group", async () => {
|
||||
render(
|
||||
<CheckboxGroup>
|
||||
<Checkbox label="Agree" />
|
||||
<Checkbox label="Disagree" />
|
||||
</CheckboxGroup>
|
||||
);
|
||||
screen.getByRole("checkbox", {
|
||||
name: "Agree",
|
||||
});
|
||||
screen.getByRole("checkbox", {
|
||||
name: "Disagree",
|
||||
});
|
||||
});
|
||||
it("renders with group text", async () => {
|
||||
render(
|
||||
<CheckboxGroup text="Text">
|
||||
<Checkbox label="Agree" />
|
||||
<Checkbox label="Disagree" />
|
||||
</CheckboxGroup>
|
||||
);
|
||||
expect(screen.getByText("Text")).toBeInTheDocument();
|
||||
});
|
||||
it("renders with group state=success", async () => {
|
||||
render(
|
||||
<CheckboxGroup state="success" text="Success text">
|
||||
<Checkbox label="Agree" />
|
||||
<Checkbox label="Disagree" />
|
||||
</CheckboxGroup>
|
||||
);
|
||||
expect(screen.getByText("Success text")).toBeInTheDocument();
|
||||
expect(
|
||||
document.querySelector(".c__checkbox__group.c__field.c__field--success")
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
it("renders with group state=error", async () => {
|
||||
render(
|
||||
<CheckboxGroup state="error" text="Error text">
|
||||
<Checkbox label="Agree" />
|
||||
<Checkbox label="Disagree" />
|
||||
</CheckboxGroup>
|
||||
);
|
||||
expect(screen.getByText("Error text")).toBeInTheDocument();
|
||||
expect(
|
||||
document.querySelector(".c__checkbox__group.c__field.c__field--error")
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
110
packages/react/src/components/Forms/Checkbox/index.stories.mdx
Normal file
110
packages/react/src/components/Forms/Checkbox/index.stories.mdx
Normal file
@@ -0,0 +1,110 @@
|
||||
import { Canvas, Meta, Story, Source, ArgsTable } from '@storybook/addon-docs';
|
||||
import { Checkbox } from "./index";
|
||||
|
||||
<Meta title="Components/Forms/Checkbox/Doc" component={Checkbox}/>
|
||||
|
||||
# Checkbox
|
||||
|
||||
Cunningham provides a versatile Checkbox component that you can use in your forms.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-forms-checkbox--group"/>
|
||||
</Canvas>
|
||||
|
||||
## Label
|
||||
|
||||
The `label` props is optional, but you can use it to provide a description of the checkbox.
|
||||
|
||||
**Without label**
|
||||
|
||||
<Canvas withSource="open">
|
||||
<Story id="components-forms-checkbox--default"/>
|
||||
</Canvas>
|
||||
|
||||
**With label**
|
||||
|
||||
<Canvas withSource="open">
|
||||
<Story id="components-forms-checkbox--with-label"/>
|
||||
</Canvas>
|
||||
|
||||
## Value
|
||||
|
||||
You can set the value of the checkbox in 3 different ways.
|
||||
|
||||
<Canvas withSource="open">
|
||||
<Story id="components-forms-checkbox--default"/>
|
||||
<Story id="components-forms-checkbox--indeterminate"/>
|
||||
<Story id="components-forms-checkbox--checked"/>
|
||||
</Canvas>
|
||||
|
||||
## Texts
|
||||
|
||||
As the component uses [Field](?path=/story/components-forms-field-doc--page), you can use the `text` props to provide a description of the checkbox.
|
||||
|
||||
<Canvas withSource="open">
|
||||
<Story id="components-forms-checkbox--with-texts"/>
|
||||
</Canvas>
|
||||
|
||||
## Disabled
|
||||
|
||||
As a regular checkbox, you can disable it by using the `disabled` props.
|
||||
|
||||
<Canvas withSource="open">
|
||||
<Story id="components-forms-checkbox--disabled"/>
|
||||
</Canvas>
|
||||
|
||||
## States
|
||||
|
||||
You can use the following props to change the state of the Input component by using the `state` props.
|
||||
|
||||
<Canvas withSource="open">
|
||||
<Story id="components-forms-checkbox--with-texts"/>
|
||||
</Canvas>
|
||||
|
||||
<Canvas withSource="open">
|
||||
<Story id="components-forms-checkbox--success"/>
|
||||
</Canvas>
|
||||
|
||||
<Canvas withSource="open">
|
||||
<Story id="components-forms-checkbox--error"/>
|
||||
</Canvas>
|
||||
|
||||
## Group
|
||||
|
||||
It will happen often that you will need to use multiple grouped checkboxes. You can use the `CheckboxGroup` component to do so.
|
||||
|
||||
<Canvas withSource="open">
|
||||
<Story id="components-forms-checkbox--group"/>
|
||||
</Canvas>
|
||||
|
||||
You can also define `state`, `text` props on the group component
|
||||
|
||||
<Canvas withSource="open">
|
||||
<Story id="components-forms-checkbox--group-error"/>
|
||||
<Story id="components-forms-checkbox--group-success"/>
|
||||
</Canvas>
|
||||
|
||||
## Design tokens
|
||||
|
||||
Here are available custom design tokens.
|
||||
|
||||
| Token | Description |
|
||||
|--------------- |----------------------------- |
|
||||
| font-size | Label font size ( shared with radio ) |
|
||||
| font-weight | Label font weight ( shared with radio ) |
|
||||
| color | Label color ( shared with radio ) |
|
||||
| border-color | Border color of the checkbox |
|
||||
| border-radius | Border radius of the checkbox |
|
||||
| accent-color | Color of the checkmark and the indeterminate mark |
|
||||
| width | Width of the checkbox |
|
||||
| height | Height of the checkbox |
|
||||
|
||||
See also [Field](?path=/story/components-forms-field-doc--page)
|
||||
|
||||
##
|
||||
|
||||
<img src="components/Forms/Checkbox/resources/dd_1.svg"/>
|
||||
|
||||
##
|
||||
|
||||
<img src="components/Forms/Checkbox/resources/dd_2.svg"/>
|
||||
@@ -1,9 +1,9 @@
|
||||
import { ComponentMeta, ComponentStory } from "@storybook/react";
|
||||
import React from "react";
|
||||
import { Checkbox } from "components/Forms/Checkbox/index";
|
||||
import { Checkbox, CheckboxGroup } from "components/Forms/Checkbox/index";
|
||||
|
||||
export default {
|
||||
title: "Components/Forms (WIP)/Checkbox",
|
||||
title: "Components/Forms/Checkbox",
|
||||
component: Checkbox,
|
||||
} as ComponentMeta<typeof Checkbox>;
|
||||
|
||||
@@ -14,12 +14,98 @@ const Template: ComponentStory<typeof Checkbox> = (args) => (
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {};
|
||||
|
||||
export const Checked = Template.bind({});
|
||||
Checked.args = {
|
||||
checked: true,
|
||||
};
|
||||
|
||||
export const Indeterminate = Template.bind({});
|
||||
Indeterminate.args = {
|
||||
indeterminate: true,
|
||||
};
|
||||
|
||||
export const Checked = Template.bind({});
|
||||
Checked.args = {
|
||||
checked: true,
|
||||
export const WithLabel = Template.bind({});
|
||||
WithLabel.args = {
|
||||
label: "Label",
|
||||
};
|
||||
|
||||
export const LabelChecked = Template.bind({});
|
||||
LabelChecked.args = {
|
||||
checked: true,
|
||||
label: "Label",
|
||||
};
|
||||
|
||||
export const WithTexts = Template.bind({});
|
||||
WithTexts.args = {
|
||||
checked: true,
|
||||
label: "Label",
|
||||
text: "This is an optional text",
|
||||
};
|
||||
|
||||
export const Disabled = Template.bind({});
|
||||
Disabled.args = {
|
||||
disabled: true,
|
||||
label: "Label",
|
||||
};
|
||||
|
||||
export const DisabledChecked = Template.bind({});
|
||||
DisabledChecked.args = {
|
||||
checked: true,
|
||||
disabled: true,
|
||||
label: "Label",
|
||||
};
|
||||
|
||||
export const Error = Template.bind({});
|
||||
Error.args = {
|
||||
checked: true,
|
||||
label: "Label",
|
||||
text: "This is an optional text",
|
||||
state: "error",
|
||||
};
|
||||
|
||||
export const Success = Template.bind({});
|
||||
Success.args = {
|
||||
checked: true,
|
||||
label: "Label",
|
||||
text: "This is an optional text",
|
||||
state: "success",
|
||||
};
|
||||
|
||||
export const Group = () => (
|
||||
<div>
|
||||
<div className="fs-l fw-bold mb-t">Your offices</div>
|
||||
<CheckboxGroup>
|
||||
<Checkbox label="Paris" />
|
||||
<Checkbox label="New York" text="United States" checked={true} />
|
||||
<Checkbox label="Hong Kong" text="Really long text to write something" />
|
||||
<Checkbox label="Singapour" checked={true} />
|
||||
<Checkbox label="London" text="Offices closed" disabled={true} />
|
||||
</CheckboxGroup>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const GroupError = () => (
|
||||
<div>
|
||||
<div className="fs-l fw-bold mb-t">Your offices</div>
|
||||
<CheckboxGroup state="error" text="An important error message">
|
||||
<Checkbox label="Paris" />
|
||||
<Checkbox label="New York" text="United States" checked={true} />
|
||||
<Checkbox label="Hong Kong" text="Really long text to write something" />
|
||||
<Checkbox label="Singapour" checked={true} />
|
||||
<Checkbox label="London" text="Offices closed" disabled={true} />
|
||||
</CheckboxGroup>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const GroupSuccess = () => (
|
||||
<div>
|
||||
<div className="fs-l fw-bold mb-t">Your offices</div>
|
||||
<CheckboxGroup state="success" text="Success message !">
|
||||
<Checkbox label="Paris" />
|
||||
<Checkbox label="New York" text="United States" checked={true} />
|
||||
<Checkbox label="Hong Kong" text="Really long text to write something" />
|
||||
<Checkbox label="Singapour" checked={true} />
|
||||
<Checkbox label="London" text="Offices closed" disabled={true} />
|
||||
</CheckboxGroup>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,17 +1,112 @@
|
||||
import React, { HTMLProps, useEffect, useRef } from "react";
|
||||
import React, {
|
||||
InputHTMLAttributes,
|
||||
PropsWithChildren,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import classNames from "classnames";
|
||||
import { Field, FieldProps } from "components/Forms/Field";
|
||||
|
||||
type Props = InputHTMLAttributes<HTMLInputElement> &
|
||||
FieldProps & {
|
||||
indeterminate?: boolean;
|
||||
label?: string;
|
||||
};
|
||||
|
||||
export const Checkbox = ({
|
||||
indeterminate,
|
||||
className = "",
|
||||
...rest
|
||||
}: { indeterminate?: boolean } & HTMLProps<HTMLInputElement>) => {
|
||||
const ref = useRef<HTMLInputElement>(null!);
|
||||
checked,
|
||||
label,
|
||||
text,
|
||||
rightText,
|
||||
state,
|
||||
...props
|
||||
}: Props) => {
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const [value, setValue] = useState<boolean>(!!checked);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof indeterminate === "boolean") {
|
||||
ref.current.indeterminate = !rest.checked && indeterminate;
|
||||
}
|
||||
}, [ref, indeterminate]);
|
||||
setValue(!!checked);
|
||||
}, [checked]);
|
||||
|
||||
return <input type="checkbox" ref={ref} className={className} {...rest} />;
|
||||
useEffect(() => {
|
||||
if (inputRef.current) {
|
||||
inputRef.current.indeterminate = !!indeterminate;
|
||||
}
|
||||
}, [indeterminate]);
|
||||
|
||||
return (
|
||||
<label
|
||||
className={classNames("c__checkbox", {
|
||||
"c__checkbox--disabled": props.disabled,
|
||||
})}
|
||||
>
|
||||
<Field text={text} rightText={rightText} compact={true} state={state}>
|
||||
<div className="c__checkbox__container">
|
||||
<div className="c__checkbox__wrapper">
|
||||
<input
|
||||
type="checkbox"
|
||||
className={className}
|
||||
onChange={(e) => setValue(e.target.checked)}
|
||||
{...props}
|
||||
checked={value}
|
||||
ref={inputRef}
|
||||
/>
|
||||
<Indeterminate />
|
||||
<Checkmark />
|
||||
</div>
|
||||
{label && <div className="c__checkbox__label">{label}</div>}
|
||||
</div>
|
||||
</Field>
|
||||
</label>
|
||||
);
|
||||
};
|
||||
|
||||
export const CheckboxGroup = ({
|
||||
children,
|
||||
state,
|
||||
text,
|
||||
rightText,
|
||||
}: PropsWithChildren & FieldProps) => {
|
||||
return (
|
||||
<Field
|
||||
className="c__checkbox__group"
|
||||
state={state}
|
||||
text={text}
|
||||
rightText={rightText}
|
||||
>
|
||||
<div className="c__checkbox__group__list">{children}</div>
|
||||
</Field>
|
||||
);
|
||||
};
|
||||
|
||||
const Checkmark = () => (
|
||||
<svg
|
||||
className="checkmark"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M17.5685 6.34318L9.8751 14.0366L7.07184 11.2333C6.84127 11.0106 6.53245 10.8874 6.21191 10.8902C5.89137 10.893 5.58474 11.0215 5.35807 11.2482C5.1314 11.4749 5.00283 11.7815 5.00005 12.102C4.99726 12.4226 5.12048 12.7314 5.34318 12.962L9.01077 16.6296C9.24003 16.8587 9.55093 16.9875 9.8751 16.9875C10.1993 16.9875 10.5102 16.8587 10.7394 16.6296L19.2972 8.07184C19.5198 7.84127 19.6431 7.53245 19.6403 7.21191C19.6375 6.89136 19.5089 6.58474 19.2823 6.35807C19.0556 6.1314 18.749 6.00283 18.4284 6.00005C18.1079 5.99726 17.7991 6.12048 17.5685 6.34318Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
const Indeterminate = () => (
|
||||
<svg
|
||||
className="indeterminate"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect x="5" y="10" width="14" height="3" rx="1.5" fill="currentColor" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 161 KiB |
105
packages/react/src/components/Forms/Checkbox/resources/dd_2.svg
Normal file
105
packages/react/src/components/Forms/Checkbox/resources/dd_2.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 383 KiB |
11
packages/react/src/components/Forms/Checkbox/tokens.ts
Normal file
11
packages/react/src/components/Forms/Checkbox/tokens.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { DefaultTokens } from "@openfun/cunningham-tokens";
|
||||
|
||||
export const tokens = (defaults: DefaultTokens) => ({
|
||||
"font-size": defaults.theme.font.sizes.m,
|
||||
"font-weight": defaults.theme.font.weights.medium,
|
||||
color: defaults.theme.colors["greyscale-900"],
|
||||
"border-color": defaults.theme.colors["greyscale-300"],
|
||||
"border-radius": "2px",
|
||||
"accent-color": defaults.theme.colors["success-700"],
|
||||
size: "1.5rem",
|
||||
});
|
||||
@@ -96,6 +96,8 @@
|
||||
--c--theme--transitions--ease-out: cubic-bezier(0.33, 1, 0.68, 1);
|
||||
--c--theme--transitions--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
|
||||
--c--theme--transitions--duration: 250ms;
|
||||
--c--components--forms-radio--border-color: #E7E8EA;
|
||||
--c--components--forms-radio--check-color: #419A14;
|
||||
--c--components--forms-input--font-weight: 400;
|
||||
--c--components--forms-input--font-size: 1rem;
|
||||
--c--components--forms-input--border-radius: 8px;
|
||||
@@ -110,6 +112,13 @@
|
||||
--c--components--forms-field--width: 292px;
|
||||
--c--components--forms-field--font-size: 0.6875rem;
|
||||
--c--components--forms-field--color: #79818A;
|
||||
--c--components--forms-checkbox--font-size: 0.8125rem;
|
||||
--c--components--forms-checkbox--font-weight: 400;
|
||||
--c--components--forms-checkbox--color: #0C1A2B;
|
||||
--c--components--forms-checkbox--border-color: #E7E8EA;
|
||||
--c--components--forms-checkbox--border-radius: 2px;
|
||||
--c--components--forms-checkbox--accent-color: #419A14;
|
||||
--c--components--forms-checkbox--size: 1.5rem;
|
||||
--c--components--button--border-radius: 8px;
|
||||
--c--components--button--border-radius--active: 2px;
|
||||
--c--components--button--medium-height: 48px;
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const tokens = {"theme":{"colors":{"primary-text":"#FFFFFF","primary-100":"#EBF2FC","primary-200":"#8CB5EA","primary-300":"#5894E1","primary-400":"#377FDB","primary-500":"#055FD2","primary-600":"#0556BF","primary-700":"#044395","primary-800":"#033474","primary-900":"#022858","secondary-text":"#555F6B","secondary-100":"#F2F7FC","secondary-200":"#EBF3FA","secondary-300":"#E2EEF8","secondary-400":"#DDEAF7","secondary-500":"#D4E5F5","secondary-600":"#C1D0DF","secondary-700":"#97A3AE","secondary-800":"#757E87","secondary-900":"#596067","greyscale-000":"#FFFFFF","greyscale-100":"#FAFAFB","greyscale-200":"#F3F4F4","greyscale-300":"#E7E8EA","greyscale-400":"#C2C6CA","greyscale-500":"#9EA3AA","greyscale-600":"#79818A","greyscale-700":"#555F6B","greyscale-800":"#303C4B","greyscale-900":"#0C1A2B","success-text":"#FFFFFF","success-100":"#EFFCD3","success-200":"#DBFAA9","success-300":"#BEF27C","success-400":"#A0E659","success-500":"#76D628","success-600":"#5AB81D","success-700":"#419A14","success-800":"#2C7C0C","success-900":"#1D6607","info-text":"#FFFFFF","info-100":"#EBF2FC","info-200":"#8CB5EA","info-300":"#5894E1","info-400":"#377FDB","info-500":"#055FD2","info-600":"#0556BF","info-700":"#044395","info-800":"#033474","info-900":"#022858","warning-text":"#FFFFFF","warning-100":"#FFF8CD","warning-200":"#FFEF9B","warning-300":"#FFE469","warning-400":"#FFDA43","warning-500":"#FFC805","warning-600":"#DBA603","warning-700":"#B78702","warning-800":"#936901","warning-900":"#7A5400","danger-text":"#FFFFFF","danger-100":"#F4B0B0","danger-200":"#EE8A8A","danger-300":"#E65454","danger-400":"#E13333","danger-500":"#DA0000","danger-600":"#C60000","danger-700":"#9B0000","danger-800":"#780000","danger-900":"#5C0000"},"font":{"sizes":{"h1":"1.75rem","h2":"1.375rem","h3":"1.125rem","h4":"0.8125rem","h5":"0.625rem","h6":"0.5rem","l":"1rem","m":"0.8125rem","s":"0.6875rem"},"weights":{"thin":100,"regular":300,"medium":400,"bold":500,"extrabold":700,"black":900},"families":{"base":"Roboto","accent":"Roboto"}},"spacings":{"xl":"4rem","l":"3rem","b":"1.625rem","s":"1rem","t":"0.5rem","st":"0.25rem"},"transitions":{"ease-in":"cubic-bezier(0.32, 0, 0.67, 0)","ease-out":"cubic-bezier(0.33, 1, 0.68, 1)","ease-in-out":"cubic-bezier(0.65, 0, 0.35, 1)","duration":"250ms"}},"components":{"forms-input":{"font-weight":400,"font-size":"1rem","border-radius":"8px","border-radius--hover":"2px","border-radius--focus":"2px","border-width":"2px","border-color":"#E7E8EA","border-color--hover":"#9EA3AA","border-color--focus":"#0556BF","border-style":"solid","color":"#303C4B"},"forms-field":{"width":"292px","font-size":"0.6875rem","color":"#79818A"},"button":{"border-radius":"8px","border-radius--active":"2px","medium-height":"48px","small-height":"32px","medium-font-size":"1rem","small-font-size":"0.8125rem","font-weight":400}}};
|
||||
export const tokens = {"theme":{"colors":{"primary-text":"#FFFFFF","primary-100":"#EBF2FC","primary-200":"#8CB5EA","primary-300":"#5894E1","primary-400":"#377FDB","primary-500":"#055FD2","primary-600":"#0556BF","primary-700":"#044395","primary-800":"#033474","primary-900":"#022858","secondary-text":"#555F6B","secondary-100":"#F2F7FC","secondary-200":"#EBF3FA","secondary-300":"#E2EEF8","secondary-400":"#DDEAF7","secondary-500":"#D4E5F5","secondary-600":"#C1D0DF","secondary-700":"#97A3AE","secondary-800":"#757E87","secondary-900":"#596067","greyscale-000":"#FFFFFF","greyscale-100":"#FAFAFB","greyscale-200":"#F3F4F4","greyscale-300":"#E7E8EA","greyscale-400":"#C2C6CA","greyscale-500":"#9EA3AA","greyscale-600":"#79818A","greyscale-700":"#555F6B","greyscale-800":"#303C4B","greyscale-900":"#0C1A2B","success-text":"#FFFFFF","success-100":"#EFFCD3","success-200":"#DBFAA9","success-300":"#BEF27C","success-400":"#A0E659","success-500":"#76D628","success-600":"#5AB81D","success-700":"#419A14","success-800":"#2C7C0C","success-900":"#1D6607","info-text":"#FFFFFF","info-100":"#EBF2FC","info-200":"#8CB5EA","info-300":"#5894E1","info-400":"#377FDB","info-500":"#055FD2","info-600":"#0556BF","info-700":"#044395","info-800":"#033474","info-900":"#022858","warning-text":"#FFFFFF","warning-100":"#FFF8CD","warning-200":"#FFEF9B","warning-300":"#FFE469","warning-400":"#FFDA43","warning-500":"#FFC805","warning-600":"#DBA603","warning-700":"#B78702","warning-800":"#936901","warning-900":"#7A5400","danger-text":"#FFFFFF","danger-100":"#F4B0B0","danger-200":"#EE8A8A","danger-300":"#E65454","danger-400":"#E13333","danger-500":"#DA0000","danger-600":"#C60000","danger-700":"#9B0000","danger-800":"#780000","danger-900":"#5C0000"},"font":{"sizes":{"h1":"1.75rem","h2":"1.375rem","h3":"1.125rem","h4":"0.8125rem","h5":"0.625rem","h6":"0.5rem","l":"1rem","m":"0.8125rem","s":"0.6875rem"},"weights":{"thin":100,"regular":300,"medium":400,"bold":500,"extrabold":700,"black":900},"families":{"base":"Roboto","accent":"Roboto"}},"spacings":{"xl":"4rem","l":"3rem","b":"1.625rem","s":"1rem","t":"0.5rem","st":"0.25rem"},"transitions":{"ease-in":"cubic-bezier(0.32, 0, 0.67, 0)","ease-out":"cubic-bezier(0.33, 1, 0.68, 1)","ease-in-out":"cubic-bezier(0.65, 0, 0.35, 1)","duration":"250ms"}},"components":{"forms-radio":{"border-color":"#E7E8EA","accent-color":"#419A14"},"forms-input":{"font-weight":400,"font-size":"1rem","border-radius":"8px","border-radius--hover":"2px","border-radius--focus":"2px","border-width":"2px","border-color":"#E7E8EA","border-color--hover":"#9EA3AA","border-color--focus":"#0556BF","border-style":"solid","color":"#303C4B"},"forms-field":{"width":"292px","font-size":"0.6875rem","color":"#79818A"},"forms-checkbox":{"font-size":"0.8125rem","font-weight":400,"color":"#0C1A2B","border-color":"#E7E8EA","border-radius":"2px","accent-color":"#419A14","size":"1.5rem"},"button":{"border-radius":"8px","border-radius--active":"2px","medium-height":"48px","small-height":"32px","medium-font-size":"1rem","small-font-size":"0.8125rem","font-weight":400}}};
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const tokens = {"theme":{"colors":{"primary-text":"#FFFFFF","primary-100":"#EBF2FC","primary-200":"#8CB5EA","primary-300":"#5894E1","primary-400":"#377FDB","primary-500":"#055FD2","primary-600":"#0556BF","primary-700":"#044395","primary-800":"#033474","primary-900":"#022858","secondary-text":"#555F6B","secondary-100":"#F2F7FC","secondary-200":"#EBF3FA","secondary-300":"#E2EEF8","secondary-400":"#DDEAF7","secondary-500":"#D4E5F5","secondary-600":"#C1D0DF","secondary-700":"#97A3AE","secondary-800":"#757E87","secondary-900":"#596067","greyscale-000":"#FFFFFF","greyscale-100":"#FAFAFB","greyscale-200":"#F3F4F4","greyscale-300":"#E7E8EA","greyscale-400":"#C2C6CA","greyscale-500":"#9EA3AA","greyscale-600":"#79818A","greyscale-700":"#555F6B","greyscale-800":"#303C4B","greyscale-900":"#0C1A2B","success-text":"#FFFFFF","success-100":"#EFFCD3","success-200":"#DBFAA9","success-300":"#BEF27C","success-400":"#A0E659","success-500":"#76D628","success-600":"#5AB81D","success-700":"#419A14","success-800":"#2C7C0C","success-900":"#1D6607","info-text":"#FFFFFF","info-100":"#EBF2FC","info-200":"#8CB5EA","info-300":"#5894E1","info-400":"#377FDB","info-500":"#055FD2","info-600":"#0556BF","info-700":"#044395","info-800":"#033474","info-900":"#022858","warning-text":"#FFFFFF","warning-100":"#FFF8CD","warning-200":"#FFEF9B","warning-300":"#FFE469","warning-400":"#FFDA43","warning-500":"#FFC805","warning-600":"#DBA603","warning-700":"#B78702","warning-800":"#936901","warning-900":"#7A5400","danger-text":"#FFFFFF","danger-100":"#F4B0B0","danger-200":"#EE8A8A","danger-300":"#E65454","danger-400":"#E13333","danger-500":"#DA0000","danger-600":"#C60000","danger-700":"#9B0000","danger-800":"#780000","danger-900":"#5C0000"},"font":{"sizes":{"h1":"1.75rem","h2":"1.375rem","h3":"1.125rem","h4":"0.8125rem","h5":"0.625rem","h6":"0.5rem","l":"1rem","m":"0.8125rem","s":"0.6875rem"},"weights":{"thin":100,"regular":300,"medium":400,"bold":500,"extrabold":700,"black":900},"families":{"base":"Roboto","accent":"Roboto"}},"spacings":{"xl":"4rem","l":"3rem","b":"1.625rem","s":"1rem","t":"0.5rem","st":"0.25rem"},"transitions":{"ease-in":"cubic-bezier(0.32, 0, 0.67, 0)","ease-out":"cubic-bezier(0.33, 1, 0.68, 1)","ease-in-out":"cubic-bezier(0.65, 0, 0.35, 1)","duration":"250ms"}},"components":{"forms-input":{"font-weight":400,"font-size":"1rem","border-radius":"8px","border-radius--hover":"2px","border-radius--focus":"2px","border-width":"2px","border-color":"#E7E8EA","border-color--hover":"#9EA3AA","border-color--focus":"#0556BF","border-style":"solid","color":"#303C4B"},"forms-field":{"width":"292px","font-size":"0.6875rem","color":"#79818A"},"button":{"border-radius":"8px","border-radius--active":"2px","medium-height":"48px","small-height":"32px","medium-font-size":"1rem","small-font-size":"0.8125rem","font-weight":400}}};
|
||||
export const tokens = {"theme":{"colors":{"primary-text":"#FFFFFF","primary-100":"#EBF2FC","primary-200":"#8CB5EA","primary-300":"#5894E1","primary-400":"#377FDB","primary-500":"#055FD2","primary-600":"#0556BF","primary-700":"#044395","primary-800":"#033474","primary-900":"#022858","secondary-text":"#555F6B","secondary-100":"#F2F7FC","secondary-200":"#EBF3FA","secondary-300":"#E2EEF8","secondary-400":"#DDEAF7","secondary-500":"#D4E5F5","secondary-600":"#C1D0DF","secondary-700":"#97A3AE","secondary-800":"#757E87","secondary-900":"#596067","greyscale-000":"#FFFFFF","greyscale-100":"#FAFAFB","greyscale-200":"#F3F4F4","greyscale-300":"#E7E8EA","greyscale-400":"#C2C6CA","greyscale-500":"#9EA3AA","greyscale-600":"#79818A","greyscale-700":"#555F6B","greyscale-800":"#303C4B","greyscale-900":"#0C1A2B","success-text":"#FFFFFF","success-100":"#EFFCD3","success-200":"#DBFAA9","success-300":"#BEF27C","success-400":"#A0E659","success-500":"#76D628","success-600":"#5AB81D","success-700":"#419A14","success-800":"#2C7C0C","success-900":"#1D6607","info-text":"#FFFFFF","info-100":"#EBF2FC","info-200":"#8CB5EA","info-300":"#5894E1","info-400":"#377FDB","info-500":"#055FD2","info-600":"#0556BF","info-700":"#044395","info-800":"#033474","info-900":"#022858","warning-text":"#FFFFFF","warning-100":"#FFF8CD","warning-200":"#FFEF9B","warning-300":"#FFE469","warning-400":"#FFDA43","warning-500":"#FFC805","warning-600":"#DBA603","warning-700":"#B78702","warning-800":"#936901","warning-900":"#7A5400","danger-text":"#FFFFFF","danger-100":"#F4B0B0","danger-200":"#EE8A8A","danger-300":"#E65454","danger-400":"#E13333","danger-500":"#DA0000","danger-600":"#C60000","danger-700":"#9B0000","danger-800":"#780000","danger-900":"#5C0000"},"font":{"sizes":{"h1":"1.75rem","h2":"1.375rem","h3":"1.125rem","h4":"0.8125rem","h5":"0.625rem","h6":"0.5rem","l":"1rem","m":"0.8125rem","s":"0.6875rem"},"weights":{"thin":100,"regular":300,"medium":400,"bold":500,"extrabold":700,"black":900},"families":{"base":"Roboto","accent":"Roboto"}},"spacings":{"xl":"4rem","l":"3rem","b":"1.625rem","s":"1rem","t":"0.5rem","st":"0.25rem"},"transitions":{"ease-in":"cubic-bezier(0.32, 0, 0.67, 0)","ease-out":"cubic-bezier(0.33, 1, 0.68, 1)","ease-in-out":"cubic-bezier(0.65, 0, 0.35, 1)","duration":"250ms"}},"components":{"forms-radio":{"border-color":"#E7E8EA","accent-color":"#419A14"},"forms-input":{"font-weight":400,"font-size":"1rem","border-radius":"8px","border-radius--hover":"2px","border-radius--focus":"2px","border-width":"2px","border-color":"#E7E8EA","border-color--hover":"#9EA3AA","border-color--focus":"#0556BF","border-style":"solid","color":"#303C4B"},"forms-field":{"width":"292px","font-size":"0.6875rem","color":"#79818A"},"forms-checkbox":{"font-size":"0.8125rem","font-weight":400,"color":"#0C1A2B","border-color":"#E7E8EA","border-radius":"2px","accent-color":"#419A14","size":"1.5rem"},"button":{"border-radius":"8px","border-radius--active":"2px","medium-height":"48px","small-height":"32px","medium-font-size":"1rem","small-font-size":"0.8125rem","font-weight":400}}};
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
@import './components/Accessibility';
|
||||
@import './components/Button';
|
||||
@import './components/DataGrid';
|
||||
@import './components/Forms/Checkbox';
|
||||
@import './components/Forms/Field';
|
||||
@import './components/Forms/Input';
|
||||
@import './components/Loader';
|
||||
|
||||
Reference in New Issue
Block a user