Skip to content

Commit

Permalink
Create Label component and improved radio/checkbox labels
Browse files Browse the repository at this point in the history
Also added a bunch of required-stars that were missing in forms
  • Loading branch information
eikhr committed Nov 11, 2024
1 parent e086323 commit 47d0c46
Show file tree
Hide file tree
Showing 18 changed files with 260 additions and 185 deletions.
14 changes: 0 additions & 14 deletions app/components/Form/Field.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,3 @@
font-size: var(--font-size-sm);
border-radius: var(--border-radius-md);
}

.labelContent {
line-height: 1.8;
}

.description {
margin-left: var(--spacing-sm);
}

.required {
color: var(--danger-color);
font-weight: 600;
margin-left: 2px;
}
56 changes: 12 additions & 44 deletions app/components/Form/Field.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Flex, Icon } from '@webkom/lego-bricks';
import { Flex } from '@webkom/lego-bricks';
import cx from 'classnames';
import Tooltip from 'app/components/Tooltip';
import { Label } from 'app/components/Form/Label';
import styles from './Field.module.css';
import type { ComponentType } from 'react';
import type { FieldInputProps, FieldRenderProps } from 'react-final-form';
Expand Down Expand Up @@ -67,7 +67,6 @@ export function createField<T, ExtraProps extends object>(
description,
fieldClassName,
labelClassName,
labelContentClassName,
onChange,
showErrors = true,
className = null,
Expand All @@ -80,30 +79,6 @@ export function createField<T, ExtraProps extends object>(
const fieldName = input?.name;
const { noLabel, inlineLabel } = options || {};

const labelComponent = (
<Flex alignItems="center">
{label && (
<div
style={{
cursor: inlineLabel && !props.disabled ? 'pointer' : 'default',
fontSize: !inlineLabel ? 'var(--font-size-lg)' : 'inherit',
}}
className={cx(labelContentClassName, styles.labelContent)}
>
{label}
</div>
)}
{required && <span className={styles.required}>*</span>}
{description && (
<Flex className={styles.description}>
<Tooltip content={description}>
<Icon size={18} name="help-circle-outline" />
</Tooltip>
</Flex>
)}
</Flex>
);

const component = (
<Component
{...(input as FieldInputProps<T>)}
Expand All @@ -117,18 +92,6 @@ export function createField<T, ExtraProps extends object>(
/>
);

const content = inlineLabel ? (
<Flex gap="var(--spacing-sm)">
{component}
{labelComponent}
</Flex>
) : (
<>
{labelComponent}
{component}
</>
);

return (
<Flex
column
Expand All @@ -139,11 +102,16 @@ export function createField<T, ExtraProps extends object>(
)}
style={fieldStyle}
>
{noLabel ? (
content
) : (
<label className={labelClassName}>{content}</label>
)}
<Label
className={labelClassName}
label={label}
noLabel={noLabel}
description={description}
inline={inlineLabel}
required={required}
>
{component}
</Label>
{hasError && (
<RenderErrorMessage error={anyError} fieldName={fieldName} />
)}
Expand Down
35 changes: 35 additions & 0 deletions app/components/Form/Label.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@import url('~app/styles/variables.css');

.label {
font-size: var(--font-size-lg);
margin-bottom: var(--spacing-xs);
}

.inline {
cursor: pointer;

.label {
font-size: inherit;
margin-bottom: 0;
}
}

.required {
color: var(--danger-color);
font-weight: 600;
margin-left: 2px;
}

.description {
display: inline-block;
vertical-align: top;
margin-left: var(--spacing-sm);
}

.fieldSet {
border: 0;
}

.fieldSetLegend {
margin-bottom: var(--spacing-sm);
}
96 changes: 96 additions & 0 deletions app/components/Form/Label.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { Flex, Icon } from '@webkom/lego-bricks';
import cx from 'classnames';
import { HelpCircle } from 'lucide-react';
import Tooltip from 'app/components/Tooltip';
import styles from './Label.module.css';
import type { HTMLProps, ReactNode } from 'react';

type LabelTextProps = {
label: ReactNode;
description?: string;
required?: boolean;
className?: string;
};

const LabelText = ({
label,
description,
required,
className,
}: LabelTextProps) => (
<div className={cx(styles.label, className)}>
{label}
{required && <span className={styles.required}>*</span>}
{description && (
<Tooltip content={description} className={styles.description}>
<Icon size={20} iconNode={<HelpCircle />} />
</Tooltip>
)}
</div>
);

type LabelProps = HTMLProps<HTMLLabelElement> & {
label: ReactNode;
noLabel?: boolean;
description?: string;
required?: boolean;
inline?: boolean;
};

export const Label = ({
label,
noLabel,
description,
required,
inline,
children,
...labelProps
}: LabelProps) => {
const LabelComponent = noLabel ? 'span' : 'label';
const labelElement = (
<LabelText label={label} description={description} required={required} />
);
return (
<LabelComponent {...labelProps}>
{inline ? (
<Flex
alignItems="center"
gap="var(--spacing-xs)"
className={styles.inline}
>
{children}
{labelElement}
</Flex>
) : (
<>
{labelElement}
{children}
</>
)}
</LabelComponent>
);
};

type FieldSetProps = HTMLProps<HTMLFieldSetElement> & {
legend: string;
description?: string;
required?: boolean;
children: ReactNode;
};
export const FieldSet = ({
legend,
description,
required,
children,
...fieldSetProps
}: FieldSetProps) => (
<fieldset
className={cx(styles.fieldSet, fieldSetProps.className)}
{...fieldSetProps}
>
<legend className={styles.fieldSetLegend}>
<LabelText label={legend} description={description} required={required} />
</legend>
{children}
</fieldset>
);
21 changes: 0 additions & 21 deletions app/components/Form/MultiSelectGroup.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,3 @@
display: flex;
flex-flow: row wrap;
}

.groupLabel {
font-size: var(--font-size-lg);
}

.radioLabel {
display: flex;
flex-direction: row;
}

.radioLabel:hover {
cursor: pointer;
}

.radioLabel > span {
font-size: var(--font-size-md);
margin-left: 15px;

/* For radio groups we want the label last: */
order: 1;
}
32 changes: 20 additions & 12 deletions app/components/Form/MultiSelectGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,36 @@
import { Children, cloneElement } from 'react';
import { FormSpy } from 'react-final-form';
import { FieldSet } from 'app/components/Form/Label';
import { RenderErrorMessage } from './Field';
import styles from './MultiSelectGroup.module.css';
import type { ReactElement } from 'react';

type Props = {
name: string;
label?: string;
legend: string;
description?: string;
required?: boolean;
children: ReactElement | ReactElement[];
};

const MultiSelectGroup = ({ name, label, children }: Props) => {
const MultiSelectGroup = ({
name,
legend,
description,
required,
children,
}: Props) => {
return (
<>
<label className={styles.groupLabel}>{label}</label>
<div className={styles.group}>
{Children.map(children, (child) =>
cloneElement(child, {
name,
fieldClassName: styles.radioField,
labelContentClassName: styles.radioLabel,
}),
)}
</div>
<FieldSet legend={legend} description={description} required={required}>
<div className={styles.group}>
{Children.map(children, (child) =>
cloneElement(child, {
name,
}),
)}
</div>
</FieldSet>
<FormSpy
subscription={{ errors: true, submitErrors: true, touched: true }}
>
Expand Down
2 changes: 1 addition & 1 deletion app/routes/bdb/components/AddSemester.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ const AddSemester = () => {
/>

<div className={styles.choices}>
<MultiSelectGroup name="semester" label="Semester">
<MultiSelectGroup name="semester" legend="Semester">
<Field
name="Spring"
label="Vår"
Expand Down
2 changes: 1 addition & 1 deletion app/routes/bdb/components/CompanyEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ const CompanyEditor = () => {
</div>

<div>
<MultiSelectGroup name="active" label="Aktiv bedrift?">
<MultiSelectGroup name="active" legend="Aktiv bedrift?">
<Field
name="Yes"
label="Ja"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,6 @@
width: 125px;
}

.heading {
font-weight: 500;
font-size: var(--font-size-lg);
line-height: 1.3;
margin: var(--spacing-sm) 0;
}

.topline {
margin: 15px 0;
padding: 10px 0;
Expand Down
Loading

0 comments on commit 47d0c46

Please sign in to comment.