From ca117c0221fd279298ecf8dc87fbf81309e88489 Mon Sep 17 00:00:00 2001 From: storywithoutend Date: Thu, 21 Sep 2023 12:39:37 +0800 Subject: [PATCH 001/223] install vanilla extract --- components/package.json | 1 + pnpm-lock.yaml | 42 +++++++++++++++++++++++++++++++++++------ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/components/package.json b/components/package.json index 8c7a8591..337f6ec8 100644 --- a/components/package.json +++ b/components/package.json @@ -61,6 +61,7 @@ "@types/rimraf": "^3.0.2", "@types/styled-components": "^5", "@types/testing-library__jest-dom": "^5.14.1", + "@vanilla-extract/css": "1.13.0", "babel-plugin-styled-components": "^2.0.6", "deepmerge": "^4.2.2", "esbuild-darwin-arm64": "^0.14.27", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5b47c41e..140d3fa6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -121,6 +121,7 @@ importers: '@types/rimraf': ^3.0.2 '@types/styled-components': ^5 '@types/testing-library__jest-dom': ^5.14.1 + '@vanilla-extract/css': 1.13.0 babel-plugin-styled-components: ^2.0.6 clsx: ^1.1.1 deepmerge: ^4.2.2 @@ -169,6 +170,7 @@ importers: '@types/rimraf': 3.0.2 '@types/styled-components': 5.1.23 '@types/testing-library__jest-dom': 5.14.5 + '@vanilla-extract/css': 1.13.0 babel-plugin-styled-components: 2.0.6 deepmerge: 4.2.2 esbuild-darwin-arm64: 0.14.53 @@ -2792,7 +2794,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.13.11 - dev: true /@babel/standalone/7.18.10: resolution: {integrity: sha512-0KWHiRX9TUHiWE+dKYYEOIiRJcPwGU6u8Bq/p+ldekj7Kew9PCwl4S4FTSEPpTrn3Vc+r3iRSaN1l9AcGgLx4Q==} @@ -2923,6 +2924,10 @@ packages: resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} dev: false + /@emotion/hash/0.9.1: + resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==} + dev: true + /@emotion/is-prop-valid/0.8.8: resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==} dependencies: @@ -4984,6 +4989,22 @@ packages: resolution: {integrity: sha512-qoxIu5E/UhJtoKsPL1JaU9nhTN0Xl5zYV0pScOgsvc3JN46TvTTt0L3GV8x3PQpZP7x3elw8BsC9czYbhJy9Gg==} dev: false + /@vanilla-extract/css/1.13.0: + resolution: {integrity: sha512-JFFBXhnJrPlGqHBabagXqo5ghXw9mtV270ycIGyLDZG8NAK5eRwAYkMowAxuzK7wZSm67GnETWYB7b0AUmyttg==} + dependencies: + '@emotion/hash': 0.9.1 + '@vanilla-extract/private': 1.0.3 + ahocorasick: 1.0.2 + chalk: 4.1.2 + css-what: 6.1.0 + cssesc: 3.0.0 + csstype: 3.0.9 + deep-object-diff: 1.1.9 + deepmerge: 4.2.2 + media-query-parser: 2.0.2 + outdent: 0.8.0 + dev: true + /@vanilla-extract/css/1.7.3: resolution: {integrity: sha512-ZwfNvk9LjVdsHON4bNAGXBu0dPo4e1RlgghnW1A4lcQruvFU7zdq+wEqodrX3O0D2qRkupOGgjAbTSddwqKoQA==} dependencies: @@ -5014,7 +5035,6 @@ packages: /@vanilla-extract/private/1.0.3: resolution: {integrity: sha512-17kVyLq3ePTKOkveHxXuIJZtGYs+cSoev7BlP+Lf4916qfDhk/HBjvlYDe8egrea7LNPHKwSZJK/bzZC+Q6AwQ==} - dev: false /@vanilla-extract/sprinkles/1.4.1_@vanilla-extract+css@1.7.3: resolution: {integrity: sha512-aW6CfMMToX4a+baLuVxwcT0FSACjX3xrNt8wdi/3LLRlLAfhyue8OK7kJxhcYNZfydBeWTP59aRy8p5FUTIeew==} @@ -5211,6 +5231,10 @@ packages: indent-string: 4.0.0 dev: true + /ahocorasick/1.0.2: + resolution: {integrity: sha512-hCOfMzbFx5IDutmWLAt6MZwOUjIfSM9G9FyVxytmE4Rs/5YDPWQrD/+IR1w+FweD9H2oOZEnv36TmkjhNURBVA==} + dev: true + /ajv-formats/2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependenciesMeta: @@ -6532,6 +6556,11 @@ packages: resolution: {integrity: sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==} engines: {node: '>= 6'} + /css-what/6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + dev: true + /css.escape/1.5.1: resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} dev: true @@ -6770,6 +6799,10 @@ packages: resolution: {integrity: sha512-QkgBca0mL08P6HiOjoqvmm6xOAl2W6CT2+34Ljhg0OeFan8cwlcdq8jrLKsBBuUFAZLsN5b6y491KdKEoSo9lg==} dev: false + /deep-object-diff/1.1.9: + resolution: {integrity: sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA==} + dev: true + /deepmerge/4.2.2: resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==} engines: {node: '>=0.10.0'} @@ -10125,8 +10158,7 @@ packages: /media-query-parser/2.0.2: resolution: {integrity: sha512-1N4qp+jE0pL5Xv4uEcwVUhIkwdUO3S/9gML90nqKA7v7FcOS5vUtatfzok9S9U1EJU8dHWlcv95WLnKmmxZI9w==} dependencies: - '@babel/runtime': 7.18.9 - dev: false + '@babel/runtime': 7.21.5 /media-typer/0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} @@ -10636,7 +10668,6 @@ packages: /outdent/0.8.0: resolution: {integrity: sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A==} - dev: false /p-finally/1.0.0: resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} @@ -11728,7 +11759,6 @@ packages: /regenerator-runtime/0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} - dev: true /regenerator-runtime/0.13.9: resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==} From b2733dbce4adfcca9c2335d9ddbe0bf0bacfe35c Mon Sep 17 00:00:00 2001 From: storywithoutend Date: Thu, 28 Sep 2023 15:06:56 +0800 Subject: [PATCH 002/223] add vanilla extract --- components/package.json | 9 +- .../src/components/atoms/Avatar/Avatar.tsx | 74 +- .../src/components/atoms/Banner/Banner.tsx | 160 ++- .../src/components/atoms/Banner/styles.css.ts | 0 components/src/components/atoms/Box/Box.tsx | 19 + components/src/components/atoms/Tag/Tag.tsx | 80 +- .../src/components/atoms/Tag/styles.css.ts | 18 + components/src/css/global.css.ts | 5 + components/src/css/layers.css.ts | 5 + components/src/css/rainbow-spinkles.css.ts | 112 ++ components/src/css/theme.css.ts | 47 + components/src/css/utils/getColorStyle.ts | 101 ++ components/src/tokens/breakpoints.ts | 11 + components/src/tokens/colors2.ts | 286 +++++ components/src/tokens/index.ts | 20 +- components/src/tokens/transition.ts | 18 + components/vite.config.ts | 4 + docs/src/pages/_app.tsx | 2 +- pnpm-lock.yaml | 1071 ++++++++++++++++- 19 files changed, 1827 insertions(+), 215 deletions(-) create mode 100644 components/src/components/atoms/Banner/styles.css.ts create mode 100644 components/src/components/atoms/Box/Box.tsx create mode 100644 components/src/components/atoms/Tag/styles.css.ts create mode 100644 components/src/css/global.css.ts create mode 100644 components/src/css/layers.css.ts create mode 100644 components/src/css/rainbow-spinkles.css.ts create mode 100644 components/src/css/theme.css.ts create mode 100644 components/src/css/utils/getColorStyle.ts create mode 100644 components/src/tokens/breakpoints.ts create mode 100644 components/src/tokens/colors2.ts create mode 100644 components/src/tokens/transition.ts diff --git a/components/package.json b/components/package.json index 337f6ec8..cf07f5ca 100644 --- a/components/package.json +++ b/components/package.json @@ -61,7 +61,13 @@ "@types/rimraf": "^3.0.2", "@types/styled-components": "^5", "@types/testing-library__jest-dom": "^5.14.1", - "@vanilla-extract/css": "1.13.0", + "@vanilla-extract/css": "^1.13.0", + "@vanilla-extract/css-utils": "^0.1.3", + "@vanilla-extract/dynamic": "^2.0.3", + "@vanilla-extract/recipes": "^0.5.0", + "@vanilla-extract/sprinkles": "^1.6.1", + "@vanilla-extract/vite-plugin": "^3.9.0", + "@vanilla-extract/private": "^1.0.3", "babel-plugin-styled-components": "^2.0.6", "deepmerge": "^4.2.2", "esbuild-darwin-arm64": "^0.14.27", @@ -69,6 +75,7 @@ "jest": "^27.3.1", "jest-styled-components": "^7.0.8", "jest-watch-typeahead": "^1.0.0", + "rainbow-sprinkles": "0.17.0", "react": "^17.0.2", "react-dom": "^17.0.2", "rimraf": "^3.0.2", diff --git a/components/src/components/atoms/Avatar/Avatar.tsx b/components/src/components/atoms/Avatar/Avatar.tsx index 58cf3257..22f82519 100644 --- a/components/src/components/atoms/Avatar/Avatar.tsx +++ b/components/src/components/atoms/Avatar/Avatar.tsx @@ -1,6 +1,8 @@ import * as React from 'react' import styled, { css } from 'styled-components' +import { rainbowSprinkles } from '@/src/css/rainbow-spinkles.css' + type NativeImgAttributes = React.ImgHTMLAttributes type Shape = 'circle' | 'square' @@ -61,41 +63,22 @@ const Container = styled.div( `, ) -const Placeholder = styled.div<{ $url?: string; $disabled: boolean }>( - ({ theme, $url, $disabled }) => css` - background: ${$url || theme.colors.gradients.blue}; - - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 100%; - - ${$disabled && - css` - filter: grayscale(1); - `} - `, -) - -const Img = styled.img<{ $shown: boolean; $disabled: boolean }>( - ({ $shown, $disabled }) => css` - height: 100%; - width: 100%; - object-fit: cover; - display: none; - - ${$shown && - css` - display: block; - `} - - ${$disabled && - css` - filter: grayscale(1); - `} - `, -) +const placeholderStyles = ({ + disabled, + url, +}: { + disabled: boolean + url?: string +}) => + rainbowSprinkles({ + filter: disabled ? 'grayscale(1)' : undefined, + backgroundColor: url || '$blueGradient', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + width: '100%', + height: '100%', + }) export type Props = { /** Accessibility text. */ @@ -153,20 +136,27 @@ export const Avatar = ({ }, [ref, hideImg, showImg]) const isImageVisible = showImage && !!src + + const imgProps = rainbowSprinkles({ + display: isImageVisible ? 'block' : 'none', + height: '100%', + objectFit: 'cover', + width: '100%', + filter: disabled ? 'grayscale(1)' : undefined, + ...props, + }) + return ( {overlay} {!isImageVisible && ( - )} - {label} @@ -52,69 +53,90 @@ type WithoutAnchor = { type NonNullableAlert = NonNullable -const Container = styled.div<{ - $alert: NonNullableAlert - $hasAction: boolean -}>( - ({ theme, $alert, $hasAction }) => css` - position: relative; - background: ${theme.colors.backgroundPrimary}; - border: 1px solid ${theme.colors.border}; - border-radius: ${theme.radii['2xLarge']}; - padding: ${theme.space[4]}; - display: flex; - align-items: stretch; - gap: ${theme.space[4]}; - width: ${theme.space.full}; - transition: all 150ms ease-in-out; - - ${mq.sm.min( - css` - padding: ${theme.space['6']}; - gap: ${theme.space[6]}; - align-items: center; - `, - )} - - ${$hasAction && - css` - padding-right: ${theme.space[8]}; - &:hover { - transform: translateY(-1px); - background: ${theme.colors.greySurface}; - ${$alert === 'error' && - css` - background: ${theme.colors.redLight}; - `} - ${$alert === 'warning' && - css` - background: ${theme.colors.yellowLight}; - `} - } - `} - - ${$alert === 'error' && - css` - background: ${theme.colors.redSurface}; - border: 1px solid ${theme.colors.redPrimary}; - `} - - ${$alert === 'warning' && - css` - background: ${theme.colors.yellowSurface}; - border: 1px solid ${theme.colors.yellowPrimary}; - `}; - `, -) +const getColorForAlert = ( + alert: NonNullableAlert, + field: 'background' | 'border', + hover = false, +) => { + return { + error: { + background: { + default: '$redSurface', + hover: '$redLight', + }, + border: { + default: '$redPrimary', + hover: '$redPrimary', + }, + }, + warning: { + background: { + default: '$yellowSurface', + hover: '$yellowLight', + }, + border: { + default: '$yellowPrimary', + hover: '$yellowPrimary', + }, + }, + info: { + background: { + default: '$backgroundPrimary', + hover: '$greySurface', + }, + border: { + default: '$border', + hover: '$border', + }, + }, + }[alert][field][hover ? 'hover' : 'default'] +} -const Content = styled.div( - ({ theme }) => css` - flex: 1; - display: flex; - flex-direction: column; - justify-content: center; - gap: ${theme.space[1]}; - `, +const ContainerBox = React.forwardRef< + HTMLDivElement, + { + $alert: NonNullableAlert + $hasAction: boolean + } & BoxProps +>( + ( + { + $alert, + $hasAction, + ...props + }: { + $alert: NonNullableAlert + $hasAction: boolean + } & BoxProps, + ref, + ) => ( + + ), ) const IconContainer = styled.div<{ @@ -299,7 +321,7 @@ export const Banner = React.forwardRef< const _iconType = iconType || defaultIconType(alert, icon) return ( - )} - + {title && {title}} {children} - + - + ) }, ) diff --git a/components/src/components/atoms/Banner/styles.css.ts b/components/src/components/atoms/Banner/styles.css.ts new file mode 100644 index 00000000..e69de29b diff --git a/components/src/components/atoms/Box/Box.tsx b/components/src/components/atoms/Box/Box.tsx new file mode 100644 index 00000000..a6e5a939 --- /dev/null +++ b/components/src/components/atoms/Box/Box.tsx @@ -0,0 +1,19 @@ +import React, { AllHTMLAttributes, ElementType, forwardRef } from 'react' + +import { Sprinkles, rainbowSprinkles } from '../../../css/rainbow-spinkles.css' + +type HTMLProperties = Omit, 'as'> + +export type BoxProps = Sprinkles & HTMLProperties & { as?: ElementType } + +export const Box = forwardRef( + ({ as, children, ...props }, ref) => { + const Component = as || 'div' + const { className, style, otherProps } = rainbowSprinkles(props) + return ( + + {children} + + ) + }, +) diff --git a/components/src/components/atoms/Tag/Tag.tsx b/components/src/components/atoms/Tag/Tag.tsx index 18221e97..8a40b090 100644 --- a/components/src/components/atoms/Tag/Tag.tsx +++ b/components/src/components/atoms/Tag/Tag.tsx @@ -1,52 +1,10 @@ import * as React from 'react' -import styled, { css } from 'styled-components' -import { - WithColorStyle, - getColorStyle, -} from '@/src/types/withColorOrColorStyle' +import { WithColorStyle } from '@/src/types/withColorOrColorStyle' -interface ContainerProps { - $hover?: boolean - $size: 'small' | 'medium' - $colorStyle: NonNullable -} - -const Container = styled.div( - ({ theme, $hover, $size, $colorStyle }) => css` - align-items: center; - display: flex; - border-radius: ${theme.radii['full']}; - font-size: ${theme.fontSizes.small}; - line-height: ${theme.lineHeights.small}; - font-weight: ${theme.fontWeights.bold}; - width: ${theme.space['max']}; - padding: ${theme.space['0.5']} ${theme.space['2']}; - background: ${getColorStyle($colorStyle, 'background')}; - color: ${getColorStyle($colorStyle, 'text')}; - border: 1px solid ${getColorStyle($colorStyle, 'border')}; - cursor: default; - - ${$size === 'small' && - css` - font-size: ${theme.fontSizes.extraSmall}; - line-height: ${theme.lineHeights.extraSmall}; - `} +import { getColorStyle } from '../../../css/utils/getColorStyle' - ${$hover && - css` - transition-duration: ${theme.transitionDuration['150']}; - transition-property: color, border-color, background-color; - transition-timing-function: ${theme.transitionTimingFunction['inOut']}; - - &:hover, - &:active { - transform: translateY(-1px); - background-color: ${getColorStyle($colorStyle, 'hover')}; - } - `} - `, -) +import { Box } from '../Box/Box' type NativeDivProps = React.HTMLAttributes @@ -69,15 +27,35 @@ export const Tag = ({ ...props }: Props) => { return ( - {children} - + ) } diff --git a/components/src/components/atoms/Tag/styles.css.ts b/components/src/components/atoms/Tag/styles.css.ts new file mode 100644 index 00000000..fdc236f1 --- /dev/null +++ b/components/src/components/atoms/Tag/styles.css.ts @@ -0,0 +1,18 @@ +import { style } from '@vanilla-extract/css' +import { recipe } from '@vanilla-extract/recipes' + +export const variants = recipe({ + base: { + background: 'red', + }, + variants: { + size: { + small: style({ + height: '1rem', + }), + medium: style({ + height: '2rem', + }), + }, + }, +}) diff --git a/components/src/css/global.css.ts b/components/src/css/global.css.ts new file mode 100644 index 00000000..07340f08 --- /dev/null +++ b/components/src/css/global.css.ts @@ -0,0 +1,5 @@ +import { globalStyle } from '@vanilla-extract/css' + +globalStyle('*', { + background: 'red', +}) diff --git a/components/src/css/layers.css.ts b/components/src/css/layers.css.ts new file mode 100644 index 00000000..c9b783f4 --- /dev/null +++ b/components/src/css/layers.css.ts @@ -0,0 +1,5 @@ +import { layer } from '@vanilla-extract/css' + +export const resetLayer = layer('reset') +export const responsiveLayer = layer('responsive') +export const interactionLayer = layer('interaction') diff --git a/components/src/css/rainbow-spinkles.css.ts b/components/src/css/rainbow-spinkles.css.ts new file mode 100644 index 00000000..de209260 --- /dev/null +++ b/components/src/css/rainbow-spinkles.css.ts @@ -0,0 +1,112 @@ +import { createRainbowSprinkles, defineProperties } from 'rainbow-sprinkles' + +import { commonVars, modeVars } from './theme.css' + +const responsiveProperties = defineProperties({ + conditions: { + base: {}, + xs: { '@media': 'screen and (min-width: 360px)' }, + sm: { '@media': 'screen and (min-width: 640px)' }, + md: { '@media': 'screen and (min-width: 768px)' }, + lg: { '@media': 'screen and (min-width: 1024px)' }, + xl: { '@media': 'screen and (min-width: 1280px)' }, + }, + defaultCondition: 'base', + dynamicProperties: { + display: true, + flexDirection: true, + flex: true, + alignItems: true, + justifyContent: true, + gap: commonVars.space, + padding: commonVars.space, + paddingLeft: commonVars.space, + paddingRight: commonVars.space, + paddingTop: commonVars.space, + paddingBottom: commonVars.space, + height: true, + borderRadius: commonVars.radii, + borderColor: modeVars.color, + borderStyle: true, + fontFamily: commonVars.fonts, + fontSize: commonVars.fontSizes, + fontWeight: commonVars.fontWeights, + lineHeight: commonVars.lineHeights, + textAlign: true, + zIndex: true, + position: true, + top: commonVars.space, + left: commonVars.space, + right: commonVars.space, + bottom: commonVars.space, + verticalAlign: true, + margin: commonVars.space, + marginBottom: commonVars.space, + marginLeft: commonVars.space, + marginRight: commonVars.space, + marginTop: commonVars.space, + width: commonVars.space, + }, + staticProperties: { + display: ['block', 'flex', 'inline-block', 'inline-flex'], + borderWidth: { + '1x': '1px', + '2x': '2px', + '3x': '3px', + }, + }, + shorthands: { + p: ['padding'], + pl: ['paddingLeft'], + pr: ['paddingRight'], + pt: ['paddingTop'], + pb: ['paddingBottom'], + paddingX: ['paddingLeft', 'paddingRight'], + paddingY: ['paddingTop', 'paddingBottom'], + px: ['paddingLeft', 'paddingRight'], + py: ['paddingTop', 'paddingBottom'], + placeItems: ['alignItems', 'justifyContent'], + typeSize: ['fontSize', 'lineHeight'], + m: ['margin'], + mr: ['marginRight'], + ml: ['marginLeft'], + mt: ['marginTop'], + mb: ['marginBottom'], + marginX: ['marginLeft', 'marginRight'], + marginY: ['marginTop', 'marginBottom'], + mx: ['marginLeft', 'marginRight'], + my: ['marginTop', 'marginBottom'], + size: ['height', 'width'], + }, +}) + +const interactiveProperties = defineProperties({ + conditions: { + base: {}, + hover: { selector: '&:hover' }, + active: { selector: '&:active' }, + }, + defaultCondition: 'base', + dynamicProperties: { + color: modeVars.color, + backgroundColor: modeVars.color, + transform: true, + transition: true, + animation: true, + filter: true, + objectFit: true, + transitionTimingFunction: commonVars.transitionTimingFunction, + transitionDuration: commonVars.transitionDuration, + transitionProperty: true, + }, + shorthands: { + bg: ['backgroundColor'], + }, +}) + +export const rainbowSprinkles = createRainbowSprinkles( + responsiveProperties, + interactiveProperties, +) + +export type Sprinkles = Parameters[0] diff --git a/components/src/css/theme.css.ts b/components/src/css/theme.css.ts new file mode 100644 index 00000000..c31a0ee5 --- /dev/null +++ b/components/src/css/theme.css.ts @@ -0,0 +1,47 @@ +import { + createGlobalTheme, + createGlobalThemeContract, +} from '@vanilla-extract/css' + +import { colors } from '../tokens/colors2' +import { borderStyles, borderWidths, radii } from '../tokens/border' +import { space } from '../tokens/space' +import { + fontSizes, + fontWeights, + fonts, + letterSpacings, + lineHeights, +} from '../tokens/typography' +import { opacity } from '../tokens/opacity' +import { shadows } from '../tokens/shadows' +import { + transitionDuration, + transitionTimingFunction, +} from '../tokens/transition' + +const getVarName = (_value: string | null, path: string[]) => + path.join('-').replace('.', '_').replace('/', '__') + +const commonTokens = { + fonts, + fontSizes, + fontWeights, + lineHeights, + letterSpacings, + opacity, + shadows, + space, + radii, + borderWidths, + borderStyles, + transitionDuration, + transitionTimingFunction, +} +export const commonVars = createGlobalThemeContract(commonTokens, getVarName) +createGlobalTheme(':root', commonVars, commonTokens) + +const modeTokens = { color: colors.light } +export const modeVars = createGlobalThemeContract(modeTokens, getVarName) +createGlobalTheme('[data-theme="light"]', modeVars, modeTokens) +createGlobalTheme('[data-theme="dark"]', modeVars, { color: colors.dark }) diff --git a/components/src/css/utils/getColorStyle.ts b/components/src/css/utils/getColorStyle.ts new file mode 100644 index 00000000..6d579179 --- /dev/null +++ b/components/src/css/utils/getColorStyle.ts @@ -0,0 +1,101 @@ +const BASE_COLORS = [ + 'accent', + 'blue', + 'indigo', + 'purple', + 'pink', + 'red', + 'orange', + 'yellow', + 'green', + 'teal', + 'grey', +] as const + +type BaseColor = typeof BASE_COLORS[number] + +const GRADIENT_COLORS = ['blue', 'purple', 'red', 'green', 'grey'] as const + +type GradientColor = typeof GRADIENT_COLORS[number] + +const makeColorStyleMap = () => { + const primaryStyles = Object.fromEntries( + BASE_COLORS.map((color) => [ + `${color}Primary`, + { + text: `$backgroundPrimary`, + background: `$${color}Primary`, + border: 'transparent', + hover: `$${color}Bright`, + }, + ]), + ) as { + [key in `${BaseColor}Primary`]: any + } + const secondaryStyles = Object.fromEntries( + BASE_COLORS.map((color) => [ + `${color}Secondary`, + { + text: `$${color}Primary`, + background: `$${color}Surface`, + border: 'transparent', + hover: `$${color}Light`, + }, + ]), + ) as { + [key in `${BaseColor}Secondary`]: any + } + + const gradientValues = Object.fromEntries( + GRADIENT_COLORS.map((color) => [ + `${color}Gradient`, + { + text: `$backgroundPrimary`, + background: `$${color}Gradient`, + border: 'transparent', + hover: `$${color}Gradient`, + }, + ]), + ) as { + [key in `${GradientColor}Gradient`]: any + } + + const transparent: any = { + text: 'initial', + background: 'transparent', + border: 'transparent', + hover: '$greyLight', + } as const + + const disabled: any = { + text: '$greyPrimary', + background: '$greyLight', + border: '$greyLight', + hover: '$greyLight', + } as const + + const background: any = { + text: '$textPrimary', + background: '$backgroundPrimary', + border: '$border', + hover: '$backgroundSecondary', + } as const + + return { + ...primaryStyles, + ...secondaryStyles, + ...gradientValues, + transparent, + disabled, + background, + } +} + +const colorStyleMap = makeColorStyleMap() + +type ColorStyle = keyof ReturnType +type ColorStyleProperty = 'text' | 'background' | 'border' | 'hover' +export const getColorStyle = ( + colorStyle: ColorStyle, + property: ColorStyleProperty, +) => colorStyleMap[colorStyle][property] diff --git a/components/src/tokens/breakpoints.ts b/components/src/tokens/breakpoints.ts new file mode 100644 index 00000000..cd96b6a0 --- /dev/null +++ b/components/src/tokens/breakpoints.ts @@ -0,0 +1,11 @@ +export const breakpoints = { + xs: 360, + sm: 640, + md: 768, + lg: 1024, + xl: 1280, +} + +export type Breakpoint = keyof typeof breakpoints + +export const breakpointNames = Object.keys(breakpoints) as Breakpoint[] diff --git a/components/src/tokens/colors2.ts b/components/src/tokens/colors2.ts new file mode 100644 index 00000000..0976c31f --- /dev/null +++ b/components/src/tokens/colors2.ts @@ -0,0 +1,286 @@ +/** + * Color Variables + * + * All the following variables are used to generate color tokens. + * Changes made to these variables will be reflected throughout the library. + */ + +// The Mode type contains all possible theme modes. +export type Mode = 'light' | 'dark' + +const shades = [50, 100, 300, 400, 500, 750] as const + +const namedShadeMap = { + Surface: 50, + Light: 100, + Bright: 300, + Primary: 400, + Dim: 500, + Active: 750, +} as const + +// The hues object is a map of HSL colors, with optional overrides for each shade. +const hues = { + blue: [216, 100, 61, { 50: [215, 100, 97] }], + indigo: [242, 61, 58], + purple: [280, 62, 55], + pink: [331, 67, 51, { 100: [331, 64, 88] }], + red: [7, 76, 44, { 50: [0, 60, 94], 100: [360, 60, 85] }], + orange: [35, 91, 50, { 100: [36, 89, 86] }], + yellow: [47, 86, 49, { 50: [48, 100, 90], 100: [48, 100, 85] }], + green: [162, 72, 40, { 50: [157, 37, 93], 100: [157, 37, 85] }], + teal: [199, 66, 49], + grey: [ + 240, + 6, + 63, + { + 50: [0, 0, 96], + 100: [0, 0, 91], + 500: [0, 0, 35], + 750: [0, 0, 15], + }, + ], +} satisfies Record + +const backgroundColor = { + light: '0 0% 100%', + dark: '0 0% 8%', +} + +// The categories object is a map of categorised colors, which can each have their own custom values. +const categories = { + background: { + hue: 'grey', + items: { + primary: backgroundColor, + secondary: 'Surface', + }, + }, + text: { + hue: 'grey', + items: { + primary: 'Active', + secondary: 'Dim', + tertiary: 'Primary', + accent: { + light: backgroundColor.light, + dark: backgroundColor.light, + }, + }, + }, + border: { + hue: 'grey', + items: { + primary: 'Light', + }, + }, +} satisfies Record + +const gradients = { + blueGradient: + 'linear-gradient(330.4deg, #44BCF0 4.54%, #7298F8 59.2%, #A099FF 148.85%)', + greenGradient: + 'linear-gradient(90deg, rgba(68,240,127,1) 4.54%, rgba(114,248,176,1) 59.2%, rgba(153,202,255,1) 148.85%)', + redGradient: + 'linear-gradient(90deg, rgba(240,68,87,1) 4.54%, rgba(248,114,149,1) 59.2%, rgba(212,153,255,1) 148.85%)', + purpleGradient: + 'linear-gradient(323.31deg, #DE82FF -15.56%, #7F6AFF 108.43%)', + greyGradient: + 'linear-gradient(330.4deg, #DFDFDF 4.54%, #959595 59.2%, #474747 148.85%)', +} + +/** + * END COLOR VARIABLES + */ + +export type NamedShade = keyof typeof namedShadeMap +export type Shade = typeof shades[number] +export type Hue = keyof typeof hues +export type Category = keyof Categories | 'accent' +export type Gradient = keyof typeof gradients + +type HSLColor = [hue: number, saturation: number, lightness: number] + +type HueItem = [ + ...hsl: HSLColor, + overrides?: { + [key in Shade]?: HSLColor + }, +] + +type Categories = typeof categories + +type CamelCaseNested = ( + T extends object + ? { + [K in Exclude]: `${K}${Capitalize< + CamelCaseNested + >}` + }[Exclude] + : '' +) extends infer D + ? Extract + : never + +type DotNestedCategoryKeys = CamelCaseNested<{ + [item in keyof Categories]: { + [key in keyof Categories[item]['items']]: string + } & { + '': string + } +}> +type DotNestedCategories = { [K in DotNestedCategoryKeys]: string } + +type GeneratedCategories = DotNestedCategories + +type CategoryItem = { + hue: Hue + items: { + [key: string]: + | { + [key in Mode]: string + } + | NamedShade + } +} + +type WithRaw = Omit & { raw: Omit } + +type ShadeColor = { [key in Shade]: string } +type NameColor = { [key in NamedShade]: string } +type ColorItem< + TObject extends Record, + TName extends string, +> = TObject extends object + ? { + [key in Exclude as `${TName}${key}`]: string + } & { + [T in `${TName}`]: string + } + : never +type CalculatedColors = WithRaw> +type AllColors = WithRaw + +const makeColorObject = ( + mode: Mode, + name: THue, + color: ShadeColor, +) => { + if (mode === 'dark') { + color = Object.fromEntries( + Object.entries(color).map(([key], index, arr) => [ + key, + arr[arr.length - index - 1][1], + ]), + ) as ShadeColor + } + + const values = Object.fromEntries( + Object.entries(namedShadeMap).map(([key, value]) => [ + `${name}${key}`, + color[value], + ]), + ) + + return { ...values, [name]: values[`${name}Primary`] } as ColorItem< + NameColor, + THue + > +} + +const makeCSSHSL = (hsl: HSLColor) => `${hsl[0]} ${hsl[1]}% ${hsl[2]}%` + +const makeColorRange = ( + mode: Mode, + name: THue, + hue: HueItem, +) => { + const color = Object.fromEntries( + shades.map((shade) => { + if (hue[3]?.[shade]) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return [shade, makeCSSHSL(hue[3]![shade]!)] + } + const hsl = hue.slice(0, 3) as HSLColor + hsl[2] = hsl[2] + (400 - shade) / 10 + return [shade, makeCSSHSL(hsl)] + }), + ) as ShadeColor + return { + normal: makeColorObject( + mode, + name, + Object.fromEntries( + Object.entries(color).map(([key, value]) => [key, `hsl(${value})`]), + ) as ShadeColor, + ), + raw: makeColorObject(mode, name, color), + } +} + +const makeGradients = (accent: unknown, colors: AllColors) => { + const accentGradient = gradients[accent as Gradient] || colors[accent as Hue] + const entries = Object.entries({ + ...gradients, + accent: accentGradient, + }) + return Object.fromEntries(entries) as Record +} + +const makeMode = (accent: Hue, mode: Mode) => { + const calculatedColors = Object.entries({ + ...hues, + accent: hues[accent], + }).reduce((prev, curr) => { + const [key, value] = curr + const colorRange = makeColorRange(mode, key as Hue, value) + return { + ...prev, + ...colorRange.normal, + raw: { + ...prev.raw, + ...colorRange.raw, + }, + } + }, {} as CalculatedColors) + + const allColours = Object.entries(categories).reduce((prev, curr) => { + const [category, value] = curr + for (const [name, shade] of Object.entries(value.items)) { + const itemKey = `${category}${name.replace(/^[a-z]/, (l) => + l.toUpperCase(), + )}` as DotNestedCategoryKeys + const newItem = + typeof shade === 'string' + ? calculatedColors.raw[`${value.hue}${shade as NamedShade}`] + : shade[mode] + + prev[itemKey] = `hsl(${newItem})` + prev.raw[itemKey] = newItem + + if (name === 'primary') { + const categoryKey = category as keyof typeof categories + prev[categoryKey] = `hsl(${newItem})` + prev.raw[categoryKey] = newItem + } + } + return prev + }, calculatedColors as AllColors) + + const allColoursWithRaw = { + ...allColours, + ...makeGradients(accent, allColours), + } + + delete (allColoursWithRaw as any)['raw'] + return allColoursWithRaw as Omit +} + +export const makeColors = (accent: Hue) => ({ + light: makeMode(accent, 'light'), + dark: makeMode(accent, 'dark'), +}) + +export const colors = makeColors('blue') +console.log(colors) diff --git a/components/src/tokens/index.ts b/components/src/tokens/index.ts index f52d7c6e..ce58cd23 100644 --- a/components/src/tokens/index.ts +++ b/components/src/tokens/index.ts @@ -10,25 +10,7 @@ import { letterSpacings, lineHeights, } from './typography' - -const transitionDuration = { - '75': '75ms', - '100': '100ms', - '150': '150ms', - '200': '200ms', - '300': '300ms', - '500': '500ms', - '700': '700ms', - '1000': '1000ms', -} - -const transitionTimingFunction = { - linear: 'linear', - in: 'cubic-bezier(0.4, 0, 1, 1)', - out: 'cubic-bezier(0, 0, 0.2, 1)', - inOut: 'cubic-bezier(0.42, 0, 0.58, 1)', - popIn: 'cubic-bezier(0.15, 1.15, 0.6, 1)', -} +import { transitionDuration, transitionTimingFunction } from './transition' export const breakpoints = { xs: 360, diff --git a/components/src/tokens/transition.ts b/components/src/tokens/transition.ts new file mode 100644 index 00000000..b209f88c --- /dev/null +++ b/components/src/tokens/transition.ts @@ -0,0 +1,18 @@ +export const transitionDuration = { + '75': '75ms', + '100': '100ms', + '150': '150ms', + '200': '200ms', + '300': '300ms', + '500': '500ms', + '700': '700ms', + '1000': '1000ms', +} + +export const transitionTimingFunction = { + linear: 'linear', + in: 'cubic-bezier(0.4, 0, 1, 1)', + out: 'cubic-bezier(0, 0, 0.2, 1)', + inOut: 'cubic-bezier(0.42, 0, 0.58, 1)', + popIn: 'cubic-bezier(0.15, 1.15, 0.6, 1)', +} diff --git a/components/vite.config.ts b/components/vite.config.ts index 191ea484..14bafde1 100644 --- a/components/vite.config.ts +++ b/components/vite.config.ts @@ -4,6 +4,7 @@ import dts from 'vite-plugin-dts' import tsconfigPaths from 'vite-tsconfig-paths' import svgrPlugin from 'vite-plugin-svgr' import stylelintPlugin from 'vite-plugin-stylelint' +import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin' import pkg from './package.json' import path from 'path' @@ -37,6 +38,9 @@ export default defineConfig({ ], }, plugins: [ + vanillaExtractPlugin({ + identifiers: 'short', + }), svgrPlugin({ svgrOptions: { icon: true, diff --git a/docs/src/pages/_app.tsx b/docs/src/pages/_app.tsx index f208b315..5f46c16f 100644 --- a/docs/src/pages/_app.tsx +++ b/docs/src/pages/_app.tsx @@ -6,7 +6,7 @@ import Script from 'next/script' import { ThemeProvider } from 'styled-components' import { ThorinGlobalStyles, lightTheme } from '@ensdomains/thorin' - +import '@ensdomains/thorin/dist/style.css' import { MDX } from '~/components' import { getLayout as getDocsLayout } from '~/layouts/docs' import GlobalStyle from '~/styles/globalStyles' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 140d3fa6..b9820da2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -121,7 +121,13 @@ importers: '@types/rimraf': ^3.0.2 '@types/styled-components': ^5 '@types/testing-library__jest-dom': ^5.14.1 - '@vanilla-extract/css': 1.13.0 + '@vanilla-extract/css': ^1.13.0 + '@vanilla-extract/css-utils': ^0.1.3 + '@vanilla-extract/dynamic': ^2.0.3 + '@vanilla-extract/private': ^1.0.3 + '@vanilla-extract/recipes': ^0.5.0 + '@vanilla-extract/sprinkles': ^1.6.1 + '@vanilla-extract/vite-plugin': ^3.9.0 babel-plugin-styled-components: ^2.0.6 clsx: ^1.1.1 deepmerge: ^4.2.2 @@ -132,6 +138,7 @@ importers: jest-styled-components: ^7.0.8 jest-watch-typeahead: ^1.0.0 lodash: ^4.17.21 + rainbow-sprinkles: 0.17.0 react: ^17.0.2 react-dom: ^17.0.2 rimraf: ^3.0.2 @@ -171,6 +178,12 @@ importers: '@types/styled-components': 5.1.23 '@types/testing-library__jest-dom': 5.14.5 '@vanilla-extract/css': 1.13.0 + '@vanilla-extract/css-utils': 0.1.3 + '@vanilla-extract/dynamic': 2.0.3 + '@vanilla-extract/private': 1.0.3 + '@vanilla-extract/recipes': 0.5.0_3qusp464cmatvw2qbjjzblbe54 + '@vanilla-extract/sprinkles': 1.6.1_3qusp464cmatvw2qbjjzblbe54 + '@vanilla-extract/vite-plugin': 3.9.0_kpzh553nyvwzbphorod6becrcm babel-plugin-styled-components: 2.0.6 deepmerge: 4.2.2 esbuild-darwin-arm64: 0.14.53 @@ -178,6 +191,7 @@ importers: jest: 27.5.1_ts-node@10.9.1 jest-styled-components: 7.0.8 jest-watch-typeahead: 1.1.0_jest@27.5.1 + rainbow-sprinkles: 0.17.0_zxjdkdpiw73alatjbkr2ai5eu4 react: 17.0.2 react-dom: 17.0.2_react@17.0.2 rimraf: 3.0.2 @@ -280,6 +294,14 @@ packages: dependencies: '@jridgewell/trace-mapping': 0.3.13 + /@ampproject/remapping/2.2.1: + resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': 0.3.2 + '@jridgewell/trace-mapping': 0.3.13 + dev: true + /@babel/cli/7.18.10_@babel+core@7.20.5: resolution: {integrity: sha512-dLvWH+ZDFAkd2jPBSghrsFBuXrREvFwjpDycXbmUoeochqKYe4zNSLEJYErpLg8dvxvZYe79/MkN461XCwpnGw==} engines: {node: '>=6.9.0'} @@ -319,6 +341,14 @@ packages: dependencies: '@babel/highlight': 7.18.6 + /@babel/code-frame/7.22.13: + resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.22.20 + chalk: 2.4.2 + dev: true + /@babel/compat-data/7.18.8: resolution: {integrity: sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==} engines: {node: '>=6.9.0'} @@ -327,6 +357,11 @@ packages: resolution: {integrity: sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==} engines: {node: '>=6.9.0'} + /@babel/compat-data/7.22.20: + resolution: {integrity: sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/core/7.12.9: resolution: {integrity: sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==} engines: {node: '>=6.9.0'} @@ -395,6 +430,29 @@ packages: transitivePeerDependencies: - supports-color + /@babel/core/7.22.20: + resolution: {integrity: sha512-Y6jd1ahLubuYweD/zJH+vvOY141v4f9igNQAQ+MBgq9JlHS2iTsZKn1aMsb3vGccZsXI16VzTBw52Xx0DWmtnA==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@babel/code-frame': 7.22.13 + '@babel/generator': 7.22.15 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-module-transforms': 7.22.20_@babel+core@7.22.20 + '@babel/helpers': 7.22.15 + '@babel/parser': 7.22.16 + '@babel/template': 7.22.15 + '@babel/traverse': 7.22.20 + '@babel/types': 7.22.19 + convert-source-map: 1.8.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/generator/7.18.10: resolution: {integrity: sha512-0+sW7e3HjQbiHbj1NeU/vN8ornohYlacAfZIaXhdoGweQqgcNy69COVciYYqEXJ/v+9OBA7Frxm4CVAuNqKeNA==} engines: {node: '>=6.9.0'} @@ -412,6 +470,16 @@ packages: '@jridgewell/gen-mapping': 0.3.2 jsesc: 2.5.2 + /@babel/generator/7.22.15: + resolution: {integrity: sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.22.19 + '@jridgewell/gen-mapping': 0.3.2 + '@jridgewell/trace-mapping': 0.3.19 + jsesc: 2.5.2 + dev: true + /@babel/helper-annotate-as-pure/7.18.6: resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==} engines: {node: '>=6.9.0'} @@ -475,6 +543,17 @@ packages: browserslist: 4.21.3 semver: 6.3.0 + /@babel/helper-compilation-targets/7.22.15: + resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.22.20 + '@babel/helper-validator-option': 7.22.15 + browserslist: 4.21.11 + lru-cache: 5.1.1 + semver: 6.3.1 + dev: true + /@babel/helper-create-class-features-plugin/7.18.9_@babel+core@7.18.10: resolution: {integrity: sha512-WvypNAYaVh23QcjpMR24CwZY2Nz6hqdOcFdPbNpV56hL5H6KiFheO7Xm1aPdlLQ7d5emYZX7VZwPp9x3z+2opw==} engines: {node: '>=6.9.0'} @@ -570,6 +649,11 @@ packages: resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==} engines: {node: '>=6.9.0'} + /@babel/helper-environment-visitor/7.22.20: + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/helper-explode-assignable-expression/7.18.6: resolution: {integrity: sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==} engines: {node: '>=6.9.0'} @@ -590,12 +674,27 @@ packages: '@babel/template': 7.18.10 '@babel/types': 7.20.5 + /@babel/helper-function-name/7.22.5: + resolution: {integrity: sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/types': 7.22.19 + dev: true + /@babel/helper-hoist-variables/7.18.6: resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.20.5 + /@babel/helper-hoist-variables/7.22.5: + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.22.19 + dev: true + /@babel/helper-member-expression-to-functions/7.18.9: resolution: {integrity: sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==} engines: {node: '>=6.9.0'} @@ -608,6 +707,13 @@ packages: dependencies: '@babel/types': 7.20.5 + /@babel/helper-module-imports/7.22.15: + resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.22.19 + dev: true + /@babel/helper-module-transforms/7.18.0: resolution: {integrity: sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA==} engines: {node: '>=6.9.0'} @@ -653,6 +759,20 @@ packages: transitivePeerDependencies: - supports-color + /@babel/helper-module-transforms/7.22.20_@babel+core@7.22.20: + resolution: {integrity: sha512-dLT7JVWIUUxKOs1UnJUBR3S70YK+pKX6AbJgB2vMIvEkZkrfJDbYDJesnPshtKV4LhDOR3Oc5YULeDizRek+5A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.20 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + dev: true + /@babel/helper-optimise-call-expression/7.18.6: resolution: {integrity: sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==} engines: {node: '>=6.9.0'} @@ -670,6 +790,11 @@ packages: resolution: {integrity: sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==} engines: {node: '>=6.9.0'} + /@babel/helper-plugin-utils/7.22.5: + resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/helper-remap-async-to-generator/7.18.9_@babel+core@7.18.10: resolution: {integrity: sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==} engines: {node: '>=6.9.0'} @@ -729,6 +854,13 @@ packages: dependencies: '@babel/types': 7.20.5 + /@babel/helper-simple-access/7.22.5: + resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.22.19 + dev: true + /@babel/helper-skip-transparent-expression-wrappers/7.18.9: resolution: {integrity: sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==} engines: {node: '>=6.9.0'} @@ -747,6 +879,13 @@ packages: dependencies: '@babel/types': 7.20.5 + /@babel/helper-split-export-declaration/7.22.6: + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.22.19 + dev: true + /@babel/helper-string-parser/7.18.10: resolution: {integrity: sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==} engines: {node: '>=6.9.0'} @@ -755,6 +894,11 @@ packages: resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} engines: {node: '>=6.9.0'} + /@babel/helper-string-parser/7.22.5: + resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/helper-validator-identifier/7.16.7: resolution: {integrity: sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==} engines: {node: '>=6.9.0'} @@ -767,10 +911,20 @@ packages: resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} engines: {node: '>=6.9.0'} + /@babel/helper-validator-identifier/7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/helper-validator-option/7.18.6: resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==} engines: {node: '>=6.9.0'} + /@babel/helper-validator-option/7.22.15: + resolution: {integrity: sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/helper-wrap-function/7.18.10: resolution: {integrity: sha512-95NLBP59VWdfK2lyLKe6eTMq9xg+yWKzxzxbJ1wcYNi1Auz200+83fMDADjRxBvc2QQor5zja2yTQzXGhk2GtQ==} engines: {node: '>=6.9.0'} @@ -813,6 +967,17 @@ packages: transitivePeerDependencies: - supports-color + /@babel/helpers/7.22.15: + resolution: {integrity: sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/traverse': 7.22.20 + '@babel/types': 7.22.19 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/highlight/7.16.10: resolution: {integrity: sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==} engines: {node: '>=6.9.0'} @@ -830,6 +995,15 @@ packages: chalk: 2.4.2 js-tokens: 4.0.0 + /@babel/highlight/7.22.20: + resolution: {integrity: sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 + dev: true + /@babel/parser/7.18.10: resolution: {integrity: sha512-TYk3OA0HKL6qNryUayb5UUEhM/rkOQozIBEA5ITXh5DWrSp0TlUQXMyZmnWxG/DizSWBeeQ0Zbc5z8UGaaqoeg==} engines: {node: '>=6.0.0'} @@ -845,6 +1019,14 @@ packages: dependencies: '@babel/types': 7.20.5 + /@babel/parser/7.22.16: + resolution: {integrity: sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.22.19 + dev: true + /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/7.18.6_@babel+core@7.18.10: resolution: {integrity: sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==} engines: {node: '>=6.9.0'} @@ -1682,6 +1864,16 @@ packages: '@babel/core': 7.20.5 '@babel/helper-plugin-utils': 7.18.9 + /@babel/plugin-syntax-typescript/7.22.5_@babel+core@7.22.20: + resolution: {integrity: sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + /@babel/plugin-transform-arrow-functions/7.18.6_@babel+core@7.18.10: resolution: {integrity: sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==} engines: {node: '>=6.9.0'} @@ -2816,6 +3008,15 @@ packages: '@babel/parser': 7.20.5 '@babel/types': 7.20.5 + /@babel/template/7.22.15: + resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.22.13 + '@babel/parser': 7.22.16 + '@babel/types': 7.22.19 + dev: true + /@babel/traverse/7.18.10: resolution: {integrity: sha512-J7ycxg0/K9XCtLyHf0cz2DqDihonJeIo+z+HEdRe9YuT8TY4A66i+Ab2/xZCEW7Ro60bPCBBfqqboHSamoV3+g==} engines: {node: '>=6.9.0'} @@ -2868,6 +3069,24 @@ packages: transitivePeerDependencies: - supports-color + /@babel/traverse/7.22.20: + resolution: {integrity: sha512-eU260mPZbU7mZ0N+X10pxXhQFMGTeLb9eFS0mxehS8HZp9o1uSnFeWQuG1UPrlxgA7QoUzFhOnilHDp0AXCyHw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.22.13 + '@babel/generator': 7.22.15 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.22.5 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.22.16 + '@babel/types': 7.22.19 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/types/7.18.10: resolution: {integrity: sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==} engines: {node: '>=6.9.0'} @@ -2884,6 +3103,15 @@ packages: '@babel/helper-validator-identifier': 7.19.1 to-fast-properties: 2.0.0 + /@babel/types/7.22.19: + resolution: {integrity: sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + dev: true + /@base2/pretty-print-object/1.0.1: resolution: {integrity: sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==} dev: false @@ -2916,46 +3144,442 @@ packages: '@emmetio/scanner': 1.0.0 dev: true - /@emmetio/scanner/1.0.0: - resolution: {integrity: sha512-8HqW8EVqjnCmWXVpqAOZf+EGESdkR27odcMMMGefgKXtar00SoYNSryGv//TELI4T3QFsECo78p+0lmalk/CFA==} + /@emmetio/scanner/1.0.0: + resolution: {integrity: sha512-8HqW8EVqjnCmWXVpqAOZf+EGESdkR27odcMMMGefgKXtar00SoYNSryGv//TELI4T3QFsECo78p+0lmalk/CFA==} + dev: true + + /@emotion/hash/0.8.0: + resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} + dev: false + + /@emotion/hash/0.9.1: + resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==} + dev: true + + /@emotion/is-prop-valid/0.8.8: + resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==} + dependencies: + '@emotion/memoize': 0.7.4 + + /@emotion/memoize/0.7.4: + resolution: {integrity: sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==} + + /@emotion/stylis/0.8.5: + resolution: {integrity: sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==} + + /@emotion/unitless/0.7.5: + resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==} + + /@esbuild/android-arm/0.15.18: + resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm/0.17.6: + resolution: {integrity: sha512-bSC9YVUjADDy1gae8RrioINU6e1lCkg3VGVwm0QQ2E1CWcC4gnMce9+B6RpxuSsrsXsk1yojn7sp1fnG8erE2g==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm/0.18.20: + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64/0.17.6: + resolution: {integrity: sha512-YnYSCceN/dUzUr5kdtUzB+wZprCafuD89Hs0Aqv9QSdwhYQybhXTaSTcrl6X/aWThn1a/j0eEpUBGOE7269REg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64/0.18.20: + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64/0.17.6: + resolution: {integrity: sha512-MVcYcgSO7pfu/x34uX9u2QIZHmXAB7dEiLQC5bBl5Ryqtpj9lT2sg3gNDEsrPEmimSJW2FXIaxqSQ501YLDsZQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64/0.18.20: + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64/0.17.6: + resolution: {integrity: sha512-bsDRvlbKMQMt6Wl08nHtFz++yoZHsyTOxnjfB2Q95gato+Yi4WnRl13oC2/PJJA9yLCoRv9gqT/EYX0/zDsyMA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64/0.18.20: + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64/0.17.6: + resolution: {integrity: sha512-xh2A5oPrYRfMFz74QXIQTQo8uA+hYzGWJFoeTE8EvoZGHb+idyV4ATaukaUvnnxJiauhs/fPx3vYhU4wiGfosg==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64/0.18.20: + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64/0.17.6: + resolution: {integrity: sha512-EnUwjRc1inT4ccZh4pB3v1cIhohE2S4YXlt1OvI7sw/+pD+dIE4smwekZlEPIwY6PhU6oDWwITrQQm5S2/iZgg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64/0.18.20: + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64/0.17.6: + resolution: {integrity: sha512-Uh3HLWGzH6FwpviUcLMKPCbZUAFzv67Wj5MTwK6jn89b576SR2IbEp+tqUHTr8DIl0iDmBAf51MVaP7pw6PY5Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64/0.18.20: + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm/0.17.6: + resolution: {integrity: sha512-7YdGiurNt7lqO0Bf/U9/arrPWPqdPqcV6JCZda4LZgEn+PTQ5SMEI4MGR52Bfn3+d6bNEGcWFzlIxiQdS48YUw==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm/0.18.20: + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64/0.17.6: + resolution: {integrity: sha512-bUR58IFOMJX523aDVozswnlp5yry7+0cRLCXDsxnUeQYJik1DukMY+apBsLOZJblpH+K7ox7YrKrHmJoWqVR9w==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64/0.18.20: + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32/0.17.6: + resolution: {integrity: sha512-ujp8uoQCM9FRcbDfkqECoARsLnLfCUhKARTP56TFPog8ie9JG83D5GVKjQ6yVrEVdMie1djH86fm98eY3quQkQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32/0.18.20: + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64/0.15.18: + resolution: {integrity: sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64/0.17.6: + resolution: {integrity: sha512-y2NX1+X/Nt+izj9bLoiaYB9YXT/LoaQFYvCkVD77G/4F+/yuVXYCWz4SE9yr5CBMbOxOfBcy/xFL4LlOeNlzYQ==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64/0.18.20: + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el/0.17.6: + resolution: {integrity: sha512-09AXKB1HDOzXD+j3FdXCiL/MWmZP0Ex9eR8DLMBVcHorrWJxWmY8Nms2Nm41iRM64WVx7bA/JVHMv081iP2kUA==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el/0.18.20: + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64/0.17.6: + resolution: {integrity: sha512-AmLhMzkM8JuqTIOhxnX4ubh0XWJIznEynRnZAVdA2mMKE6FAfwT2TWKTwdqMG+qEaeyDPtfNoZRpJbD4ZBv0Tg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64/0.18.20: + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64/0.17.6: + resolution: {integrity: sha512-Y4Ri62PfavhLQhFbqucysHOmRamlTVK10zPWlqjNbj2XMea+BOs4w6ASKwQwAiqf9ZqcY9Ab7NOU4wIgpxwoSQ==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64/0.18.20: + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x/0.17.6: + resolution: {integrity: sha512-SPUiz4fDbnNEm3JSdUW8pBJ/vkop3M1YwZAVwvdwlFLoJwKEZ9L98l3tzeyMzq27CyepDQ3Qgoba44StgbiN5Q==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x/0.18.20: + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64/0.17.6: + resolution: {integrity: sha512-a3yHLmOodHrzuNgdpB7peFGPx1iJ2x6m+uDvhP2CKdr2CwOaqEFMeSqYAHU7hG+RjCq8r2NFujcd/YsEsFgTGw==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64/0.18.20: + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64/0.17.6: + resolution: {integrity: sha512-EanJqcU/4uZIBreTrnbnre2DXgXSa+Gjap7ifRfllpmyAU7YMvaXmljdArptTHmjrkkKm9BK6GH5D5Yo+p6y5A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64/0.18.20: + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64/0.17.6: + resolution: {integrity: sha512-xaxeSunhQRsTNGFanoOkkLtnmMn5QbA0qBhNet/XLVsc+OVkpIWPHcr3zTW2gxVU5YOHFbIHR9ODuaUdNza2Vw==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64/0.18.20: + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64/0.17.6: + resolution: {integrity: sha512-gnMnMPg5pfMkZvhHee21KbKdc6W3GR8/JuE0Da1kjwpK6oiFU3nqfHuVPgUX2rsOx9N2SadSQTIYV1CIjYG+xw==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64/0.18.20: + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64/0.17.6: + resolution: {integrity: sha512-G95n7vP1UnGJPsVdKXllAJPtqjMvFYbN20e8RK8LVLhlTiSOH1sd7+Gt7rm70xiG+I5tM58nYgwWrLs6I1jHqg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true dev: true + optional: true - /@emotion/hash/0.8.0: - resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} - dev: false - - /@emotion/hash/0.9.1: - resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==} + /@esbuild/win32-arm64/0.18.20: + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true dev: true + optional: true - /@emotion/is-prop-valid/0.8.8: - resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==} - dependencies: - '@emotion/memoize': 0.7.4 - - /@emotion/memoize/0.7.4: - resolution: {integrity: sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==} - - /@emotion/stylis/0.8.5: - resolution: {integrity: sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==} + /@esbuild/win32-ia32/0.17.6: + resolution: {integrity: sha512-96yEFzLhq5bv9jJo5JhTs1gI+1cKQ83cUpyxHuGqXVwQtY5Eq54ZEsKs8veKtiKwlrNimtckHEkj4mRh4pPjsg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true - /@emotion/unitless/0.7.5: - resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==} + /@esbuild/win32-ia32/0.18.20: + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true - /@esbuild/android-arm/0.15.18: - resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==} + /@esbuild/win32-x64/0.17.6: + resolution: {integrity: sha512-n6d8MOyUrNp6G4VSpRcgjs5xj4A91svJSaiwLIDWVWEsZtpN5FA9NlBbZHDmAJc2e8e6SF4tkBD3HAvPF+7igA==} engines: {node: '>=12'} - cpu: [arm] - os: [android] + cpu: [x64] + os: [win32] requiresBuild: true dev: true optional: true - /@esbuild/linux-loong64/0.15.18: - resolution: {integrity: sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==} + /@esbuild/win32-x64/0.18.20: + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} engines: {node: '>=12'} - cpu: [loong64] - os: [linux] + cpu: [x64] + os: [win32] requiresBuild: true dev: true optional: true @@ -3257,12 +3881,16 @@ packages: dependencies: '@jridgewell/set-array': 1.1.1 '@jridgewell/sourcemap-codec': 1.4.11 - '@jridgewell/trace-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.19 /@jridgewell/resolve-uri/3.0.5: resolution: {integrity: sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==} engines: {node: '>=6.0.0'} + /@jridgewell/resolve-uri/3.1.1: + resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + engines: {node: '>=6.0.0'} + /@jridgewell/set-array/1.1.1: resolution: {integrity: sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==} engines: {node: '>=6.0.0'} @@ -3277,12 +3905,21 @@ packages: /@jridgewell/sourcemap-codec/1.4.11: resolution: {integrity: sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==} + /@jridgewell/sourcemap-codec/1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + /@jridgewell/trace-mapping/0.3.13: resolution: {integrity: sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==} dependencies: '@jridgewell/resolve-uri': 3.0.5 '@jridgewell/sourcemap-codec': 1.4.11 + /@jridgewell/trace-mapping/0.3.19: + resolution: {integrity: sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + /@jridgewell/trace-mapping/0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} dependencies: @@ -4974,6 +5611,14 @@ packages: eslint-visitor-keys: 3.3.0 dev: true + /@vanilla-extract/babel-plugin-debug-ids/1.0.3: + resolution: {integrity: sha512-vm4jYu1xhSa6ofQ9AhIpR3DkAp4c+eoR1Rpm8/TQI4DmWbmGbOjYRcqV0aWsfaIlNhN4kFuxFMKBNN9oG6iRzA==} + dependencies: + '@babel/core': 7.22.20 + transitivePeerDependencies: + - supports-color + dev: true + /@vanilla-extract/babel-plugin/1.1.7: resolution: {integrity: sha512-nTCOb1N/u1FUxACxV/jvpLm4xchiCdEHTUZrxCWjYOrIxqkfgpJXE4T7q/1VyEje/M929DFBUaD+YkPzaqGMzA==} deprecated: The features of this plugin are now built-in to all vanilla-extract bundler integrations — making this plugin no longer required. For more information about test environment integrations, see https://vanilla-extract.style/documentation/test-environments/ @@ -4989,6 +5634,10 @@ packages: resolution: {integrity: sha512-qoxIu5E/UhJtoKsPL1JaU9nhTN0Xl5zYV0pScOgsvc3JN46TvTTt0L3GV8x3PQpZP7x3elw8BsC9czYbhJy9Gg==} dev: false + /@vanilla-extract/css-utils/0.1.3: + resolution: {integrity: sha512-PZAcHROlgtCUGI2y0JntdNwvPwCNyeVnkQu6KTYKdmxBbK3w72XJUmLFYapfaFfgami4I9CTLnrJTPdtmS3gpw==} + dev: true + /@vanilla-extract/css/1.13.0: resolution: {integrity: sha512-JFFBXhnJrPlGqHBabagXqo5ghXw9mtV270ycIGyLDZG8NAK5eRwAYkMowAxuzK7wZSm67GnETWYB7b0AUmyttg==} dependencies: @@ -5021,6 +5670,12 @@ packages: outdent: 0.8.0 dev: false + /@vanilla-extract/dynamic/2.0.3: + resolution: {integrity: sha512-Rglfw2gXAYiBzAQ4jgUG7rBgE2c88e/zcG27ZVoIqMHVq56wf2C1katGMm1yFMNBgzqM7oBNYzz4YOMzznydkg==} + dependencies: + '@vanilla-extract/private': 1.0.3 + dev: true + /@vanilla-extract/integration/5.0.0: resolution: {integrity: sha512-HwglsIxGYtV4IXFfyQ6GzZLFoaWaW+QkNx8UhXbgsCWUoPqpSbioukCOA+SuSuzsIcEZ3hkD0Y5ixITQNtnzjQ==} dependencies: @@ -5033,9 +5688,44 @@ packages: outdent: 0.8.0 dev: false + /@vanilla-extract/integration/6.2.2_@types+node@16.11.6: + resolution: {integrity: sha512-gV3qPFjFap1+IrPeuFy+tEZOq7l7ifJf1ik/kluDWhPr1ffsFG9puq1/jjJ4rod1BIC79Q5ZWPNvBInHyxfCew==} + dependencies: + '@babel/core': 7.22.20 + '@babel/plugin-syntax-typescript': 7.22.5_@babel+core@7.22.20 + '@vanilla-extract/babel-plugin-debug-ids': 1.0.3 + '@vanilla-extract/css': 1.13.0 + esbuild: 0.17.6 + eval: 0.1.8 + find-up: 5.0.0 + javascript-stringify: 2.1.0 + lodash: 4.17.21 + mlly: 1.4.2 + outdent: 0.8.0 + vite: 4.4.9_@types+node@16.11.6 + vite-node: 0.28.5_@types+node@16.11.6 + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + /@vanilla-extract/private/1.0.3: resolution: {integrity: sha512-17kVyLq3ePTKOkveHxXuIJZtGYs+cSoev7BlP+Lf4916qfDhk/HBjvlYDe8egrea7LNPHKwSZJK/bzZC+Q6AwQ==} + /@vanilla-extract/recipes/0.5.0_3qusp464cmatvw2qbjjzblbe54: + resolution: {integrity: sha512-NfdZ8XyqCDG2RsO3FmYPALDMKg5045dRD97NbBb0Fog3LMDVXZxYgDOct5FAWob8U6W4GbhVpRZt1X9hNnH6fA==} + peerDependencies: + '@vanilla-extract/css': ^1.0.0 + dependencies: + '@vanilla-extract/css': 1.13.0 + dev: true + /@vanilla-extract/sprinkles/1.4.1_@vanilla-extract+css@1.7.3: resolution: {integrity: sha512-aW6CfMMToX4a+baLuVxwcT0FSACjX3xrNt8wdi/3LLRlLAfhyue8OK7kJxhcYNZfydBeWTP59aRy8p5FUTIeew==} peerDependencies: @@ -5044,6 +5734,36 @@ packages: '@vanilla-extract/css': 1.7.3 dev: false + /@vanilla-extract/sprinkles/1.6.1_3qusp464cmatvw2qbjjzblbe54: + resolution: {integrity: sha512-N/RGKwGAAidBupZ436RpuweRQHEFGU+mvAqBo8PRMAjJEmHoPDttV8RObaMLrJHWLqvX+XUMinHUnD0hFRQISw==} + peerDependencies: + '@vanilla-extract/css': ^1.0.0 + dependencies: + '@vanilla-extract/css': 1.13.0 + dev: true + + /@vanilla-extract/vite-plugin/3.9.0_kpzh553nyvwzbphorod6becrcm: + resolution: {integrity: sha512-Q2HYAyEJ93Uy7GHQPPiP8SXwPMHGpd4d0YnrIQqB0YZccYbGJR/WFIln9Dmbzx2pdngQUoOfhwEg6kJF8sQrog==} + peerDependencies: + vite: ^2.2.3 || ^3.0.0 || ^4.0.3 + dependencies: + '@vanilla-extract/integration': 6.2.2_@types+node@16.11.6 + outdent: 0.8.0 + postcss: 8.4.19 + postcss-load-config: 3.1.4_v776zzvn44o7tpgzieipaairwm + vite: 3.2.5_@types+node@16.11.6 + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + - ts-node + dev: true + /@vanilla-extract/webpack-plugin/2.1.12_webpack@5.58.2: resolution: {integrity: sha512-8mAbIDEh9r7a5cgb3wcILzuhEbGNddV4/qvwogOlxhoGrP4deUKJHEtPURDviWZ+x/FzFZtZ3glWU7WD8+WN8A==} peerDependencies: @@ -5209,6 +5929,12 @@ packages: hasBin: true dev: true + /acorn/8.10.0: + resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + /acorn/8.5.0: resolution: {integrity: sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==} engines: {node: '>=0.4.0'} @@ -5844,6 +6570,17 @@ packages: node-releases: 2.0.5 picocolors: 1.0.0 + /browserslist/4.21.11: + resolution: {integrity: sha512-xn1UXOKUz7DjdGlg9RrUr0GGiWzI97UQJnugHtH0OLDfJB7jMgoIkYvRIEO1l9EeEERVqeqLYOcFBW9ldjypbQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001538 + electron-to-chromium: 1.4.528 + node-releases: 2.0.13 + update-browserslist-db: 1.0.13_browserslist@4.21.11 + dev: true + /browserslist/4.21.3: resolution: {integrity: sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -5896,6 +6633,11 @@ packages: engines: {node: '>= 0.8'} dev: false + /cac/6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + dev: true + /call-bind/1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: @@ -5955,6 +6697,10 @@ packages: resolution: {integrity: sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==} dev: false + /caniuse-lite/1.0.30001538: + resolution: {integrity: sha512-HWJnhnID+0YMtGlzcp3T9drmBJUVDchPJ08tpUGFLs9CYlwWPH2uLgpHn8fND5pCgXVtnGS3H4QR9XLMHVNkHw==} + dev: true + /capital-case/1.0.4: resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==} dependencies: @@ -6988,6 +7734,10 @@ packages: /electron-to-chromium/1.4.210: resolution: {integrity: sha512-kSiX4tuyZijV7Cz0MWVmGT8K2siqaOA4Z66K5dCttPPRh0HicOcOAEj1KlC8O8J1aOS/1M8rGofOzksLKaHWcQ==} + /electron-to-chromium/1.4.528: + resolution: {integrity: sha512-UdREXMXzLkREF4jA8t89FQjA8WHI6ssP38PMY4/4KhXFQbtImnghh4GkCgrtiZwLKUKVD2iTVXvDVQjfomEQuA==} + dev: true + /emittery/0.10.2: resolution: {integrity: sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==} engines: {node: '>=12'} @@ -7346,6 +8096,66 @@ packages: esbuild-windows-arm64: 0.15.18 dev: true + /esbuild/0.17.6: + resolution: {integrity: sha512-TKFRp9TxrJDdRWfSsSERKEovm6v30iHnrjlcGhLBOtReE28Yp1VSBRfO3GTaOFMoxsNerx4TjrhzSuma9ha83Q==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.17.6 + '@esbuild/android-arm64': 0.17.6 + '@esbuild/android-x64': 0.17.6 + '@esbuild/darwin-arm64': 0.17.6 + '@esbuild/darwin-x64': 0.17.6 + '@esbuild/freebsd-arm64': 0.17.6 + '@esbuild/freebsd-x64': 0.17.6 + '@esbuild/linux-arm': 0.17.6 + '@esbuild/linux-arm64': 0.17.6 + '@esbuild/linux-ia32': 0.17.6 + '@esbuild/linux-loong64': 0.17.6 + '@esbuild/linux-mips64el': 0.17.6 + '@esbuild/linux-ppc64': 0.17.6 + '@esbuild/linux-riscv64': 0.17.6 + '@esbuild/linux-s390x': 0.17.6 + '@esbuild/linux-x64': 0.17.6 + '@esbuild/netbsd-x64': 0.17.6 + '@esbuild/openbsd-x64': 0.17.6 + '@esbuild/sunos-x64': 0.17.6 + '@esbuild/win32-arm64': 0.17.6 + '@esbuild/win32-ia32': 0.17.6 + '@esbuild/win32-x64': 0.17.6 + dev: true + + /esbuild/0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + dev: true + /escalade/3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} @@ -7832,6 +8642,14 @@ packages: require-like: 0.1.2 dev: false + /eval/0.1.8: + resolution: {integrity: sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==} + engines: {node: '>= 0.8'} + dependencies: + '@types/node': 16.11.6 + require-like: 0.1.2 + dev: true + /eventemitter3/4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} dev: false @@ -8089,7 +8907,6 @@ packages: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 - dev: false /flat-cache/3.0.4: resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} @@ -9118,7 +9935,6 @@ packages: /javascript-stringify/2.1.0: resolution: {integrity: sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==} - dev: false /jest-changed-files/27.5.1: resolution: {integrity: sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==} @@ -9803,10 +10619,20 @@ packages: engines: {node: '>=6'} hasBin: true + /json5/2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + dev: true + /jsonc-parser/2.3.1: resolution: {integrity: sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==} dev: true + /jsonc-parser/3.2.0: + resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + dev: true + /jsonfile/4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} optionalDependencies: @@ -9888,6 +10714,11 @@ packages: engines: {node: '>=10'} dev: true + /lilconfig/2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + dev: true + /lines-and-columns/1.1.6: resolution: {integrity: sha512-8ZmlJFVK9iCmtLz19HpSsR8HaAMWBT284VMNednLwlIMDP2hJDCIhUp0IZ2xUcZ+Ob6BM0VvCSJwzASDM45NLQ==} @@ -9965,7 +10796,6 @@ packages: engines: {node: '>=10'} dependencies: p-locate: 5.0.0 - dev: false /lodash.camelcase/4.3.0: resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} @@ -10036,6 +10866,12 @@ packages: yallist: 2.1.2 dev: false + /lru-cache/5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + dev: true + /lru-cache/6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} @@ -10312,6 +11148,15 @@ packages: hasBin: true dev: true + /mlly/1.4.2: + resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==} + dependencies: + acorn: 8.10.0 + pathe: 1.1.1 + pkg-types: 1.0.3 + ufo: 1.3.0 + dev: true + /ms/2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} @@ -10364,6 +11209,12 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + /nanoid/3.3.6: + resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + /nanospinner/0.3.1: resolution: {integrity: sha512-esx373MR7OP0y7sz97FgcCDH+Mx67GW+1IuBgivf2o2MkASybBM1lL0bkrCAWTz3DHf3XaAovMisefiIFJMkzQ==} dependencies: @@ -10467,6 +11318,10 @@ packages: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} dev: true + /node-releases/2.0.13: + resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + dev: true + /node-releases/2.0.5: resolution: {integrity: sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==} @@ -10697,7 +11552,6 @@ packages: engines: {node: '>=10'} dependencies: p-limit: 3.1.0 - dev: false /p-map/4.0.0: resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} @@ -10813,6 +11667,10 @@ packages: engines: {node: '>=8'} dev: true + /pathe/1.1.1: + resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==} + dev: true + /pend/1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} dev: true @@ -10850,6 +11708,14 @@ packages: find-up: 5.0.0 dev: false + /pkg-types/1.0.3: + resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==} + dependencies: + jsonc-parser: 3.2.0 + mlly: 1.4.2 + pathe: 1.1.1 + dev: true + /playroom/0.28.1_sfoxds7t5ydpegc3knd667wn6m: resolution: {integrity: sha512-sXcAUYY6boeOA9hkBFGwemob0peltYhUyPozhNh+yd1Fj8wYr873oe93T33pYrBUfweow9pzRD0VoHggF6SAtw==} hasBin: true @@ -11021,6 +11887,24 @@ packages: postcss: 8.4.19 dev: true + /postcss-load-config/3.1.4_v776zzvn44o7tpgzieipaairwm: + resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} + engines: {node: '>= 10'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 2.1.0 + postcss: 8.4.19 + ts-node: 10.9.1_bt5sflnlgjdtoyp24iylol6xsy + yaml: 1.10.2 + dev: true + /postcss-media-query-parser/0.2.3: resolution: {integrity: sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==} dev: true @@ -11347,6 +12231,15 @@ packages: picocolors: 1.0.0 source-map-js: 1.0.2 + /postcss/8.4.30: + resolution: {integrity: sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.6 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + /prelude-ls/1.1.2: resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} engines: {node: '>= 0.8.0'} @@ -11531,6 +12424,16 @@ packages: engines: {node: '>=8'} dev: true + /rainbow-sprinkles/0.17.0_zxjdkdpiw73alatjbkr2ai5eu4: + resolution: {integrity: sha512-ok3NrylQ0szvJtuBYaB/w09L9zOvvqcSQrvycT2A5XJxQNvwvkeADvTqQWGOQ3b6MkO8UmYccBPt8g8vVvxM9A==} + peerDependencies: + '@vanilla-extract/css': ^1 + '@vanilla-extract/dynamic': ^2 + dependencies: + '@vanilla-extract/css': 1.13.0 + '@vanilla-extract/dynamic': 2.0.3 + dev: true + /randombytes/2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: @@ -11893,7 +12796,6 @@ packages: /require-like/0.1.2: resolution: {integrity: sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==} - dev: false /requires-port/1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} @@ -11989,6 +12891,14 @@ packages: fsevents: 2.3.2 dev: true + /rollup/3.29.3: + resolution: {integrity: sha512-T7du6Hum8jOkSWetjRgbwpM6Sy0nECYrYRSmZjayFcOddtKJWU4d17AC3HNUk7HRuqy4p+G7aEZclSHytqUmEg==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.2 + dev: true + /rtl-css-js/1.16.0: resolution: {integrity: sha512-Oc7PnzwIEU4M0K1J4h/7qUUaljXhQ0kCObRsZjxs2HjkpKsnoTMvSmvJ4sqgJZd0zBoEfAyTdnK/jMIYvrjySQ==} dependencies: @@ -12106,6 +13016,11 @@ packages: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} hasBin: true + /semver/6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + dev: true + /semver/7.0.0: resolution: {integrity: sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==} hasBin: true @@ -12329,6 +13244,13 @@ packages: buffer-from: 1.1.2 source-map: 0.6.1 + /source-map-support/0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: true + /source-map/0.5.6: resolution: {integrity: sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==} engines: {node: '>=0.10.0'} @@ -13292,6 +14214,10 @@ packages: engines: {node: '>=8'} dev: false + /ufo/1.3.0: + resolution: {integrity: sha512-bRn3CsoojyNStCZe0BG0Mt4Nr/4KF+rhFlnNXybgqt5pXHNFRlqinSoQaTrGyzE4X8aHplSb+TorH+COin9Yxw==} + dev: true + /unbox-primitive/1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: @@ -13419,6 +14345,17 @@ packages: resolution: {integrity: sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==} dev: true + /update-browserslist-db/1.0.13_browserslist@4.21.11: + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.21.11 + escalade: 3.1.1 + picocolors: 1.0.0 + dev: true + /update-browserslist-db/1.0.5_browserslist@4.21.3: resolution: {integrity: sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==} hasBin: true @@ -13558,6 +14495,30 @@ packages: unist-util-stringify-position: 2.0.3 vfile-message: 2.0.4 + /vite-node/0.28.5_@types+node@16.11.6: + resolution: {integrity: sha512-LmXb9saMGlrMZbXTvOveJKwMTBTNUH66c8rJnQ0ZPNX+myPEol64+szRzXtV5ORb0Hb/91yq+/D3oERoyAt6LA==} + engines: {node: '>=v14.16.0'} + hasBin: true + dependencies: + cac: 6.7.14 + debug: 4.3.4 + mlly: 1.4.2 + pathe: 1.1.1 + picocolors: 1.0.0 + source-map: 0.6.1 + source-map-support: 0.5.21 + vite: 4.4.9_@types+node@16.11.6 + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + /vite-plugin-babel-macros/1.0.6_vite@3.2.5: resolution: {integrity: sha512-7cCT8jtu5UjpE46pH7RyVltWw5FbhDAtQliZ6QGqRNR5RUZKdAsB0CDjuF+VBoDpnl0KuESPu22SoNqXRYYWyQ==} engines: {node: '>=16'} @@ -13667,6 +14628,42 @@ packages: fsevents: 2.3.2 dev: true + /vite/4.4.9_@types+node@16.11.6: + resolution: {integrity: sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 16.11.6 + esbuild: 0.18.20 + postcss: 8.4.30 + rollup: 3.29.3 + optionalDependencies: + fsevents: 2.3.2 + dev: true + /vscode-css-languageservice/5.4.2: resolution: {integrity: sha512-DT7+7vfdT2HDNjDoXWtYJ0lVDdeDEdbMNdK4PKqUl2MS8g7PWt7J5G9B6k9lYox8nOfhCEjLnoNC3UKHHCR1lg==} dependencies: @@ -14037,6 +15034,10 @@ packages: resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} dev: false + /yallist/3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + dev: true + /yallist/4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} From 357be171a78f82938995e51adf802c7993d18b01 Mon Sep 17 00:00:00 2001 From: storywithoutend Date: Thu, 12 Oct 2023 10:17:36 +0800 Subject: [PATCH 003/223] convert styled components to vanilla extract --- .stylelintrc.json | 7 +- components/package.json | 2 +- .../src/components/atoms/Banner/Banner.tsx | 309 +++---- .../src/components/atoms/Banner/styles.css.ts | 6 + .../atoms/Banner/utils/getValueForAlert.ts | 60 ++ components/src/components/atoms/Box/Box.tsx | 37 +- components/src/components/atoms/Box/index.ts | 2 + .../src/components/atoms/Button/Button.tsx | 419 +++++---- .../atoms/Button/utils/getValueForSize.ts | 42 + .../atoms/Button/utils/withColorStyle.ts | 80 ++ components/src/components/atoms/Card/Card.tsx | 59 +- .../atoms/DynamicPopover/DynamicPopover.tsx | 66 +- .../utils/getValueForTransitionState.ts | 84 ++ .../src/components/atoms/Field/Field.tsx | 231 ++--- .../src/components/atoms/Heading/Heading.tsx | 97 +-- .../atoms/Heading/utils/getValueForLevel.ts | 24 + .../atoms/RecordItem/RecordItem.tsx | 223 +++-- .../components/atoms/ScrollBox/ScrollBox.tsx | 154 ++-- .../components/atoms/ScrollBox/styles.css.ts | 44 + .../components/atoms/Skeleton/Skeleton.tsx | 57 +- .../components/atoms/Skeleton/styles.css.ts | 26 + .../src/components/atoms/Spinner/Spinner.tsx | 123 ++- .../components/atoms/Spinner/styles.css.ts | 14 + .../atoms/Spinner/utils/getValueForSize.ts | 21 + .../atoms/Spinner/utils/withColor.ts | 20 + components/src/components/atoms/Tag/Tag.tsx | 23 +- .../atoms/Tag/utils/withColorStyle.ts | 47 + .../atoms/Typography/Typography.tsx | 82 +- .../Typography/utils/getValueForVariant.ts | 117 +++ .../atoms/VisuallyHidden/VisuallyHidden.tsx | 40 +- components/src/components/atoms/index.ts | 2 + .../molecules/Checkbox/Checkbox.tsx | 126 ++- .../molecules/Checkbox/styles.css.ts | 23 + .../Checkbox/utils/getValueForColorStyle.ts | 44 + .../molecules/CheckboxRow/CheckboxRow.tsx | 238 +++--- .../molecules/CheckboxRow/styles.css.ts | 56 ++ .../utils/getValueForColorStyle.ts | 50 ++ .../CountdownCircle/CountdownCircle.tsx | 238 +++--- .../utils/getValidatedColor.ts | 12 + .../utils/getValueForNumberForSize.ts | 23 + .../CurrencyToggle/CurrencyToggle.tsx | 246 +++--- .../molecules/CurrencyToggle/styles.css.ts | 31 + .../CurrencyToggle/utils/constants.ts | 45 + .../CurrencyToggle/utils/getValidatedColor.ts | 12 + .../utils/getValueForCheckBox.ts | 31 + .../CurrencyToggle/utils/getValuesForKnob.ts | 20 + .../CurrencyToggle/utils/getValuesForLabel.ts | 9 + .../molecules/Dropdown/Dropdown.tsx | 341 ++++---- .../molecules/Dropdown/styles.css.ts | 3 + .../molecules/FieldSet/FieldSet.tsx | 62 +- .../components/molecules/Helper/Helper.tsx | 98 +-- .../Helper/utils/getValueForAlert.ts | 36 + .../src/components/molecules/Input/Input.tsx | 562 +++++------- .../components/molecules/Input/styles.css.ts | 79 ++ .../molecules/Input/utils/getValueForSize.ts | 61 ++ .../src/components/molecules/Modal/Modal.tsx | 103 +-- .../molecules/Modal/utils/getValueForMode.ts | 42 + .../components/molecules/Profile/Profile.tsx | 157 ++-- .../Profile/utils/getValueForSize.ts | 39 + .../molecules/RadioButton/RadioButton.tsx | 137 ++- .../molecules/RadioButton/styles.css.ts | 26 + .../RadioButton/utils/getValidatedColor.ts | 12 + .../RadioButtonGroup/RadioButtonGroup.tsx | 28 +- .../components/molecules/Select/Select.tsx | 800 ++++++++---------- .../components/molecules/Select/styles.css.ts | 11 + .../molecules/Select/utils/getValueForSize.ts | 43 + .../utils/getValueForTransitionState.ts | 63 ++ .../components/molecules/Slider/Slider.tsx | 114 +-- .../components/molecules/Slider/styles.css.ts | 43 + .../molecules/Textarea/Textarea.tsx | 295 +++---- .../molecules/Textarea/styles.css.ts | 24 + .../Textarea/utils/getValueForSize.ts | 38 + .../components/molecules/Toggle/Toggle.tsx | 130 +-- .../components/molecules/Toggle/styles.css.ts | 110 +++ .../Toggle/utils/getValidatedColor.ts | 12 + .../molecules/Toggle/utils/getValueForSize.ts | 40 + .../components/molecules/Tooltip/Tooltip.tsx | 181 ++-- .../Tooltip/utils/getValueForPlacement.ts | 79 ++ .../components/organisms/Dialog/Dialog.tsx | 311 +++---- .../Dialog/utils/getValueForAlert.ts | 36 + .../Dialog/utils/getValueForStepType.ts | 36 + .../src/components/organisms/Toast/Toast.tsx | 258 +++--- components/src/css/rainbow-spinkles.css.ts | 61 +- .../src/css/recipes/statusBorder.css.ts | 48 ++ components/src/css/recipes/statusDot.css.ts | 70 ++ components/src/css/theme.css.ts | 6 +- components/src/css/utils/common.ts | 28 + components/src/css/utils/getColorStyle.ts | 11 +- components/src/interfaces/withColor.ts | 20 + components/src/interfaces/withColourStyle.ts | 70 ++ components/src/tokens/color3.ts | 235 +++++ components/src/tokens/dialog.ts | 0 components/src/tokens/space.ts | 9 + components/src/tokens/typography.ts | 43 +- components/src/types/index.ts | 3 +- components/src/types/withTypography2.ts | 130 +++ docs/next.config.js | 5 +- docs/package.json | 2 + .../components/CodePreview/CodePreview.tsx | 45 +- docs/src/components/CodePreview/styles.css.ts | 8 + docs/src/layouts/docs.tsx | 23 +- docs/src/pages/components/[...slug].tsx | 2 +- docs/src/reference/mdx/atoms/Button.docs.mdx | 15 - docs/src/reference/mdx/atoms/Tag.docs.mdx | 13 - .../reference/mdx/atoms/Typography.docs.mdx | 13 +- .../reference/mdx/molecules/Checkbox.docs.mdx | 13 +- .../mdx/molecules/CheckboxRow.docs.mdx | 39 +- .../mdx/molecules/CurrencyToggle.docs.mdx | 17 + .../reference/mdx/molecules/Helper.docs.mdx | 6 +- .../mdx/molecules/RadioButton.docs.mdx | 6 +- .../reference/mdx/molecules/Toggle.docs.mdx | 10 + pnpm-lock.yaml | 180 ++-- 112 files changed, 5430 insertions(+), 3833 deletions(-) create mode 100644 components/src/components/atoms/Banner/utils/getValueForAlert.ts create mode 100644 components/src/components/atoms/Box/index.ts create mode 100644 components/src/components/atoms/Button/utils/getValueForSize.ts create mode 100644 components/src/components/atoms/Button/utils/withColorStyle.ts create mode 100644 components/src/components/atoms/DynamicPopover/utils/getValueForTransitionState.ts create mode 100644 components/src/components/atoms/Heading/utils/getValueForLevel.ts create mode 100644 components/src/components/atoms/ScrollBox/styles.css.ts create mode 100644 components/src/components/atoms/Skeleton/styles.css.ts create mode 100644 components/src/components/atoms/Spinner/styles.css.ts create mode 100644 components/src/components/atoms/Spinner/utils/getValueForSize.ts create mode 100644 components/src/components/atoms/Spinner/utils/withColor.ts create mode 100644 components/src/components/atoms/Tag/utils/withColorStyle.ts create mode 100644 components/src/components/atoms/Typography/utils/getValueForVariant.ts create mode 100644 components/src/components/molecules/Checkbox/styles.css.ts create mode 100644 components/src/components/molecules/Checkbox/utils/getValueForColorStyle.ts create mode 100644 components/src/components/molecules/CheckboxRow/styles.css.ts create mode 100644 components/src/components/molecules/CheckboxRow/utils/getValueForColorStyle.ts create mode 100644 components/src/components/molecules/CountdownCircle/utils/getValidatedColor.ts create mode 100644 components/src/components/molecules/CountdownCircle/utils/getValueForNumberForSize.ts create mode 100644 components/src/components/molecules/CurrencyToggle/styles.css.ts create mode 100644 components/src/components/molecules/CurrencyToggle/utils/constants.ts create mode 100644 components/src/components/molecules/CurrencyToggle/utils/getValidatedColor.ts create mode 100644 components/src/components/molecules/CurrencyToggle/utils/getValueForCheckBox.ts create mode 100644 components/src/components/molecules/CurrencyToggle/utils/getValuesForKnob.ts create mode 100644 components/src/components/molecules/CurrencyToggle/utils/getValuesForLabel.ts create mode 100644 components/src/components/molecules/Dropdown/styles.css.ts create mode 100644 components/src/components/molecules/Helper/utils/getValueForAlert.ts create mode 100644 components/src/components/molecules/Input/styles.css.ts create mode 100644 components/src/components/molecules/Input/utils/getValueForSize.ts create mode 100644 components/src/components/molecules/Modal/utils/getValueForMode.ts create mode 100644 components/src/components/molecules/Profile/utils/getValueForSize.ts create mode 100644 components/src/components/molecules/RadioButton/styles.css.ts create mode 100644 components/src/components/molecules/RadioButton/utils/getValidatedColor.ts create mode 100644 components/src/components/molecules/Select/styles.css.ts create mode 100644 components/src/components/molecules/Select/utils/getValueForSize.ts create mode 100644 components/src/components/molecules/Select/utils/getValueForTransitionState.ts create mode 100644 components/src/components/molecules/Slider/styles.css.ts create mode 100644 components/src/components/molecules/Textarea/styles.css.ts create mode 100644 components/src/components/molecules/Textarea/utils/getValueForSize.ts create mode 100644 components/src/components/molecules/Toggle/styles.css.ts create mode 100644 components/src/components/molecules/Toggle/utils/getValidatedColor.ts create mode 100644 components/src/components/molecules/Toggle/utils/getValueForSize.ts create mode 100644 components/src/components/molecules/Tooltip/utils/getValueForPlacement.ts create mode 100644 components/src/components/organisms/Dialog/utils/getValueForAlert.ts create mode 100644 components/src/components/organisms/Dialog/utils/getValueForStepType.ts create mode 100644 components/src/css/recipes/statusBorder.css.ts create mode 100644 components/src/css/recipes/statusDot.css.ts create mode 100644 components/src/css/utils/common.ts create mode 100644 components/src/interfaces/withColor.ts create mode 100644 components/src/interfaces/withColourStyle.ts create mode 100644 components/src/tokens/color3.ts create mode 100644 components/src/tokens/dialog.ts create mode 100644 components/src/types/withTypography2.ts create mode 100644 docs/src/components/CodePreview/styles.css.ts diff --git a/.stylelintrc.json b/.stylelintrc.json index c8135b9f..291949e2 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -11,12 +11,7 @@ } ], "rules": { - "property-no-unknown": [ - true, - { - "ignoreProperties": ["flex-gap", "webkit-appearance"] - } - ], + "property-no-unknown": null, "no-duplicate-selectors": null, "function-no-unknown": null } diff --git a/components/package.json b/components/package.json index cf07f5ca..81a3b4df 100644 --- a/components/package.json +++ b/components/package.json @@ -64,10 +64,10 @@ "@vanilla-extract/css": "^1.13.0", "@vanilla-extract/css-utils": "^0.1.3", "@vanilla-extract/dynamic": "^2.0.3", + "@vanilla-extract/private": "^1.0.3", "@vanilla-extract/recipes": "^0.5.0", "@vanilla-extract/sprinkles": "^1.6.1", "@vanilla-extract/vite-plugin": "^3.9.0", - "@vanilla-extract/private": "^1.0.3", "babel-plugin-styled-components": "^2.0.6", "deepmerge": "^4.2.2", "esbuild-darwin-arm64": "^0.14.27", diff --git a/components/src/components/atoms/Banner/Banner.tsx b/components/src/components/atoms/Banner/Banner.tsx index 9328c81c..f2e82868 100644 --- a/components/src/components/atoms/Banner/Banner.tsx +++ b/components/src/components/atoms/Banner/Banner.tsx @@ -1,10 +1,6 @@ import * as React from 'react' -import styled, { css } from 'styled-components' - -import { mq } from '@/src/utils/responsiveHelpers' - -import { WithAlert } from '../../../types' +import { WithAlert, getValueForAlert } from './utils/getValueForAlert' import { Typography } from '../Typography' import { AlertSVG, CrossSVG, EthSVG, UpRightArrowSVG } from '../..' @@ -53,76 +49,25 @@ type WithoutAnchor = { type NonNullableAlert = NonNullable -const getColorForAlert = ( - alert: NonNullableAlert, - field: 'background' | 'border', - hover = false, -) => { - return { - error: { - background: { - default: '$redSurface', - hover: '$redLight', - }, - border: { - default: '$redPrimary', - hover: '$redPrimary', - }, - }, - warning: { - background: { - default: '$yellowSurface', - hover: '$yellowLight', - }, - border: { - default: '$yellowPrimary', - hover: '$yellowPrimary', - }, - }, - info: { - background: { - default: '$backgroundPrimary', - hover: '$greySurface', - }, - border: { - default: '$border', - hover: '$border', - }, - }, - }[alert][field][hover ? 'hover' : 'default'] +type ContainerProps = BoxProps & { + $alert: NonNullableAlert + $hasAction: boolean } - -const ContainerBox = React.forwardRef< - HTMLDivElement, - { - $alert: NonNullableAlert - $hasAction: boolean - } & BoxProps ->( - ( - { - $alert, - $hasAction, - ...props - }: { - $alert: NonNullableAlert - $hasAction: boolean - } & BoxProps, - ref, - ) => ( +const ContainerBox = React.forwardRef( + ({ $alert, $hasAction, ...props }, ref) => ( -}>( - ({ theme, $alert, $type }) => css` - width: ${theme.space[8]}; - height: ${theme.space[8]}; - flex: 0 0 ${theme.space[8]}; - - svg { - display: block; - width: 100%; - height: 100%; - } - - ${mq.sm.min(css` - width: ${theme.space[10]}; - height: ${theme.space[10]}; - flex: 0 0 ${theme.space[10]}; - `)} - - ${$type === 'filledCircle' && - css` - color: ${theme.colors.backgroundPrimary}; - border-radius: ${theme.radii.full}; - - svg { - transform: scale(0.5); - } - - ${$alert === 'info' && - css` - background: ${theme.colors.text}; - `} - `} - - ${$alert === 'error' && - css` - background: ${theme.colors.redPrimary}; - `} - - ${$alert === 'warning' && - css` - background: ${theme.colors.yellowPrimary}; - `} - `, +const IconBox = ({ + $alert, + ...props +}: BoxProps & { $alert: NonNullableAlert }) => ( + ) -const ActionButtonContainer = styled.button( - ({ theme }) => css` - position: absolute; - top: 0; - right: 0; - padding: ${theme.space[2]}; - `, +const SVGBox = ({ + $alert, + ...props +}: BoxProps & { $alert: NonNullableAlert }) => ( + ) -const ActionButtonIconWrapper = styled.div<{ - $alert: NonNullableAlert - $hasAction?: boolean -}>( - ({ theme, $alert, $hasAction }) => css` - width: ${theme.space[5]}; - height: ${theme.space[5]}; - border-radius: ${theme.radii.full}; - background: ${theme.colors.accentSurface}; - color: ${theme.colors.accentPrimary}; - transition: all 150ms ease-in-out; - - display: flex; - align-items: center; - justify-content: center; - - svg { - display: block; - width: ${theme.space[3]}; - height: ${theme.space[3]}; - } - - ${$alert === 'error' && - css` - background: ${theme.colors.backgroundPrimary}; - color: ${theme.colors.redPrimary}; - `} +const ActionButtonBox = (props: BoxProps) => ( + +) - ${$alert === 'warning' && - css` - background: ${theme.colors.backgroundPrimary}; - color: ${theme.colors.yellowPrimary}; - `} +const ActionButtonIconBox = ({ + $alert, + $hasAction, + ...props +}: BoxProps & { $alert: NonNullableAlert; $hasAction: boolean }) => ( + +) - ${$hasAction && - css` - cursor: pointer; - &:hover { - transform: translateY(-1px); - background: ${theme.colors.accentLight}; - color: ${theme.colors.accentDim}; - ${$alert === 'error' && - css` - background: ${theme.colors.redLight}; - color: ${theme.colors.redDim}; - `} - ${$alert === 'warning' && - css` - background: ${theme.colors.yellowLight}; - color: ${theme.colors.yellowDim}; - `} - } - `} - `, +const ActionButtonSVGBox = (props: BoxProps) => ( + ) const ActionButton = ({ @@ -258,22 +166,26 @@ const ActionButton = ({ hasHref, onDismiss, }: Pick & { hasHref: boolean } & WithIcon) => { - if (onDismiss) + if (onDismiss) { + const Icon = (icon || ) as React.ReactElement return ( - onDismiss()}> - - {icon || } - - + onDismiss()}> + + + + ) - if (hasHref || icon) + } + if (hasHref || icon) { + const Icon = (icon || ) as React.ReactElement return ( - - - {icon || } - - + + + + + ) + } return null } @@ -282,30 +194,12 @@ export type Props = BaseProps & (WithIcon | WithoutIcon) & WithAlert -const defaultIconType = ( - alert: NonNullableAlert, - icon: React.ReactNode | undefined, -): IconTypes => { - if (alert !== 'info') return 'filledCircle' - if (icon) return 'normal' - return 'none' -} - export const Banner = React.forwardRef< HTMLDivElement, React.PropsWithChildren >( ( - { - title, - alert = 'info', - icon, - iconType, - as: asProp, - children, - onDismiss, - ...props - }, + { title, alert = 'info', icon, as: asProp, children, onDismiss, ...props }, ref, ) => { const Icon = @@ -318,7 +212,6 @@ export const Banner = React.forwardRef< const hasHref = !!props.href const hasAction = hasHref || !!props.onClick - const _iconType = iconType || defaultIconType(alert, icon) return ( - {_iconType !== 'none' && ( - - {Icon} - - )} + + + ( + alert: Alert, + property: Property, +): Properties[T] => { + return alertMap[alert][property] || alertMap.info[property] +} diff --git a/components/src/components/atoms/Box/Box.tsx b/components/src/components/atoms/Box/Box.tsx index a6e5a939..4e1c4e86 100644 --- a/components/src/components/atoms/Box/Box.tsx +++ b/components/src/components/atoms/Box/Box.tsx @@ -1,15 +1,42 @@ -import React, { AllHTMLAttributes, ElementType, forwardRef } from 'react' +import React, { + AllHTMLAttributes, + ElementType, + ReactElement, + cloneElement, + forwardRef, + isValidElement, +} from 'react' +import classNames from 'clsx' import { Sprinkles, rainbowSprinkles } from '../../../css/rainbow-spinkles.css' -type HTMLProperties = Omit, 'as'> +type HTMLProperties = Omit< + AllHTMLAttributes, + 'as' | 'width' | 'height' | 'color' | 'translate' | 'transform' +> -export type BoxProps = Sprinkles & HTMLProperties & { as?: ElementType } +export type BoxProps = Sprinkles & + HTMLProperties & { as?: ElementType | ReactElement } export const Box = forwardRef( - ({ as, children, ...props }, ref) => { + ( + { as: _as, className: _className, style: _style, children, ...props }, + ref, + ) => { + const { + className: sprinklesClassName, + style: sprinklesStyle, + otherProps, + } = rainbowSprinkles(props) + + const className = classNames(sprinklesClassName, _className) + const style = { ...sprinklesStyle, ..._style } + if (isValidElement(_as)) { + const as = _as as ReactElement + return cloneElement(as, { className, style, ...otherProps }) + } + const as = _as as ElementType const Component = as || 'div' - const { className, style, otherProps } = rainbowSprinkles(props) return ( {children} diff --git a/components/src/components/atoms/Box/index.ts b/components/src/components/atoms/Box/index.ts new file mode 100644 index 00000000..6067699a --- /dev/null +++ b/components/src/components/atoms/Box/index.ts @@ -0,0 +1,2 @@ +export { Box } from './Box' +export type { BoxProps } from './Box' diff --git a/components/src/components/atoms/Button/Button.tsx b/components/src/components/atoms/Button/Button.tsx index b3c172d3..eb5d0224 100644 --- a/components/src/components/atoms/Button/Button.tsx +++ b/components/src/components/atoms/Button/Button.tsx @@ -1,15 +1,18 @@ import * as React from 'react' -import styled, { css } from 'styled-components' + +import { P, match } from 'ts-pattern' import { Space } from '@/src/tokens' -import { - WithColorStyle, - getColorStyle, -} from '@/src/types/withColorOrColorStyle' +import { scale, translateY } from '@/src/css/utils/common' + +import { WithColorStyle, getValueForColourStyle } from './utils/withColorStyle' + +import { getValueForSize } from './utils/getValueForSize' import { ReactNodeNoStrings } from '../../../types' import { Spinner } from '../Spinner' +import { Box, BoxProps } from '../Box/Box' export type Size = 'small' | 'medium' | 'flexible' @@ -27,7 +30,7 @@ type BaseProps = { /** Shows loading spinner inside button */ loading?: boolean /** Constrains button to specific shape */ - shape?: 'square' | 'rounded' | 'circle' + shape?: 'rectangle' | 'square' | 'rounded' | 'circle' /** Sets dimensions and layout */ size?: Size /** Adds ReactNode after children */ @@ -65,211 +68,175 @@ type WithoutAnchor = { target?: never } -interface ButtonElement { +type ButtonBoxProps = { $pressed: boolean $shadow: boolean - $outlined: boolean $shape?: BaseProps['shape'] $size?: BaseProps['size'] $type?: BaseProps['type'] $center: boolean | undefined $colorStyle: WithColorStyle['colorStyle'] $hasCounter?: boolean - $width: BaseProps['width'] + $width: any } - -const ButtonElement = styled.button( - ({ - theme, - $pressed, - $shadow, - $size, - $colorStyle = 'accentPrimary', - $shape, - $hasCounter, - $width, - }) => css` - position: relative; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - gap: ${theme.space['2']}; - - transition-property: all; - transition-duration: ${theme.transitionDuration['150']}; - transition-timing-function: ${theme.transitionTimingFunction['inOut']}; - width: 100%; - border-radius: ${theme.radii.large}; - font-weight: ${theme.fontWeights.bold}; - border-width: ${theme.borderWidths.px}; - border-style: ${theme.borderStyles.solid}; - - background: ${getColorStyle($colorStyle, 'background')}; - color: ${getColorStyle($colorStyle, 'text')}; - border-color: ${getColorStyle($colorStyle, 'border')}; - - /* solves sticky problem */ - @media (hover: hover) { - &:hover { - transform: translateY(-1px); - background: ${getColorStyle($colorStyle, 'hover')}; - } - &:active { - transform: translateY(0px); - } - } - @media (hover: none) { - &:active { - transform: translateY(-1px); - background: ${getColorStyle($colorStyle, 'hover')}; - } - } - - &:disabled { - cursor: not-allowed; - background: ${getColorStyle('disabled', 'background')}; - transform: none; - color: ${getColorStyle('disabled', 'text')}; - border-color: transparent; - } - - ${$pressed && - css` - background: ${getColorStyle($colorStyle, 'hover')}; - `}; - - ${$shadow && - css` - box-shadow: ${theme.shadows['0.25']} ${theme.colors.grey}; - `}; - - ${$size === 'small' && - css` - font-size: ${theme.fontSizes.small}; - line-height: ${theme.lineHeights.small}; - height: ${theme.space['10']}; - padding: 0 ${theme.space['3.5']}; - svg { - display: block; - width: ${theme.space['3']}; - height: ${theme.space['3']}; - color: ${getColorStyle($colorStyle, 'text')}; - } - `} - - ${$size === 'medium' && - css` - font-size: ${theme.fontSizes.body}; - line-height: ${theme.lineHeights.body}; - height: ${theme.space['12']}; - padding: 0 ${theme.space['4']}; - svg { - display: block; - width: ${theme.space['4']}; - height: ${theme.space['4']}; - color: ${getColorStyle($colorStyle, 'text')}; +const ButtonBox = React.forwardRef< + HTMLButtonElement, + BoxProps & ButtonBoxProps +>( + ( + { + $pressed, + $shadow, + $shape = 'rectangle', + $size = 'medium', + $colorStyle = 'accentPrimary', + $hasCounter, + $width = '$full', + as, + ...props + }, + ref, + ) => ( + + ), ) -const ContentContainer = styled.div<{ $fullWidth?: boolean }>( - ({ $fullWidth }) => css` - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - - ${$fullWidth && - css` - width: 100%; - `} - `, +const SVGBox = ({ + $size, + $colorStyle, + ...props +}: BoxProps & { $size: 'small' | 'medium' | 'flexible'; $colorStyle: any }) => ( + ) -const CounterWrapper = styled.div( - ({ theme }) => css` - position: absolute; - top: 0; - right: 0; - height: 100%; - padding-right: ${theme.space[3]}; - - display: flex; - align-items: center; - justify-content: flex-end; - pointer-events: none; - `, +const ContentBox = ({ + $fullWidth, + ...props +}: BoxProps & { $fullWidth?: boolean }) => ( + ) -const Counter = styled.div<{ $visible: boolean }>( - ({ theme, $visible }) => css` - display: flex; - padding: 0 ${theme.space[1]}; - justify-content: center; - align-items: center; - border: 2px solid white; - border-radius: ${theme.radii.full}; - font-size: ${theme.space[3]}; - min-width: ${theme.space[6]}; - height: ${theme.space[6]}; - box-sizing: border-box; - transform: scale(1); - opacity: 1; - transition: all 0.3s ease-in-out; +const CounterBox = (props: BoxProps) => ( + +) - ${!$visible && - css` - transform: scale(0.3); - opacity: 0; - `} - `, +const CounterIconBox = ({ + $visible, + $colourStyle, + ...props +}: BoxProps & { + $visible: boolean + $colourStyle: WithColorStyle['colorStyle'] +}) => ( + ) -const TooltipIndicator = styled.div` - display: flex; - align-items: center; - justify-content: center; - background: #e9b911; - border-radius: 50%; - width: 24px; - height: 24px; - position: absolute; - right: -10px; - top: -10px; - color: white; -` +const TooltipIndicatorBox = (props: BoxProps) => ( + +) export type Props = BaseProps & (WithoutAnchor | WithAnchor) & WithColorStyle @@ -287,7 +254,7 @@ export const Button = React.forwardRef( suffix, tabIndex, target, - colorStyle = 'accentPrimary', + colorStyle: colourStyle = 'accent', type = 'button', zIndex, onClick, @@ -303,39 +270,52 @@ export const Button = React.forwardRef( ref: React.Ref, ) => { const labelContent = ( - - {children} - + {children} ) let childContent: ReactNodeNoStrings if (shape === 'circle' || shape === 'square') { childContent = loading ? : labelContent } else { - const hasPrefix = !!prefix - const hasNoPrefixNoSuffix = !hasPrefix && !suffix - const hasSuffixNoPrefix = !hasPrefix && !!suffix - - let prefixOrLoading = prefix - if (loading && hasPrefix) prefixOrLoading = - else if (loading && hasNoPrefixNoSuffix) prefixOrLoading = - - let suffixOrLoading = suffix - if (loading && hasSuffixNoPrefix) suffixOrLoading = + const prefixOrLoading = match([loading, !!prefix, !!suffix]) + .with([true, true, P._], () => ) + .with([true, false, false], () => ) + .with([P._, true, P._], () => + React.isValidElement(prefix) ? ( + + ) : null, + ) + .otherwise(() => null) + + const suffixOrLoading = match([loading, !!prefix, !!suffix]) + .with([true, false, true], () => ) + .with([P._, P._, true], () => + React.isValidElement(suffix) ? ( + + ) : null, + ) + .otherwise(() => null) childContent = ( <> {!!prefixOrLoading && prefixOrLoading} {labelContent} - {!!suffixOrLoading && suffixOrLoading} + {!!suffixOrLoading && ( + + )} ) } return ( - {shouldShowTooltipIndicator && ( - ? + + ? + )} {childContent} - - {count} - - + + + {count} + + + ) }, ) diff --git a/components/src/components/atoms/Button/utils/getValueForSize.ts b/components/src/components/atoms/Button/utils/getValueForSize.ts new file mode 100644 index 00000000..be8c8435 --- /dev/null +++ b/components/src/components/atoms/Button/utils/getValueForSize.ts @@ -0,0 +1,42 @@ +import type { Size } from '../Button' + +type Properties = { + fontSize: string + lineHeight: string + height: string + px: string + svgSize: string +} + +type Property = keyof Properties + +const sizeMap: { [key in Size]: Properties } = { + small: { + fontSize: '$small', + lineHeight: '$small', + height: '$10', + px: '$3.5', + svgSize: '$3', + }, + medium: { + fontSize: '$body', + lineHeight: '$body', + height: '$12', + px: '$4', + svgSize: '$4', + }, + flexible: { + fontSize: '$body', + lineHeight: '$body', + height: 'initial', + px: '$4', + svgSize: '$4', + }, +} + +export const getValueForSize = ( + size: Size, + property: T, +): Properties[T] => { + return sizeMap[size]?.[property] || sizeMap.medium[property] +} diff --git a/components/src/components/atoms/Button/utils/withColorStyle.ts b/components/src/components/atoms/Button/utils/withColorStyle.ts new file mode 100644 index 00000000..8311c826 --- /dev/null +++ b/components/src/components/atoms/Button/utils/withColorStyle.ts @@ -0,0 +1,80 @@ +import { P, match } from 'ts-pattern' + +import { BaseColour, validateBaseColour } from '@/src/tokens/color3' + +type Shade = 'Primary' | 'Secondary' + +type ColorStyle = + | BaseColour + | `${BaseColour}${Shade}` + | 'background' + | 'disabled' + | 'transparent' + +export type WithColorStyle = { colorStyle: ColorStyle } + +type Properties = { + background: string + content: string + hover: string + border: string +} + +type Property = keyof Properties + +const getPrimaryColor = (color: BaseColour, property: Property): string => + match(property) + .with(P.union('background', 'border'), () => `$${color}Primary`) + .with('content', () => '$textAccent') + .with('hover', () => `$${color}Bright`) + .exhaustive() + +const getSecondaryColor = (color: BaseColour, property: Property): string => + match(property) + .with(P.union('background', 'border'), () => `$${color}Surface`) + .with('content', () => `$${color}Dim`) + .with('hover', () => `$${color}Light`) + .exhaustive() + +const getBackgroundColor = (property: Property): string => + match(property) + .with('background', () => '$backgroundPrimary') + .with('content', () => '$textSecondary') + .with('border', () => '$border') + .with('hover', () => '$greySurface') + .exhaustive() + +const getDisabledColor = (property: Property): string => + match(property) + .with('background', () => '$greyLight') + .with('content', () => '$textDisabled') + .with('border', () => '$greyLight') + .with('hover', () => '$greyLight') + .exhaustive() + +const getTransparentColor = (property: Property): string => + match(property) + .with('background', () => 'transparent') + .with('content', () => '$textPrimary') + .with('border', () => 'transparent') + .with('hover', () => '$greyLight') + .exhaustive() + +export const getValueForColourStyle = ( + colorStyle: ColorStyle, + property: Property, +): string => { + const matches = colorStyle.match('^(.*?)(Primary|Secondary)?$') + const color = matches?.[1] || 'accent' + const style = matches?.[2] + return match([color, style]) + .with([P._, 'Secondary'], ([color]) => + getSecondaryColor(validateBaseColour(color), property), + ) + .with(['background', P._], () => getBackgroundColor(property)) + .with(['disabled', P._], () => getDisabledColor(property)) + .with(['transparent', P._], () => getTransparentColor(property)) + .otherwise(([color]) => + getPrimaryColor(validateBaseColour(color), property), + ) +} diff --git a/components/src/components/atoms/Card/Card.tsx b/components/src/components/atoms/Card/Card.tsx index 875a4fe7..bbb08810 100644 --- a/components/src/components/atoms/Card/Card.tsx +++ b/components/src/components/atoms/Card/Card.tsx @@ -1,56 +1,45 @@ import * as React from 'react' -import styled, { css } from 'styled-components' - -import { mq } from '@/src/utils/responsiveHelpers' import { Typography } from '../Typography' +import { Box, BoxProps } from '../Box/Box' export type Props = { title?: string } & NativeDivProps -const Container = styled.div( - ({ theme }) => css` - display: flex; - flex-direction: column; - gap: ${theme.space['4']}; - - padding: ${theme.space['4']}; - border-radius: ${theme.radii['2xLarge']}; - background-color: ${theme.colors.backgroundPrimary}; - border: 1px solid ${theme.colors.border}; - - ${mq.sm.min( - css` - padding: ${theme.space['6']}; - `, - )} - `, +const ContainerBox = (props: BoxProps) => ( + ) -const Divider = styled.div( - ({ theme }) => css` - width: calc(100% + 2 * ${theme.space['4']}); - height: 1px; - background: ${theme.colors.border}; - margin: 0 -${theme.space['4']}; - ${mq.sm.min( - css` - margin: 0 -${theme.space['6']}; - width: calc(100% + 2 * ${theme.space['6']}); - `, - )} - `, +const Divider = (props: BoxProps) => ( + ) type NativeDivProps = React.HTMLAttributes export const Card = ({ title, children, ...props }: Props) => { return ( - + {title && {title}} {children} - + ) } diff --git a/components/src/components/atoms/DynamicPopover/DynamicPopover.tsx b/components/src/components/atoms/DynamicPopover/DynamicPopover.tsx index ee6b1ce5..2693e43b 100644 --- a/components/src/components/atoms/DynamicPopover/DynamicPopover.tsx +++ b/components/src/components/atoms/DynamicPopover/DynamicPopover.tsx @@ -7,6 +7,8 @@ import { debounce } from 'lodash' import { mq } from '@/src/utils/responsiveHelpers' import { Portal } from '../Portal' +import { Box, BoxProps } from '../Box/Box' +import { getValueForTransitionState } from './utils/getValueForTransitionState' export type DynamicPopoverSide = 'top' | 'right' | 'bottom' | 'left' @@ -139,6 +141,66 @@ const checkRectContainsPoint = ( const makeWidth = (width: number | string) => typeof width === 'number' ? `${width}px` : width +const PopoverBox = React.forwardRef( + ( + { + $state, + $translate, + $mobileTranslate, + $width, + $mobileWidth, + $x, + $y, + // $isControlled, + $transitionDuration, + $hideOverflow, + ...props + }: BoxProps & { + $state: TransitionState + $translate: string + $mobileTranslate: string + $width: number | string + $mobileWidth: number | string + $x: number + $y: number + $isControlled: boolean + $transitionDuration: number + $hideOverflow: boolean | undefined + }, + ref, + ) => ( + + ), +) + +// eslint-disable-next-line @typescript-eslint/no-unused-vars const PopoverContainer = styled.div<{ $state: TransitionState $translate: string @@ -490,7 +552,7 @@ export const DynamicPopover = ({ return ( - + ) } diff --git a/components/src/components/atoms/DynamicPopover/utils/getValueForTransitionState.ts b/components/src/components/atoms/DynamicPopover/utils/getValueForTransitionState.ts new file mode 100644 index 00000000..5bb7d7fc --- /dev/null +++ b/components/src/components/atoms/DynamicPopover/utils/getValueForTransitionState.ts @@ -0,0 +1,84 @@ +import { TransitionState } from 'react-transition-state' + +const transitionStateValues: { + [key in TransitionState]: { + display: string + visibility: string + opacity: number + transitionProperty: string + pointerEvents: string + topFunc: (x: number) => string + leftFunc: (y: number) => string + } +} = { + unmounted: { + display: 'block', + visibility: 'hidden', + opacity: 0, + transitionProperty: 'none', + pointerEvents: 'none', + topFunc: () => `0px`, + leftFunc: () => `0px`, + }, + preEnter: { + display: 'block', + visibility: 'visible', + opacity: 0, + transitionProperty: 'none', + pointerEvents: 'none', + topFunc: (x: number) => `${x}px`, + leftFunc: (y: number) => `${y}px`, + }, + entering: { + display: 'block', + visibility: 'visible', + opacity: 1, + transitionProperty: 'all', + pointerEvents: 'auto', + topFunc: (x: number) => `${x}px`, + leftFunc: (y: number) => `${y}px`, + }, + entered: { + display: 'block', + visibility: 'visible', + opacity: 1, + transitionProperty: 'all', + topFunc: (x: number) => `${x}px`, + leftFunc: (y: number) => `${y}px`, + pointerEvents: 'auto', + }, + preExit: { + display: 'block', + visibility: 'visible', + opacity: 0, + transitionProperty: 'all', + topFunc: (x: number) => `${x}px`, + leftFunc: (y: number) => `${y}px`, + pointerEvents: 'none', + }, + exiting: { + display: 'block', + visibility: 'visible', + opacity: 0, + transitionProperty: 'all', + topFunc: (x: number) => `${x}px`, + leftFunc: (y: number) => `${y}px`, + pointerEvents: 'none', + }, + exited: { + display: 'block', + visibility: 'hidden', + opacity: 0, + transitionProperty: 'none', + topFunc: () => `0px`, + leftFunc: () => `0px`, + pointerEvents: 'none', + }, +} + +type Property = keyof typeof transitionStateValues['unmounted'] + +export const getValueForTransitionState = ( + state: TransitionState, + property: Property, +): any => transitionStateValues[state][property] diff --git a/components/src/components/atoms/Field/Field.tsx b/components/src/components/atoms/Field/Field.tsx index e569863f..8dc2a25f 100644 --- a/components/src/components/atoms/Field/Field.tsx +++ b/components/src/components/atoms/Field/Field.tsx @@ -1,6 +1,6 @@ import * as React from 'react' -import styled, { css } from 'styled-components' +import { P, match } from 'ts-pattern' import { Space } from '@/src/tokens' @@ -8,6 +8,7 @@ import { ReactNodeNoStrings } from '../../../types' import { useFieldIds } from '../../../hooks' import { VisuallyHidden } from '../VisuallyHidden' import { Typography } from '../Typography/Typography' +import { Box, BoxProps } from '../Box/Box' export type State = ReturnType | undefined const Context = React.createContext(undefined) @@ -45,67 +46,70 @@ type Props = FieldBaseProps & { disabled?: boolean } & Omit -const Label = styled.label<{ +const RequiredBox = () => ( + + * + +) + +const LabelBox = ({ + $disabled = false, + $readOnly = false, + $required, + children, + ...props +}: BoxProps & { $disabled?: boolean $readOnly?: boolean $required?: boolean -}>( - ({ theme, $disabled, $readOnly, $required }) => css` - display: flex; - flex-basis: auto; - flex-grow: 2; - flex-shrink: 1; - overflow: hidden; - position: relative; - cursor: pointer; - - ${$readOnly && - css` - cursor: default; - pointer-events: none; - `} - - ${$disabled && - css` - cursor: not-allowed; - `} - - ${$required && - css` - ::after { - content: ' *'; - white-space: pre; - color: ${theme.colors.red}; - } - `} - `, +}) => ( + 'not-allowed') + .with([false, true], () => 'none') + .with([false, false], () => 'pointer') + .exhaustive()} + display="flex" + flexBasis="$auto" + flexGrow="2" + flexShrink="1" + overflow="hidden" + position="relative" + {...props} + > + {children} + {$required && } + ) -const InnerLabel = styled(Typography)( - () => css` - width: 100%; - `, +const InnerLabelBox = (props: React.ComponentProps) => ( + ) -const SecondaryLabel = styled(Typography)( - () => css` - flex-basis: auto; - flex-grow: 0; - flex-shrink: 2; - text-align: right; - overflow: hidden; - position: relative; - `, +const SecondaryLabelBox = (props: React.ComponentProps) => ( + ) -const LabelContentContainer = styled.div<{ $inline?: boolean }>( - ({ theme, $inline }) => css` - display: flex; - align-items: center; - padding: 0 ${$inline ? '0' : theme.space['2']}; - overflow: hidden; - gap: ${theme.space['2']}; - `, +const LabelContentContainerBox = ({ + $inline, + ...props +}: BoxProps & { $inline?: boolean }) => ( + ) const LabelContent = ({ @@ -128,42 +132,54 @@ const LabelContent = ({ readOnly?: boolean }) => { const content = ( - - + + {labelSecondary && ( - + {labelSecondary} - + )} - + ) if (hideLabel) return {content} return content } -const Description = styled(Typography)<{ $inline?: boolean }>( - ({ theme, $inline }) => css` - padding: 0 ${$inline ? '0' : theme.space['2']}; - width: 100%; - overflow: hidden; - `, +const DescriptionBox = ({ + $inline, + ...props +}: React.ComponentProps & { $inline: boolean }) => ( + ) -const Error = styled(Typography)<{ $inline?: boolean }>( - ({ theme, $inline }) => ` - padding: 0 ${$inline ? '0' : theme.space[2]}; -`, +const ErrorBox = ({ + $inline, + ...props +}: React.ComponentProps & { $inline: boolean }) => ( + ) + const DecorativeContent = ({ ids, error, @@ -182,7 +198,7 @@ const DecorativeContent = ({ if (hideLabel) return null if (error) return ( - {error} - + ) if (description) return ( - {description} - + ) return null } @@ -214,32 +230,37 @@ interface ContainerProps { $reverse?: boolean } -const Container = styled.div( - ({ theme, $inline, $width, $reverse }) => css` - position: relative; - display: flex; - flex-direction: column; - justify-content: flex-start; - align-items: 'normal'; - gap: ${theme.space['2']}; - width: ${theme.space[$width]}; - - ${$inline && - css` - flex-direction: ${$reverse ? 'row-reverse' : 'row'}; - align-items: 'flex-start'; - `} - `, +const ContainerBox = ({ + $width, + $inline, + $reverse, + ...props +}: BoxProps & ContainerProps) => ( + 'row-reverse' as const) + .with([true, false], () => 'row' as const) + .with([false, P._], () => 'column' as const) + .exhaustive()} + gap="$2" + justifyContent="flex-start" + position="relative" + width={$width} + {...props} + /> ) -const ContainerInner = styled.div( - ({ theme }) => css` - display: flex; - flex-direction: column; - gap: ${theme.space[1]}; - flex: 1; - overflow: hidden; - `, +const ContainerInnerBox = (props: BoxProps) => ( + ) export const Field = ({ @@ -299,21 +320,21 @@ export const Field = ({ if (inline) return ( - +
{content}
- + {labelContent} {decorativeContent} - -
+ + ) return ( - + {labelContent} {content} {decorativeContent} - + ) } diff --git a/components/src/components/atoms/Heading/Heading.tsx b/components/src/components/atoms/Heading/Heading.tsx index 99ad5a71..d64d22f3 100644 --- a/components/src/components/atoms/Heading/Heading.tsx +++ b/components/src/components/atoms/Heading/Heading.tsx @@ -1,8 +1,9 @@ import * as React from 'react' -import styled, { css } from 'styled-components' -import { mq } from '@/src/utils/responsiveHelpers' -import { WithColor, getColor } from '@/src/types/withColorOrColorStyle' +import { WithColor } from '@/src/types/withColorOrColorStyle' + +import { Box, BoxProps } from '../Box/Box' +import { getValueForLevel } from './utils/getValueForLevel' interface HeadingContainerProps { $textAlign?: React.CSSProperties['textAlign'] @@ -12,72 +13,26 @@ interface HeadingContainerProps { $color: NonNullable } -const HeadingContainer = styled.div( - ({ theme, $textAlign, $textTransform, $level, $responsive, $color }) => css` - ${$textAlign - ? css` - text-align: ${$textAlign}; - ` - : ``} - ${$textTransform - ? css` - text-transform: ${$textTransform}; - ` - : ``} - - ${() => { - switch ($level) { - case '1': - return css` - font-size: ${theme.fontSizes.headingOne}; - font-weight: ${theme.fontWeights.extraBold}; - line-height: ${theme.lineHeights.headingOne}; - ` - case '2': - return css` - font-size: ${theme.fontSizes.headingTwo}; - font-weight: ${theme.fontWeights.bold}; - line-height: ${theme.lineHeights.headingTwo}; - ` - default: - return `` - } - }} - - ${() => { - if ($responsive) { - switch ($level) { - case '1': - return css` - font-size: ${theme.fontSizes.headingTwo}; - line-height: ${theme.lineHeights.headingTwo}; - ${mq.lg.min(css` - font-size: ${theme.fontSizes.headingOne}; - line-height: ${theme.lineHeights.headingOne}; - `)} - ` - case '2': - return css` - font-size: ${theme.fontSizes.extraLarge}; - line-height: ${theme.lineHeights.extraLarge}; - ${mq.sm.min(css` - font-size: ${theme.fontSizes.headingTwo}; - line-height: ${theme.lineHeights.headingTwo}; - `)} - ` - default: - return `` - } - } - }} - - ${$color && - css` - color: ${getColor($color)}; - `} - - font-family: ${theme.fonts['sans']}; - `, +const ContainerBox = React.forwardRef< + HTMLElement, + BoxProps & HeadingContainerProps +>( + ( + { $textAlign, $textTransform, $level, $responsive, $color, ...props }, + ref, + ) => ( + + ), ) type NativeDivAttributes = React.HTMLAttributes @@ -113,7 +68,7 @@ export const Heading = React.forwardRef( }: Props, ref: React.ForwardedRef, ) => ( - {children} - + ), ) diff --git a/components/src/components/atoms/Heading/utils/getValueForLevel.ts b/components/src/components/atoms/Heading/utils/getValueForLevel.ts new file mode 100644 index 00000000..3b327cae --- /dev/null +++ b/components/src/components/atoms/Heading/utils/getValueForLevel.ts @@ -0,0 +1,24 @@ +type Property = 'fontSize' | 'fontWeight' | 'lineHeight' + +const levelMap = { + 1: { + fontSize: { xs: '$headingTwo', lg: '$headingOne' }, + fontWeight: { xs: '$extraBold', lg: '$extraBold' }, + lineHeight: { xs: '$headingTwo', lg: '$headingOne' }, + }, + 2: { + fontSize: { xs: '$extraLarge', sm: '$headingTwo' }, + fontWeight: { xs: '$bold', sm: '$bold' }, + lineHeight: { xs: '$extraLarge', sm: '$headingTwo' }, + }, +} + +export const getValueForLevel = ( + level: '1' | '2', + property: Property, + responsive = false, +) => { + const value = levelMap[level][property] + if (responsive) return value + return (value as any).lg || (value as any).sm +} diff --git a/components/src/components/atoms/RecordItem/RecordItem.tsx b/components/src/components/atoms/RecordItem/RecordItem.tsx index 34c7a123..e7673a4e 100644 --- a/components/src/components/atoms/RecordItem/RecordItem.tsx +++ b/components/src/components/atoms/RecordItem/RecordItem.tsx @@ -1,13 +1,15 @@ import * as React from 'react' -import styled, { css } from 'styled-components' import { ReactNode } from 'react' +import { match } from 'ts-pattern' + import { CheckSVG, CopySVG, UpArrowSVG } from '@/src' import { Neverable } from '@/src/types' import { Typography } from '../Typography/Typography' import { useCopied } from '../../../hooks/useCopied' +import { Box, BoxProps } from '../Box/Box' type Size = 'small' | 'large' @@ -52,113 +54,97 @@ export type Props = BaseProps & NativeElementProps & (AsAnchorProps | AsButtonProps) -const Container = styled.button<{ - $inline: boolean -}>( - ({ theme, $inline }) => css` - display: flex; - align-items: flex-start; - - gap: ${theme.space[2]}; - padding: ${theme.space['2.5']} ${theme.space[3]}; - width: 100%; - height: fit-content; - background: ${theme.colors.greySurface}; - border: 1px solid ${theme.colors.border}; - border-radius: ${theme.radii.large}; - transition: all 150ms ease-in-out; - cursor: pointer; - - ${$inline && - css` - width: fit-content; - height: ${theme.space['10']}; - `} - - &:hover { - transform: translateY(-1px); - background: ${theme.colors.greyLight}; - } - `, -) - -const PrefixContainer = styled.div<{ $size: Size; $inline: boolean }>( - ({ theme, $inline, $size }) => css` - display: flex; - gap: ${theme.space[2]}; - align-items: flex-start; - width: ${$size === 'large' ? theme.space['30'] : theme.space['22.5']}; - flex: 0 0 ${$size === 'large' ? theme.space['30'] : theme.space['22.5']}; - - ${$inline && - css` - width: fit-content; - flex: initial; - `} - `, +const ContainerBox = ({ + $inline, + ...props +}: BoxProps & { $inline: boolean }) => ( + ) -const PrefixLabelsContainer = styled.div<{ $inline: boolean }>( - ({ theme, $inline }) => css` - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 0; - overflow: hidden; - - ${$inline && - css` - flex-direction: row; - gap: ${theme.space[2]}; - align-items: center; - `} - `, +const PrefixBox = ({ + $inline, + $size, + ...props +}: BoxProps & { $inline: boolean; $size: Size }) => ( + 'initial') + .otherwise(() => ($size === 'large' ? '$30' : '$22.5'))} + flexGrow="0" + flexShrink="0" + gap="$2" + width={match($inline) + .with(true, () => 'fit-content' as const) + .otherwise(() => ($size === 'large' ? '$30' : '$22.5'))} + {...props} + /> ) -const PrefixLabel = styled(Typography)<{ - $inline: boolean -}>( - () => css` - text-align: left; - width: 100%; - `, +const PrefixLabelsContainerBox = ({ + $inline, + ...props +}: BoxProps & { $inline: boolean }) => ( + ) -const PrefixIcon = styled.div( - ({ theme }) => css` - svg { - display: block; - width: ${theme.space['5']}; - height: ${theme.space['5']}; - } - `, -) +// const PrefixLabelBox = (props: BoxProps) => ( +// +// ) -const Label = styled(Typography)<{ $inline: boolean }>( - ({ $inline }) => css` - flex: 1; - text-align: left; - word-break: break-all; - - ${$inline && - css` - word-break: initial; - `} - `, +const PrefixSVGBox = (props: BoxProps) => ( + ) -const TrailingIcon = styled.svg<{ $rotate?: boolean }>( - ({ theme, $rotate }) => css` - display: block; - margin-top: ${theme.space['1']}; - width: ${theme.space['3']}; - height: ${theme.space['3']}; - color: ${theme.colors.greyPrimary}; - ${$rotate && - css` - transform: rotate(45deg); - `} - `, +// const LabelBox = ({ $inline, ...props }: BoxProps & { $inline: boolean }) => ( +// +// ) + +const TrailingSVGBox = ({ + $rotate, + ...props +}: BoxProps & { $rotate: boolean }) => ( + ) export const RecordItem = ({ @@ -195,28 +181,30 @@ export const RecordItem = ({ const KeyLabel = typeof keyLabel === 'string' ? ( - {keyLabel} - + ) : ( keyLabel ) const KeySublabel = typeof keySublabel === 'string' ? ( - {keySublabel} - + ) : ( keySublabel ) @@ -227,23 +215,28 @@ export const RecordItem = ({ : { as: CopySVG } return ( - + {hasPrefix && ( - - {icon && {icon}} + + {icon && } {hasLabels && ( - + {KeyLabel} {KeySublabel} - + )} - + )} - - - +
+ + ) } diff --git a/components/src/components/atoms/ScrollBox/ScrollBox.tsx b/components/src/components/atoms/ScrollBox/ScrollBox.tsx index 4381bfb0..8a70dac8 100644 --- a/components/src/components/atoms/ScrollBox/ScrollBox.tsx +++ b/components/src/components/atoms/ScrollBox/ScrollBox.tsx @@ -1,93 +1,43 @@ import * as React from 'react' -import styled, { css } from 'styled-components' -const StyledScrollBox = styled.div<{ $showTop: boolean; $showBottom: boolean }>( - ({ theme, $showTop, $showBottom }) => css` - overflow: auto; - position: relative; - - border-color: ${theme.colors.greyLight}; - transition: border-color 0.15s ease-in-out; - - /* stylelint-disable-next-line selector-pseudo-element-no-unknown */ - &::-webkit-scrollbar-track { - background-color: transparent; - } - - &::-webkit-scrollbar { - background-color: transparent; - } - - &::-webkit-scrollbar:vertical { - width: ${theme.space['1.5']}; - background-color: transparent; - } - - &::-webkit-scrollbar:horizontal { - height: ${theme.space['1.5']}; - background-color: transparent; - } - - &::-webkit-scrollbar-thumb:vertical { - border: none; - border-radius: ${theme.radii.full}; - border-right-style: inset; - border-right-width: calc(100vw + 100vh); - border-color: inherit; - } - - &::-webkit-scrollbar-thumb:horizontal { - border: none; - border-radius: ${theme.radii.full}; - border-bottom-style: inset; - border-bottom-width: calc(100vw + 100vh); - border-color: inherit; - } - - &::-webkit-scrollbar-button { - display: none; - } - - &:hover { - border-color: ${theme.colors.greyBright}; - } - - &::before, - &::after { - content: ''; - position: sticky; - left: 0; - width: 100%; - display: block; - height: ${theme.space.px}; - background-color: hsla(${theme.colors.raw.greyLight} / 0); - transition: background-color 0.15s ease-in-out; - } - - &::before { - top: 0; - ${$showTop && - css` - background-color: hsla(${theme.colors.raw.greyLight} / 1); - z-index: 100; - `} - } - &::after { - bottom: 0; - ${$showBottom && - css` - background-color: hsla(${theme.colors.raw.greyLight} / 1); - z-index: 100; - `} - } - `, -) - -const IntersectElement = styled.div( - () => css` - display: block; - height: 0px; - `, +import * as styles from './styles.css' +import { Box, BoxProps } from '../Box/Box' + +const ScrollBoxBox = React.forwardRef((props, ref) => ( + +)) + +const DividerBox = ({ + show, + position, +}: { + show: boolean + position: 'top' | 'bottom' +}) => ( + ) type Props = { @@ -96,7 +46,7 @@ type Props = { bottomTriggerPx?: number onReachedTop?: () => void onReachedBottom?: () => void -} & React.HTMLAttributes +} & BoxProps export const ScrollBox = ({ hideDividers = false, @@ -125,8 +75,8 @@ export const ScrollBox = ({ const [showBottom, setShowBottom] = React.useState(false) const handleIntersect: IntersectionObserverCallback = (entries) => { - const intersectingTop = [false, -1] - const intersectingBottom = [false, -1] + const intersectingTop: [boolean, number] = [false, -1] + const intersectingBottom: [boolean, number] = [false, -1] for (let i = 0; i < entries.length; i += 1) { const entry = entries[i] const iref = @@ -169,18 +119,28 @@ export const ScrollBox = ({ }, [onReachedTop, onReachedBottom]) return ( - - + + {children} - - + + ) } diff --git a/components/src/components/atoms/ScrollBox/styles.css.ts b/components/src/components/atoms/ScrollBox/styles.css.ts new file mode 100644 index 00000000..d2a0a8ae --- /dev/null +++ b/components/src/components/atoms/ScrollBox/styles.css.ts @@ -0,0 +1,44 @@ +import { style } from '@vanilla-extract/css' + +import { commonVars, modeVars } from '@/src/css/theme.css' + +export const scrollBox = style({ + borderColor: modeVars.color.greyLight, + selectors: { + '&::-webkit-scrollbar-track': { + backgroundColor: 'transparent', + }, + '&::-webkit-scrollbar': { + backgroundColor: 'transparent', + }, + '&::-webkit-scrollbar:vertical': { + width: commonVars.space['1.5'], + backgroundColor: 'transparent', + }, + '&::-webkit-scrollbar:horizontal': { + height: commonVars.space['1.5'], + backgroundColor: 'transparent', + }, + '&::-webkit-scrollbar-thumb': { + borderColor: 'inherit!important', + }, + '&::-webkit-scrollbar-thumb:vertical': { + border: 'none', + borderRadius: '99999999999px', + borderRightStyle: 'inset', + borderRightWidth: 'calc(100vw + 100vh)', + }, + '&::-webkit-scrollbar-thumb:horizontal': { + border: 'none', + borderRadius: '99999999999px', + borderRightStyle: 'inset', + borderRightWidth: 'calc(100vw + 100vh)', + }, + '&::-webkit-scrollbar-button': { + display: 'none', + }, + '&:hover': { + borderColor: modeVars.color.greyBright, + }, + }, +}) diff --git a/components/src/components/atoms/Skeleton/Skeleton.tsx b/components/src/components/atoms/Skeleton/Skeleton.tsx index 10e05bf1..1b8afb8c 100644 --- a/components/src/components/atoms/Skeleton/Skeleton.tsx +++ b/components/src/components/atoms/Skeleton/Skeleton.tsx @@ -1,50 +1,11 @@ import * as React from 'react' -import styled, { css, keyframes } from 'styled-components' -import { Context } from '../../molecules/SkeletonGroup' - -interface ContainerProps { - $active?: boolean -} +import classNames from 'clsx' -const shine = keyframes` - to { - background-position-x: -200%; - } -` +import * as styles from './styles.css' -const Container = styled.div( - ({ theme, $active }) => css` - ${$active && - css` - background: ${theme.colors.greyLight} - linear-gradient( - 110deg, - ${theme.colors.greyLight} 8%, - ${theme.colors.greySurface} 18%, - ${theme.colors.greyLight} 33% - ); - background-size: 200% 100%; - animation: 1.5s ${shine} infinite linear; - border-radius: ${theme.radii.medium}; - width: ${theme.space.fit}; - `} - `, -) - -const ContainerInner = styled.span<{ $active?: boolean }>( - ({ $active }) => css` - display: block; - ${$active - ? css` - visibility: hidden; - * { - visibility: hidden !important; - } - ` - : ``} - `, -) +import { Context } from '../../molecules/SkeletonGroup' +import { Box } from '../Box/Box' type NativeDivProps = React.HTMLAttributes @@ -60,9 +21,13 @@ export const Skeleton = ({ as, children, loading, ...props }: Props) => { const active = loading ?? groupLoading return ( - - {children} - + + {children} + ) } diff --git a/components/src/components/atoms/Skeleton/styles.css.ts b/components/src/components/atoms/Skeleton/styles.css.ts new file mode 100644 index 00000000..292c9d79 --- /dev/null +++ b/components/src/components/atoms/Skeleton/styles.css.ts @@ -0,0 +1,26 @@ +import { keyframes, style } from '@vanilla-extract/css' + +import { commonVars, modeVars } from '@/src/css/theme.css' + +const shine = keyframes({ + to: { + backgroundPositionX: '-200%', + }, +}) + +export const animations = style({ + backgroundColor: modeVars.color.greyLight, + backgroundImage: `linear-gradient( + 90deg, + ${modeVars.color.greyLight} 0px, + ${modeVars.color.greySurface} 18%, + ${modeVars.color.greyLight} 33% + )`, + backgroundSize: '200% 100%', + animationName: shine, + animationDuration: '1.5s', + animationTimingFunction: 'linear', + animationIterationCount: 'infinite', + borderRadius: commonVars.radii.medium, + width: 'fit-content', +}) diff --git a/components/src/components/atoms/Spinner/Spinner.tsx b/components/src/components/atoms/Spinner/Spinner.tsx index aebb4017..dc9cd5cf 100644 --- a/components/src/components/atoms/Spinner/Spinner.tsx +++ b/components/src/components/atoms/Spinner/Spinner.tsx @@ -1,9 +1,10 @@ import * as React from 'react' -import styled, { css, keyframes } from 'styled-components' - -import { Colors } from '@/src/tokens' +import { Color, validateColor } from './utils/withColor' import { VisuallyHidden } from '../VisuallyHidden' +import * as styles from './styles.css' +import { Box, BoxProps } from '../Box/Box' +import { getValueForSize } from './utils/getValueForSize' type NativeDivProps = React.HTMLAttributes type Size = 'small' | 'medium' | 'large' @@ -11,88 +12,68 @@ type Props = { /** Hidden text used for accessibilty. */ accessibilityLabel?: string /** A tokens 'mode' color value */ - color?: Colors + color?: Color size?: Size } & Omit -const rotate = keyframes` - 100% { - transform: rotate(1turn); - } -` - -const Container = styled.div<{ $size: Size; $color?: Colors }>( - ({ theme, $color, $size }) => css` - animation: ${rotate} 1.1s linear infinite; - - ${$color && - css` - color: ${theme.colors[$color]}; - `} - - ${() => { - switch ($size) { - case 'small': - return css` - height: ${theme.space['4']}; - width: ${theme.space['4']}; - stroke-width: ${theme.space['1']}; - ` - case 'medium': - return css` - height: ${theme.space['6']}; - stroke-width: ${theme.space['1.25']}; - width: ${theme.space['6']}; - ` - case 'large': - return css` - height: ${theme.space['16']}; - stroke-width: ${theme.space['1']}; - width: ${theme.space['16']}; - ` - default: - return `` - } - }} +const ContainerBox = React.forwardRef< + HTMLElement, + BoxProps & { $size: Size; $color?: Color } +>(({ $size, $color, ...props }, ref) => ( + +)) - svg { - display: block; - stroke: currentColor; - height: 100%; - width: 100%; - } - `, +const svg = ( + + + + ) export const Spinner = React.forwardRef( ( - { accessibilityLabel, size = 'small', color = 'text', ...props }: Props, + { accessibilityLabel, size = 'small', color, ...props }: Props, ref: React.Ref, ) => { return ( - + {accessibilityLabel && ( {accessibilityLabel} )} - - - - - + + ) }, ) diff --git a/components/src/components/atoms/Spinner/styles.css.ts b/components/src/components/atoms/Spinner/styles.css.ts new file mode 100644 index 00000000..1990e464 --- /dev/null +++ b/components/src/components/atoms/Spinner/styles.css.ts @@ -0,0 +1,14 @@ +import { keyframes, style } from '@vanilla-extract/css' + +const rotate = keyframes({ + '100%': { + transform: 'rotate(1turn)', + }, +}) + +export const animation = style({ + animationName: rotate, + animationDuration: '1.1s', + animationTimingFunction: 'linear', + animationIterationCount: 'infinite', +}) diff --git a/components/src/components/atoms/Spinner/utils/getValueForSize.ts b/components/src/components/atoms/Spinner/utils/getValueForSize.ts new file mode 100644 index 00000000..138a01d9 --- /dev/null +++ b/components/src/components/atoms/Spinner/utils/getValueForSize.ts @@ -0,0 +1,21 @@ +const sizesMap = { + small: { + size: '$4', + strokeWidth: '$1', + }, + medium: { + size: '$6', + strokeWidth: '$1.25', + }, + large: { + size: '$16', + strokeWidth: '$1', + }, +} + +export const getValueForSize = ( + size: 'small' | 'medium' | 'large', + property: 'size' | 'strokeWidth', +) => { + return sizesMap[size]?.[property] || sizesMap.small[property] +} diff --git a/components/src/components/atoms/Spinner/utils/withColor.ts b/components/src/components/atoms/Spinner/utils/withColor.ts new file mode 100644 index 00000000..13721316 --- /dev/null +++ b/components/src/components/atoms/Spinner/utils/withColor.ts @@ -0,0 +1,20 @@ +import { + ADDITIONAL_COLORS, + AdditionalColour, + BASE_COLOURS, + BaseColour, + SHADED_COLORS, + ShadedColor, +} from '@/src/tokens/color3' + +export type Color = BaseColour | ShadedColor | AdditionalColour + +export type WithColor = { color: Color } + +const COLORS = [...BASE_COLOURS, ...SHADED_COLORS, ...ADDITIONAL_COLORS] + +export const validateColor = (color: unknown, fallback = 'unset') => { + if (!color) return fallback + if (COLORS.includes(color as Color)) return `$${color}` + return fallback +} diff --git a/components/src/components/atoms/Tag/Tag.tsx b/components/src/components/atoms/Tag/Tag.tsx index 8a40b090..c78879cb 100644 --- a/components/src/components/atoms/Tag/Tag.tsx +++ b/components/src/components/atoms/Tag/Tag.tsx @@ -1,8 +1,8 @@ import * as React from 'react' -import { WithColorStyle } from '@/src/types/withColorOrColorStyle' +import { translateY } from '@/src/css/utils/common' -import { getColorStyle } from '../../../css/utils/getColorStyle' +import { WithColorStyle, getValueForColorStyle } from './utils/withColorStyle' import { Box } from '../Box/Box' @@ -31,12 +31,15 @@ export const Tag = ({ alignItems="center" as={as} backgroundColor={{ - base: getColorStyle(colorStyle as any, 'background'), - hover: getColorStyle(colorStyle as any, hover ? 'hover' : 'background'), - active: getColorStyle(colorStyle as any, 'hover'), + base: getValueForColorStyle(colorStyle, 'background'), + hover: getValueForColorStyle( + colorStyle as any, + hover ? 'hover' : 'background', + ), + active: getValueForColorStyle(colorStyle, 'hover'), }} borderRadius="$full" - color={getColorStyle(colorStyle as any, 'text')} + color={getValueForColorStyle(colorStyle, 'content')} display="flex" fontSize={size === 'small' ? '$extraSmall' : '$small'} fontWeight="$bold" @@ -44,12 +47,12 @@ export const Tag = ({ px="$2" py="$0.5" transform={{ - hover: hover ? 'translateY(-1px)' : 'translateY(0px)', - base: 'translateY(0px)', - active: 'translateY(-1px)', + base: translateY(0), + hover: translateY(hover ? -1 : 0), + active: translateY(-1), }} transitionDuration="$150" - transitionProperty="color, border-color, background-color" + transitionProperty="color, border-color, background-color, transform" transitionTimingFunction="$inOut" width="$max" {...props} diff --git a/components/src/components/atoms/Tag/utils/withColorStyle.ts b/components/src/components/atoms/Tag/utils/withColorStyle.ts new file mode 100644 index 00000000..26094fb3 --- /dev/null +++ b/components/src/components/atoms/Tag/utils/withColorStyle.ts @@ -0,0 +1,47 @@ +import { P, match } from 'ts-pattern' + +import { BaseColour, validateBaseColour } from '@/src/tokens/color3' + +type Shade = 'Primary' | 'Secondary' + +type ColorStyle = BaseColour | `${BaseColour}${Shade}` + +export type WithColorStyle = { colorStyle?: ColorStyle } + +type Properties = { + background: string + content: string + hover: string +} + +type Property = keyof Properties + +const getPrimaryColor = (color: BaseColour, property: Property): string => + match(property) + .with('background', () => `$${color}Primary`) + .with('content', () => '$textAccent') + .with('hover', () => `$${color}Bright`) + .exhaustive() + +const getSecondaryColor = (color: BaseColour, property: Property): string => + match(property) + .with('background', () => `$${color}Surface`) + .with('content', () => `$${color}Primary`) + .with('hover', () => `$${color}Light`) + .exhaustive() + +export const getValueForColorStyle = ( + colorStyle: ColorStyle, + property: Property, +): string => { + const matches = colorStyle.match('^(.*?)(Primary|Secondary)?$') + const color = matches?.[1] || 'accent' + const style = matches?.[2] + return match([color, style]) + .with([P._, 'Secondary'], ([color]) => + getSecondaryColor(validateBaseColour(color), property), + ) + .otherwise(([color]) => + getPrimaryColor(validateBaseColour(color), property), + ) +} diff --git a/components/src/components/atoms/Typography/Typography.tsx b/components/src/components/atoms/Typography/Typography.tsx index b6a0b1c1..9645d678 100644 --- a/components/src/components/atoms/Typography/Typography.tsx +++ b/components/src/components/atoms/Typography/Typography.tsx @@ -1,55 +1,42 @@ import * as React from 'react' -import styled, { css } from 'styled-components' import { Font, FontSize, FontWeight } from '@/src/tokens/typography' -import { - WithTypography, - getFontSize, - getFontWeight, - getLineHeight, -} from '@/src/types/withTypography' -import { WithColor, getColor } from '@/src/types/withColorOrColorStyle' +import { Color, WithColor, validateColor } from '@/src/interfaces/withColor' + +import { Box, BoxProps } from '../Box/Box' +import { FontVariant, getValueForVariant } from './utils/getValueForVariant' type ContainerProps = { $ellipsis?: boolean - $fontVariant: WithTypography['fontVariant'] + $fontVariant: FontVariant $size?: FontSize - $color: NonNullable + $color: Color $weight?: FontWeight $font: Font } -const Container = styled.div( - ({ theme, $ellipsis, $fontVariant = 'body', $color, $font, $weight }) => css` - font-family: ${theme.fonts.sans}; - line-height: ${theme.lineHeights.body}; - color: ${getColor($color)}; - - ${$ellipsis && - css` - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - `} - - ${$fontVariant && - css` - font-size: ${getFontSize($fontVariant)}; - font-weight: ${getFontWeight($fontVariant)}; - line-height: ${getLineHeight($fontVariant)}; - `} - - ${$font === 'mono' && - css` - font-family: ${theme.fonts.mono}; - `} - - ${$weight && - css` - font-weight: ${theme.fontWeights[$weight]}; - `}; - `, +const ContainerBox = React.forwardRef( + ( + { $ellipsis, $fontVariant = 'body', $color, $font, $weight, ...props }, + ref, + ) => ( + + ), ) type NativeDivProps = React.HTMLAttributes @@ -78,9 +65,11 @@ type Props = { font?: Font /** A weight value that overrides existing weight property */ weight?: FontWeight + + fontVariant?: FontVariant } & Omit & - WithTypography & - WithColor + WithColor & + Omit & { fontVariant?: FontVariant } export const Typography = React.forwardRef( ( @@ -88,17 +77,18 @@ export const Typography = React.forwardRef( asProp, children, ellipsis, - className, + className = '', fontVariant = 'body', font = 'sans', - color = 'text', + color = 'textPrimary', weight, ...props }, ref, ) => { + console.log('className', className) return ( - ( ref={ref} > {children} - + ) }, ) diff --git a/components/src/components/atoms/Typography/utils/getValueForVariant.ts b/components/src/components/atoms/Typography/utils/getValueForVariant.ts new file mode 100644 index 00000000..ca30496b --- /dev/null +++ b/components/src/components/atoms/Typography/utils/getValueForVariant.ts @@ -0,0 +1,117 @@ +import { FontSize } from '@/src/tokens/typography' + +type LegacyFont = 'label' | 'labelHeading' + +type HeadingFont = Extract< + FontSize, + 'headingOne' | 'headingTwo' | 'headingThree' | 'headingFour' +> + +type VariableFont = Exclude< + FontSize, + 'headingOne' | 'headingTwo' | 'headingThree' | 'headingFour' +> + +export type FontVariant = + | LegacyFont + | HeadingFont + | VariableFont + | `${VariableFont}Bold` + +type Properties = { + fontSize: string + lineHeight: string + fontWeight: string +} + +type Property = keyof Properties + +const variantMap: { [key in FontVariant]: Properties } = { + label: { + fontSize: '$extraSmall', + lineHeight: '$extraSmall', + fontWeight: '$normal', + }, + labelHeading: { + fontSize: '$small', + lineHeight: '$small', + fontWeight: '$normal', + }, + headingOne: { + fontSize: '$headingOne', + lineHeight: '$headingOne', + fontWeight: '$extraBold', + }, + headingTwo: { + fontSize: '$headingTwo', + lineHeight: '$headingTwo', + fontWeight: '$bold', + }, + headingThree: { + fontSize: '$headingThree', + lineHeight: '$headingThree', + fontWeight: '$bold', + }, + headingFour: { + fontSize: '$headingFour', + lineHeight: '$headingFour', + fontWeight: '$bold', + }, + extraLargeBold: { + fontSize: '$extraLarge', + lineHeight: '$extraLarge', + fontWeight: '$bold', + }, + extraLarge: { + fontSize: '$extraLarge', + lineHeight: '$extraLarge', + fontWeight: '$normal', + }, + largeBold: { + fontSize: '$large', + lineHeight: '$large', + fontWeight: '$bold', + }, + large: { + fontSize: '$large', + lineHeight: '$large', + fontWeight: '$normal', + }, + bodyBold: { + fontSize: '$body', + lineHeight: '$body', + fontWeight: '$bold', + }, + body: { + fontSize: '$body', + lineHeight: '$body', + fontWeight: '$normal', + }, + smallBold: { + fontSize: '$small', + lineHeight: '$small', + fontWeight: '$bold', + }, + small: { + fontSize: '$small', + lineHeight: '$small', + fontWeight: '$normal', + }, + extraSmallBold: { + fontSize: '$extraSmall', + lineHeight: '$extraSmall', + fontWeight: '$bold', + }, + extraSmall: { + fontSize: '$extraSmall', + lineHeight: '$extraSmall', + fontWeight: '$normal', + }, +} + +export const getValueForVariant = ( + variant: FontVariant, + property: Property, +): Properties[T] => { + return variantMap[variant]?.[property] || variantMap.body[property] +} diff --git a/components/src/components/atoms/VisuallyHidden/VisuallyHidden.tsx b/components/src/components/atoms/VisuallyHidden/VisuallyHidden.tsx index c8742b93..43c4f8c0 100644 --- a/components/src/components/atoms/VisuallyHidden/VisuallyHidden.tsx +++ b/components/src/components/atoms/VisuallyHidden/VisuallyHidden.tsx @@ -1,14 +1,30 @@ -import styled, { css } from 'styled-components' +import * as React from 'react' -export const VisuallyHidden = styled.div( - () => css` - border-width: 0; - height: 1px; - margin: -1px; - overflow: hidden; - padding: 0; - position: absolute; - white-space: nowrap; - width: 1px; - `, +import { Box, BoxProps } from '../Box/Box' + +export const VisuallyHidden = (props: BoxProps) => ( + ) +// export const VisuallyHidden = styled.div( +// () => css` +// border-width: 0; +// height: 1px; +// margin: -1px; +// overflow: hidden; +// padding: 0; +// position: absolute; +// white-space: nowrap; +// width: 1px; +// `, +// ) diff --git a/components/src/components/atoms/index.ts b/components/src/components/atoms/index.ts index 1f264d06..a73bd207 100644 --- a/components/src/components/atoms/index.ts +++ b/components/src/components/atoms/index.ts @@ -15,3 +15,5 @@ export { Spinner } from './Spinner' export { Tag } from './Tag' export { Typography } from './Typography' export { VisuallyHidden } from './VisuallyHidden' +export { Box } from './Box' +export type { BoxProps } from './Box' diff --git a/components/src/components/molecules/Checkbox/Checkbox.tsx b/components/src/components/molecules/Checkbox/Checkbox.tsx index 12771804..d12c7331 100644 --- a/components/src/components/molecules/Checkbox/Checkbox.tsx +++ b/components/src/components/molecules/Checkbox/Checkbox.tsx @@ -1,14 +1,18 @@ import * as React from 'react' -import styled, { css } from 'styled-components' + +import { translateY } from '@/src/css/utils/common' import { WithColorStyle, - getColorStyle, -} from '@/src/types/withColorOrColorStyle' + getValueForColorStyle, +} from './utils/getValueForColorStyle' + +import * as styles from './styles.css' import { Field } from '../..' import { FieldBaseProps } from '../../atoms/Field' import { getTestId } from '../../../utils/utils' +import { Box, BoxProps } from '../../atoms/Box/Box' type NativeInputProps = React.InputHTMLAttributes @@ -54,66 +58,52 @@ type Props = { | 'aria-invalid' > & WithColorStyle -interface InputProps { - $colorStyle: Props['colorStyle'] -} - -const Input = styled.input( - ({ theme, $colorStyle = 'accentPrimary' }) => css` - font: inherit; - display: grid; - position: relative; - place-content: center; - transition: transform 150ms ease-in-out, filter 150ms ease-in-out; - cursor: pointer; - - width: ${theme.space['5']}; - height: ${theme.space['5']}; - border-radius: ${theme.radii.small}; - background-color: ${theme.colors.border}; - - &:checked { - background: ${getColorStyle($colorStyle, 'background')}; - } - - &::before { - content: ''; - background: ${theme.colors.border}; - mask-image: ${`url('data:image/svg+xml; utf8, ')`}; - mask-repeat: no-repeat; - width: ${theme.space['3']}; - height: ${theme.space['3']}; - transition: all 90ms ease-in-out; - } - &:hover { - transform: translateY(-1px); - } - - &:hover::before, - &:checked::before { - background: ${getColorStyle($colorStyle, 'text')}; - } - - &:disabled { - cursor: not-allowed; - } - - &:disabled::before, - &:disabled:hover::before { - background: ${theme.colors.border}; - } - - &:disabled:checked, - &:disabled:checked:hover { - background: ${theme.colors.border}; - } - - &:disabled:checked::before, - &:disabled:checked:hover::before { - background: ${theme.colors.greyPrimary}; - } - `, +const InputBox = React.forwardRef( + ({ $colorStyle, disabled, checked, ...props }, ref) => ( + + + ')`} + maskPosition="center" + maskRepeat="no-repeat" + pointerEvents="none" + position="absolute" + top="$0" + transition="background-color 150ms ease-in-out" + wh="$full" + /> + + ), ) export const Checkbox = React.forwardRef( @@ -157,16 +147,13 @@ export const Checkbox = React.forwardRef( required={required} width={width} > - ) diff --git a/components/src/components/molecules/Checkbox/styles.css.ts b/components/src/components/molecules/Checkbox/styles.css.ts new file mode 100644 index 00000000..788ec883 --- /dev/null +++ b/components/src/components/molecules/Checkbox/styles.css.ts @@ -0,0 +1,23 @@ +import { globalStyle, style } from '@vanilla-extract/css' + +import { modeVars } from '@/src/css/theme.css' + +export const checkbox = style({}) + +export const icon = style({}) + +globalStyle(`${checkbox}:disabled:checked ~ ${icon}`, { + backgroundColor: `${modeVars.color.greyPrimary} !important`, +}) + +globalStyle(`${checkbox}:disabled:not(:checked) ~ ${icon}`, { + backgroundColor: `${modeVars.color.border} !important`, +}) + +globalStyle(`${checkbox}:not(:checked):not(:hover) ~ ${icon}`, { + backgroundColor: `${modeVars.color.border} !important`, +}) + +globalStyle(`${checkbox}:not(:checked):hover ~ ${icon}`, { + backgroundColor: `${modeVars.color.backgroundPrimary} !important`, +}) diff --git a/components/src/components/molecules/Checkbox/utils/getValueForColorStyle.ts b/components/src/components/molecules/Checkbox/utils/getValueForColorStyle.ts new file mode 100644 index 00000000..f9f348a5 --- /dev/null +++ b/components/src/components/molecules/Checkbox/utils/getValueForColorStyle.ts @@ -0,0 +1,44 @@ +import { P, match } from 'ts-pattern' + +import { BaseColour, validateBaseColour } from '@/src/tokens/color3' + +type Shade = 'Primary' | 'Secondary' + +type ColorStyle = BaseColour | `${BaseColour}${Shade}` + +export type WithColorStyle = { colorStyle: ColorStyle } + +type Properties = { + background: string + content: string +} + +type Property = keyof Properties + +const getPrimaryColor = (color: BaseColour, property: Property): string => + match(property) + .with('background', () => `$${color}Primary`) + .with('content', () => '$textAccent') + .exhaustive() + +const getSecondaryColor = (color: BaseColour, property: Property): string => + match(property) + .with(P.union('background'), () => `$${color}Surface`) + .with('content', () => `$${color}Primary`) + .exhaustive() + +export const getValueForColorStyle = ( + colorStyle: ColorStyle, + property: Property, +): string => { + const matches = colorStyle.match('^(.*?)(Primary|Secondary)?$') + const color = matches?.[1] || 'accent' + const style = matches?.[2] + return match([color, style]) + .with([P._, 'Secondary'], ([color]) => + getSecondaryColor(validateBaseColour(color), property), + ) + .otherwise(([color]) => + getPrimaryColor(validateBaseColour(color), property), + ) +} diff --git a/components/src/components/molecules/CheckboxRow/CheckboxRow.tsx b/components/src/components/molecules/CheckboxRow/CheckboxRow.tsx index 07d2859e..1c709791 100644 --- a/components/src/components/molecules/CheckboxRow/CheckboxRow.tsx +++ b/components/src/components/molecules/CheckboxRow/CheckboxRow.tsx @@ -1,137 +1,113 @@ import * as React from 'react' -import styled, { css } from 'styled-components' -import { Hue } from '@/src/tokens' +import { translateY } from '@/src/css/utils/common' +import { + ColorStyle, + getValueForColorStyle, +} from './utils/getValueForColorStyle' + +import * as styles from './styles.css' import { CheckSVG, Typography } from '../..' import { useId } from '../../../hooks/useId' +import { Box, BoxProps } from '../../atoms/Box/Box' export type Props = { label: string subLabel?: string - color?: Hue + colorStyle?: ColorStyle } & React.InputHTMLAttributes -const Container = styled.div<{ - $color: Hue -}>( - ({ theme, $color }) => css` - position: relative; - width: 100%; - - input ~ label:hover { - transform: translateY(-1px); - } - - input ~ label:hover div#circle { - background: ${theme.colors.border}; - } - - input:checked ~ label { - background: ${theme.colors[`${$color}Surface`]}; - border-color: transparent; - } - - input:disabled ~ label { - cursor: not-allowed; - } - - input:checked ~ label div#circle { - background: ${theme.colors[`${$color}Primary`]}; - border-color: transparent; - } - - input:disabled ~ label div#circle, - input:disabled ~ label:hover div#circle { - background: ${theme.colors.greySurface}; - } - - input:checked ~ label:hover div#circle { - background: ${theme.colors[`${$color}Bright`]}; - } - - input:disabled ~ label, - input:disabled ~ label:hover { - background: ${theme.colors.greySurface}; - transform: initial; - } - - input:disabled ~ label div#circle svg, - input:disabled ~ label:hover div#circle svg { - color: ${theme.colors.greySurface}; - } - - input:disabled:checked ~ label div#circle, - input:disabled:checked ~ label:hover div#circle { - background: ${theme.colors.border}; - } - - input:disabled:checked ~ label div#circle svg, - input:disabled:checked ~ label:hover div#circle svg { - color: ${theme.colors.greyPrimary}; - } - `, +const ContainerBox = ({ disabled, ...props }: BoxProps) => ( + ) -const RootInput = styled.input( - () => css` - position: absolute; - width: 1px; - height: 1px; - `, +const Input = React.forwardRef((props, ref) => ( + +)) + +const Label = ({ + $colorStyle = 'blueSecondary', + ...props +}: BoxProps & { $colorStyle?: ColorStyle }) => ( + ) -const Label = styled.label( - ({ theme }) => css` - display: flex; - align-items: center; - gap: ${theme.space['4']}; - - width: 100%; - height: 100%; - padding: ${theme.space['4']}; - - border-radius: ${theme.space['2']}; - border: 1px solid ${theme.colors.border}; - - cursor: pointer; - - transition: all 0.3s ease-in-out; - `, +const CircleFrame = (props: BoxProps) => ( + ) -const Circle = styled.div( - ({ theme }) => css` - display: flex; - align-items: center; - justify-content: center; - - flex: 0 0 ${theme.space['7']}; - width: ${theme.space['7']}; - height: ${theme.space['7']}; - border-radius: ${theme.radii.full}; - border: 1px solid ${theme.colors.border}; - - transition: all 0.3s ease-in-out; - - svg { - display: block; - color: ${theme.colors.backgroundPrimary}; - width: ${theme.space['4']}; - height: ${theme.space['4']}; - } - `, +const SVG = (props: BoxProps) => ( + ) -const Content = styled.div( - () => css` - display: flex; - flex-direction: column; - `, +const Circle = ({ + $hover, + $colorStyle, + ...props +}: BoxProps & { $hover: boolean; $colorStyle: ColorStyle }) => ( + + } /> + ) export const CheckboxRow = React.forwardRef( - ({ label, subLabel, name, color = 'blue', disabled, ...props }, ref) => { + ({ label, subLabel, name, colorStyle = 'blue', disabled, ...props }, ref) => { const defaultRef = React.useRef(null) const inputRef = ref || defaultRef @@ -140,20 +116,36 @@ export const CheckboxRow = React.forwardRef( const textColor = disabled ? 'grey' : 'text' return ( - - + -
)} - +
-
+ ) }, ) diff --git a/components/src/components/molecules/CheckboxRow/styles.css.ts b/components/src/components/molecules/CheckboxRow/styles.css.ts new file mode 100644 index 00000000..419aa186 --- /dev/null +++ b/components/src/components/molecules/CheckboxRow/styles.css.ts @@ -0,0 +1,56 @@ +import { globalStyle, style } from '@vanilla-extract/css' + +import { modeVars } from '@/src/css/theme.css' + +export const input = style({}) + +export const label = style({}) + +export const circle = style({}) + +export const circleHover = style({}) + +globalStyle(`${input}:not(:disabled) ~ ${label}:hover ${circle}`, { + opacity: 0, +}) + +globalStyle(`${input}:not(:checked) ~ ${label}`, { + borderColor: modeVars.color.border, + backgroundColor: modeVars.color.backgroundPrimary, +}) + +globalStyle(`${input}:not(:checked) ~ ${label} ${circle}`, { + backgroundColor: modeVars.color.backgroundPrimary, + color: modeVars.color.backgroundPrimary, + borderColor: modeVars.color.border, +}) + +globalStyle(`${input}:not(:checked) ~ ${label} ${circleHover}`, { + backgroundColor: modeVars.color.border, + color: modeVars.color.textAccent, + borderColor: modeVars.color.border, +}) + +globalStyle(`${input}:disabled:not(:checked) ~ ${label}`, { + borderColor: modeVars.color.border, + backgroundColor: modeVars.color.greySurface, + color: modeVars.color.greyPrimary, +}) + +globalStyle(`${input}:disabled:not(:checked) ~ ${label} ${circle}`, { + backgroundColor: modeVars.color.greySurface, + color: modeVars.color.greySurface, + borderColor: modeVars.color.border, +}) + +globalStyle(`${input}:disabled:checked ~ ${label}`, { + borderColor: 'transparent', + backgroundColor: modeVars.color.greySurface, + color: modeVars.color.greyPrimary, +}) + +globalStyle(`${input}:disabled:checked ~ ${label} ${circle}`, { + backgroundColor: modeVars.color.border, + color: modeVars.color.greyPrimary, + borderColor: 'transparent', +}) diff --git a/components/src/components/molecules/CheckboxRow/utils/getValueForColorStyle.ts b/components/src/components/molecules/CheckboxRow/utils/getValueForColorStyle.ts new file mode 100644 index 00000000..428747b4 --- /dev/null +++ b/components/src/components/molecules/CheckboxRow/utils/getValueForColorStyle.ts @@ -0,0 +1,50 @@ +import { P, match } from 'ts-pattern' + +import { BaseColour, validateBaseColour } from '@/src/tokens/color3' + +type Shade = 'Primary' | 'Secondary' + +export type ColorStyle = BaseColour | `${BaseColour}${Shade}` + +export type WithColorStyle = { colorStyle: ColorStyle } + +type Properties = { + background: string + icon: string + iconHover: string + svg: string +} + +type Property = keyof Properties + +const getPrimaryColor = (color: BaseColour, property: Property): string => + match(property) + .with('background', () => `$${color}Surface`) + .with('svg', () => '$textAccent') + .with('icon', () => `$${color}Primary`) + .with('iconHover', () => `$${color}Bright`) + .exhaustive() + +const getSecondaryColor = (color: BaseColour, property: Property): string => + match(property) + .with('background', () => `$${color}Surface`) + .with('svg', () => `$${color}Dim`) + .with('iconHover', () => `$${color}Light`) + .with('icon', () => `$${color}Light`) + .exhaustive() + +export const getValueForColorStyle = ( + colorStyle: ColorStyle, + property: Property, +): string => { + const matches = colorStyle.match('^(.*?)(Primary|Secondary)?$') + const color = matches?.[1] || 'accent' + const style = matches?.[2] + return match([color, style]) + .with([P._, 'Secondary'], ([color]) => + getSecondaryColor(validateBaseColour(color), property), + ) + .otherwise(([color]) => + getPrimaryColor(validateBaseColour(color), property), + ) +} diff --git a/components/src/components/molecules/CountdownCircle/CountdownCircle.tsx b/components/src/components/molecules/CountdownCircle/CountdownCircle.tsx index a5db05b0..b71932a3 100644 --- a/components/src/components/molecules/CountdownCircle/CountdownCircle.tsx +++ b/components/src/components/molecules/CountdownCircle/CountdownCircle.tsx @@ -1,125 +1,96 @@ import * as React from 'react' -import styled, { css } from 'styled-components' -import { Colors } from '@/src/tokens' +import { P, match } from 'ts-pattern' import { CheckSVG } from '@/src/icons' import { VisuallyHidden } from '../..' import { getTestId } from '../../../utils/utils' - -const CountDownContainer = styled.div( - () => css` - position: relative; - `, +import { Box, BoxProps } from '../../atoms/Box/Box' +import { getValueForNumberForSize } from './utils/getValueForNumberForSize' +import { Color, getValidatedColor } from './utils/getValidatedColor' + +const NumberBox = ({ + $size, + $color, + disabled, + ...props +}: BoxProps & { $size: 'small' | 'large'; $color: any }) => ( + ) -interface NumberBox { - $disabled?: boolean - $size: 'small' | 'large' -} - -const NumberBox = styled.div( - ({ theme, $disabled, $size }) => css` - position: absolute; - display: flex; - align-items: center; - justify-content: center; - font-weight: ${theme.fontWeights.extraBold}; - - color: ${theme.colors.accent}; - - ${$disabled && - css` - color: ${theme.colors.greyLight}; - `} - - #countdown-complete-check { - stroke-width: ${theme.borderWidths['1.5']}; - overflow: visible; - display: block; - } - - ${() => { - switch ($size) { - case 'small': - return css` - height: ${theme.space['16']}; - width: ${theme.space['16']}; - ` - case 'large': - return css` - font-size: ${theme.fontSizes.extraLarge}; - line-height: ${theme.lineHeights.extraLarge}; - margin-top: -${theme.space['0.5']}; - height: ${theme.space['24']}; - width: ${theme.space['24']}; - ` - default: - return `` +const ContainerBox = React.forwardRef< + HTMLElement, + BoxProps & { + $size: 'small' | 'large' + $color: Color + disabled?: boolean + } +>(({ $size, $color, disabled, ...props }, ref) => ( + +)) + +const Circle = ({ + $progress, + disabled, + ...props +}: BoxProps & { + $progress?: number +}) => { + const showProgress = typeof $progress === 'number' && !disabled + const strokeDashArray = showProgress + ? `${48 * ($progress ?? 1)}, 56` + : '100, 100' + const opacity = showProgress || disabled ? '1' : '0.25' + return ( + typeof x === 'number' && x <= 0)], + () => '0', + ) + .otherwise(() => '4')} + /> } - }} - `, -) - -interface ContainerProps { - $disabled?: boolean - $size: 'small' | 'large' - $color: Colors + transition="all 1s linear, stroke-width 0.2s ease-in-out 1s" + /> + ) } -const Container = styled.div( - ({ theme, $disabled, $size, $color }) => css` - stroke: ${theme.colors.accent}; - - color: ${theme.colors[$color]}; - - ${$disabled && - css` - color: ${theme.colors.greyLight}; - `} - - ${() => { - switch ($size) { - case 'small': - return css` - height: ${theme.space['16']}; - width: ${theme.space['16']}; - stroke-width: ${theme.space['1']}; - ` - case 'large': - return css` - height: ${theme.space['24']}; - width: ${theme.space['24']}; - stroke-width: ${theme.space['1']}; - ` - default: - return `` - } - }} - `, -) - -interface CircleProps { - $finished: boolean -} - -const Circle = styled.circle( - ({ $finished }) => css` - transition: all 1s linear, stroke-width 0.2s ease-in-out 1s; - - ${$finished && - css` - stroke-width: 0; - `} - `, -) - type NativeDivProps = React.HTMLAttributes type Props = { accessibilityLabel?: string - color?: Colors + color?: Color startTimestamp?: number countdownSeconds: number disabled?: boolean @@ -131,7 +102,7 @@ export const CountdownCircle = React.forwardRef( ( { accessibilityLabel, - color = 'textSecondary', + color = 'accent', size = 'small', countdownSeconds, startTimestamp, @@ -172,49 +143,40 @@ export const CountdownCircle = React.forwardRef( }, [calculateCurrentCount, callback, countdownSeconds, disabled]) return ( - - - {disabled && countdownSeconds} - {!disabled && - (currentCount > 0 ? ( - currentCount - ) : ( - + {match([!!disabled, !!currentCount]) + .with([true, P._], () => countdownSeconds) + .with([false, true], () => currentCount) + .with([false, false], () => ( + } data-testid="countdown-complete-check" + display="block" id="countdown-complete-check" + overflow="visible" + strokeWidth="$1.5" /> - ))} + )) + .exhaustive()} - + {accessibilityLabel && ( {accessibilityLabel} )} - + - - + + ) }, ) diff --git a/components/src/components/molecules/CountdownCircle/utils/getValidatedColor.ts b/components/src/components/molecules/CountdownCircle/utils/getValidatedColor.ts new file mode 100644 index 00000000..fcfc4653 --- /dev/null +++ b/components/src/components/molecules/CountdownCircle/utils/getValidatedColor.ts @@ -0,0 +1,12 @@ +import { BaseColour, validateBaseColour } from '@/src/tokens/color3' + +export type Color = BaseColour + +export type WithColor = { color: Color } + +export const getValidatedColor = (color: Color): string => { + const matches = color.match('^(.*?)(Primary|Secondary)?$') + const baseColor = matches?.[1] || 'accent' + const validatedColor = validateBaseColour(baseColor, 'accent') + return `$${validatedColor}Primary` +} diff --git a/components/src/components/molecules/CountdownCircle/utils/getValueForNumberForSize.ts b/components/src/components/molecules/CountdownCircle/utils/getValueForNumberForSize.ts new file mode 100644 index 00000000..0c8e39f7 --- /dev/null +++ b/components/src/components/molecules/CountdownCircle/utils/getValueForNumberForSize.ts @@ -0,0 +1,23 @@ +type Property = 'size' | 'fontSize' | 'lineHeight' | 'marginTop' + +const sizeMap = { + small: { + size: '$16', + fontSize: '$normal', + lineHeight: '$normal', + marginTop: '$0', + }, + large: { + size: '$24', + fontSize: '$extraLarge', + lineHeight: '$extraLarge', + marginTop: '$-0.5', + }, +} + +export const getValueForNumberForSize = ( + size: 'small' | 'large', + property: Property, +) => { + return sizeMap[size]?.[property] || sizeMap.small[property] +} diff --git a/components/src/components/molecules/CurrencyToggle/CurrencyToggle.tsx b/components/src/components/molecules/CurrencyToggle/CurrencyToggle.tsx index 9c0afcc1..e186078b 100644 --- a/components/src/components/molecules/CurrencyToggle/CurrencyToggle.tsx +++ b/components/src/components/molecules/CurrencyToggle/CurrencyToggle.tsx @@ -1,169 +1,100 @@ import * as React from 'react' -import styled, { css } from 'styled-components' - -import type { Space } from '@/src/tokens' import { useId } from '../../../hooks/useId' +import { Box, BoxProps } from '../../atoms/Box/Box' +import { getValuesForKnob } from './utils/getValuesForKnob' +import * as styles from './styles.css' +import { getValueForCheckbox } from './utils/getValueForCheckBox' +import { Color, getValidatedColor } from './utils/getValidatedColor' -type Size = 'extraSmall' | 'small' | 'medium' +export type Size = 'extraSmall' | 'small' | 'medium' export type Props = { size?: Size fiat?: string + color?: Color } & Omit, 'size'> -const CONTAINER_SIZES: { - [key in Size]: { - width: Space - height: Space - } -} = { - extraSmall: { - width: '22.5', - height: '7', - }, - small: { - width: '26', - height: '10', - }, - medium: { - width: '32', - height: '12', - }, -} - -const KNOB_SIZES: { - [key in Size]: { - width: Space - height: Space - translateX: Space - } -} = { - extraSmall: { - width: '10', - height: '5.5', - translateX: '5', - }, - small: { - width: '12', - height: '8', - translateX: '6', - }, - medium: { - width: '15', - height: '10', - translateX: '7.5', - }, -} - -const Container = styled.div<{ $size: Size }>( - ({ theme, $size }) => css` - position: relative; - width: fit-content; - - label { - position: absolute; - left: 50%; - top: 50%; - width: ${theme.space[KNOB_SIZES[$size].width]}; - height: ${theme.space[KNOB_SIZES[$size].height]}; - font-size: ${theme.fontSizes.small}; - font-weight: ${$size === 'extraSmall' - ? theme.fontWeights.normal - : theme.fontWeights.bold}; - display: flex; - align-items: center; - justify-content: center; - transition: color 0.1s linear; - cursor: pointer; - } - - label#eth { - color: ${theme.colors.textAccent}; - transform: translate(-50%, -50%) - translateX(-${theme.space[KNOB_SIZES[$size].translateX]}); - } - - label#fiat { - color: ${theme.colors.greyPrimary}; - transform: translate(-50%, -50%) - translateX(${theme.space[KNOB_SIZES[$size].translateX]}); - } - - input[type='checkbox']:checked ~ label#eth { - color: ${theme.colors.greyPrimary}; - } - - input[type='checkbox']:checked ~ label#fiat { - color: ${theme.colors.textAccent}; - } - - input[type='checkbox']:disabled ~ label#eth { - color: ${theme.colors.backgroundPrimary}; - } - - input[type='checkbox']:disabled ~ label#fiat { - color: ${theme.colors.greyPrimary}; - } - - input[type='checkbox']:disabled:checked ~ label#fiat { - color: ${theme.colors.backgroundPrimary}; - } - - input[type='checkbox']:disabled:checked ~ label#eth { - color: ${theme.colors.greyPrimary}; - } - - input[type='checkbox']:disabled ~ label { - cursor: not-allowed; - } - `, +const Container = (props: BoxProps) => ( + ) -const InputComponent = styled.input<{ $size?: Size }>( - ({ theme, $size = 'medium' }) => css` - position: relative; - background-color: ${theme.colors.greySurface}; - height: ${theme.space[CONTAINER_SIZES[$size].height]}; - width: ${theme.space[CONTAINER_SIZES[$size].width]}; - border-radius: ${$size === 'extraSmall' - ? theme.radii.full - : theme.radii.large}; - - display: flex; - align-items: center; - justify-content: center; - - &::after { - content: ''; - display: block; - position: absolute; - background-color: ${theme.colors.bluePrimary}; - width: ${theme.space[KNOB_SIZES[$size].width]}; - height: ${theme.space[KNOB_SIZES[$size].height]}; - border-radius: ${$size === 'extraSmall' - ? theme.radii.full - : theme.space['1.5']}; - transform: translateX(-${theme.space[KNOB_SIZES[$size].translateX]}); - transition: transform 0.3s ease-in-out, background-color 0.1s ease-in-out; - } +const Label = ({ + $type, + $size, + ...props +}: BoxProps & { $size: Size; $type: 'eth' | 'fiat' }) => ( + +) - &:checked::after { - transform: translateX(${theme.space[KNOB_SIZES[$size].translateX]}); - } +const Checkbox = React.forwardRef( + ({ $size, ...props }, ref) => ( + + ), +) - &:disabled::after { - background-color: ${theme.colors.greyPrimary}; - } - `, +const Slider = ({ + $size, + $color, + ...props +}: BoxProps & { $size: Size; $color: Color }) => ( + ) export const CurrencyToggle = React.forwardRef( - ({ size = 'medium', disabled, fiat = 'usd', ...props }, ref) => { + ( + { size = 'medium', color = 'accent', disabled, fiat = 'usd', ...props }, + ref, + ) => { const id = useId() return ( - - + ( {...props} $size={size} /> - ) }, diff --git a/components/src/components/molecules/CurrencyToggle/styles.css.ts b/components/src/components/molecules/CurrencyToggle/styles.css.ts new file mode 100644 index 00000000..0747ccb2 --- /dev/null +++ b/components/src/components/molecules/CurrencyToggle/styles.css.ts @@ -0,0 +1,31 @@ +import { globalStyle, style } from '@vanilla-extract/css' + +import { modeVars } from '@/src/css/theme.css' + +export const labelEth = style({}) + +export const labelFiat = style({}) + +export const checkbox = style({}) + +export const slider = style({}) + +globalStyle(`${checkbox}:not(:checked) ~ ${slider}`, { + transform: 'translateX(-50%)', +}) + +globalStyle(`${checkbox}:checked ~ ${slider}`, { + transform: 'translateX(50%)', +}) + +globalStyle(`${checkbox}:disabled ~ ${slider}`, { + backgroundColor: modeVars.color.greyPrimary, +}) + +globalStyle(`${checkbox}:checked ~ ${labelEth}`, { + color: modeVars.color.greyPrimary, +}) + +globalStyle(`${checkbox}:not(:checked) ~ ${labelFiat}`, { + color: modeVars.color.greyPrimary, +}) diff --git a/components/src/components/molecules/CurrencyToggle/utils/constants.ts b/components/src/components/molecules/CurrencyToggle/utils/constants.ts new file mode 100644 index 00000000..a4ba4057 --- /dev/null +++ b/components/src/components/molecules/CurrencyToggle/utils/constants.ts @@ -0,0 +1,45 @@ +import type { Size } from '../CurrencyToggle' + +export const CONTAINER_SIZES: { + [key in Size]: { + width: string + height: string + } +} = { + extraSmall: { + width: '22.5', + height: '7', + }, + small: { + width: '26', + height: '10', + }, + medium: { + width: '32', + height: '12', + }, +} + +export const KNOB_SIZES: { + [key in Size]: { + width: string + height: string + translateX: string + } +} = { + extraSmall: { + width: '10', + height: '5.5', + translateX: '5', + }, + small: { + width: '12', + height: '8', + translateX: '6', + }, + medium: { + width: '15', + height: '10', + translateX: '7.5', + }, +} diff --git a/components/src/components/molecules/CurrencyToggle/utils/getValidatedColor.ts b/components/src/components/molecules/CurrencyToggle/utils/getValidatedColor.ts new file mode 100644 index 00000000..9e7b938f --- /dev/null +++ b/components/src/components/molecules/CurrencyToggle/utils/getValidatedColor.ts @@ -0,0 +1,12 @@ +import { BaseColour, validateBaseColour } from '@/src/tokens/color3' + +export type Color = BaseColour + +export type WithColor = { color: Color } + +export const getValidatedColor = (color: Color = 'accent'): string => { + const matches = color.match('^(.*?)(Primary|Secondary)?$') + const baseColor = matches?.[1] || 'accent' + const validatedColor = validateBaseColour(baseColor, 'accent') + return `$${validatedColor}Primary` +} diff --git a/components/src/components/molecules/CurrencyToggle/utils/getValueForCheckBox.ts b/components/src/components/molecules/CurrencyToggle/utils/getValueForCheckBox.ts new file mode 100644 index 00000000..4a1bea94 --- /dev/null +++ b/components/src/components/molecules/CurrencyToggle/utils/getValueForCheckBox.ts @@ -0,0 +1,31 @@ +import type { Size } from '../CurrencyToggle' + +type Properties = { + width: string + height: string + borderRadius: string +} + +type Property = keyof Properties + +const checkBoxValues: { [key in Size]: Properties } = { + extraSmall: { + width: '$22.5', + height: '$7', + borderRadius: '$full', + }, + small: { + width: '$26', + height: '$10', + borderRadius: '$large', + }, + medium: { + width: '$32', + height: '$12', + borderRadius: '$large', + }, +} + +export const getValueForCheckbox = (size: Size, property: Property) => { + return checkBoxValues[size]?.[property] || checkBoxValues.extraSmall[property] +} diff --git a/components/src/components/molecules/CurrencyToggle/utils/getValuesForKnob.ts b/components/src/components/molecules/CurrencyToggle/utils/getValuesForKnob.ts new file mode 100644 index 00000000..07078b97 --- /dev/null +++ b/components/src/components/molecules/CurrencyToggle/utils/getValuesForKnob.ts @@ -0,0 +1,20 @@ +import { commonVars } from '@/src/css/theme.css' + +import { Size } from '../CurrencyToggle' +import { KNOB_SIZES } from './constants' + +type Property = 'width' | 'height' | 'translateX' + +export const getValuesForKnob = (size: Size, property: Property) => { + const value = + KNOB_SIZES[size]?.[property] || (KNOB_SIZES.small[property] as any) + console.log( + 'var', + value, + commonVars.space[value as keyof typeof commonVars.space], + ) + if (property === 'translateX') + return commonVars.space[value as keyof typeof commonVars.space] + if (property === 'width' || property === 'height') return `$${value}` + return '' +} diff --git a/components/src/components/molecules/CurrencyToggle/utils/getValuesForLabel.ts b/components/src/components/molecules/CurrencyToggle/utils/getValuesForLabel.ts new file mode 100644 index 00000000..41adc185 --- /dev/null +++ b/components/src/components/molecules/CurrencyToggle/utils/getValuesForLabel.ts @@ -0,0 +1,9 @@ +import { Size } from '../CurrencyToggle' +import { getValuesForKnob } from './getValuesForKnob' + +export const getTransform = ($size: Size, $type: 'eth' | 'fiat') => { + const translateX = getValuesForKnob($size, 'translateX') + if ($type === 'eth') + return `translate(-50%,-50%) translateX(calc(${translateX} * -1))` + return `translate(-50%,-50%) translateX(${translateX})` +} diff --git a/components/src/components/molecules/Dropdown/Dropdown.tsx b/components/src/components/molecules/Dropdown/Dropdown.tsx index 5ed64ddd..04d89a91 100644 --- a/components/src/components/molecules/Dropdown/Dropdown.tsx +++ b/components/src/components/molecules/Dropdown/Dropdown.tsx @@ -1,5 +1,4 @@ import * as React from 'react' -import styled, { DefaultTheme, css, useTheme } from 'styled-components' import { P, match } from 'ts-pattern' import { debounce } from 'lodash' @@ -8,8 +7,11 @@ import { TransitionState } from 'react-transition-state' import { Button, ButtonProps } from '@/src/components/atoms/Button' import { Colors, breakpoints } from '@/src/tokens' +import { commonVars, modeVars } from '@/src/css/theme.css' + import { DownChevronSVG, DynamicPopover, ScrollBox } from '../..' import { ActionSheet } from './ActionSheet' +import { Box, BoxProps } from '../../atoms/Box/Box' type Align = 'left' | 'right' type LabelAlign = 'flex-start' | 'flex-end' | 'center' @@ -97,155 +99,110 @@ type DropdownMenuContainerProps = { $state?: TransitionState } -type DropdownMenuInnerProps = { - $labelAlign?: LabelAlign -} - -const DropdownMenuContainer = styled.div( - ({ theme, $shortThrow, $direction, $state }) => css` - padding: ${theme.space['1.5']}; - width: 100%; - - ${ - $direction === 'up' && - css` - bottom: 100%; - ` - } - - z-index: 0; - opacity: 0; - - ${ - $state === 'entered' && - css` - z-index: 1; - ` - } - - background-color: ${theme.colors.background}; - border-radius: ${theme.radii['2xLarge']}; - - border: 1px solid ${theme.colors.border}; - transition: all 0.35s cubic-bezier(1, 0, 0.22, 1.6); - margin-${$direction === 'down' ? 'top' : 'bottom'}: ${theme.space['1.5']}; - - transform: translateY(calc(${$direction === 'down' ? '-1' : '1'} * ${ - theme.space['12'] - })); - - ${ - $shortThrow && - css` - transform: translateY( - calc(${$direction === 'down' ? '-1' : '1'} * ${theme.space['2.5']}) - ); - ` - } - - ${ - ($state === 'entering' || $state === 'entered') && - css` - transform: translateY(0); - opacity: 1; - ` - } -`, -) - -const dropdownInnerStyles = ({ - theme, - $labelAlign, -}: DropdownMenuInnerProps & { theme: DefaultTheme }) => css` - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - gap: ${theme.space['1']}; - width: 100%; - - ${$labelAlign && - css` - & > * { - justify-content: ${$labelAlign}; - } - `} -` - -const DropdownMenuInner = - styled.div(dropdownInnerStyles) - -const StyledScrollBox = styled(ScrollBox)( - dropdownInnerStyles, - ({ theme }) => css` - padding-right: ${theme.space['1']}; - `, +const DropdownMenuBox = ({ + $shortThrow, + $direction, + $state, + ...props +}: BoxProps & DropdownMenuContainerProps) => ( + `translateY(0)`) + .with( + [P._, 'up', true], + () => `translateY(calc(${commonVars.space['2.5']}))`, + ) + .with( + [P._, 'down', true], + () => `translateY(calc(-1 * ${commonVars.space['2.5']}))`, + ) + .with( + [P._, 'up', false], + () => `translateY(calc(${commonVars.space['12']}))`, + ) + .with( + [P._, 'down', false], + () => `translateY(calc(-1 * ${commonVars.space['12']}))`, + ) + .exhaustive()} + transition="all .35s cubic-bezier(1, 0, 0.22, 1.6)" + width="$full" + zIndex={1} + /> ) interface MenuButtonProps { $color?: Colors + $icon?: React.ReactElement $showIndicator?: boolean | Colors } -const MenuButton = styled.button( - ({ theme, $color, disabled, $showIndicator }) => css` - align-items: center; - cursor: pointer; - display: flex; - gap: ${theme.space['2']}; - width: ${theme.space['full']}; - height: ${theme.space['12']}; - padding: ${theme.space['3']}; - border-radius: ${theme.radii.large}; - font-weight: ${theme.fontWeights.normal}; - transition-duration: 0.15s; - transition-property: color, transform, filter; - transition-timing-function: ease-in-out; - - &:active { - transform: translateY(0px); - filter: brightness(1); - } - - color: ${theme.colors[$color || 'textPrimary']}; - - svg { - min-width: ${theme.space['4']}; - width: ${theme.space['4']}; - height: ${theme.space['4']}; - color: ${theme.colors[$color || 'text']}; - } - ${disabled && - css` - color: ${theme.colors.textTertiary}; - cursor: not-allowed; - `} - - justify-content: flex-start; - - &:hover { - background: ${theme.colors.greySurface}; - } - - ${$showIndicator && - css` - position: relative; - padding-right: ${theme.space['6']}; - &::after { - position: absolute; - content: ''; - top: 50%; - right: ${theme.space['3']}; - transform: translateY(-50%); - width: ${theme.space['2']}; - height: ${theme.space['2']}; - border-radius: ${theme.radii.full}; - background: ${theme.colors[ - typeof $showIndicator === 'boolean' ? 'accent' : $showIndicator - ]}; - } - `} - `, +const MenuButton = ({ + $color, + $icon, + $showIndicator, + disabled, + children, + ...props +}: BoxProps & MenuButtonProps) => ( + + {$icon && ( + + )} + {children} + {$showIndicator && ( + + )} + ) const DropdownChild: React.FC<{ @@ -272,16 +229,7 @@ const DropdownChild: React.FC<{ const DropdownMenu = React.forwardRef( ( - { - items, - setIsOpen, - shortThrow, - labelAlign, - direction, - state, - height, - ...props - }, + { items, setIsOpen, shortThrow, direction, state, height, ...props }, ref, ) => { const Content = items.map((item: DropdownItem) => { @@ -304,18 +252,14 @@ const DropdownMenu = React.forwardRef( $hasColor: !!color, $color: color, $showIndicator: showIndicator, + $icon: icon, disabled, onClick: () => { setIsOpen(false) onClick?.(value) }, as, - children: ( - <> - {icon} - {label} - - ), + children: <>{label}, } if (wrapper) { @@ -339,48 +283,54 @@ const DropdownMenu = React.forwardRef( if (height) { return ( - - + + {Content} - - + + ) } return ( - - + + {Content} - - + + ) }, ) -const Chevron = styled((props) => )<{ - $open?: boolean - $direction: Direction -}>( - ({ theme, $open, $direction }) => css` - margin-left: ${theme.space['1']}; - width: ${theme.space['3']}; - margin-right: ${theme.space['0.5']}; - transition-duration: ${theme.transitionDuration['200']}; - transition-property: all; - transition-timing-function: ${theme.transitionTimingFunction['inOut']}; - transform: rotate(${$direction === 'down' ? '0deg' : '180deg'}); - display: flex; - - & > svg { - fill: currentColor; - } - fill: currentColor; - - ${$open && - css` - transform: rotate(${$direction === 'down' ? '180deg' : '0deg'}); - `} - `, +const rotation = (direction: Direction, open: boolean) => + match([direction, open]) + .with(['down', false], () => 'rotate(0deg)') + .with(['down', true], () => 'rotate(180deg)') + .with(['up', false], () => 'rotate(180deg)') + .with(['up', true], () => 'rotate(0deg)') + .exhaustive() + +const Chevron = ({ + $open, + $direction, +}: { $open?: boolean; $direction: Direction } & BoxProps) => ( + } + fill="currentColor" + marginLeft="$1" + marginRight="$0.5" + transform={rotation($direction, !!$open)} + transitionDuration="$200" + transitionProperty="all" + transitionTimingFunction="$inOut" + width="$3" + /> ) interface DropdownButtonProps { @@ -408,7 +358,6 @@ const DropdownButton: React.FC = ({ buttonProps, indicatorColor, }): React.ReactElement => { - const { colors } = useTheme() const hasIndicator = React.useMemo( () => items.some((item) => 'showIndicator' in item && item.showIndicator), [items], @@ -419,13 +368,13 @@ const DropdownButton: React.FC = ({ 'data-indicator': hasIndicator && !isOpen, style: { ...buttonProps?.style, - '--indicator-color': indicatorColor - ? colors[indicatorColor] - : colors.accent, + '--indicator-color': + modeVars.color[`$${indicatorColor}` as keyof typeof modeVars.color] || + modeVars.color.accent, }, className: `${buttonProps?.className} indicator-container`, }), - [buttonProps, hasIndicator, indicatorColor, colors, isOpen], + [buttonProps, hasIndicator, indicatorColor, isOpen], ) return ( diff --git a/components/src/components/molecules/Dropdown/styles.css.ts b/components/src/components/molecules/Dropdown/styles.css.ts new file mode 100644 index 00000000..6eb93474 --- /dev/null +++ b/components/src/components/molecules/Dropdown/styles.css.ts @@ -0,0 +1,3 @@ +import { style } from '@vanilla-extract/css' + +export const innerDropdown = style() diff --git a/components/src/components/molecules/FieldSet/FieldSet.tsx b/components/src/components/molecules/FieldSet/FieldSet.tsx index 0e7561e6..7b42bc97 100644 --- a/components/src/components/molecules/FieldSet/FieldSet.tsx +++ b/components/src/components/molecules/FieldSet/FieldSet.tsx @@ -1,50 +1,40 @@ import * as React from 'react' -import styled, { css } from 'styled-components' import { ReactNodeNoStrings } from '../../../types' import { Heading, Tag } from '../..' import { TagProps } from '../../atoms/Tag' +import { Box, BoxProps } from '../../atoms/Box/Box' -const Container = styled.fieldset( - ({ theme }) => css` - display: flex; - flex-direction: column; - gap: ${theme.space['4']}; - `, +const Container = (props: BoxProps) => ( + ) -const ContainerInner = styled.div( - ({ theme }) => css` - display: flex; - flex-direction: column; - gap: ${theme.space['1']}; - padding: 0 ${theme.space['4']}; - `, +const ContainerInner = (props: BoxProps) => ( + ) -const Row = styled.div( - ({ theme }) => css` - display: flex; - align-items: center; - flex-direction: row; - gap: ${theme.space['3']}; - `, +const Row = (props: BoxProps) => ( + ) -const Description = styled.div( - ({ theme }) => css` - color: ${theme.colors.textSecondary}; - font-size: ${theme.fontSizes.body}; - line-height: ${theme.lineHeights.body}; - `, +const Description = (props: BoxProps) => ( + ) -const ChildrenContainer = styled.div( - ({ theme }) => css` - display: flex; - flex-direction: column; - gap: ${theme.space['4']}; - `, +const ChildrenContainer = (props: BoxProps) => ( + ) type NativeFieldSetProps = React.FieldsetHTMLAttributes @@ -84,7 +74,7 @@ export const FieldSet = ({ ...props }: Props) => { let statusText: string | undefined - let statusTone: TagProps['color'] + let statusTone: TagProps['colorStyle'] switch (status) { case 'complete': { statusText = 'Complete' @@ -105,7 +95,7 @@ export const FieldSet = ({ } if (typeof status === 'object') { statusText = status.name - statusTone = status.tone + statusTone = status.tone as TagProps['colorStyle'] } return ( @@ -116,7 +106,7 @@ export const FieldSet = ({ {legend} {statusTone && statusText && ( - {statusText} + {statusText} )} diff --git a/components/src/components/molecules/Helper/Helper.tsx b/components/src/components/molecules/Helper/Helper.tsx index 53c453dd..76b308de 100644 --- a/components/src/components/molecules/Helper/Helper.tsx +++ b/components/src/components/molecules/Helper/Helper.tsx @@ -1,89 +1,63 @@ import * as React from 'react' -import styled, { css } from 'styled-components' import { AlertSVG, InfoCircleSVG } from '@/src/icons' +import type { Alert } from '@/src/types' + +import { Box, BoxProps } from '../../atoms/Box/Box' + +import { getValueForAlert } from './utils/getValueForAlert' + type NativeDivProps = React.HTMLAttributes -type HelperType = 'info' | 'warning' | 'error' type Alignment = 'horizontal' | 'vertical' export type Props = NativeDivProps & { - type?: HelperType + alert?: Alert alignment?: Alignment children: React.ReactNode } -const Container = styled.div<{ $type: HelperType; $alignment: Alignment }>( - ({ theme, $type, $alignment }) => css` - width: ${theme.space.full}; - padding: ${theme.space['6']} ${theme.space['4']}; - - display: flex; - align-items: center; - flex-direction: column; - justify-content: center; - gap: ${theme.space['2']}; - border-radius: ${theme.radii.large}; - - text-align: center; - overflow-x: auto; - - ${$alignment === 'horizontal' && - css` - flex-direction: row; - justify-content: flex-start; - gap: ${theme.space['4']}; - padding: ${theme.space['4']}; - text-align: left; - `} - - background-color: ${theme.colors.blueSurface}; - border: ${theme.borderWidths.px} solid ${theme.colors.blue}; - - ${$type === 'warning' && - css` - background-color: ${theme.colors.yellowSurface}; - border-color: ${theme.colors.yellow}; - `} - - ${$type === 'error' && - css` - background-color: ${theme.colors.redSurface}; - border-color: ${theme.colors.red}; - `} - `, +const Container = ({ + $alert, + $alignment, + ...props +}: BoxProps & { $alert: Alert; $alignment: Alignment }) => ( + ) -const IconElement = styled.div<{ $type: HelperType }>( - ({ theme, $type }) => css` - width: ${theme.space['6']}; - height: ${theme.space['6']}; - - color: ${theme.colors.blue}; - - ${$type === 'warning' && - css` - color: ${theme.colors.yellow}; - `} - ${$type === 'error' && - css` - color: ${theme.colors.red}; - `} - `, +const IconElement = ({ $alert, ...props }: BoxProps & { $alert: Alert }) => ( + ) export const Helper = ({ - type = 'info', + alert = 'info', alignment = 'vertical', children, ...props }: Props) => { - const Icon = type === 'info' ? InfoCircleSVG : AlertSVG + const Icon = alert === 'info' ? InfoCircleSVG : AlertSVG return ( - - + + {children} ) diff --git a/components/src/components/molecules/Helper/utils/getValueForAlert.ts b/components/src/components/molecules/Helper/utils/getValueForAlert.ts new file mode 100644 index 00000000..c42574c2 --- /dev/null +++ b/components/src/components/molecules/Helper/utils/getValueForAlert.ts @@ -0,0 +1,36 @@ +import type { Alert } from '@/src/types' + +type Properties = { + background: string + border: string + svg: string +} + +type Property = keyof Properties + +export type WithAlert = { alert?: Alert } + +const alertMap: { [key in Alert]: Properties } = { + error: { + background: '$redSurface', + border: '$redPrimary', + svg: '$redPrimary', + }, + warning: { + background: '$yellowSurface', + border: '$yellowPrimary', + svg: '$yellowPrimary', + }, + info: { + background: '$blueSurface', + border: '$bluePrimary', + svg: '$bluePrimary', + }, +} + +export const getValueForAlert = ( + alert: Alert, + property: Property, +): Properties[T] => { + return alertMap[alert][property] || alertMap.info[property] +} diff --git a/components/src/components/molecules/Input/Input.tsx b/components/src/components/molecules/Input/Input.tsx index 4fdaec2e..5984f58f 100644 --- a/components/src/components/molecules/Input/Input.tsx +++ b/components/src/components/molecules/Input/Input.tsx @@ -1,17 +1,18 @@ import * as React from 'react' -import styled, { FlattenInterpolation, css } from 'styled-components' +import { StatusDot, statusDot } from '@/src/css/recipes/statusDot.css' +import { statusBorder } from '@/src/css/recipes/statusBorder.css' import { setNativeValue } from '@/src/utils/setNativeValue' +import { scale } from '@/src/css/utils/common' + +import * as styles from './styles.css' + import { CrossCircleSVG, Field } from '../..' import { FieldBaseProps } from '../../atoms/Field' -import { Radii, Space } from '../../../tokens/index' -import { DefaultTheme } from '../../../types/index' -import { - FontVariant, - getFontSize, - getLineHeight, -} from '../../../types/withTypography' +import { Space } from '../../../tokens/index' +import { Box, BoxProps } from '../../atoms/Box/Box' +import { getValueForSize } from './utils/getValueForSize' type NativeInputProps = React.InputHTMLAttributes @@ -80,7 +81,7 @@ type BaseProps = Omit & { /** Sets the height of the input element. */ size?: 'small' | 'medium' | 'large' | 'extraLarge' /** Set of styles */ - parentStyles?: FlattenInterpolation + parentStyles?: BoxProps } & Omit< NativeInputProps, | 'size' @@ -108,371 +109,202 @@ type WithTypeDateTimeLocal = { type?: 'datetime-local' } -type Size = NonNullable - -const SPACES: { - [key in Size]: { - outerPadding: Space - gap: Space - icon: Space - iconPadding: Space - height: Space - } -} = { - small: { - outerPadding: '3.5', - gap: '2', - icon: '3', - iconPadding: '8.5', - height: '10', - }, - medium: { - outerPadding: '4', - gap: '2', - icon: '4', - iconPadding: '10', - height: '12', - }, - large: { - outerPadding: '4', - gap: '2', - icon: '5', - iconPadding: '11', - height: '16', - }, - extraLarge: { - outerPadding: '6', - gap: '2', - icon: '6', - iconPadding: '14', - height: '20', - }, -} - -const getSpaceValue = ( - theme: DefaultTheme, - size: keyof typeof SPACES, - key: keyof typeof SPACES['small'], -): string => { - return theme.space[SPACES[size][key]] -} - -const getIconPadding = ( - theme: DefaultTheme, - size: keyof typeof SPACES, - iconWidth?: Space, - negative?: boolean, -) => { - if (iconWidth) - return negative - ? `calc(-${theme.space[SPACES[size].outerPadding]} - ${ - theme.space[iconWidth] - } - ${theme.space[SPACES[size].gap]})` - : `calc(${theme.space[SPACES[size].outerPadding]} + ${ - theme.space[iconWidth] - } + ${theme.space[SPACES[size].gap]})` - return negative - ? `-${theme.space[SPACES[size].iconPadding]}` - : theme.space[SPACES[size].iconPadding] -} - -const RADII: { - [key in Size]: Radii -} = { - small: 'large', - medium: 'large', - large: '2.5xLarge', - extraLarge: '2.5xLarge', -} - -const getRadiusValue = (theme: DefaultTheme, size: keyof typeof RADII) => { - return theme.radii[RADII[size]] -} - -const TYPOGRAPHIES: { - [key in Size]: FontVariant -} = { - small: 'small', - medium: 'body', - large: 'large', - extraLarge: 'headingThree', -} - -const getTypographyValue = (size: keyof typeof TYPOGRAPHIES) => { - return TYPOGRAPHIES[size] -} +export type Size = NonNullable -const Container = styled.div<{ +type ContainerProps = { $size: Size $disabled?: boolean $hasError?: boolean $suffix: boolean $validated?: boolean $showDot?: boolean - $userStyles?: FlattenInterpolation -}>( - ({ theme, $size, $hasError, $userStyles, $validated, $showDot }) => css` - position: relative; - height: ${getSpaceValue(theme, $size, 'height')}; - display: flex; - transition-duration: ${theme.transitionDuration['150']}; - transition-property: color, border-color, background-color; - transition-timing-function: ${theme.transitionTimingFunction['inOut']}; - - :after { - content: ''; - position: absolute; - width: ${theme.space['4']}; - height: ${theme.space['4']}; - border: 2px solid ${theme.colors.backgroundPrimary}; - box-sizing: border-box; - border-radius: 50%; - right: -${theme.space['1.5']}; - top: -${theme.space['1.5']}; - transition: all 0.3s ease-out; - transform: scale(0.3); - opacity: 0; - } - - ${$showDot && - $validated && - css` - :after { - background: ${theme.colors.greenPrimary}; - transform: scale(1); - opacity: 1; - } - `} - - ${$showDot && - !$hasError && - css` - &:focus-within:after { - background: ${theme.colors.bluePrimary}; - transform: scale(1); - opacity: 1; - } - `} - - ${$hasError && - $showDot && - css` - :after { - background: ${theme.colors.redPrimary}; - transform: scale(1); - opacity: 1; - } - `} - - ${$userStyles} - `, + $userStyles?: BoxProps +} +const Container = ({ + $size, + ...props +}: BoxProps & ContainerProps & StatusDot) => ( + ) -const Label = styled.label<{ $size: Size }>( - ({ theme, $size }) => css` - display: flex; - align-items: center; - gap: ${theme.space[2]}; - - height: ${theme.space.full}; - color: ${theme.colors.greyPrimary}; - background: ${theme.colors.greySurface}; - font-size: ${getFontSize(getTypographyValue($size))}; - line-height: ${getLineHeight(getTypographyValue($size))}; - font-weight: ${theme.fontWeights.normal}; - padding: 0 ${getSpaceValue(theme, $size, 'outerPadding')}; - - svg { - display: block; - color: ${theme.colors.greyPrimary}; - } - `, +const Label = ({ + $size, + $disabled, + ...props +}: BoxProps & { $disabled?: boolean; $size: Size }) => ( + ) -const Prefix = styled(Label)( - () => css` - order: -2; - `, -) +type IconBoxProps = { + $icon: React.ReactElement + $iconWidth?: any + $size: Size +} -const IconWrapper = styled.div<{ $size: Size; $iconWidth?: Space }>( - ({ theme, $size, $iconWidth }) => css` - order: -1; - padding-left: ${getSpaceValue(theme, $size, 'outerPadding')}; - flex: 0 0 ${getIconPadding(theme, $size, $iconWidth)}; - margin-right: ${getIconPadding(theme, $size, $iconWidth, true)}; - display: flex; - align-items: center; - justify-content: flex-start; - pointer-events: none; - svg { - display: block; - width: ${$iconWidth - ? theme.space[$iconWidth] - : getSpaceValue(theme, $size, 'icon')}; - height: ${$iconWidth - ? theme.space[$iconWidth] - : getSpaceValue(theme, $size, 'icon')}; - color: ${theme.colors.greyPrimary}; - } - z-index: 1; - `, +const Icon = ({ + $icon, + $iconWidth, + $size, + ...props +}: BoxProps & IconBoxProps) => ( + + {$icon} + ) -const ActionButton = styled.button<{ $size: Size }>( - ({ theme, $size }) => css` - padding-right: ${getSpaceValue(theme, $size, 'outerPadding')}; - margin-left: -${getSpaceValue(theme, $size, 'iconPadding')}; - flex: 0 0 ${getSpaceValue(theme, $size, 'iconPadding')}; - display: flex; - justify-content: flex-end; - align-items: center; - transition: all 0.1s ease-in-out; - transform: scale(1); - opacity: 1; - cursor: pointer; - - svg { - display: block; - width: ${getSpaceValue(theme, $size, 'icon')}; - height: ${getSpaceValue(theme, $size, 'icon')}; - color: ${theme.colors.greyPrimary}; - transition: all 150ms ease-in-out; - } - - &:hover svg { - color: ${theme.colors.greyBright}; - transform: translateY(-1px); - } - `, -) +const ActionButton = ({ + $icon, + $size, + ...props +}: BoxProps & { $size: Size; $icon?: React.ReactNode }) => { + const Icon: React.ReactElement = React.isValidElement($icon) ? ( + $icon + ) : ( + + ) + return ( + + + + ) +} -const InputComponent = styled.input<{ +type InputProps = { $size: Size $hasAction: boolean $hasIcon: boolean $hasError: boolean $iconWidth?: Space -}>( - ({ theme, $size, $hasIcon, $hasAction, $hasError, $iconWidth }) => css` - background-color: transparent; - position: relative; - width: ${theme.space['full']}; - height: ${theme.space['full']}; - font-weight: ${theme.fontWeights.normal}; - text-overflow: ellipsis; - color: ${theme.colors.textPrimary}; - padding: 0 ${getSpaceValue(theme, $size, 'outerPadding')}; - font-size: ${getFontSize(getTypographyValue($size))}; - line-height: ${getLineHeight(getTypographyValue($size))}; - - ${$hasIcon && - css` - padding-left: ${getIconPadding(theme, $size, $iconWidth)}; - `} - - ${$hasAction && - css` - padding-right: ${getSpaceValue(theme, $size, 'iconPadding')}; - `} - - &::placeholder { - color: ${theme.colors.greyPrimary}; - font-weight: ${$size === 'large' || $size === 'extraLarge' - ? theme.fontWeights.bold - : theme.fontWeights.normal}; - } - - &:read-only { - cursor: default; - } - - &:disabled { - background: ${theme.colors.greyLight}; - cursor: not-allowed; - color: ${theme.colors.greyPrimary}; - } +} - ${$hasError && - css` - color: ${theme.colors.redPrimary}; - `} - `, +const InputComponent = React.forwardRef( + ( + { + $size, + $hasIcon, + $hasAction, + $hasError, + // $iconWidth, + ...props + }, + ref, + ) => ( + + ), ) -const InnerContainer = styled.div<{ +type InnerContainerProps = { $size: Size $hasError: boolean $disabled: boolean $readOnly: boolean $alwaysShowAction: boolean -}>( - ({ theme, $size, $hasError, $disabled, $readOnly, $alwaysShowAction }) => css` - position: relative; - background-color: ${theme.colors.backgroundPrimary}; - border-radius: ${getRadiusValue(theme, $size)}; - border-width: ${theme.space.px}; - border-color: ${theme.colors.border}; - color: ${theme.colors.textPrimary}; - overflow: hidden; - width: 100%; - height: 100%; - display: flex; - transition-duration: ${theme.transitionDuration['150']}; - transition-property: color, border-color, background-color; - transition-timing-function: ${theme.transitionTimingFunction['inOut']}; - - ${$disabled && - css` - border-color: ${theme.colors.border}; - background-color: ${theme.colors.greyLight}; - `} - - ${$hasError && - css` - border-color: ${theme.colors.redPrimary}; - cursor: default; - `} - - ${!$hasError && - !$readOnly && - css` - &:focus-within { - border-color: ${theme.colors.accentBright}; - } - `} - - input ~ label { - cursor: text; - } - - input:read-only ~ label, - input:read-only ~ button { - cursor: default; - } - - input:disabled ~ label, - input:disabled ~ button { - background: ${theme.colors.greyLight}; - cursor: not-allowed; - } - - input:disabled ~ button, - input:read-only ~ button { - opacity: 0; - transform: scale(0.8); - pointer-events: none; - } +} - ${!$alwaysShowAction && - css` - input:placeholder-shown ~ button { - opacity: 0; - transform: scale(0.8); - pointer-events: none; - } - `} - `, +const InnerContainer = ({ + $size, + $disabled, + ...props +}: BoxProps & InnerContainerProps) => ( + ) type Props = BaseProps & (WithTypeEmail | WithTypeText | WithTypeDateTimeLocal) @@ -568,6 +400,11 @@ export const Input = React.forwardRef( > {(ids) => ( {prefix && ( - + )} - {icon && ( - - {icon} - + {icon && React.isValidElement(icon) && ( + )} {hasAction && ( e.preventDefault()} - > - {actionIcon ? actionIcon : } - + /> )} {suffix && (