From 53f0f9d35b562682d6a705813134cad73d91f088 Mon Sep 17 00:00:00 2001 From: Rafael Youakeem Date: Wed, 18 Sep 2024 11:48:01 +0200 Subject: [PATCH] Move Switch component to `ui` package --- .../ShopBreakdown/DiscountField.tsx | 3 +- apps/store/src/components/Switch.tsx | 55 ------------------- .../src/components/ToggleCard/ToggleCard.tsx | 7 +-- packages/ui/package.json | 2 + .../ui/src/components/Switch/Switch.css.ts | 48 ++++++++++++++++ .../src/components/Switch/Switch.stories.tsx | 41 ++++++++++++++ packages/ui/src/components/Switch/Switch.tsx | 13 +++++ packages/ui/src/index.ts | 1 + yarn.lock | 17 ++++++ 9 files changed, 126 insertions(+), 61 deletions(-) delete mode 100644 apps/store/src/components/Switch.tsx create mode 100644 packages/ui/src/components/Switch/Switch.css.ts create mode 100644 packages/ui/src/components/Switch/Switch.stories.tsx create mode 100644 packages/ui/src/components/Switch/Switch.tsx diff --git a/apps/store/src/components/ShopBreakdown/DiscountField.tsx b/apps/store/src/components/ShopBreakdown/DiscountField.tsx index 98158e7d82..ad810eb7a9 100644 --- a/apps/store/src/components/ShopBreakdown/DiscountField.tsx +++ b/apps/store/src/components/ShopBreakdown/DiscountField.tsx @@ -1,8 +1,7 @@ import { useTranslation } from 'next-i18next' import { useState } from 'react' -import { sprinkles, Text, xStack } from 'ui' +import { sprinkles, Switch, Text, xStack } from 'ui' import Collapsible from '@/components/Collapsible/Collapsible' -import { Switch } from '@/components/Switch' import { AddCampaignForm } from './AddCampaignForm/AddCampaignForm' import { AddedCampaignForm } from './AddedCampaignForm' diff --git a/apps/store/src/components/Switch.tsx b/apps/store/src/components/Switch.tsx deleted file mode 100644 index 05d4c6e772..0000000000 --- a/apps/store/src/components/Switch.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import styled from '@emotion/styled' -import * as RadixSwitch from '@radix-ui/react-switch' -import { theme } from 'ui' - -export type SwitchProps = RadixSwitch.SwitchProps - -export const Switch = (props: SwitchProps) => { - return ( - - - - ) -} - -export const SwitchWrapper = styled(RadixSwitch.Root)({ - boxSizing: 'border-box', - width: '1.75rem', - borderRadius: 9999, - display: 'flex', - alignItems: 'center', - justifyContent: 'flex-start', - - backgroundColor: theme.colors.opaque3, - borderWidth: 1, - borderStyle: 'solid', - borderColor: 'transparent', - - ':focus-visible': { - borderColor: theme.colors.gray1000, - }, - - '&[data-state=checked], &[data-state=open]': { - backgroundColor: theme.colors.signalGreenElement, - }, - - '&[disabled]': { - backgroundColor: theme.colors.opaque3, - cursor: 'not-allowed', - }, -}) - -const SwitchHandle = styled(RadixSwitch.Thumb)({ - width: '1rem', - height: '1rem', - borderRadius: '100%', - backgroundColor: theme.colors.textNegative, - - transition: 'transform 100ms', - transform: 'translateX(0)', - willChange: 'transform', - - '&[data-state=checked]': { - transform: 'translateX(0.6rem)', - }, -}) diff --git a/apps/store/src/components/ToggleCard/ToggleCard.tsx b/apps/store/src/components/ToggleCard/ToggleCard.tsx index 801695b1b2..38d3134f73 100644 --- a/apps/store/src/components/ToggleCard/ToggleCard.tsx +++ b/apps/store/src/components/ToggleCard/ToggleCard.tsx @@ -1,11 +1,10 @@ -import type { ReactNode } from 'react' +import type { ComponentProps, ReactNode } from 'react' import { useId } from 'react' -import { Space, useHighlightAnimation } from 'ui' +import { Space, Switch, useHighlightAnimation } from 'ui' import { SpaceFlex } from '@/components/SpaceFlex/SpaceFlex' -import { Switch, type SwitchProps } from '@/components/Switch' import { wrapper, checkboxHeader, labelText } from './ToggleCard.css' -type Props = SwitchProps & { +type Props = ComponentProps & { label: string Icon?: ReactNode } diff --git a/packages/ui/package.json b/packages/ui/package.json index b3b36cb567..74ad64dcb5 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -54,8 +54,10 @@ "@emotion/styled": "11.13.0", "@radix-ui/react-dialog": "1.1.1", "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-switch": "1.1.0", "@radix-ui/react-tabs": "1.1.0", "@radix-ui/react-tooltip": "1.1.2", + "@storybook/addon-actions": "8.3.1", "@vanilla-extract/css": "1.15.5", "@vanilla-extract/dynamic": "2.1.2", "@vanilla-extract/recipes": "0.5.5", diff --git a/packages/ui/src/components/Switch/Switch.css.ts b/packages/ui/src/components/Switch/Switch.css.ts new file mode 100644 index 0000000000..6ab9bee50a --- /dev/null +++ b/packages/ui/src/components/Switch/Switch.css.ts @@ -0,0 +1,48 @@ +import { style } from '@vanilla-extract/css' +import { tokens } from '../../theme' + +export const switchStyles = style({ + boxSizing: 'border-box', + width: '1.75rem', + borderRadius: 9999, + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-start', + + backgroundColor: tokens.colors.opaque3, + borderWidth: 1, + borderStyle: 'solid', + borderColor: 'transparent', + + ':focus-visible': { + borderColor: tokens.colors.gray1000, + }, + + selectors: { + '&[data-state=checked], &[data-state=open]': { + backgroundColor: tokens.colors.signalGreenElement, + }, + + '&[disabled]': { + backgroundColor: tokens.colors.opaque3, + cursor: 'not-allowed', + }, + }, +}) + +export const thumbStyles = style({ + width: '1rem', + height: '1rem', + borderRadius: '100%', + backgroundColor: tokens.colors.textNegative, + + transition: 'transform 100ms', + transform: 'translateX(0)', + willChange: 'transform', + + selectors: { + '&[data-state=checked]': { + transform: 'translateX(0.6rem)', + }, + }, +}) diff --git a/packages/ui/src/components/Switch/Switch.stories.tsx b/packages/ui/src/components/Switch/Switch.stories.tsx new file mode 100644 index 0000000000..b6644cb58e --- /dev/null +++ b/packages/ui/src/components/Switch/Switch.stories.tsx @@ -0,0 +1,41 @@ +import { action } from '@storybook/addon-actions' +import type { Meta, StoryObj } from '@storybook/react' +import { useState, type ComponentProps } from 'react' +import { Switch } from './Switch' + +type Controls = ComponentProps + +const meta: Meta = { + title: 'Switch', + component: Switch, +} +export default meta + +type Story = StoryObj + +export const Controlled: Story = { + render: () => { + const [checked, setIsChecked] = useState(true) + + const toggle = () => setIsChecked((isChecked) => !isChecked) + + return ( +
+ +
+ ) + }, +} + +export const Uncontrolled: Story = { + render: (args: Controls) => { + return ( +
+ +
+ ) + }, + args: { + onCheckedChange: action('onCheckedChange'), + }, +} diff --git a/packages/ui/src/components/Switch/Switch.tsx b/packages/ui/src/components/Switch/Switch.tsx new file mode 100644 index 0000000000..611474ff98 --- /dev/null +++ b/packages/ui/src/components/Switch/Switch.tsx @@ -0,0 +1,13 @@ +import * as RadixSwitch from '@radix-ui/react-switch' +import clsx from 'clsx' +import { switchStyles, thumbStyles } from './Switch.css' + +export type SwitchProps = RadixSwitch.SwitchProps + +export const Switch = ({ className, ...props }: SwitchProps) => { + return ( + + + + ) +} diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index 14b47ea50f..90d1422e04 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -13,6 +13,7 @@ export { IconButton } from './components/Button/IconButton' export { Tooltip } from './components/Tooltip/Tooltip' export { Card } from './components/Card/Card' export { InputBase } from './components/InputBase' +export { Switch } from './components/Switch/Switch' export type { InputBaseProps } from './components/InputBase' export { Heading } from './components/Heading/Heading' export type { HeadingProps, PossibleHeadingVariant } from './components/Heading/Heading' diff --git a/yarn.lock b/yarn.lock index 511ac6a65b..88acbfefb6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8563,6 +8563,21 @@ __metadata: languageName: node linkType: hard +"@storybook/addon-actions@npm:8.3.1": + version: 8.3.1 + resolution: "@storybook/addon-actions@npm:8.3.1" + dependencies: + "@storybook/global": "npm:^5.0.0" + "@types/uuid": "npm:^9.0.1" + dequal: "npm:^2.0.2" + polished: "npm:^4.2.2" + uuid: "npm:^9.0.0" + peerDependencies: + storybook: ^8.3.1 + checksum: 10c0/f8b763e5133e9f01be41f351d69b5638b9f62be58ac51c100c753bd9b66d0d42242672fd062bcf5924b9186192b6e2c7f8dfd2dd5b36799d18dcc0a1ba52ef40 + languageName: node + linkType: hard + "@storybook/addon-backgrounds@npm:8.2.9": version: 8.2.9 resolution: "@storybook/addon-backgrounds@npm:8.2.9" @@ -24408,8 +24423,10 @@ __metadata: "@emotion/styled": "npm:11.13.0" "@radix-ui/react-dialog": "npm:1.1.1" "@radix-ui/react-slot": "npm:1.1.0" + "@radix-ui/react-switch": "npm:1.1.0" "@radix-ui/react-tabs": "npm:1.1.0" "@radix-ui/react-tooltip": "npm:1.1.2" + "@storybook/addon-actions": "npm:8.3.1" "@storybook/react": "npm:8.2.9" "@testing-library/dom": "npm:10.4.0" "@testing-library/jest-dom": "npm:6.5.0"