diff options
| author | Armand Philippot <git@armandphilippot.com> | 2023-10-30 12:44:11 +0100 |
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2023-11-11 18:15:27 +0100 |
| commit | 0e52a59917406ad03c174e030c6c1c92ab23449d (patch) | |
| tree | 693bbcc5edbe78ebd2f0050fddbc45c706e0ba61 /src/components/organisms/forms/settings-form/theme-toggle | |
| parent | 84a679b0e48ed76eee2fa44d3caac83591aa3c8c (diff) | |
refactor(components): extract SettingsForm component form SettingsModal
We could use an array of items and map over it instead of repeating the
Switch component for each settings but with translations, it becomes
quickly unreadable. So I prefer to keep separate components.
Diffstat (limited to 'src/components/organisms/forms/settings-form/theme-toggle')
4 files changed, 126 insertions, 0 deletions
diff --git a/src/components/organisms/forms/settings-form/theme-toggle/index.ts b/src/components/organisms/forms/settings-form/theme-toggle/index.ts new file mode 100644 index 0000000..0dbf668 --- /dev/null +++ b/src/components/organisms/forms/settings-form/theme-toggle/index.ts @@ -0,0 +1 @@ +export * from './theme-toggle'; diff --git a/src/components/organisms/forms/settings-form/theme-toggle/theme-toggle.stories.tsx b/src/components/organisms/forms/settings-form/theme-toggle/theme-toggle.stories.tsx new file mode 100644 index 0000000..4742adf --- /dev/null +++ b/src/components/organisms/forms/settings-form/theme-toggle/theme-toggle.stories.tsx @@ -0,0 +1,20 @@ +import type { ComponentMeta, ComponentStory } from '@storybook/react'; +import { ThemeToggle } from './theme-toggle'; + +/** + * ThemeToggle - Storybook Meta + */ +export default { + title: 'Organisms/Forms/Settings/Items', + component: ThemeToggle, + argTypes: {}, +} as ComponentMeta<typeof ThemeToggle>; + +const Template: ComponentStory<typeof ThemeToggle> = (args) => ( + <ThemeToggle {...args} /> +); + +/** + * Toggle Stories - Theme + */ +export const Theme = Template.bind({}); diff --git a/src/components/organisms/forms/settings-form/theme-toggle/theme-toggle.test.tsx b/src/components/organisms/forms/settings-form/theme-toggle/theme-toggle.test.tsx new file mode 100644 index 0000000..e74842e --- /dev/null +++ b/src/components/organisms/forms/settings-form/theme-toggle/theme-toggle.test.tsx @@ -0,0 +1,27 @@ +import { describe, expect, it } from '@jest/globals'; +import { render, screen as rtlScreen } from '../../../../../../tests/utils'; +import { ThemeProvider } from '../../../../../utils/providers'; +import { ThemeToggle } from './theme-toggle'; + +describe('ThemeToggle', () => { + it('renders a radio group of two radio buttons', () => { + const defaultTheme = 'dark'; + + render( + <ThemeProvider + attribute="voluptas" + storageKey="alias" + defaultTheme={defaultTheme} + > + <ThemeToggle /> + </ThemeProvider> + ); + + expect( + rtlScreen.getByRole('radiogroup', { + name: /Theme:/i, + }) + ).toBeInTheDocument(); + expect(rtlScreen.getAllByRole('radio')).toHaveLength(2); + }); +}); diff --git a/src/components/organisms/forms/settings-form/theme-toggle/theme-toggle.tsx b/src/components/organisms/forms/settings-form/theme-toggle/theme-toggle.tsx new file mode 100644 index 0000000..d719434 --- /dev/null +++ b/src/components/organisms/forms/settings-form/theme-toggle/theme-toggle.tsx @@ -0,0 +1,78 @@ +import { forwardRef, type ForwardRefRenderFunction } from 'react'; +import { useIntl } from 'react-intl'; +import { useTheme } from '../../../../../utils/hooks'; +import { Icon, Legend } from '../../../../atoms'; +import { + Switch, + type SwitchOption, + type SwitchProps, +} from '../../../../molecules'; + +export type ThemeToggleProps = Omit< + SwitchProps, + 'isInline' | 'items' | 'legend' | 'name' | 'onSwitch' | 'value' +>; + +const ThemeToggleWithRef: ForwardRefRenderFunction< + HTMLFieldSetElement, + ThemeToggleProps +> = (props, ref) => { + const intl = useIntl(); + const { resolvedTheme, toggleTheme } = useTheme(); + + const messages = { + legend: intl.formatMessage({ + defaultMessage: 'Theme:', + description: 'ThemeToggle: theme label', + id: 'suXOBu', + }), + options: { + dark: intl.formatMessage({ + defaultMessage: 'Dark theme', + description: 'ThemeToggle: dark theme label', + id: '2QwvtS', + }), + light: intl.formatMessage({ + defaultMessage: 'Light theme', + description: 'ThemeToggle: light theme label', + id: 'Ygea7s', + }), + }, + }; + + const options: [SwitchOption, SwitchOption] = [ + { + id: 'theme-light', + // eslint-disable-next-line react/jsx-no-literals + label: <Icon aria-label={messages.options.light} shape="sun" size="sm" />, + value: 'light', + }, + { + id: 'theme-dark', + // eslint-disable-next-line react/jsx-no-literals + label: <Icon aria-label={messages.options.dark} shape="moon" size="sm" />, + value: 'dark', + }, + ]; + + return ( + <Switch + {...props} + isInline + items={options} + legend={<Legend>{messages.legend}</Legend>} + // eslint-disable-next-line react/jsx-no-literals + name="theme" + onSwitch={toggleTheme} + ref={ref} + value={resolvedTheme} + /> + ); +}; + +/** + * ThemeToggle component + * + * Render a Toggle component to set theme. + */ +export const ThemeToggle = forwardRef(ThemeToggleWithRef); |
