generated from nl-design-system/example
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Jaap-Hein Wester
committed
Nov 21, 2024
1 parent
3636be3
commit cf5127d
Showing
6 changed files
with
358 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
166 changes: 166 additions & 0 deletions
166
packages/components-react/src/form-field-checkbox/FormFieldCheckbox.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
/* stylelint-disable selector-class-pattern */ | ||
:root { | ||
--lux-form-field-checkbox-inner-column-gap: var(--lux-space-100); | ||
--lux-form-field-checkbox-inner-padding-inline-start: var(--lux-space-200, 0.5rem); | ||
--lux-form-field-checkbox-inner-padding-inline-end: var(--lux-space-200, 0.5rem); | ||
--lux-form-field-checkbox-inner-padding-block-start: var(--lux-space-200, 0.5rem); | ||
--lux-form-field-checkbox-inner-padding-block-end: var(--lux-space-200, 0.5rem); | ||
--lux-form-field-checkbox-inner-border-radius: var(--lux-border-radius-default); | ||
--lux-form-field-checkbox-inner-border-width: var(--lux-border-width-default, 1px); | ||
--lux-form-field-checkbox-inner-border-style: solid; | ||
--lux-form-field-checkbox-inner-border-color: var(--lux-color-brand-default); | ||
--lux-form-field-checkbox-inner-background-color: var(--lux-color-none); | ||
--lux-form-field-checkbox-invalid-inner-border-color: var(--lux-color-feedback-error-default); | ||
--lux-form-field-checkbox-invalid-inner-background-color: var(--lux-color-none); | ||
--lux-form-field-checkbox-invalid-inner-row-gap: var(--lux-space-100); | ||
--lux-form-field-checkbox-hover-inner-border-color: var(--lux-color-brand-default); | ||
--lux-form-field-checkbox-hover-inner-background-color: var(--lux-color-brand-subdued); | ||
--lux-form-field-checkbox-active-inner-border-color: var(--lux-color-brand-default); | ||
--lux-form-field-checkbox-active-inner-background-color: var(--lux-color-none); | ||
--lux-form-field-checkbox-focus-visible-inner-border-color: var(--lux-color-brand-default); | ||
--lux-form-field-checkbox-focus-visible-background-color: var(--lux-color-none); | ||
--lux-form-field-checkbox-disabled-inner-border-color: var(--lux-color-border-subdued); | ||
--lux-form-field-checkbox-disabled-inner-background-color: var(--lux-color-none); | ||
} | ||
|
||
.lux-form-field-checkbox--robbert { | ||
--utrecht-checkbox-size: 24px; | ||
--utrecht-checkbox-margin-inline-end: 12px; | ||
--lux-indent: calc(var(--utrecht-checkbox-size) + var(--utrecht-checkbox-margin-inline-end)); | ||
|
||
position: relative; | ||
margin-inline-start: var(--lux-indent); | ||
|
||
/* FIXME: remove */ | ||
outline: 1pt dotted gold; | ||
outline-offset: 2px; | ||
|
||
.utrecht-form-label.utrecht-form-label--checkbox { | ||
display: block; | ||
margin-inline-start: revert; | ||
text-indent: calc(-1 * var(--lux-indent)); | ||
|
||
&::before { | ||
position: absolute; | ||
|
||
/* stylelint-disable property-disallowed-list */ | ||
top: 0; | ||
right: 0; | ||
bottom: 0; | ||
left: calc(-1 * var(--lux-indent)); | ||
border: var(--lux-form-field-checkbox-inner-border-width) var(--lux-form-field-checkbox-inner-border-style) | ||
var(--lux-form-field-checkbox-inner-border-color); | ||
border-radius: var(--lux-form-field-checkbox-inner-border-radius); | ||
pointer-events: none; | ||
content: ""; | ||
|
||
/* stylelint-enable property-disallowed-list */ | ||
} | ||
} | ||
|
||
.utrecht-checkbox { | ||
margin-inline-end: var(--lux-form-field-checkbox-inner-column-gap); | ||
} | ||
|
||
.utrecht-form-field-description { | ||
text-indent: -0.25rem; | ||
} | ||
|
||
.utrecht-form-field-error-message { | ||
text-indent: calc(-1 * var(--lux-indent)); | ||
} | ||
} | ||
|
||
.lux-form-field-checkbox { | ||
/* prettier-ignore */ | ||
--_lux-checkbox-size: calc(var(--utrecht-checkbox-size) + var(--utrecht-checkbox-margin-inline-end) + var(--lux-form-field-checkbox-inner-padding-inline-start)); | ||
--_lux-column-gap: var(--lux-form-field-checkbox-inner-column-gap, var(--utrecht-checkbox-margin-inline-end, 12px)); | ||
|
||
position: relative; | ||
grid-template-columns: var(--_lux-checkbox-size) 100fr; | ||
grid-template-areas: | ||
"input label" | ||
". description" | ||
"error-message error-message"; | ||
gap: 0 var(--_lux-column-gap); | ||
|
||
/* FIXME: remove */ | ||
outline: 1pt dotted gold; | ||
outline-offset: 2px; | ||
|
||
&::before { | ||
grid-row-start: label; | ||
grid-row-end: description; | ||
grid-column-start: input; | ||
grid-column-end: description; | ||
border: var(--lux-form-field-checkbox-inner-border-width) var(--lux-form-field-checkbox-inner-border-style) | ||
var(--lux-form-field-checkbox-inner-border-color); | ||
border-radius: var(--lux-form-field-checkbox-inner-border-radius); | ||
pointer-events: none; | ||
content: ""; | ||
} | ||
|
||
&--disabled::before { | ||
border-color: var(--lux-form-field-checkbox-disabled-inner-border-color); | ||
background-color: var(--lux-form-field-checkbox-disabled-inner-background-color); | ||
} | ||
|
||
&--invalid::before { | ||
border-color: var(--lux-form-field-checkbox-invalid-inner-border-color); | ||
background-color: var(--lux-form-field-checkbox-invalid-inner-background-color); | ||
} | ||
|
||
&:has(:focus-visible)::before { | ||
--_utrecht-focus-ring-box-shadow: 0 0 0 var(--utrecht-focus-outline-width, 0) | ||
var(--utrecht-focus-inverse-outline-color, transparent); | ||
|
||
/* TODO: maybe use utrecht mixin */ | ||
outline-color: var(--utrecht-focus-outline-color, revert); | ||
outline-style: var(--utrecht-focus-outline-style, revert); | ||
outline-width: var(--utrecht-focus-outline-width, revert); | ||
outline-offset: var(--utrecht-focus-outline-offset, revert); | ||
box-shadow: var(--_utrecht-focus-ring-box-shadow); | ||
border-color: var(--lux-form-field-checkbox-focus-visible-inner-border-color); | ||
background-color: var(--lux-form-field-checkbox-focus-visible-inner-background-color); | ||
} | ||
|
||
.utrecht-checkbox:focus-visible { | ||
outline: none; | ||
} | ||
|
||
&:not(#{&}--disabled):has(.utrecht-form-field__input .utrecht-checkbox:hover)::before { | ||
border-color: var(--lux-form-field-checkbox-hover-inner-border-color); | ||
background-color: var(--lux-form-field-checkbox-hover-inner-background-color); | ||
} | ||
|
||
/* TODO: only when block prop is set?? */ | ||
&__label::before { | ||
position: absolute; | ||
inset-block-end: 0; | ||
inset-block-start: 0; | ||
inset-inline-end: 0; | ||
inset-inline-start: 0; | ||
pointer-events: visible; | ||
|
||
/* outline: 1mm dashed salmon; */ | ||
content: ""; | ||
} | ||
|
||
.utrecht-form-field__label, | ||
.utrecht-form-field__input { | ||
padding-block-start: var(--lux-form-field-checkbox-inner-padding-block-start); | ||
} | ||
|
||
.utrecht-form-field__label + .utrecht-form-field__input, | ||
.utrecht-form-field__description { | ||
padding-block-end: var(--lux-form-field-checkbox-inner-padding-block-end); | ||
} | ||
|
||
.utrecht-form-field__input { | ||
padding-inline-start: var(--lux-form-field-checkbox-inner-padding-inline-start); | ||
} | ||
|
||
.utrecht-form-field__error-message { | ||
padding-block-start: var(--lux-form-field-checkbox-invalid-inner-row-gap); | ||
} | ||
} |
107 changes: 107 additions & 0 deletions
107
packages/components-react/src/form-field-checkbox/FormFieldCheckbox.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import clsx from 'clsx'; | ||
import { ReactNode, useId } from 'react'; | ||
import { LuxCheckbox } from '../checkbox/Checkbox'; | ||
import { LuxFormField, LuxFormFieldProps } from '../form-field/FormField'; | ||
import { | ||
LuxFormFieldDescription, | ||
type LuxFormFieldDescriptionAppearance, | ||
} from '../form-field-description/FormFieldDescription'; | ||
import { LuxFormFieldErrorMessage } from '../form-field-error-message/FormFieldErrorMessage'; | ||
import { LuxFormFieldLabel } from '../form-field-label/FormFieldLabel'; | ||
import './FormFieldCheckbox.scss'; | ||
|
||
export type LuxFormFieldCheckboxProps = LuxFormFieldProps & { | ||
label: ReactNode; | ||
description: ReactNode; | ||
errorMessage: ReactNode; | ||
disabled: boolean; | ||
invalid: boolean; | ||
appearance: LuxFormFieldDescriptionAppearance; | ||
distanced: boolean; | ||
children: any; | ||
restProps: any; | ||
}; | ||
|
||
export const LuxFormFieldCheckbox = ({ | ||
label, | ||
description, | ||
errorMessage, | ||
disabled, | ||
invalid, | ||
appearance, | ||
distanced, | ||
children, | ||
...restProps | ||
}: LuxFormFieldCheckboxProps) => { | ||
const inputId = useId(); | ||
const descriptionId = useId(); | ||
const errorMessageId = useId(); | ||
|
||
const labelNode = | ||
typeof label === 'string' ? ( | ||
<LuxFormFieldLabel | ||
type="checkbox" | ||
disabled={disabled} | ||
htmlFor={inputId} | ||
className="lux-form-field-checkbox__label" | ||
> | ||
{label} | ||
</LuxFormFieldLabel> | ||
) : ( | ||
label | ||
); | ||
const descriptionNode = | ||
typeof description === 'string' && description !== '' ? ( | ||
<LuxFormFieldDescription | ||
appearance={invalid ? 'invalid' : appearance} | ||
id={descriptionId} | ||
className="lux-form-field-checkbox__description" | ||
> | ||
<label htmlFor={inputId}>{description}</label> | ||
</LuxFormFieldDescription> | ||
) : ( | ||
description | ||
); | ||
const errorMessageNode = | ||
typeof errorMessage === 'string' ? ( | ||
<LuxFormFieldErrorMessage | ||
distanced={distanced} | ||
id={errorMessageId} | ||
className="lux-form-field-checkbox__error-message" | ||
> | ||
{errorMessage} | ||
</LuxFormFieldErrorMessage> | ||
) : ( | ||
errorMessage | ||
); | ||
|
||
return ( | ||
<> | ||
<LuxFormField type="custom" className={clsx('lux-form-field-checkbox--robbert')} invalid={invalid} {...restProps}> | ||
<LuxFormFieldLabel type="checkbox"> | ||
<LuxCheckbox /> | ||
{label} | ||
<LuxFormFieldDescription>{description}</LuxFormFieldDescription> | ||
</LuxFormFieldLabel> | ||
<LuxFormFieldErrorMessage>{errorMessage}</LuxFormFieldErrorMessage> | ||
{children} | ||
</LuxFormField> | ||
<hr /> | ||
<LuxFormField | ||
type="checkbox" | ||
label={labelNode} | ||
description={descriptionNode} | ||
errorMessage={errorMessageNode} | ||
invalid={invalid} | ||
input={<LuxCheckbox id={inputId} disabled={disabled} invalid={invalid} />} | ||
className={clsx('lux-form-field-checkbox', { | ||
'lux-form-field-checkbox--invalid': invalid, | ||
'lux-form-field-checkbox--disabled': disabled, | ||
})} | ||
{...restProps} | ||
> | ||
{children} | ||
</LuxFormField> | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 11 additions & 0 deletions
11
...ages/storybook/src/react-components/form-field-checkbox/form-field-checkbox.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { Canvas, Controls, Meta } from "@storybook/blocks"; | ||
import * as FormFieldCheckboxStories from "./form-field-checkbox.stories"; | ||
|
||
<Meta of={FormFieldCheckboxStories} /> | ||
|
||
# Form Field Checkbox | ||
|
||
## Playground | ||
|
||
<Canvas of={FormFieldCheckboxStories.Playground} /> | ||
<Controls of={FormFieldCheckboxStories.Playground} /> |
72 changes: 72 additions & 0 deletions
72
packages/storybook/src/react-components/form-field-checkbox/form-field-checkbox.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { LuxFormFieldCheckbox, type LuxFormFieldCheckboxProps } from '@lux-design-system/components-react'; | ||
import tokens from '@lux-design-system/design-tokens/dist/index.json'; | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
import { BADGES } from '../../../config/preview'; | ||
import CheckboxMeta from '../checkbox/checkbox.stories'; | ||
import FormFieldDescriptionMeta from '../form-field-description/form-field-description.stories'; | ||
import FormFieldErrorMessageMeta from '../form-field-error-message/form-field-error-message.stories'; | ||
|
||
const meta = { | ||
title: 'React Components/Form Field/Form Field Checkbox', | ||
id: 'react-components-form-field-form-field-checkbox', | ||
component: LuxFormFieldCheckbox, | ||
parameters: { | ||
badges: [BADGES.WIP, BADGES.CANARY], | ||
tokens, | ||
tokensPrefix: 'utrecht-form-field-checkbox', | ||
}, | ||
argTypes: { | ||
...CheckboxMeta.argTypes, | ||
appearance: { | ||
...FormFieldDescriptionMeta.argTypes.appearance, | ||
}, | ||
distanced: { | ||
...FormFieldErrorMessageMeta.argTypes.distanced, | ||
}, | ||
disabled: { | ||
type: 'boolean', | ||
}, | ||
errorMessage: { | ||
if: { | ||
arg: 'invalid', | ||
truthy: true, | ||
}, | ||
}, | ||
}, | ||
} satisfies Meta<LuxFormFieldCheckboxProps>; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof meta>; | ||
|
||
export const Playground: Story = { | ||
name: 'Playground', | ||
args: { | ||
label: 'Label', | ||
description: 'Description', | ||
errorMessage: 'ErrorMessage', | ||
invalid: false, | ||
appearance: undefined, | ||
}, | ||
parameters: { | ||
docs: { | ||
sourceState: 'shown', | ||
}, | ||
}, | ||
tags: ['!autodocs'], | ||
}; | ||
|
||
export const Invalid: Story = { | ||
name: 'Invalid', | ||
args: { | ||
...Playground.args, | ||
invalid: true, | ||
}, | ||
}; | ||
|
||
export const Disabled: Story = { | ||
name: 'Disabled', | ||
args: { | ||
...Playground.args, | ||
disabled: true, | ||
}, | ||
}; |