diff --git a/app/javascript/flavours/glitch/components/form_fields/checkbox.module.scss b/app/javascript/flavours/glitch/components/form_fields/checkbox.module.scss index 36f029a17b..8f4ab99a5c 100644 --- a/app/javascript/flavours/glitch/components/form_fields/checkbox.module.scss +++ b/app/javascript/flavours/glitch/components/form_fields/checkbox.module.scss @@ -1,5 +1,6 @@ .checkbox { --size: 16px; + --border-width: 1px; appearance: none; box-sizing: border-box; @@ -10,18 +11,26 @@ height: var(--size); vertical-align: top; border-radius: calc(var(--size) / 4); - border: 1px solid var(--color-border-primary); + border: var(--border-width) solid var(--color-border-primary); background-color: var(--color-bg-primary); transition: 0.15s ease-out; transition-property: background-color, border-color; cursor: pointer; - @supports not (appearance: none) { - accent-color: var(--color-bg-brand-base); + /* Increase clickable area, prevents misclicks and covers gap between control and label */ + &::after { + content: ''; + position: absolute; + + --spread: calc(var(--border-width) + var(--form-field-label-gap, 8px)); + + inset-inline: calc(-1 * var(--spread)); + inset-block: calc(-0.75 * var(--spread)); } &:disabled { - background: var(--color-bg-secondary); + background: var(--color-bg-tertiary); + border: none; cursor: not-allowed; } @@ -53,9 +62,12 @@ border-color: var(--color-bg-brand-base); &:disabled { - border-color: var(--color-bg-disabled); - background: var(--color-bg-disabled); - color: var(--color-text-on-disabled); + border: none; + background-color: var(--color-text-disabled); + + &::before { + background-color: var(--color-bg-tertiary); + } } &::before { diff --git a/app/javascript/flavours/glitch/components/form_fields/checkbox_field.stories.tsx b/app/javascript/flavours/glitch/components/form_fields/checkbox_field.stories.tsx index 3f73143ba6..4d208cf21b 100644 --- a/app/javascript/flavours/glitch/components/form_fields/checkbox_field.stories.tsx +++ b/app/javascript/flavours/glitch/components/form_fields/checkbox_field.stories.tsx @@ -1,6 +1,7 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; import { Checkbox, CheckboxField } from './checkbox_field'; +import { Fieldset } from './fieldset'; const meta = { title: 'Components/Form Fields/CheckboxField', @@ -29,6 +30,37 @@ export const WithoutHint: Story = { }, }; +export const InFieldset: Story = { + render() { + return ( +
+ ); + }, +}; + +export const InFieldsetHorizontal: Story = { + render() { + return ( + + ); + }, +}; + export const Required: Story = { args: { required: true, @@ -82,6 +114,6 @@ export const Small: Story = { export const Large: Story = { args: { - size: 64, + size: 36, }, }; diff --git a/app/javascript/flavours/glitch/components/form_fields/fieldset.module.scss b/app/javascript/flavours/glitch/components/form_fields/fieldset.module.scss new file mode 100644 index 0000000000..f222762af5 --- /dev/null +++ b/app/javascript/flavours/glitch/components/form_fields/fieldset.module.scss @@ -0,0 +1,19 @@ +.fieldset { + display: flex; + flex-direction: column; + gap: 12px; + color: var(--color-text-primary); + font-size: 15px; +} + +.fieldsWrapper { + display: flex; + flex-direction: column; + row-gap: 8px; + + &[data-layout='horizontal'] { + flex-direction: row; + flex-wrap: wrap; + column-gap: 24px; + } +} diff --git a/app/javascript/flavours/glitch/components/form_fields/fieldset.tsx b/app/javascript/flavours/glitch/components/form_fields/fieldset.tsx new file mode 100644 index 0000000000..d52a95130b --- /dev/null +++ b/app/javascript/flavours/glitch/components/form_fields/fieldset.tsx @@ -0,0 +1,64 @@ +/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */ + +import type { ReactNode, FC } from 'react'; +import { createContext, useId } from 'react'; + +import classes from './fieldset.module.scss'; +import formFieldWrapperClasses from './form_field_wrapper.module.scss'; + +interface FieldsetProps { + legend: ReactNode; + hint?: ReactNode; + name?: string; + hasError?: boolean; + layout?: 'vertical' | 'horizontal'; + children: ReactNode; +} + +export const FieldsetNameContext = createContext