From 45b83041c8f786274ef3558e650762ab388525cd Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Sun, 12 Feb 2023 21:20:08 +0330 Subject: [PATCH 1/3] story(lsd-react): add disabled property to Button stories --- .../lsd-react/src/components/Button/Button.stories.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/lsd-react/src/components/Button/Button.stories.tsx b/packages/lsd-react/src/components/Button/Button.stories.tsx index a820d76..d834efa 100644 --- a/packages/lsd-react/src/components/Button/Button.stories.tsx +++ b/packages/lsd-react/src/components/Button/Button.stories.tsx @@ -1,9 +1,14 @@ import { Meta, Story } from '@storybook/react' -import { Button } from './Button' +import { Button, ButtonProps } from './Button' export default { title: 'Button', component: Button, } as Meta -export const Root: Story = (args) => +export const Root: Story = (args) => ( + +) +Root.args = { + disabled: false, +} From a6b437f26fa95e10ae150c9622010494bdec4e85 Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Mon, 13 Feb 2023 13:13:50 +0330 Subject: [PATCH 2/3] feat: update design tokens --- packages/lsd-react/.storybook/preview.tsx | 2 +- .../.storybook/withTheme.decorator.tsx | 23 +- .../src/components/Button/Button.styles.ts | 71 +++--- .../components/CSSBaseline/CSSBaseline.tsx | 9 +- .../src/components/Theme/baseTheme.ts | 241 ++++++++---------- .../src/components/Theme/constants.ts | 41 ++- .../src/components/Theme/createTheme.ts | 35 ++- .../src/components/Theme/defaultThemes.ts | 11 +- .../src/components/Theme/globalStyles.ts | 164 ++++++------ .../lsd-react/src/components/Theme/index.ts | 2 +- .../lsd-react/src/components/Theme/types.ts | 47 ++-- 11 files changed, 317 insertions(+), 329 deletions(-) diff --git a/packages/lsd-react/.storybook/preview.tsx b/packages/lsd-react/.storybook/preview.tsx index 6de7b71..0b4845b 100644 --- a/packages/lsd-react/.storybook/preview.tsx +++ b/packages/lsd-react/.storybook/preview.tsx @@ -14,7 +14,7 @@ export const parameters: Parameters = { default: 'light', values: Object.entries(defaultThemes).map(([name, theme]) => ({ name, - value: theme.palette.background.primary, + value: `rgb(${theme.palette.secondary})`, })), }, viewport: { diff --git a/packages/lsd-react/.storybook/withTheme.decorator.tsx b/packages/lsd-react/.storybook/withTheme.decorator.tsx index 3f85a8c..312e4e7 100644 --- a/packages/lsd-react/.storybook/withTheme.decorator.tsx +++ b/packages/lsd-react/.storybook/withTheme.decorator.tsx @@ -1,23 +1,28 @@ import { DecoratorFunction, useGlobals } from '@storybook/addons' import React, { useEffect } from 'react' -import { defaultThemes, ThemeProvider } from '../src' +import { defaultThemes, Theme, ThemeProvider } from '../src' export const withTheme: DecoratorFunction = (Story, context) => { const StoryComponent = Story as any as React.ComponentType const themeName = context.globals?.theme ?? 'light' - const theme = defaultThemes[themeName] + const theme = defaultThemes[themeName] as Theme const [globals, setGlobals] = useGlobals() useEffect(() => { - setGlobals({ - ...globals, - backgrounds: { - ...(globals.background ?? {}), - value: theme.palette.background.primary, - }, - }) + const background = (context.parameters.backgrounds?.values ?? []).find( + (value) => value.name === themeName, + )?.value + + globals.backgrounds?.value !== background && + setGlobals({ + ...globals, + backgrounds: { + ...(globals.background ?? {}), + value: background, + }, + }) }, [theme]) return ( diff --git a/packages/lsd-react/src/components/Button/Button.styles.ts b/packages/lsd-react/src/components/Button/Button.styles.ts index 6432e0a..df6e2aa 100644 --- a/packages/lsd-react/src/components/Button/Button.styles.ts +++ b/packages/lsd-react/src/components/Button/Button.styles.ts @@ -1,47 +1,38 @@ import { css } from '@emotion/react' -import { withTheme } from '../Theme/withTheme' import { buttonClasses } from './Button.classes' -export const ButtonStyles = withTheme( - (theme) => css` - .${buttonClasses.root} { - width: auto; - color: var(--lsd-text-primary); - background: none; - border: 1px solid var(--lsd-surface-primary); +export const ButtonStyles = css` + .${buttonClasses.root} { + width: auto; + color: rgb(var(--lsd-text-primary)); + background: none; + border: 1px solid rgb(var(--lsd-border-primary)); - cursor: pointer; - padding: 6px 24px; + cursor: pointer; + padding: 6px 24px; + } - @media (max-width: ${theme.breakpoints.lg.width}px) { - color: red; - border-color: red; + .${buttonClasses.disabled} { + cursor: default; + opacity: 0.34; + } + + .${buttonClasses.large} { + padding: 10px 40px; + } + + .${buttonClasses.medium} { + } + + .${buttonClasses.small} { + padding: 6px 12px; + } + + .${buttonClasses.root}:hover { + &:not(.${buttonClasses.disabled}) { + .${buttonClasses.text} { + text-decoration: underline; } } - - .${buttonClasses.disabled} { - cursor: default; - color: var(--lsd-surface-disabled); - border-color: var(--lsd-surface-disabled); - } - - .${buttonClasses.large} { - padding: 10px 40px; - } - - .${buttonClasses.medium} { - } - - .${buttonClasses.small} { - padding: 6px 12px; - } - - .${buttonClasses.root}:hover { - &:not(.${buttonClasses.disabled}) { - .${buttonClasses.text} { - text-decoration: underline; - } - } - } - `, -) + } +` diff --git a/packages/lsd-react/src/components/CSSBaseline/CSSBaseline.tsx b/packages/lsd-react/src/components/CSSBaseline/CSSBaseline.tsx index 345e546..bb1e5e4 100644 --- a/packages/lsd-react/src/components/CSSBaseline/CSSBaseline.tsx +++ b/packages/lsd-react/src/components/CSSBaseline/CSSBaseline.tsx @@ -1,14 +1,17 @@ -import { Global } from '@emotion/react' +import { Global, SerializedStyles } from '@emotion/react' import React, { useMemo } from 'react' import { ButtonStyles } from '../Button/Button.styles' -import { defaultThemes, Theme } from '../Theme' +import { defaultThemes, Theme, withTheme } from '../Theme' + +const componentStyles: Array | SerializedStyles> = + [ButtonStyles] export const CSSBaseline: React.FC<{ theme?: Theme }> = ({ theme = defaultThemes.light, }) => { const styles = useMemo( () => - [ButtonStyles] + componentStyles .map((style) => (typeof style === 'function' ? style(theme) : style)) .map((style) => ), [theme], diff --git a/packages/lsd-react/src/components/Theme/baseTheme.ts b/packages/lsd-react/src/components/Theme/baseTheme.ts index 2e0c67e..61cbcb9 100644 --- a/packages/lsd-react/src/components/Theme/baseTheme.ts +++ b/packages/lsd-react/src/components/Theme/baseTheme.ts @@ -7,173 +7,140 @@ export const baseTheme: Theme = { xs: { width: 0, typography: { - headlineLg: {}, - headlineMd: {}, - headlineStd: {}, - headlineSm: {}, - titleLg: {}, - titleMd: {}, - titleSm: {}, - bodyLg: {}, - bodyMd: {}, - bodySm: {}, - labelLg: {}, - labelMd: {}, - labelSm: {}, + display1: {}, + display2: {}, + h1: {}, + h2: {}, + h3: {}, + h4: {}, + h5: {}, + h6: {}, + body1: {}, + body2: {}, + body3: {}, + label1: {}, + label2: {}, + subtitle1: {}, + subtitle2: {}, }, }, sm: { width: 400, typography: { - headlineLg: {}, - headlineMd: {}, - headlineStd: {}, - headlineSm: {}, - titleLg: {}, - titleMd: {}, - titleSm: {}, - bodyLg: {}, - bodyMd: {}, - bodySm: {}, - labelLg: {}, - labelMd: {}, - labelSm: {}, + display1: {}, + display2: {}, + h1: {}, + h2: {}, + h3: {}, + h4: {}, + h5: {}, + h6: {}, + body1: {}, + body2: {}, + body3: {}, + label1: {}, + label2: {}, + subtitle1: {}, + subtitle2: {}, }, }, md: { width: 768, typography: { - headlineLg: {}, - headlineMd: {}, - headlineStd: {}, - headlineSm: {}, - titleLg: {}, - titleMd: {}, - titleSm: {}, - bodyLg: {}, - bodyMd: {}, - bodySm: {}, - labelLg: {}, - labelMd: {}, - labelSm: {}, + display1: {}, + display2: {}, + h1: {}, + h2: {}, + h3: {}, + h4: {}, + h5: {}, + h6: {}, + body1: {}, + body2: {}, + body3: {}, + label1: {}, + label2: {}, + subtitle1: {}, + subtitle2: {}, }, }, lg: { width: 1024, typography: { - headlineLg: {}, - headlineMd: {}, - headlineStd: {}, - headlineSm: {}, - titleLg: {}, - titleMd: {}, - titleSm: {}, - bodyLg: {}, - bodyMd: {}, - bodySm: {}, - labelLg: {}, - labelMd: {}, - labelSm: {}, + display1: {}, + display2: {}, + h1: {}, + h2: {}, + h3: {}, + h4: {}, + h5: {}, + h6: {}, + body1: {}, + body2: {}, + body3: {}, + label1: {}, + label2: {}, + subtitle1: {}, + subtitle2: {}, }, }, xl: { width: 1200, typography: { - headlineLg: {}, - headlineMd: {}, - headlineStd: {}, - headlineSm: {}, - titleLg: {}, - titleMd: {}, - titleSm: {}, - bodyLg: {}, - bodyMd: {}, - bodySm: {}, - labelLg: {}, - labelMd: {}, - labelSm: {}, + display1: {}, + display2: {}, + h1: {}, + h2: {}, + h3: {}, + h4: {}, + h5: {}, + h6: {}, + body1: {}, + body2: {}, + body3: {}, + label1: {}, + label2: {}, + subtitle1: {}, + subtitle2: {}, }, }, }, typography: { - headlineLg: { - fontSize: '2.875rem', - lineHeight: '3.25rem', - }, - headlineMd: { - fontSize: '1.75rem', - lineHeight: '2.25rem', - }, - headlineStd: { - fontSize: '2rem', - lineHeight: '2.5rem', - }, - headlineSm: { - fontSize: '1.5rem', - lineHeight: '2rem', - }, - titleLg: { - fontSize: '1.375rem', - lineHeight: '1.75rem', - }, - titleMd: { - fontSize: '1rem', - lineHeight: '1.5rem', - }, - titleSm: { - fontSize: '0.875rem', - lineHeight: '1.25rem', - }, - bodyLg: { - fontSize: '1rem', - lineHeight: '1.5rem', - }, - bodyMd: { - fontSize: '0.875rem', - lineHeight: '1.25rem', - }, - bodySm: { - fontSize: '0.75rem', - lineHeight: '1rem', - }, - labelLg: { - fontSize: '0.875rem', - lineHeight: '1.25rem', - }, - labelMd: { - fontSize: '0.875rem', - lineHeight: '1.25rem', - }, - labelSm: { - fontSize: '0.75rem', - lineHeight: '1rem', - }, + display1: { fontSize: '5.625rem', lineHeight: '6.125rem' }, + display2: { fontSize: '3.5625rem', lineHeight: '4rem' }, + h1: { fontSize: '2.875rem', lineHeight: '3.25rem' }, + h2: { fontSize: '2.25rem', lineHeight: '2.75rem' }, + h3: { fontSize: '2rem', lineHeight: '2.5rem' }, + h4: { fontSize: '1.75rem', lineHeight: '2.25rem' }, + h5: { fontSize: '1.5rem', lineHeight: '2rem' }, + h6: { fontSize: '1.375rem', lineHeight: '1.75rem' }, + subtitle1: { fontSize: '1rem', lineHeight: '1.5rem' }, + subtitle2: { fontSize: '0.875rem', lineHeight: '1.25rem' }, + body1: { fontSize: '1rem', lineHeight: '1.5rem' }, + body2: { fontSize: '0.875rem', lineHeight: '1.25rem' }, + body3: { fontSize: '0.75rem', lineHeight: '1rem' }, + label1: { fontSize: '0.875rem', lineHeight: '1.25rem' }, + label2: { fontSize: '0.75rem', lineHeight: '1rem' }, }, palette: { - background: { - primary: 'rgba(255, 255, 255, 1)', - secondary: 'rgba(0, 0, 0, 1)', - }, - border: { - primary: 'rgba(51, 51, 56, 1)', - secondary: 'rgba(255, 255, 255, 1)', - tertiary: 'rgba(223, 223, 226, 1)', - }, + primary: '0, 0, 0', + secondary: '255, 255, 255', surface: { - primary: 'rgba(0, 0, 0, 1)', - secondary: 'rgba(0, 0, 0, 0.34)', - tertiary: 'rgba(0, 0, 0, 0.2)', - disabled: 'rgba(168, 168, 168, 1)', + primary: '255, 255, 255', + secondary: '0, 0, 0', }, text: { - primary: 'rgba(0, 0, 0, 1)', - secondary: 'rgba(0, 0, 0, 0.34)', - placeholder: 'rgba(0, 0, 0, 0.34)', - disabled: 'rgba(0, 0, 0, 0.34)', + primary: '0, 0, 0', + secondary: '255, 255, 255', + tertiary: '0, 0, 0, 0.34', }, - icons: { - primary: 'rgba(0, 0, 0, 1)', - disabled: 'rgba(0, 0, 0, 0.34)', + border: { + primary: '0, 0, 0', + secondary: '255, 255, 255', + }, + icon: { + primary: '0, 0, 0', + secondary: '255, 255, 255', }, }, globalStyles: css``, diff --git a/packages/lsd-react/src/components/Theme/constants.ts b/packages/lsd-react/src/components/Theme/constants.ts index 5d41e89..21572d8 100644 --- a/packages/lsd-react/src/components/Theme/constants.ts +++ b/packages/lsd-react/src/components/Theme/constants.ts @@ -10,21 +10,36 @@ export const LSD_NAMESPACE = 'lsd' export const THEME_BREAKPOINTS = ['xs', 'sm', 'md', 'lg', 'xl'] as Breakpoints[] export const THEME_TYPOGRAPHY_VARIANTS = [ - 'headlineLg', - 'headlineStd', - 'headlineMd', - 'headlineSm', - 'titleLg', - 'titleMd', - 'titleSm', - 'bodySm', - 'bodyMd', - 'bodyLg', - 'labelLg', - 'labelMd', - 'labelSm', + 'display1', + 'display2', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'subtitle1', + 'subtitle2', + 'body1', + 'body2', + 'body3', + 'label1', + 'label2', ] as TypographyVariants[] +export const THEME_TYPOGRAPHY_ELEMENTS: Partial< + Record +> = { + h1: ['h1'], + h2: ['h2'], + h3: ['h3'], + h4: ['h4'], + h5: ['h5'], + h6: ['h6'], + body1: ['body'], + label1: ['label'], +} + export const THEME_TYPOGRAPHY_PROPERTIES = [ 'fontSize', 'lineHeight', diff --git a/packages/lsd-react/src/components/Theme/createTheme.ts b/packages/lsd-react/src/components/Theme/createTheme.ts index 38e03f9..d5ef8c6 100644 --- a/packages/lsd-react/src/components/Theme/createTheme.ts +++ b/packages/lsd-react/src/components/Theme/createTheme.ts @@ -1,5 +1,4 @@ import { css } from '@emotion/react' -import defaultsDeep from 'lodash/defaultsDeep' import { pairs } from '../../utils/object.utils' import { baseTheme } from './baseTheme' import { THEME_BREAKPOINTS, THEME_TYPOGRAPHY_VARIANTS } from './constants' @@ -9,6 +8,7 @@ import type { CreateThemeProps, Theme, ThemeBreakpoints, + ThemePalette, TypographyVariants, VariantThemeProperties, } from './types' @@ -32,6 +32,9 @@ const createBreakpointStyle = ( ...defaultTheme[key][variant], ...theme[key][variant], ...(all?.[index - 1]?.[key]?.[variant] ?? {}), + ...(defaultTheme.breakpoints?.[THEME_BREAKPOINTS[index]]?.[key]?.[ + variant + ] ?? {}), ...(theme.breakpoints?.[THEME_BREAKPOINTS[index]]?.[key]?.[variant] ?? {}), })) @@ -68,8 +71,34 @@ const createBreakpointStyles = ( ).map((styles, index) => [THEME_BREAKPOINTS[index], styles]), ) as ThemeBreakpoints -const createPaletteStyles = (theme: CreateThemeProps, defaultTheme: Theme) => - defaultsDeep(theme.palette, defaultTheme.palette) +const createPaletteStyles = (theme: CreateThemeProps, defaultTheme: Theme) => { + const primary = theme.palette.primary ?? defaultTheme.palette.primary + const secondary = theme.palette.secondary ?? defaultTheme.palette.secondary + + const palette: ThemePalette = { + primary, + secondary, + surface: { + primary: theme.palette.surface?.primary ?? secondary, + secondary: theme.palette.surface?.secondary ?? primary, + }, + border: { + primary: theme.palette.border?.primary ?? primary, + secondary: theme.palette.border?.secondary ?? secondary, + }, + icon: { + primary: theme.palette.icon?.primary ?? primary, + secondary: theme.palette.icon?.secondary ?? secondary, + }, + text: { + primary: theme.palette.text?.primary ?? primary, + secondary: theme.palette.text?.secondary ?? secondary, + tertiary: theme.palette.text?.tertiary ?? `${primary}, 0.34`, + }, + } + + return palette +} export const createTheme = ( props: CreateThemeProps, diff --git a/packages/lsd-react/src/components/Theme/defaultThemes.ts b/packages/lsd-react/src/components/Theme/defaultThemes.ts index 7959160..cf34a31 100644 --- a/packages/lsd-react/src/components/Theme/defaultThemes.ts +++ b/packages/lsd-react/src/components/Theme/defaultThemes.ts @@ -15,15 +15,8 @@ const darkTheme = createTheme( breakpoints: {}, typography: {}, palette: { - background: { - primary: '#000', - }, - surface: { - primary: '#fff', - }, - text: { - primary: 'rgb(255, 255, 255)', - }, + primary: '255, 255, 255', + secondary: '0, 0, 0', }, }, lightTheme, diff --git a/packages/lsd-react/src/components/Theme/globalStyles.ts b/packages/lsd-react/src/components/Theme/globalStyles.ts index da75269..c7874b8 100644 --- a/packages/lsd-react/src/components/Theme/globalStyles.ts +++ b/packages/lsd-react/src/components/Theme/globalStyles.ts @@ -1,109 +1,104 @@ import { css } from '@emotion/react' import { - LSD_NAMESPACE, THEME_BREAKPOINTS, THEME_TYPOGRAPHY_PROPERTIES, THEME_TYPOGRAPHY_VARIANTS, } from './constants' -import { Breakpoints, Theme, TypographyVariants } from './types' - -export const gs = { - breakpoint: ( - theme: Theme, - breakpoint: Breakpoints, - content: string, - ) => `@media (min-width: ${theme.breakpoints[breakpoint].width}px) { - ${content} - }`, +import { Theme, TypographyProperties, TypographyVariants } from './types' +import { withTheme } from './withTheme' +const cssUtils = { vars: { - name: (...parts: string[]) => `--${[LSD_NAMESPACE, ...parts].join('-')}`, - wrap: (v: string, wrap = true) => (!wrap ? v : `var(${v})`), - define: (name: string, value: any) => `${name}: ${value};`, + lsd: (...seq: string[]) => `--${['lsd', ...seq].join('-')}`, typography: ( - variant: TypographyVariants, - property: string, - breakpoint?: Breakpoints | 'default', - ) => gs.vars.name(variant, property, ...(breakpoint ? [breakpoint] : [])), - palette: (category: string, variant: string) => - gs.vars.name(category, variant), + variant: TypographyVariants | string, + property: TypographyProperties | string, + ) => cssUtils.vars.lsd(variant, property), + color: (category: string, variant: string) => + cssUtils.vars.lsd(category, variant), + wrap: (name: string) => `var(${name})`, }, - all: (theme: Theme) => - [gs.typography.all(theme), gs.palette.all(theme)].join('\n'), + define: (name: string, value: string) => `${name}: ${value};`, +} - typography: { - all: (theme: Theme) => [gs.typography.variants(theme)].join('\n'), +const generateThemeGlobalStyles = withTheme((theme) => { + const vars: Array = [] + const styles: Array = [] + const breakpointStyles: string[][] = THEME_BREAKPOINTS.map(() => []) + const breakpointVars: string[][] = THEME_BREAKPOINTS.map(() => []) - variants: (theme: Theme) => - [ - ...THEME_TYPOGRAPHY_VARIANTS.flatMap((variant) => - THEME_TYPOGRAPHY_PROPERTIES.map((prop) => - gs.vars.define( - gs.vars.typography(variant, prop), - theme.typography[variant][prop], - ), - ), - ), - gs.typography.breakpoints(theme), - ].join('\n'), + { + THEME_TYPOGRAPHY_VARIANTS.forEach((variant) => { + THEME_TYPOGRAPHY_PROPERTIES.forEach((property) => { + const value = theme.typography[variant][property]?.toString() ?? 'unset' + vars.push( + cssUtils.define(cssUtils.vars.typography(variant, property), value), + ) + }) + }) - breakpoints: (theme: Theme) => - THEME_BREAKPOINTS.map((breakpoint, index) => - gs.breakpoint( - theme, - breakpoint, - gs.typography.breakpoint(theme, breakpoint, index), - ), - ).join('\n'), + THEME_BREAKPOINTS.forEach((breakpoint, breakpointIndex) => { + THEME_TYPOGRAPHY_VARIANTS.forEach((variant) => { + THEME_TYPOGRAPHY_PROPERTIES.forEach((property) => { + const value = + theme.breakpoints[breakpoint].typography[variant][property] - breakpoint: ( - theme: Theme, - breakpoint: Breakpoints, - breakpointIndex: number, - ) => - THEME_TYPOGRAPHY_VARIANTS.flatMap((variant) => - THEME_TYPOGRAPHY_PROPERTIES.map((prop) => { - const value = theme.breakpoints[breakpoint].typography[variant][prop] const current = breakpointIndex > 0 ? theme.breakpoints?.[THEME_BREAKPOINTS[breakpointIndex - 1]] - ?.typography?.[variant]?.[prop] - : theme.typography[variant][prop] + ?.typography?.[variant]?.[property] + : theme.typography[variant][property] - return value !== current - ? gs.vars.define(gs.vars.typography(variant, prop), value) - : undefined - }), - ) - .filter((value) => !!value) - .join('\n'), - }, + if (value && value !== current) { + breakpointVars[breakpointIndex].push( + cssUtils.define( + cssUtils.vars.typography(variant, property), + value.toString(), + ), + ) + } + }) + }) + }) + } - palette: { - all: (theme: Theme) => { - const palette = theme.palette as Record> + { + const { primary, secondary, ...rest } = theme.palette + const palette = rest as Record> - return [ - ...Object.keys(palette).flatMap((name) => - Object.keys(palette[name]).map((variant) => - gs.palette.color(name, variant, palette[name][variant]), + vars.push( + cssUtils.define(cssUtils.vars.color('theme', 'primary'), primary), + cssUtils.define(cssUtils.vars.color('theme', 'secondary'), secondary), + ...Object.keys(palette).flatMap((name) => + Object.keys(palette[name]).map((variant) => + cssUtils.define( + cssUtils.vars.color(name, variant), + palette[name][variant], ), ), + ), + ) + } - `:root { - html, body { - background-color: ${theme.palette.background.primary}; - } + THEME_BREAKPOINTS.map((breakpoint, index) => { + styles.push(`@media (min-width: ${theme.breakpoints[breakpoint].width}px) { + :root { + ${breakpointVars[index]} } - `, - ].join('\n') - }, - color: (name: string, variant: string, value: string) => - gs.vars.define(gs.vars.palette(name, variant), value), - }, -} + ${breakpointStyles[index]} + }`) + }) + + return css` + :root { + ${vars} + } + + ${styles} + ` +}) export const createThemeGlobalStyles = (() => { return (theme: Theme) => { @@ -117,15 +112,8 @@ export const createThemeGlobalStyles = (() => { ) return cache[key] - const styles = globalStyles.all(theme) - cache[key] = css` - :root { - ${styles} - } - ` + cache[key] = generateThemeGlobalStyles(theme) return cache[key] } })() - -export const globalStyles = gs diff --git a/packages/lsd-react/src/components/Theme/index.ts b/packages/lsd-react/src/components/Theme/index.ts index 2285588..786f3ef 100644 --- a/packages/lsd-react/src/components/Theme/index.ts +++ b/packages/lsd-react/src/components/Theme/index.ts @@ -7,7 +7,7 @@ export { } from './constants' export { createTheme } from './createTheme' export { defaultThemes } from './defaultThemes' -export { createThemeGlobalStyles, globalStyles } from './globalStyles' +export { createThemeGlobalStyles } from './globalStyles' export { ThemeProvider, type ThemeProviderProps } from './ThemeProvider' export * from './types' export { useTheme } from './useTheme' diff --git a/packages/lsd-react/src/components/Theme/types.ts b/packages/lsd-react/src/components/Theme/types.ts index 8aed48f..66bf066 100644 --- a/packages/lsd-react/src/components/Theme/types.ts +++ b/packages/lsd-react/src/components/Theme/types.ts @@ -5,19 +5,21 @@ import { DeepPartial } from 'utility-types' export type Breakpoints = 'xs' | 'sm' | 'md' | 'lg' | 'xl' export type TypographyTypefaces = 'sans-serif' | 'serif' | 'mono' export type TypographyVariants = - | 'headlineLg' - | 'headlineStd' - | 'headlineMd' - | 'headlineSm' - | 'titleLg' - | 'titleMd' - | 'titleSm' - | 'bodyLg' - | 'bodyMd' - | 'bodySm' - | 'labelLg' - | 'labelMd' - | 'labelSm' + | 'display1' + | 'display2' + | 'h1' + | 'h2' + | 'h3' + | 'h4' + | 'h5' + | 'h6' + | 'subtitle1' + | 'subtitle2' + | 'body1' + | 'body2' + | 'body3' + | 'label1' + | 'label2' export type VariantThemeProperties = keyof Pick @@ -28,30 +30,25 @@ export type ThemeTypography = { } export type ThemePalette = { - background: { + primary: string + secondary: string + + surface: { primary: string secondary: string } border: { primary: string secondary: string - tertiary: string - } - surface: { - primary: string - secondary: string - tertiary: string - disabled: string } text: { primary: string secondary: string - placeholder: string - disabled: string + tertiary: string } - icons: { + icon: { primary: string - disabled: string + secondary: string } } From 1603b4ab8fcbd947f7f461803ae813fc0026279b Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Mon, 13 Feb 2023 13:18:48 +0330 Subject: [PATCH 3/3] feat: implement Typography component --- .../components/CSSBaseline/CSSBaseline.tsx | 3 +- .../Typography/Typography.classes.ts | 17 +++++ .../Typography/Typography.stories.tsx | 32 ++++++++ .../Typography/Typography.styles.ts | 44 +++++++++++ .../src/components/Typography/Typography.tsx | 73 +++++++++++++++++++ .../src/components/Typography/index.ts | 1 + 6 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 packages/lsd-react/src/components/Typography/Typography.classes.ts create mode 100644 packages/lsd-react/src/components/Typography/Typography.stories.tsx create mode 100644 packages/lsd-react/src/components/Typography/Typography.styles.ts create mode 100644 packages/lsd-react/src/components/Typography/Typography.tsx create mode 100644 packages/lsd-react/src/components/Typography/index.ts diff --git a/packages/lsd-react/src/components/CSSBaseline/CSSBaseline.tsx b/packages/lsd-react/src/components/CSSBaseline/CSSBaseline.tsx index bb1e5e4..84421ae 100644 --- a/packages/lsd-react/src/components/CSSBaseline/CSSBaseline.tsx +++ b/packages/lsd-react/src/components/CSSBaseline/CSSBaseline.tsx @@ -2,9 +2,10 @@ import { Global, SerializedStyles } from '@emotion/react' import React, { useMemo } from 'react' import { ButtonStyles } from '../Button/Button.styles' import { defaultThemes, Theme, withTheme } from '../Theme' +import { TypographyStyles } from '../Typography/Typography.styles' const componentStyles: Array | SerializedStyles> = - [ButtonStyles] + [ButtonStyles, TypographyStyles] export const CSSBaseline: React.FC<{ theme?: Theme }> = ({ theme = defaultThemes.light, diff --git a/packages/lsd-react/src/components/Typography/Typography.classes.ts b/packages/lsd-react/src/components/Typography/Typography.classes.ts new file mode 100644 index 0000000..8358596 --- /dev/null +++ b/packages/lsd-react/src/components/Typography/Typography.classes.ts @@ -0,0 +1,17 @@ +import { pairs } from '../../utils/object.utils' +import { TypographyVariants } from '../Theme' +import { THEME_TYPOGRAPHY_VARIANTS } from '../Theme/constants' + +export const typographyClasses: { + root: string + primary: string + secondary: string +} & Record = { + ...pairs( + THEME_TYPOGRAPHY_VARIANTS, + (variant) => `lsd-typography--${variant}`, + ), + root: `lsd-typography`, + primary: `lsd-typography--primary`, + secondary: `lsd-typography--secondary`, +} diff --git a/packages/lsd-react/src/components/Typography/Typography.stories.tsx b/packages/lsd-react/src/components/Typography/Typography.stories.tsx new file mode 100644 index 0000000..7bed5ea --- /dev/null +++ b/packages/lsd-react/src/components/Typography/Typography.stories.tsx @@ -0,0 +1,32 @@ +import { Meta, Story } from '@storybook/react' +import { THEME_TYPOGRAPHY_VARIANTS } from '../Theme' +import { Typography, TypographyProps } from './Typography' + +export default { + title: 'Typography', + component: Typography, + argTypes: { + variant: { + type: { + name: 'enum', + value: THEME_TYPOGRAPHY_VARIANTS, + }, + defaultValue: 'body1', + }, + color: { + type: { + name: 'enum', + value: ['primary', 'secondary'], + required: false, + }, + }, + }, +} as Meta + +export const Root: Story = (args) => ( + Text +) + +Root.args = { + color: 'primary', +} diff --git a/packages/lsd-react/src/components/Typography/Typography.styles.ts b/packages/lsd-react/src/components/Typography/Typography.styles.ts new file mode 100644 index 0000000..12d852a --- /dev/null +++ b/packages/lsd-react/src/components/Typography/Typography.styles.ts @@ -0,0 +1,44 @@ +import { css } from '@emotion/react' +import { + THEME_TYPOGRAPHY_VARIANTS, + TypographyVariants, + withTheme, +} from '../Theme' +import { THEME_TYPOGRAPHY_ELEMENTS } from '../Theme/constants' +import { typographyClasses } from './Typography.classes' + +const selectors = (variant: TypographyVariants) => + [ + ...(THEME_TYPOGRAPHY_ELEMENTS[variant] ?? []), + `.${typographyClasses[variant]}`, + ].join(', ') + +export const TypographyStyles = withTheme( + (theme) => css` + .${typographyClasses.root} { + } + + .${typographyClasses.primary} { + color: rgb(var(--lsd-text-primary)); + } + + .${typographyClasses.secondary} { + color: rgb(var(--lsd-text-secondary)); + } + + ${THEME_TYPOGRAPHY_VARIANTS.map( + (variant) => css` + ${selectors(variant)} { + color: rgb(var(--lsd-text-primary)); + font-weight: normal; + font-size: var(--lsd-${variant}-fontSize); + line-height: var(--lsd-${variant}-lineHeight); + } + `, + )} + + h1, h2, h3, h4, h5, h6, p, span { + margin: 0; + } + `, +) diff --git a/packages/lsd-react/src/components/Typography/Typography.tsx b/packages/lsd-react/src/components/Typography/Typography.tsx new file mode 100644 index 0000000..de08172 --- /dev/null +++ b/packages/lsd-react/src/components/Typography/Typography.tsx @@ -0,0 +1,73 @@ +import clsx from 'clsx' +import React from 'react' +import { TypographyVariants } from '../Theme' +import { typographyClasses } from './Typography.classes' + +export type TypographyProps = { + variant?: TypographyVariants + color?: 'primary' | 'secondary' +} & ( + | ({ + component?: 'p' + } & React.HTMLAttributes) + | ({ + component?: 'span' + } & React.HTMLAttributes) + | ({ + component?: 'label' + } & React.LabelHTMLAttributes) + | ({ + component?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' + } & React.HTMLAttributes) + | ({ + component?: 'div' + } & React.HtmlHTMLAttributes) + | ({ + component?: 'a' + } & React.AnchorHTMLAttributes) +) + +export const Typography: React.FC & { + classes: typeof typographyClasses +} = ({ + color, + variant = 'body1', + component, + className, + children, + ...props +}) => { + const componentName = + component ?? + ( + { + h1: 'h1', + h2: 'h2', + h3: 'h3', + h4: 'h4', + h5: 'h5', + h6: 'h6', + label1: 'label', + label2: 'label', + } as Record + )[variant] ?? + 'span' + + const Component = componentName as any as React.ComponentType + + return ( + + {children} + + ) +} + +Typography.classes = typographyClasses diff --git a/packages/lsd-react/src/components/Typography/index.ts b/packages/lsd-react/src/components/Typography/index.ts new file mode 100644 index 0000000..2a899b5 --- /dev/null +++ b/packages/lsd-react/src/components/Typography/index.ts @@ -0,0 +1 @@ +export * from './Typography'