Adds new Checkbox and CheckboxField components (#37665)
This commit is contained in:
parent
a75790143c
commit
a7a33ef6bc
@ -0,0 +1,70 @@
|
|||||||
|
.checkbox {
|
||||||
|
--size: 16px;
|
||||||
|
|
||||||
|
appearance: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
margin: 0;
|
||||||
|
width: var(--size);
|
||||||
|
height: var(--size);
|
||||||
|
vertical-align: top;
|
||||||
|
border-radius: calc(var(--size) / 4);
|
||||||
|
border: 1px 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
background: var(--color-bg-secondary);
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tick icon */
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
opacity: 0;
|
||||||
|
background-color: var(--color-text-on-brand-base);
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
width: calc(var(--size) * 0.625);
|
||||||
|
height: calc(var(--size) * 0.5);
|
||||||
|
mask-image: url("data:image/svg+xml;utf8,<svg width='10' height='8' viewBox='0 0 10 8' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M8.29289 0.292893C8.68342 -0.0976311 9.31643 -0.0976311 9.70696 0.292893C10.0975 0.683418 10.0975 1.31643 9.70696 1.70696L4.20696 7.20696C3.81643 7.59748 3.18342 7.59748 2.79289 7.20696L0.292893 4.70696C-0.0976311 4.31643 -0.0976311 3.68342 0.292893 3.29289C0.683418 2.90237 1.31643 2.90237 1.70696 3.29289L3.49992 5.08586L8.29289 0.292893Z' fill='black'/></svg>");
|
||||||
|
mask-position: center;
|
||||||
|
mask-size: 100%;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 'Minus' icon */
|
||||||
|
&:indeterminate::before {
|
||||||
|
width: calc(var(--size) * 0.5);
|
||||||
|
height: calc(var(--size) * 0.125);
|
||||||
|
mask-image: url("data:image/svg+xml;utf8,<svg width='8' height='2' viewBox='0 0 8 2' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M7.11111 0C7.60203 0 8 0.447715 8 1C8 1.55228 7.60203 2 7.11111 2H0.888889C0.397969 2 0 1.55228 0 1C0 0.447715 0.397969 0 0.888889 0H7.11111Z' fill='black'/></svg>");
|
||||||
|
}
|
||||||
|
|
||||||
|
&:checked,
|
||||||
|
&:indeterminate {
|
||||||
|
background-color: var(--color-bg-brand-base);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
outline: var(--outline-focus-default);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
import type { Meta, StoryObj } from '@storybook/react-vite';
|
||||||
|
|
||||||
|
import { Checkbox, CheckboxField } from './checkbox_field';
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
title: 'Components/Form Fields/CheckboxField',
|
||||||
|
component: CheckboxField,
|
||||||
|
args: {
|
||||||
|
label: 'Label',
|
||||||
|
hint: 'This is a description of this form field',
|
||||||
|
disabled: false,
|
||||||
|
},
|
||||||
|
argTypes: {
|
||||||
|
size: {
|
||||||
|
control: { type: 'range', min: 10, max: 64, step: 1 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} satisfies Meta<typeof CheckboxField>;
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
type Story = StoryObj<typeof meta>;
|
||||||
|
|
||||||
|
export const Simple: Story = {};
|
||||||
|
|
||||||
|
export const WithoutHint: Story = {
|
||||||
|
args: {
|
||||||
|
hint: undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Required: Story = {
|
||||||
|
args: {
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Optional: Story = {
|
||||||
|
args: {
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WithError: Story = {
|
||||||
|
args: {
|
||||||
|
required: false,
|
||||||
|
hasError: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DisabledChecked: Story = {
|
||||||
|
args: {
|
||||||
|
disabled: true,
|
||||||
|
checked: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DisabledUnchecked: Story = {
|
||||||
|
args: {
|
||||||
|
disabled: true,
|
||||||
|
checked: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Indeterminate: Story = {
|
||||||
|
args: {
|
||||||
|
indeterminate: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Plain: Story = {
|
||||||
|
render(props) {
|
||||||
|
return <Checkbox {...props} />;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Small: Story = {
|
||||||
|
args: {
|
||||||
|
size: 14,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Large: Story = {
|
||||||
|
args: {
|
||||||
|
size: 64,
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
import type { ComponentPropsWithoutRef, CSSProperties } from 'react';
|
||||||
|
import { forwardRef, useCallback, useEffect, useRef } from 'react';
|
||||||
|
|
||||||
|
import classes from './checkbox.module.scss';
|
||||||
|
import type { CommonFieldWrapperProps } from './form_field_wrapper';
|
||||||
|
import { FormFieldWrapper } from './form_field_wrapper';
|
||||||
|
|
||||||
|
type Props = Omit<ComponentPropsWithoutRef<'input'>, 'type'> & {
|
||||||
|
size?: number;
|
||||||
|
indeterminate?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CheckboxField = forwardRef<
|
||||||
|
HTMLInputElement,
|
||||||
|
Props & CommonFieldWrapperProps
|
||||||
|
>(({ id, label, hint, hasError, required, ...otherProps }, ref) => (
|
||||||
|
<FormFieldWrapper
|
||||||
|
label={label}
|
||||||
|
hint={hint}
|
||||||
|
required={required}
|
||||||
|
hasError={hasError}
|
||||||
|
inputId={id}
|
||||||
|
inputPlacement='inline-start'
|
||||||
|
>
|
||||||
|
{(inputProps) => <Checkbox {...otherProps} {...inputProps} ref={ref} />}
|
||||||
|
</FormFieldWrapper>
|
||||||
|
));
|
||||||
|
|
||||||
|
CheckboxField.displayName = 'CheckboxField';
|
||||||
|
|
||||||
|
export const Checkbox = forwardRef<HTMLInputElement, Props>(
|
||||||
|
({ className, size, indeterminate, ...otherProps }, ref) => {
|
||||||
|
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||||
|
|
||||||
|
const handleRef = useCallback(
|
||||||
|
(element: HTMLInputElement | null) => {
|
||||||
|
inputRef.current = element;
|
||||||
|
if (typeof ref === 'function') {
|
||||||
|
ref(element);
|
||||||
|
} else if (ref) {
|
||||||
|
ref.current = element;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[ref],
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (inputRef.current) {
|
||||||
|
inputRef.current.indeterminate = indeterminate || false;
|
||||||
|
}
|
||||||
|
}, [indeterminate]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
{...otherProps}
|
||||||
|
type='checkbox'
|
||||||
|
className={classes.checkbox}
|
||||||
|
style={size ? ({ '--size': `${size}px` } as CSSProperties) : undefined}
|
||||||
|
ref={handleRef}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
Checkbox.displayName = 'Checkbox';
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
.wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
font-size: 15px;
|
||||||
|
|
||||||
|
&[data-input-placement^='inline'] {
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-input-placement='inline-start'] {
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-input-placement='inline-end'] {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.labelWrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
[data-has-error='true'] & {
|
||||||
|
color: var(--color-text-error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hint {
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputWrapper {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
@ -5,7 +5,7 @@ import { useId } from 'react';
|
|||||||
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classes from './form_field_wrapper.module.scss';
|
||||||
|
|
||||||
interface InputProps {
|
interface InputProps {
|
||||||
id: string;
|
id: string;
|
||||||
@ -19,6 +19,7 @@ interface FieldWrapperProps {
|
|||||||
required?: boolean;
|
required?: boolean;
|
||||||
hasError?: boolean;
|
hasError?: boolean;
|
||||||
inputId?: string;
|
inputId?: string;
|
||||||
|
inputPlacement?: 'inline-start' | 'inline-end';
|
||||||
children: (inputProps: InputProps) => ReactNode;
|
children: (inputProps: InputProps) => ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,6 +43,7 @@ export const FormFieldWrapper: FC<FieldWrapperProps> = ({
|
|||||||
hint,
|
hint,
|
||||||
required,
|
required,
|
||||||
hasError,
|
hasError,
|
||||||
|
inputPlacement,
|
||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
const uniqueId = useId();
|
const uniqueId = useId();
|
||||||
@ -57,26 +59,32 @@ export const FormFieldWrapper: FC<FieldWrapperProps> = ({
|
|||||||
inputProps['aria-describedby'] = hintId;
|
inputProps['aria-describedby'] = hintId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const input = (
|
||||||
|
<div className={classes.inputWrapper}>{children(inputProps)}</div>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames('input with_block_label', {
|
className={classes.wrapper}
|
||||||
field_with_errors: hasError,
|
data-has-error={hasError}
|
||||||
})}
|
data-input-placement={inputPlacement}
|
||||||
>
|
>
|
||||||
<div className='label_input'>
|
{inputPlacement === 'inline-start' && input}
|
||||||
<label htmlFor={inputId}>
|
|
||||||
|
<div className={classes.labelWrapper}>
|
||||||
|
<label htmlFor={inputId} className={classes.label}>
|
||||||
{label}
|
{label}
|
||||||
{required !== undefined && <RequiredMark required={required} />}
|
{required !== undefined && <RequiredMark required={required} />}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{hasHint && (
|
{hasHint && (
|
||||||
<span className='hint' id={hintId}>
|
<span className={classes.hint} id={hintId}>
|
||||||
{hint}
|
{hint}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className='label_input__wrapper'>{children(inputProps)}</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{inputPlacement !== 'inline-start' && input}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -1,4 +1,5 @@
|
|||||||
export { TextInputField } from './text_input_field';
|
export { TextInputField } from './text_input_field';
|
||||||
export { TextAreaField } from './text_area_field';
|
export { TextAreaField } from './text_area_field';
|
||||||
export { ToggleField, PlainToggleField } from './toggle_field';
|
export { CheckboxField, Checkbox } from './checkbox_field';
|
||||||
|
export { ToggleField, Toggle } from './toggle_field';
|
||||||
export { SelectField } from './select_field';
|
export { SelectField } from './select_field';
|
||||||
|
|||||||
@ -35,6 +35,12 @@ type Story = StoryObj<typeof meta>;
|
|||||||
|
|
||||||
export const Simple: Story = {};
|
export const Simple: Story = {};
|
||||||
|
|
||||||
|
export const WithoutHint: Story = {
|
||||||
|
args: {
|
||||||
|
hint: undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const Required: Story = {
|
export const Required: Story = {
|
||||||
args: {
|
args: {
|
||||||
required: true,
|
required: true,
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import type { ComponentPropsWithoutRef } from 'react';
|
import type { ComponentPropsWithoutRef } from 'react';
|
||||||
import { forwardRef } from 'react';
|
import { forwardRef } from 'react';
|
||||||
|
|
||||||
import { FormFieldWrapper } from './wrapper';
|
import { FormFieldWrapper } from './form_field_wrapper';
|
||||||
import type { CommonFieldWrapperProps } from './wrapper';
|
import type { CommonFieldWrapperProps } from './form_field_wrapper';
|
||||||
|
|
||||||
interface Props
|
interface Props
|
||||||
extends ComponentPropsWithoutRef<'select'>, CommonFieldWrapperProps {}
|
extends ComponentPropsWithoutRef<'select'>, CommonFieldWrapperProps {}
|
||||||
|
|||||||
@ -25,6 +25,12 @@ type Story = StoryObj<typeof meta>;
|
|||||||
|
|
||||||
export const Simple: Story = {};
|
export const Simple: Story = {};
|
||||||
|
|
||||||
|
export const WithoutHint: Story = {
|
||||||
|
args: {
|
||||||
|
hint: undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const Required: Story = {
|
export const Required: Story = {
|
||||||
args: {
|
args: {
|
||||||
required: true,
|
required: true,
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import type { ComponentPropsWithoutRef } from 'react';
|
import type { ComponentPropsWithoutRef } from 'react';
|
||||||
import { forwardRef } from 'react';
|
import { forwardRef } from 'react';
|
||||||
|
|
||||||
import { FormFieldWrapper } from './wrapper';
|
import { FormFieldWrapper } from './form_field_wrapper';
|
||||||
import type { CommonFieldWrapperProps } from './wrapper';
|
import type { CommonFieldWrapperProps } from './form_field_wrapper';
|
||||||
|
|
||||||
interface Props
|
interface Props
|
||||||
extends ComponentPropsWithoutRef<'textarea'>, CommonFieldWrapperProps {}
|
extends ComponentPropsWithoutRef<'textarea'>, CommonFieldWrapperProps {}
|
||||||
|
|||||||
@ -25,6 +25,12 @@ type Story = StoryObj<typeof meta>;
|
|||||||
|
|
||||||
export const Simple: Story = {};
|
export const Simple: Story = {};
|
||||||
|
|
||||||
|
export const WithoutHint: Story = {
|
||||||
|
args: {
|
||||||
|
hint: undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const Required: Story = {
|
export const Required: Story = {
|
||||||
args: {
|
args: {
|
||||||
required: true,
|
required: true,
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import type { ComponentPropsWithoutRef } from 'react';
|
import type { ComponentPropsWithoutRef } from 'react';
|
||||||
import { forwardRef } from 'react';
|
import { forwardRef } from 'react';
|
||||||
|
|
||||||
import { FormFieldWrapper } from './wrapper';
|
import { FormFieldWrapper } from './form_field_wrapper';
|
||||||
import type { CommonFieldWrapperProps } from './wrapper';
|
import type { CommonFieldWrapperProps } from './form_field_wrapper';
|
||||||
|
|
||||||
interface Props
|
interface Props
|
||||||
extends ComponentPropsWithoutRef<'input'>, CommonFieldWrapperProps {}
|
extends ComponentPropsWithoutRef<'input'>, CommonFieldWrapperProps {}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react-vite';
|
import type { Meta, StoryObj } from '@storybook/react-vite';
|
||||||
|
|
||||||
import { PlainToggleField, ToggleField } from './toggle_field';
|
import { Toggle, ToggleField } from './toggle_field';
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
title: 'Components/Form Fields/ToggleField',
|
title: 'Components/Form Fields/ToggleField',
|
||||||
@ -16,14 +16,6 @@ const meta = {
|
|||||||
control: { type: 'range', min: 10, max: 40, step: 1 },
|
control: { type: 'range', min: 10, max: 40, step: 1 },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
render(args) {
|
|
||||||
// Component styles require a wrapper class at the moment
|
|
||||||
return (
|
|
||||||
<div className='simple_form'>
|
|
||||||
<ToggleField {...args} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
} satisfies Meta<typeof ToggleField>;
|
} satisfies Meta<typeof ToggleField>;
|
||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
@ -32,6 +24,12 @@ type Story = StoryObj<typeof meta>;
|
|||||||
|
|
||||||
export const Simple: Story = {};
|
export const Simple: Story = {};
|
||||||
|
|
||||||
|
export const WithoutHint: Story = {
|
||||||
|
args: {
|
||||||
|
hint: undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const Required: Story = {
|
export const Required: Story = {
|
||||||
args: {
|
args: {
|
||||||
required: true,
|
required: true,
|
||||||
@ -60,7 +58,7 @@ export const Disabled: Story = {
|
|||||||
|
|
||||||
export const Plain: Story = {
|
export const Plain: Story = {
|
||||||
render(props) {
|
render(props) {
|
||||||
return <PlainToggleField {...props} />;
|
return <Toggle {...props} />;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -3,9 +3,9 @@ import { forwardRef } from 'react';
|
|||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import type { CommonFieldWrapperProps } from './form_field_wrapper';
|
||||||
|
import { FormFieldWrapper } from './form_field_wrapper';
|
||||||
import classes from './toggle.module.css';
|
import classes from './toggle.module.css';
|
||||||
import type { CommonFieldWrapperProps } from './wrapper';
|
|
||||||
import { FormFieldWrapper } from './wrapper';
|
|
||||||
|
|
||||||
type Props = Omit<ComponentPropsWithoutRef<'input'>, 'type'> & {
|
type Props = Omit<ComponentPropsWithoutRef<'input'>, 'type'> & {
|
||||||
size?: number;
|
size?: number;
|
||||||
@ -21,16 +21,15 @@ export const ToggleField = forwardRef<
|
|||||||
required={required}
|
required={required}
|
||||||
hasError={hasError}
|
hasError={hasError}
|
||||||
inputId={id}
|
inputId={id}
|
||||||
|
inputPlacement='inline-end'
|
||||||
>
|
>
|
||||||
{(inputProps) => (
|
{(inputProps) => <Toggle {...otherProps} {...inputProps} ref={ref} />}
|
||||||
<PlainToggleField {...otherProps} {...inputProps} ref={ref} />
|
|
||||||
)}
|
|
||||||
</FormFieldWrapper>
|
</FormFieldWrapper>
|
||||||
));
|
));
|
||||||
|
|
||||||
ToggleField.displayName = 'ToggleField';
|
ToggleField.displayName = 'ToggleField';
|
||||||
|
|
||||||
export const PlainToggleField = forwardRef<HTMLInputElement, Props>(
|
export const Toggle = forwardRef<HTMLInputElement, Props>(
|
||||||
({ className, size, ...otherProps }, ref) => (
|
({ className, size, ...otherProps }, ref) => (
|
||||||
<span className={classes.wrapper}>
|
<span className={classes.wrapper}>
|
||||||
<input
|
<input
|
||||||
@ -49,4 +48,4 @@ export const PlainToggleField = forwardRef<HTMLInputElement, Props>(
|
|||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
PlainToggleField.displayName = 'PlainToggleField';
|
Toggle.displayName = 'Toggle';
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { useParams } from 'react-router';
|
|||||||
|
|
||||||
import Overlay from 'react-overlays/esm/Overlay';
|
import Overlay from 'react-overlays/esm/Overlay';
|
||||||
|
|
||||||
import { PlainToggleField } from '@/mastodon/components/form_fields/toggle_field';
|
import { Toggle } from '@/mastodon/components/form_fields';
|
||||||
import { Icon } from '@/mastodon/components/icon';
|
import { Icon } from '@/mastodon/components/icon';
|
||||||
import KeyboardArrowDownIcon from '@/material-icons/400-24px/keyboard_arrow_down.svg?react';
|
import KeyboardArrowDownIcon from '@/material-icons/400-24px/keyboard_arrow_down.svg?react';
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ const FilterDropdown: FC = () => {
|
|||||||
defaultMessage='Show replies'
|
defaultMessage='Show replies'
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<PlainToggleField
|
<Toggle
|
||||||
name='replies'
|
name='replies'
|
||||||
checked={replies}
|
checked={replies}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
@ -132,7 +132,7 @@ const FilterDropdown: FC = () => {
|
|||||||
defaultMessage='Show boosts'
|
defaultMessage='Show boosts'
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<PlainToggleField
|
<Toggle
|
||||||
name='boosts'
|
name='boosts'
|
||||||
checked={boosts}
|
checked={boosts}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import type {
|
|||||||
import { Button } from 'mastodon/components/button';
|
import { Button } from 'mastodon/components/button';
|
||||||
import { Column } from 'mastodon/components/column';
|
import { Column } from 'mastodon/components/column';
|
||||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||||
import { TextAreaField, ToggleField } from 'mastodon/components/form_fields';
|
import { CheckboxField, TextAreaField } from 'mastodon/components/form_fields';
|
||||||
import { TextInputField } from 'mastodon/components/form_fields/text_input_field';
|
import { TextInputField } from 'mastodon/components/form_fields/text_input_field';
|
||||||
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
import {
|
import {
|
||||||
@ -194,7 +194,7 @@ const CollectionSettings: React.FC<{
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='fields-group'>
|
<div className='fields-group'>
|
||||||
<ToggleField
|
<CheckboxField
|
||||||
label={
|
label={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='collections.mark_as_sensitive'
|
id='collections.mark_as_sensitive'
|
||||||
|
|||||||
@ -549,8 +549,8 @@ code {
|
|||||||
input[type='email'],
|
input[type='email'],
|
||||||
input[type='password'],
|
input[type='password'],
|
||||||
input[type='datetime-local'] {
|
input[type='datetime-local'] {
|
||||||
&:focus:invalid:not(:placeholder-shown),
|
&:focus:user-invalid:not(:placeholder-shown),
|
||||||
&:required:invalid:not(:placeholder-shown) {
|
&:required:user-invalid:not(:placeholder-shown) {
|
||||||
border-color: var(--color-text-error);
|
border-color: var(--color-text-error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -560,16 +560,6 @@ code {
|
|||||||
color: var(--color-text-error);
|
color: var(--color-text-error);
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type='text'],
|
|
||||||
input[type='number'],
|
|
||||||
input[type='email'],
|
|
||||||
input[type='password'],
|
|
||||||
input[type='datetime-local'],
|
|
||||||
textarea,
|
|
||||||
select {
|
|
||||||
border-color: var(--color-text-error);
|
|
||||||
}
|
|
||||||
|
|
||||||
.error {
|
.error {
|
||||||
display: block;
|
display: block;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@ -732,9 +722,23 @@ code {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.simple_form .input.field_with_errors,
|
||||||
|
[data-has-error='true'] {
|
||||||
|
input[type='text'],
|
||||||
|
input[type='number'],
|
||||||
|
input[type='email'],
|
||||||
|
input[type='password'],
|
||||||
|
input[type='datetime-local'],
|
||||||
|
textarea,
|
||||||
|
select {
|
||||||
|
border-color: var(--color-text-error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Double-chevron icon for custom select components */
|
/* Double-chevron icon for custom select components */
|
||||||
.select-wrapper,
|
.select-wrapper,
|
||||||
.select .label_input__wrapper {
|
.select .label_input__wrapper {
|
||||||
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user