diff --git a/app/javascript/mastodon/components/button/redesign.module.scss b/app/javascript/mastodon/components/button/redesign.module.scss index 8dd6ab90a8a..a504108713f 100644 --- a/app/javascript/mastodon/components/button/redesign.module.scss +++ b/app/javascript/mastodon/components/button/redesign.module.scss @@ -139,9 +139,10 @@ a.base { // Helper classes -.icon { - width: 1em; - height: 1em; +.icon, +.loading { + width: var(--fs-xl); + height: var(--fs-xl); } // Adds padding to the text label. This is supposed to be there even if there is no icon. @@ -156,15 +157,9 @@ a.base { .iconOnly { aspect-ratio: 1; + padding: 0; } .loading { color: inherit; - height: 0.8em; - width: 0.8em; - - .iconOnly & { - height: 1em; - width: 1em; - } } diff --git a/app/javascript/mastodon/components/form_fields/checkbox_field.tsx b/app/javascript/mastodon/components/form_fields/checkbox_field.tsx index 78bbb32e4fe..47e4c7051b5 100644 --- a/app/javascript/mastodon/components/form_fields/checkbox_field.tsx +++ b/app/javascript/mastodon/components/form_fields/checkbox_field.tsx @@ -13,18 +13,24 @@ type Props = Omit, 'type'> & { export const CheckboxField = forwardRef< HTMLInputElement, Props & CommonFieldWrapperProps ->(({ id, label, hint, status, required, ...otherProps }, ref) => ( - - {(inputProps) => } - -)); +>( + ( + { id, label, hint, status, required, wrapperClassName, ...otherProps }, + ref, + ) => ( + + {(inputProps) => } + + ), +); CheckboxField.displayName = 'CheckboxField'; diff --git a/app/javascript/mastodon/components/form_fields/combobox_field.tsx b/app/javascript/mastodon/components/form_fields/combobox_field.tsx index 9c93d3f4f18..b92fdb9e895 100644 --- a/app/javascript/mastodon/components/form_fields/combobox_field.tsx +++ b/app/javascript/mastodon/components/form_fields/combobox_field.tsx @@ -180,7 +180,15 @@ export const ComboboxFieldWithRef = < Item extends ComboboxItem, GroupKey extends string, >( - { id, label, hint, status, required, ...otherProps }: Props, + { + id, + label, + hint, + status, + required, + wrapperClassName, + ...otherProps + }: Props, ref: React.ForwardedRef, ) => ( {(inputProps) => } diff --git a/app/javascript/mastodon/components/form_fields/copy_link_field.tsx b/app/javascript/mastodon/components/form_fields/copy_link_field.tsx index 062a9074a3b..0476afe6446 100644 --- a/app/javascript/mastodon/components/form_fields/copy_link_field.tsx +++ b/app/javascript/mastodon/components/form_fields/copy_link_field.tsx @@ -22,7 +22,17 @@ interface CopyLinkFieldProps extends CommonFieldWrapperProps, TextInputProps { export const CopyLinkField = forwardRef( ( - { id, label, hint, status, value, required, className, ...otherProps }, + { + id, + label, + hint, + status, + value, + required, + className, + wrapperClassName, + ...otherProps + }, ref, ) => { const intl = useIntl(); @@ -50,6 +60,7 @@ export const CopyLinkField = forwardRef( required={required} status={status} inputId={id} + className={wrapperClassName} > {(inputProps) => (
diff --git a/app/javascript/mastodon/components/form_fields/fieldset.tsx b/app/javascript/mastodon/components/form_fields/fieldset.tsx index 06882d8e816..02ee92cf0de 100644 --- a/app/javascript/mastodon/components/form_fields/fieldset.tsx +++ b/app/javascript/mastodon/components/form_fields/fieldset.tsx @@ -3,6 +3,8 @@ import type { ReactNode, FC } from 'react'; import { createContext, useId } from 'react'; +import classNames from 'classnames'; + import { A11yLiveRegion } from 'mastodon/components/a11y_live_region'; import { CalloutInline } from 'mastodon/components/callout_inline'; @@ -17,6 +19,7 @@ interface FieldsetProps { name?: string; status?: FieldStatus | FieldStatus['variant']; layout?: 'vertical' | 'horizontal'; + className?: string; children: ReactNode; } @@ -33,6 +36,7 @@ export const Fieldset: FC = ({ name, status, layout, + className, children, }) => { const uniqueId = useId(); @@ -54,23 +58,23 @@ export const Fieldset: FC = ({ return (
-
+
{legend}
{hasHint && ( -

+

{hint}

)}
-
+
{children} diff --git a/app/javascript/mastodon/components/form_fields/form_field_wrapper.tsx b/app/javascript/mastodon/components/form_fields/form_field_wrapper.tsx index 579d6e814ca..841247373b9 100644 --- a/app/javascript/mastodon/components/form_fields/form_field_wrapper.tsx +++ b/app/javascript/mastodon/components/form_fields/form_field_wrapper.tsx @@ -83,7 +83,9 @@ export const FormFieldWrapper: FC = ({ }; const input = ( -
{children(inputProps)}
+
+ {children(inputProps)} +
); return ( @@ -105,7 +107,7 @@ export const FormFieldWrapper: FC = ({ {hasHint && ( - + {hint} )} diff --git a/app/javascript/mastodon/components/form_fields/radio_button_field.tsx b/app/javascript/mastodon/components/form_fields/radio_button_field.tsx index cbc9020ca7f..a16bf8a3db2 100644 --- a/app/javascript/mastodon/components/form_fields/radio_button_field.tsx +++ b/app/javascript/mastodon/components/form_fields/radio_button_field.tsx @@ -3,6 +3,8 @@ import type { ComponentPropsWithoutRef, CSSProperties } from 'react'; import { forwardRef, useContext } from 'react'; +import classNames from 'classnames'; + import { FieldsetNameContext } from './fieldset'; import type { CommonFieldWrapperProps } from './form_field_wrapper'; import { FormFieldWrapper } from './form_field_wrapper'; @@ -15,41 +17,50 @@ type Props = Omit, 'type'> & { export const RadioButtonField = forwardRef< HTMLInputElement, Props & CommonFieldWrapperProps ->(({ id, label, hint, status, required, ...otherProps }, ref) => { - const fieldsetName = useContext(FieldsetNameContext); +>( + ( + { id, label, hint, status, required, wrapperClassName, ...otherProps }, + ref, + ) => { + const fieldsetName = useContext(FieldsetNameContext); - return ( - - {(inputProps) => ( - - )} - - ); -}); + return ( + + {(inputProps) => ( + + )} + + ); + }, +); RadioButtonField.displayName = 'RadioButtonField'; export const RadioButton = forwardRef( - ({ className, size, ...otherProps }, ref) => ( - + ({ className, size, children, ...otherProps }, ref) => ( + <> + {children} + + ), ); diff --git a/app/javascript/mastodon/components/form_fields/redesign.module.scss b/app/javascript/mastodon/components/form_fields/redesign.module.scss index 87337e3af16..af0d9c1ad2f 100644 --- a/app/javascript/mastodon/components/form_fields/redesign.module.scss +++ b/app/javascript/mastodon/components/form_fields/redesign.module.scss @@ -1,3 +1,39 @@ +// Radio + +.radioWrapper { + [data-input] { + position: relative; + } + + .icon { + position: absolute; + pointer-events: none; + opacity: 0; + transition: + color 200ms, + opacity 200ms; + } + + .icon:has(+ :checked) { + opacity: 1; + } + + input { + opacity: 0; + } + + label { + font-size: var(--fs-sm); + } +} + +.icon { + width: var(--fs-lg); + height: var(--fs-lg); +} + +// Text Input + .inputWrapper { label { font-size: var(--fs-sm); diff --git a/app/javascript/mastodon/components/form_fields/redesign.stories.tsx b/app/javascript/mastodon/components/form_fields/redesign.stories.tsx index a8b45e3fff4..6ab651a4534 100644 --- a/app/javascript/mastodon/components/form_fields/redesign.stories.tsx +++ b/app/javascript/mastodon/components/form_fields/redesign.stories.tsx @@ -1,6 +1,9 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; -import { TextInputField, ToggleField } from './redesign'; +import CheckIcon from '@/material-icons/400-24px/check.svg?react'; + +import { Fieldset } from './fieldset'; +import { RadioButtonField, TextInputField, ToggleField } from './redesign'; interface FieldProps { label: string; @@ -28,6 +31,17 @@ export default meta; type Story = StoryObj; +export const RadioButton: Story = { + render(args) { + return ( +
+ + +
+ ); + }, +}; + export const TextInput: Story = { render(args) { return ; diff --git a/app/javascript/mastodon/components/form_fields/redesign.tsx b/app/javascript/mastodon/components/form_fields/redesign.tsx index e2f00456dd6..7d5ecd4e598 100644 --- a/app/javascript/mastodon/components/form_fields/redesign.tsx +++ b/app/javascript/mastodon/components/form_fields/redesign.tsx @@ -2,6 +2,10 @@ import classNames from 'classnames'; import type { Merge } from 'type-fest'; +import { Icon } from '../icon'; +import type { IconProp } from '../icon'; + +import { RadioButtonField as OldRadioButtonField } from './radio_button_field'; import classes from './redesign.module.scss'; import { TextInput as OldTextInput, @@ -18,6 +22,31 @@ type RedesignComponent< P = object, > = React.FC, P>>; +// Radio button field + +interface RadioButtonProps { + icon?: IconProp | null; + iconClassName?: string; +} + +export const RadioButtonField: RedesignComponent< + typeof OldRadioButtonField, + RadioButtonProps +> = ({ icon, iconClassName, wrapperClassName, ...props }) => ( + + {icon && ( + + )} + +); + // Text field export const TextInputField: RedesignComponent = ({ @@ -71,5 +100,6 @@ export const ToggleField: RedesignComponent< classes.toggle, size === 'sm' && classes.toggleSmall, )} + size={size === 'sm' ? 14 : 20} /> ); diff --git a/app/javascript/mastodon/components/form_fields/toggle_field.tsx b/app/javascript/mastodon/components/form_fields/toggle_field.tsx index 3de09823d3e..ea995305ddd 100644 --- a/app/javascript/mastodon/components/form_fields/toggle_field.tsx +++ b/app/javascript/mastodon/components/form_fields/toggle_field.tsx @@ -14,18 +14,24 @@ type Props = Omit, 'type'> & { export const ToggleField = forwardRef< HTMLInputElement, Props & CommonFieldWrapperProps ->(({ id, label, hint, status, required, ...otherProps }, ref) => ( - - {(inputProps) => } - -)); +>( + ( + { id, label, hint, status, required, wrapperClassName, ...otherProps }, + ref, + ) => ( + + {(inputProps) => } + + ), +); ToggleField.displayName = 'ToggleField';