feat(ui): add form field with text, textarea and checkbox support
This commit is contained in:
68
pkgs/clan-app/ui/src/components/v2/Form/Checkbox.stories.tsx
Normal file
68
pkgs/clan-app/ui/src/components/v2/Form/Checkbox.stories.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
import meta, { Story } from "./TextField.stories";
|
||||
|
||||
const checkboxMeta = {
|
||||
...meta,
|
||||
title: "Components/Form/Checkbox",
|
||||
};
|
||||
|
||||
export default checkboxMeta;
|
||||
|
||||
export const Bare: Story = {
|
||||
args: {
|
||||
type: "checkbox",
|
||||
},
|
||||
};
|
||||
|
||||
export const Label: Story = {
|
||||
args: {
|
||||
...Bare.args,
|
||||
label: "Accept Terms",
|
||||
},
|
||||
};
|
||||
|
||||
export const Description: Story = {
|
||||
args: {
|
||||
...Label.args,
|
||||
description: "That stuff you never bother reading",
|
||||
},
|
||||
};
|
||||
|
||||
export const Required: Story = {
|
||||
args: {
|
||||
...Description.args,
|
||||
required: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const Tooltip: Story = {
|
||||
args: {
|
||||
...Required.args,
|
||||
tooltip:
|
||||
"Let people know how you got here, great achievements or obstacles overcome",
|
||||
},
|
||||
};
|
||||
|
||||
export const Invalid: Story = {
|
||||
args: {
|
||||
...Tooltip.args,
|
||||
invalid: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const Disabled: Story = {
|
||||
args: {
|
||||
...Tooltip.args,
|
||||
disabled: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const ReadOnly: Story = {
|
||||
args: {
|
||||
...Tooltip.args,
|
||||
readOnly: true,
|
||||
checkbox: {
|
||||
...Tooltip.args.checkbox,
|
||||
defaultChecked: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
212
pkgs/clan-app/ui/src/components/v2/Form/Field.css
Normal file
212
pkgs/clan-app/ui/src/components/v2/Form/Field.css
Normal file
@@ -0,0 +1,212 @@
|
||||
div.form-field {
|
||||
@apply flex items-center w-full;
|
||||
|
||||
& > div.meta {
|
||||
@apply flex flex-col gap-1 w-full;
|
||||
|
||||
& > label,
|
||||
& > div {
|
||||
@apply w-full;
|
||||
/* remove line height which messes with sizing */
|
||||
@apply leading-none;
|
||||
}
|
||||
|
||||
& > label {
|
||||
@apply flex items-center gap-1;
|
||||
}
|
||||
|
||||
& > label[data-required] {
|
||||
span.typography::after {
|
||||
@apply fg-def-4 ml-1;
|
||||
|
||||
content: "*";
|
||||
font-family: "Commit Mono", monospace;
|
||||
font-size: 0.6875rem;
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip-trigger {
|
||||
}
|
||||
}
|
||||
|
||||
& input,
|
||||
& textarea {
|
||||
@apply w-full px-2 py-1.5 rounded-sm;
|
||||
@apply outline outline-1 outline-def-acc-1 bg-def-1 fg-def-1;
|
||||
|
||||
font-weight: 500;
|
||||
font-family: "Archivo", sans-serif;
|
||||
line-height: 132%;
|
||||
|
||||
&::placeholder {
|
||||
@apply fg-def-4;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@apply bg-def-acc-1 outline-def-acc-2;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
@apply bg-def-1 outline-def-acc-3;
|
||||
|
||||
box-shadow:
|
||||
0 0 0 0.125rem theme(colors.bg.def.1),
|
||||
0 0 0 0.1875rem theme(colors.border.semantic.info.1);
|
||||
}
|
||||
|
||||
&[data-invalid] {
|
||||
@apply outline-semantic-error-4;
|
||||
}
|
||||
|
||||
&[data-disabled] {
|
||||
@apply outline-def-2 fg-def-4 cursor-not-allowed;
|
||||
}
|
||||
|
||||
&[data-readonly] {
|
||||
@apply outline-def-2 cursor-not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
&.orientation-vertical {
|
||||
@apply flex-col gap-2;
|
||||
}
|
||||
|
||||
&.orientation-horizontal {
|
||||
@apply flex-row gap-2 justify-between;
|
||||
|
||||
& > div.meta {
|
||||
@apply w-1/2 shrink;
|
||||
}
|
||||
|
||||
& div.input-container,
|
||||
& textarea {
|
||||
@apply w-1/2 grow;
|
||||
}
|
||||
|
||||
&:has(> textarea) {
|
||||
@apply items-start;
|
||||
}
|
||||
}
|
||||
|
||||
div.input-container {
|
||||
@apply inline-block relative w-full;
|
||||
|
||||
/* I'm unsure why I have to do this */
|
||||
@apply leading-none;
|
||||
|
||||
& > input {
|
||||
@apply w-full;
|
||||
|
||||
&.has-icon {
|
||||
@apply pl-7;
|
||||
}
|
||||
}
|
||||
|
||||
& > .icon {
|
||||
@apply absolute left-2 top-1/2 transform -translate-y-1/2;
|
||||
@apply w-[0.875rem] h-[0.875rem] pointer-events-none;
|
||||
}
|
||||
}
|
||||
|
||||
&.form-field-checkbox {
|
||||
@apply items-start;
|
||||
|
||||
& > div.checkbox-control {
|
||||
@apply w-5 h-5 rounded-sm bg-def-1 border border-inv-1 p-[0.0625rem];
|
||||
|
||||
&[data-disabled] {
|
||||
@apply border-def-2;
|
||||
}
|
||||
|
||||
&[data-invalid] {
|
||||
@apply border-semantic-error-4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.size-default {
|
||||
& input,
|
||||
& textarea {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
div.input-container {
|
||||
@apply h-[1.875rem];
|
||||
|
||||
input {
|
||||
@apply h-[1.875rem];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.size-s {
|
||||
& input,
|
||||
& textarea {
|
||||
@apply px-1.5 py-1;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
div.input-container {
|
||||
@apply h-[1.25rem];
|
||||
|
||||
input {
|
||||
@apply h-[1.25rem];
|
||||
}
|
||||
|
||||
input.has-icon {
|
||||
@apply pl-6;
|
||||
}
|
||||
|
||||
& > .icon {
|
||||
@apply w-[0.6875rem] h-[0.6875rem] transform -translate-y-1/2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.inverted {
|
||||
& input,
|
||||
& textarea {
|
||||
@apply bg-inv-1 fg-inv-1 outline-inv-acc-1;
|
||||
|
||||
&::placeholder {
|
||||
@apply fg-inv-4;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@apply bg-inv-acc-2 outline-inv-acc-2;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
@apply bg-inv-acc-4;
|
||||
box-shadow:
|
||||
0 0 0 0.125rem theme(colors.bg.inv.1),
|
||||
0 0 0 0.1875rem theme(colors.border.semantic.info.1);
|
||||
}
|
||||
|
||||
&[data-invalid] {
|
||||
@apply outline-semantic-error-4;
|
||||
}
|
||||
}
|
||||
|
||||
&.form-field-checkbox {
|
||||
& > div.checkbox-control {
|
||||
@apply bg-inv-acc-4;
|
||||
|
||||
&[data-disabled] {
|
||||
@apply bg-def-4 border-none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.ghost {
|
||||
& input,
|
||||
& textarea {
|
||||
@apply outline-none;
|
||||
|
||||
&:hover {
|
||||
@apply outline-none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
214
pkgs/clan-app/ui/src/components/v2/Form/Field.tsx
Normal file
214
pkgs/clan-app/ui/src/components/v2/Form/Field.tsx
Normal file
@@ -0,0 +1,214 @@
|
||||
import {
|
||||
TextField as KTextField,
|
||||
TextFieldInputProps as KTextFieldInputProps,
|
||||
TextFieldTextAreaProps as KTextFieldTextAreaProps,
|
||||
} from "@kobalte/core/text-field";
|
||||
import {
|
||||
Checkbox as KCheckbox,
|
||||
CheckboxInputProps as KCheckboxInputProps,
|
||||
} from "@kobalte/core/checkbox";
|
||||
import { Typography } from "@/src/components/v2/Typography/Typography";
|
||||
import Icon, { IconVariant } from "@/src/components/v2/Icon/Icon";
|
||||
|
||||
import cx from "classnames";
|
||||
import { Match, splitProps, Switch } from "solid-js";
|
||||
import { Dynamic } from "solid-js/web";
|
||||
import { Tooltip as KTooltip } from "@kobalte/core/tooltip";
|
||||
import "./Field.css";
|
||||
|
||||
type Size = "default" | "s";
|
||||
type Orientation = "horizontal" | "vertical";
|
||||
type FieldType = "text" | "textarea" | "checkbox";
|
||||
|
||||
export interface TextFieldProps {
|
||||
input?: KTextFieldInputProps;
|
||||
value?: string;
|
||||
onChange?: (value: string) => void;
|
||||
defaultValue?: string;
|
||||
}
|
||||
|
||||
export interface TextAreaProps {
|
||||
input?: KTextFieldTextAreaProps;
|
||||
value?: string;
|
||||
onChange?: (value: string) => void;
|
||||
defaultValue?: string;
|
||||
}
|
||||
|
||||
export interface CheckboxProps {
|
||||
input?: KCheckboxInputProps;
|
||||
checked?: boolean;
|
||||
defaultChecked?: boolean;
|
||||
indeterminate?: boolean;
|
||||
onChange?: (value: boolean) => void;
|
||||
}
|
||||
|
||||
export interface FieldProps {
|
||||
class?: string;
|
||||
name?: string;
|
||||
label?: string;
|
||||
description?: string;
|
||||
tooltip?: string;
|
||||
icon?: IconVariant;
|
||||
ghost?: boolean;
|
||||
|
||||
size?: Size;
|
||||
orientation?: Orientation;
|
||||
inverted?: boolean;
|
||||
|
||||
required?: boolean;
|
||||
disabled?: boolean;
|
||||
readOnly?: boolean;
|
||||
invalid?: boolean;
|
||||
|
||||
type: FieldType;
|
||||
text?: TextFieldProps;
|
||||
textarea?: TextAreaProps;
|
||||
checkbox?: CheckboxProps;
|
||||
}
|
||||
|
||||
const componentsForType = {
|
||||
text: {
|
||||
container: KTextField,
|
||||
label: KTextField.Label,
|
||||
description: KTextField.Description,
|
||||
},
|
||||
textarea: {
|
||||
container: KTextField,
|
||||
label: KTextField.Label,
|
||||
description: KTextField.Description,
|
||||
},
|
||||
checkbox: {
|
||||
container: KCheckbox,
|
||||
label: KCheckbox.Label,
|
||||
description: KCheckbox.Description,
|
||||
},
|
||||
};
|
||||
|
||||
export const Field = (props: FieldProps) => {
|
||||
const [commonProps] = splitProps(props, [
|
||||
"name",
|
||||
"class",
|
||||
"required",
|
||||
"disabled",
|
||||
"readOnly",
|
||||
]);
|
||||
|
||||
const [textProps] = splitProps(props.text || props.textarea || {}, [
|
||||
"value",
|
||||
"onChange",
|
||||
"defaultValue",
|
||||
]);
|
||||
|
||||
const [checkboxProps] = splitProps(props.checkbox || {}, [
|
||||
"checked",
|
||||
"defaultChecked",
|
||||
"indeterminate",
|
||||
]);
|
||||
|
||||
const validationState = () => (props.invalid ? "invalid" : "valid");
|
||||
|
||||
const labelSize = () => `size-${props.size || "default"}`;
|
||||
const orientation = () => `orientation-${props.orientation || "vertical"}`;
|
||||
const descriptionSize = () => (labelSize() == "size-default" ? "xs" : "xxs");
|
||||
const fieldClass = () => (props.type ? `form-field-${props.type}` : "");
|
||||
|
||||
const { container, label, description } = componentsForType[props.type];
|
||||
|
||||
return (
|
||||
<Dynamic
|
||||
component={container}
|
||||
class={cx("form-field", fieldClass(), labelSize(), orientation(), {
|
||||
inverted: props.inverted,
|
||||
ghost: props.ghost,
|
||||
})}
|
||||
validationState={validationState()}
|
||||
{...commonProps}
|
||||
{...textProps}
|
||||
{...checkboxProps}
|
||||
>
|
||||
{props.label && (
|
||||
<div class="meta">
|
||||
{props.label && (
|
||||
<Dynamic component={label}>
|
||||
<Typography
|
||||
hierarchy="label"
|
||||
size={props.size || "default"}
|
||||
color={props.invalid ? "error" : "primary"}
|
||||
weight="bold"
|
||||
inverted={props.inverted}
|
||||
>
|
||||
{props.label}
|
||||
</Typography>
|
||||
|
||||
{props.tooltip && (
|
||||
<KTooltip>
|
||||
<KTooltip.Trigger class="tooltip-trigger">
|
||||
<Icon
|
||||
icon="Info"
|
||||
color="tertiary"
|
||||
inverted={props.inverted}
|
||||
size={props.size == "default" ? "0.85em" : "0.75rem"}
|
||||
/>
|
||||
<KTooltip.Portal>
|
||||
<KTooltip.Content>
|
||||
<Typography hierarchy="body" size="xs">
|
||||
{props.tooltip}
|
||||
</Typography>
|
||||
</KTooltip.Content>
|
||||
</KTooltip.Portal>
|
||||
</KTooltip.Trigger>
|
||||
</KTooltip>
|
||||
)}
|
||||
</Dynamic>
|
||||
)}
|
||||
{props.description && (
|
||||
<Dynamic component={description}>
|
||||
<Typography
|
||||
hierarchy="body"
|
||||
size={descriptionSize()}
|
||||
color="secondary"
|
||||
weight="normal"
|
||||
inverted={props.inverted}
|
||||
>
|
||||
{props.description}
|
||||
</Typography>
|
||||
</Dynamic>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Switch>
|
||||
<Match when={props.type == "text"}>
|
||||
<div class="input-container">
|
||||
{props.icon && (
|
||||
<Icon
|
||||
icon={props.icon}
|
||||
inverted={props.inverted}
|
||||
color={props.disabled ? "quaternary" : "tertiary"}
|
||||
/>
|
||||
)}
|
||||
<KTextField.Input
|
||||
{...props.text?.input}
|
||||
classList={{ "has-icon": props.icon }}
|
||||
/>
|
||||
</div>
|
||||
</Match>
|
||||
<Match when={props.type == "textarea"}>
|
||||
<KTextField.TextArea {...props.textarea?.input} />
|
||||
</Match>
|
||||
<Match when={props.type == "checkbox"}>
|
||||
<KCheckbox.Input {...props.checkbox?.input} />
|
||||
<KCheckbox.Control class="checkbox-control">
|
||||
<KCheckbox.Indicator>
|
||||
<Icon
|
||||
icon="Checkmark"
|
||||
inverted={props.inverted}
|
||||
color="secondary"
|
||||
/>
|
||||
</KCheckbox.Indicator>
|
||||
</KCheckbox.Control>
|
||||
</Match>
|
||||
</Switch>
|
||||
</Dynamic>
|
||||
);
|
||||
};
|
||||
82
pkgs/clan-app/ui/src/components/v2/Form/TextArea.stories.tsx
Normal file
82
pkgs/clan-app/ui/src/components/v2/Form/TextArea.stories.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import meta, { Icon, Story } from "./TextField.stories";
|
||||
|
||||
const textAreaMeta = {
|
||||
...meta,
|
||||
title: "Components/Form/TextArea",
|
||||
};
|
||||
|
||||
export default textAreaMeta;
|
||||
|
||||
export const Bare: Story = {
|
||||
args: {
|
||||
type: "textarea",
|
||||
textarea: {
|
||||
input: {
|
||||
rows: 10,
|
||||
placeholder: "I like craft beer and long walks on the beach",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Label: Story = {
|
||||
args: {
|
||||
...Bare.args,
|
||||
label: "Biography",
|
||||
},
|
||||
};
|
||||
|
||||
export const Description: Story = {
|
||||
args: {
|
||||
...Label.args,
|
||||
description: "Tell us about yourself",
|
||||
},
|
||||
};
|
||||
|
||||
export const Required: Story = {
|
||||
args: {
|
||||
...Description.args,
|
||||
required: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const Tooltip: Story = {
|
||||
args: {
|
||||
...Required.args,
|
||||
tooltip:
|
||||
"Let people know how you got here, great achievements or obstacles overcome",
|
||||
},
|
||||
};
|
||||
|
||||
export const Ghost: Story = {
|
||||
args: {
|
||||
...Tooltip.args,
|
||||
ghost: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const Invalid: Story = {
|
||||
args: {
|
||||
...Tooltip.args,
|
||||
invalid: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const Disabled: Story = {
|
||||
args: {
|
||||
...Tooltip.args,
|
||||
disabled: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const ReadOnly: Story = {
|
||||
args: {
|
||||
...Tooltip.args,
|
||||
readOnly: true,
|
||||
textarea: {
|
||||
...Tooltip.args.textarea,
|
||||
defaultValue:
|
||||
"Good evening. I'm Ron Burgundy, and this is what's happening in your world tonight. ",
|
||||
},
|
||||
},
|
||||
};
|
||||
125
pkgs/clan-app/ui/src/components/v2/Form/TextField.stories.tsx
Normal file
125
pkgs/clan-app/ui/src/components/v2/Form/TextField.stories.tsx
Normal file
@@ -0,0 +1,125 @@
|
||||
import type { Meta, StoryContext, StoryObj } from "@kachurun/storybook-solid";
|
||||
import { Field, FieldProps } from "./Field";
|
||||
import cx from "classnames";
|
||||
|
||||
const FieldExamples = (props: FieldProps) => (
|
||||
<div class="flex flex-col gap-8">
|
||||
<div class="flex flex-col gap-8 p-8">
|
||||
<Field {...props} />
|
||||
<Field {...props} size="s" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-8 p-8 bg-inv-acc-3">
|
||||
<Field {...props} inverted={true} />
|
||||
<Field {...props} inverted={true} size="s" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-8 p-8">
|
||||
<Field {...props} orientation="horizontal" />
|
||||
<Field {...props} orientation="horizontal" size="s" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-8 p-8 bg-inv-acc-3">
|
||||
<Field {...props} inverted={true} orientation="horizontal" />
|
||||
<Field {...props} inverted={true} orientation="horizontal" size="s" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const meta = {
|
||||
title: "Components/Form/TextField",
|
||||
component: FieldExamples,
|
||||
decorators: [
|
||||
(Story: StoryObj, context: StoryContext<FieldProps>) => {
|
||||
return (
|
||||
<div
|
||||
class={cx({
|
||||
"w-[600px]": (context.args.orientation || "vertical") == "vertical",
|
||||
"w-[1024px]": context.args.orientation == "horizontal",
|
||||
"bg-inv-acc-3": context.args.inverted,
|
||||
})}
|
||||
>
|
||||
<Story />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
],
|
||||
} satisfies Meta<FieldProps>;
|
||||
|
||||
export default meta;
|
||||
|
||||
export type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Bare: Story = {
|
||||
args: {
|
||||
type: "text",
|
||||
text: {
|
||||
input: {
|
||||
placeholder: "e.g. 11/06/89",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Label: Story = {
|
||||
args: {
|
||||
...Bare.args,
|
||||
label: "DOB",
|
||||
},
|
||||
};
|
||||
|
||||
export const Description: Story = {
|
||||
args: {
|
||||
...Label.args,
|
||||
description: "The date you were born",
|
||||
},
|
||||
};
|
||||
|
||||
export const Required: Story = {
|
||||
args: {
|
||||
...Description.args,
|
||||
required: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const Tooltip: Story = {
|
||||
args: {
|
||||
...Required.args,
|
||||
tooltip: "The day you came out of your momma",
|
||||
},
|
||||
};
|
||||
|
||||
export const Icon: Story = {
|
||||
args: {
|
||||
...Tooltip.args,
|
||||
icon: "Checkmark",
|
||||
},
|
||||
};
|
||||
|
||||
export const Ghost: Story = {
|
||||
args: {
|
||||
...Icon.args,
|
||||
ghost: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const Invalid: Story = {
|
||||
args: {
|
||||
...Tooltip.args,
|
||||
invalid: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const Disabled: Story = {
|
||||
args: {
|
||||
...Icon.args,
|
||||
disabled: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const ReadOnly: Story = {
|
||||
args: {
|
||||
...Icon.args,
|
||||
readOnly: true,
|
||||
text: {
|
||||
defaultValue: "14/05/02",
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -67,6 +67,12 @@
|
||||
line-height: 1;
|
||||
letter-spacing: 0.0075rem;
|
||||
}
|
||||
|
||||
&.size-xxs {
|
||||
font-size: 0.6875rem;
|
||||
line-height: 1;
|
||||
letter-spacing: normal;
|
||||
}
|
||||
}
|
||||
|
||||
&.family-mono {
|
||||
|
||||
@@ -21,6 +21,7 @@ interface SizeForHierarchy {
|
||||
default: string;
|
||||
s: string;
|
||||
xs: string;
|
||||
xxs: string;
|
||||
};
|
||||
headline: {
|
||||
default: string;
|
||||
@@ -62,6 +63,7 @@ const sizeHierarchyMap: SizeForHierarchy = {
|
||||
default: cx("size-default"),
|
||||
s: cx("size-s"),
|
||||
xs: cx("size-xs"),
|
||||
xxs: cx("size-xxs"),
|
||||
},
|
||||
teaser: {
|
||||
default: cx("size-default"),
|
||||
|
||||
@@ -3,6 +3,7 @@ export type Color =
|
||||
| "secondary"
|
||||
| "tertiary"
|
||||
| "quaternary"
|
||||
| "error"
|
||||
| "inherit";
|
||||
|
||||
export const AllColors: Color[] = [
|
||||
@@ -10,6 +11,7 @@ export const AllColors: Color[] = [
|
||||
"secondary",
|
||||
"tertiary",
|
||||
"quaternary",
|
||||
"error",
|
||||
"inherit",
|
||||
];
|
||||
|
||||
@@ -18,6 +20,7 @@ const colorMap: Record<Color, string> = {
|
||||
secondary: "fg-def-2",
|
||||
tertiary: "fg-def-3",
|
||||
quaternary: "fg-def-4",
|
||||
error: "fg-semantic-error-4",
|
||||
inherit: "text-inherit",
|
||||
};
|
||||
|
||||
@@ -26,6 +29,7 @@ const invertedColorMap: Record<Color, string> = {
|
||||
secondary: "fg-inv-2",
|
||||
tertiary: "fg-inv-3",
|
||||
quaternary: "fg-inv-4",
|
||||
error: "fg-semantic-error-2",
|
||||
inherit: "text-inherit",
|
||||
};
|
||||
|
||||
|
||||
@@ -202,7 +202,7 @@ const colorSystem = {
|
||||
1: primaries.secondary["950"],
|
||||
2: primaries.secondary["900"],
|
||||
3: primaries.secondary["700"],
|
||||
4: primaries.secondary["400"],
|
||||
4: primaries.secondary["500"],
|
||||
},
|
||||
inv: {
|
||||
1: primaries.off.white,
|
||||
@@ -283,6 +283,13 @@ export default plugin.withOptions(
|
||||
addUtilities(mkColorUtil(["border-r"], "borderRight", border));
|
||||
addUtilities(mkColorUtil(["border-b"], "borderBottom", border));
|
||||
addUtilities(mkColorUtil(["border-l"], "borderLeft", border));
|
||||
|
||||
// re-use the border colors for outline colors
|
||||
addUtilities(mkColorUtil(["outline"], "outlineColor", border));
|
||||
addUtilities(mkColorUtil(["outline-t"], "outlineTop", border));
|
||||
addUtilities(mkColorUtil(["outline-r"], "outlineRight", border));
|
||||
addUtilities(mkColorUtil(["outline-b"], "outlineBottom", border));
|
||||
addUtilities(mkColorUtil(["outline-l"], "outlineLeft", border));
|
||||
},
|
||||
// add configuration which is merged with the final config
|
||||
() => ({
|
||||
|
||||
Reference in New Issue
Block a user