diff --git a/src/icons/stories/Icons.stories.tsx b/src/icons/stories/Icons.stories.tsx index 3b91995..63f0692 100644 --- a/src/icons/stories/Icons.stories.tsx +++ b/src/icons/stories/Icons.stories.tsx @@ -1,5 +1,5 @@ import * as Icons from '../.'; -import { styled } from '../../../stitches.config'; +import { styled } from '../../theme'; const IconsWrapper = styled('div', { display: 'flex', diff --git a/src/index.ts b/src/index.ts index bfa1511..17c137f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,38 @@ +// Primitives export { colorPrimitives } from './primitives/colorPrimitives'; export { textStyles } from './primitives/textStyles'; + +// Icons +export * from './icons'; + +// Theme export { createBreakpoints, fontStack, generateCSSVariablesMap, generateThemeScaleCssVariables, - theme, +} from './theme/utils'; +export { + theme as styledComponentsTheme, themeCssVariables, -} from './theme'; -export * from './icons'; +} from './theme/theme'; +export { UIKitProvider } from './theme/UIKitProvider'; +export { + styled, + css, + theme, + createTheme, + getCssText, + globalCss, + keyframes, + config, +} from './theme/stitches.config'; +export type { + VariantProps, + CSS, + ThemeConfig, + UIKitTheme, + ThemeType, + CreateTheme, + UIKitThemeContextProps, +} from './theme/types'; diff --git a/src/theme/UIKitProvider.tsx b/src/theme/UIKitProvider.tsx new file mode 100644 index 0000000..97e77da --- /dev/null +++ b/src/theme/UIKitProvider.tsx @@ -0,0 +1,29 @@ +import type { ReactNode } from 'react'; +import { useMemo } from 'react'; +import { + defaultUIKitThemeContext, + UIKitThemeContext, +} from './UIKitThemeContext'; +// import type { CreateTheme } from './types'; + +type UIKitProviderProps = { + children: ReactNode; + // theme?: CreateTheme; +}; + +export const UIKitProvider = ({ + children, +}: UIKitProviderProps): JSX.Element => { + const uiKitThemeContext = useMemo( + () => + // Will add more logic to this later. + defaultUIKitThemeContext, + [] + ); + + return ( + + {children} + + ); +}; diff --git a/src/theme/UIKitThemeContext.ts b/src/theme/UIKitThemeContext.ts new file mode 100644 index 0000000..52af6a5 --- /dev/null +++ b/src/theme/UIKitThemeContext.ts @@ -0,0 +1,13 @@ +import { createContext } from 'react'; +import { theme } from './stitches.config'; +import type { UIKitThemeContextProps } from './types'; + +export const defaultUIKitThemeContext: UIKitThemeContextProps = { + isDark: false, + theme, + type: 'light', +}; + +export const UIKitThemeContext = createContext( + defaultUIKitThemeContext +); diff --git a/src/theme/common.ts b/src/theme/common.ts new file mode 100644 index 0000000..48f8366 --- /dev/null +++ b/src/theme/common.ts @@ -0,0 +1,240 @@ +import { defaultThemeMap as defaultStitchesThemeMap } from '@stitches/react'; +import type * as Stitches from '@stitches/react'; +import { colorPrimitives } from 'index'; +import { breakpoints } from './breakpoints'; +import { fontStacks } from './fonts'; + +export const commonTokens = { + borderWeights: { + /* eslint-disable sort-keys-fix/sort-keys-fix */ + light: '1px', + normal: '2px', + bold: '3px', + extrabold: '4px', + black: '5px', + /* eslint-enable sort-keys-fix/sort-keys-fix */ + }, + breakpoints: { + lg: breakpoints.lg, + md: breakpoints.md, + sm: breakpoints.sm, + xl: breakpoints.xl, + }, + fonts: fontStacks, + fontSizes: { + /* eslint-disable sort-keys-fix/sort-keys-fix */ + base: '1rem', + tiny: '.75rem', + xs: '0.875rem', + sm: '1.25rem', + md: '1.5rem', + lg: '2.25rem', + xl: '3rem', + /* eslint-enable sort-keys-fix/sort-keys-fix */ + }, + fontWeights: { + /* eslint-disable sort-keys-fix/sort-keys-fix */ + hairline: 100, + thin: 200, + light: 300, + normal: 400, + medium: 500, + semibold: 600, + bold: 700, + extrabold: 800, + black: 900, + /* eslint-enable sort-keys-fix/sort-keys-fix */ + }, + letterSpacings: { + /* eslint-disable sort-keys-fix/sort-keys-fix */ + tighter: '-0.05em', + tight: '-0.025em', + normal: '0', + wide: '0.025em', + wider: '0.05em', + widest: '0.1em', + /* eslint-enable sort-keys-fix/sort-keys-fix */ + }, + lineHeights: { + /* eslint-disable sort-keys-fix/sort-keys-fix */ + xs: 1, + sm: 1.25, + md: 1.5, + lg: 1.625, + xl: 1.75, + /* eslint-enable sort-keys-fix/sort-keys-fix */ + }, + radii: { + // TODO: Add defined "xs", "sm", "md", "lg", "xl" and "base" + pill: '9999px', + rounded: '50%', + squared: '33%', + }, + space: { + /* eslint-disable sort-keys-fix/sort-keys-fix */ + 0: '0rem', + xs: '0.5rem', + sm: '0.75rem', + md: '1rem', + lg: '1.25rem', + xl: '2.25rem', + px: '1px', + 1: '0.125rem', + 2: '0.25rem', + 3: '0.375rem', + 4: '0.5rem', + 5: '0.625rem', + 6: '0.75rem', + 7: '0.875rem', + 8: '1rem', + 9: '1.25rem', + 10: '1.5rem', + 11: '1.75rem', + 12: '2rem', + 13: '2.25rem', + 14: '2.5rem', + 15: '2.75rem', + 16: '3rem', + 17: '3.5rem', + 18: '4rem', + 20: '5rem', + 24: '6rem', + 28: '7rem', + 32: '8rem', + 36: '9rem', + 40: '10rem', + 44: '11rem', + 48: '12rem', + 52: '13rem', + 56: '14rem', + 60: '15rem', + 64: '16rem', + 72: '18rem', + 80: '20rem', + 96: '24rem', + /* eslint-enable sort-keys-fix/sort-keys-fix */ + }, + transitions: { + default: 'all 250ms ease', + }, + zIndices: { + 1: '100', + 2: '200', + 3: '300', + 4: '400', + 5: '500', + 6: '600', + 7: '700', + 8: '800', + 9: '900', + 10: '1000', + max: '9999', + }, +}; + +export const commonColors = { + ...colorPrimitives, + // generic colors + black: '#000000', + white: '#ffffff', +}; + +export const commonMedia = { + /* eslint-disable sort-keys-fix/sort-keys-fix */ + sm: `(min-width: ${commonTokens.breakpoints.sm})`, + md: `(min-width: ${commonTokens.breakpoints.md})`, + lg: `(min-width: ${commonTokens.breakpoints.lg})`, + xl: `(min-width: ${commonTokens.breakpoints.xl})`, + smMax: `(max-width: ${commonTokens.breakpoints.sm})`, + mdMax: `(max-width: ${commonTokens.breakpoints.md})`, + lgMax: `(max-width: ${commonTokens.breakpoints.lg})`, + xlMax: `(max-width: ${commonTokens.breakpoints.xl})`, + motion: '(prefers-reduced-motion)', + safari: 'not all and (min-resolution:.001dpcm)', + hover: '(any-hover: hover)', + dark: '(prefers-color-scheme: dark)', + light: '(prefers-color-scheme: light)', + /* eslint-enable sort-keys-fix/sort-keys-fix */ +}; + +export const commonUtils = { + /* eslint-disable id-length */ + m: (value: Stitches.PropertyValue<'margin'>) => ({ + margin: value, + }), + mb: (value: Stitches.PropertyValue<'marginBottom'>) => ({ + marginBottom: value, + }), + ml: (value: Stitches.PropertyValue<'marginLeft'>) => ({ + marginLeft: value, + }), + mr: (value: Stitches.PropertyValue<'marginRight'>) => ({ + marginRight: value, + }), + mt: (value: Stitches.PropertyValue<'marginTop'>) => ({ + marginTop: value, + }), + mx: (value: Stitches.PropertyValue<'marginLeft'>) => ({ + marginLeft: value, + marginRight: value, + }), + my: (value: Stitches.PropertyValue<'marginTop'>) => ({ + marginBottom: value, + marginTop: value, + }), + p: (value: Stitches.PropertyValue<'padding'>) => ({ + padding: value, + }), + pb: (value: Stitches.PropertyValue<'paddingBottom'>) => ({ + paddingBottom: value, + }), + pl: (value: Stitches.PropertyValue<'paddingLeft'>) => ({ + paddingLeft: value, + }), + pr: (value: Stitches.PropertyValue<'paddingRight'>) => ({ + paddingRight: value, + }), + pt: (value: Stitches.PropertyValue<'paddingTop'>) => ({ + paddingTop: value, + }), + px: (value: Stitches.PropertyValue<'paddingLeft'>) => ({ + paddingLeft: value, + paddingRight: value, + }), + py: (value: Stitches.PropertyValue<'paddingTop'>) => ({ + paddingBottom: value, + paddingTop: value, + }), + /* eslint-enable id-length */ +}; + +export const commonThemeMap = { + ...defaultStitchesThemeMap, + blockSize: 'space', + borderWidth: 'borderWeights', + flexBasis: 'space', + gridTemplateColumns: 'space', + gridTemplateRows: 'space', + height: 'space', + inlineSize: 'space', + maxBlockSize: 'space', + maxHeight: 'space', + maxInlineSize: 'space', + maxWidth: 'space', + minBlockSize: 'space', + minHeight: 'space', + minInlineSize: 'space', + minWidth: 'space', + width: 'space', +}; + +export const commonTheme = { + media: commonMedia, + prefix: 'uikit', + theme: { + ...commonTokens, + colors: commonColors, + }, + themeMap: commonThemeMap, + utils: commonUtils, +}; diff --git a/src/theme/fonts.ts b/src/theme/fonts.ts index 1dea56c..4af400d 100644 --- a/src/theme/fonts.ts +++ b/src/theme/fonts.ts @@ -1,6 +1,6 @@ import { fontStack, generateThemeScaleCssVariables } from './utils'; -const fontStacks = { +export const fontStacks = { body: fontStack([ 'Inter', '-apple-system', diff --git a/src/theme/index.ts b/src/theme/index.ts index 31060d9..af0ac7e 100644 --- a/src/theme/index.ts +++ b/src/theme/index.ts @@ -1,4 +1,7 @@ -export { theme, themeCssVariables } from './theme'; +export * from './types'; +export * from './stitches.config'; +export { UIKitProvider } from './UIKitProvider'; +export { theme as styledComponentsTheme, themeCssVariables } from './theme'; export { createBreakpoints, fontStack, diff --git a/src/theme/light-theme.ts b/src/theme/light-theme.ts new file mode 100644 index 0000000..620f654 --- /dev/null +++ b/src/theme/light-theme.ts @@ -0,0 +1,2 @@ +// Any theme configs that are specific to the "light" theme. +export const lightThemeConfig = {}; diff --git a/src/theme/stitches.config.ts b/src/theme/stitches.config.ts new file mode 100644 index 0000000..ae70427 --- /dev/null +++ b/src/theme/stitches.config.ts @@ -0,0 +1,63 @@ +import { createStitches } from '@stitches/react'; +import { commonTheme } from './common'; +import type { ThemeConfig } from './types'; + +// export const { +// styled, +// css, +// globalCss, +// keyframes, +// getCssText, +// theme, +// createTheme, +// config, +// } = createStitches({ +// media: {}, +// theme: { +// colors: colorPrimitives, +// space: { +// 4: '4px', +// 8: '8px', +// 16: '16px', +// 24: '24px', +// 32: '32px', +// 48: '48px', +// 64: '64px', +// 96: '96px', +// 128: '128px', +// }, +// }, +// utils: { +// mx: (value: Stitches.ScaleValue<'space'>) => ({ +// marginLeft: value, +// marginRight: value, +// }), +// }, +// }); + +export const { + createTheme: createThemeBase, + styled, + css, + globalCss, + keyframes, + getCssText, + theme, + config, +} = createStitches({ + // TODO: Manually add any "light theme" configs here once added. + ...commonTheme, +}); + +export const createTheme = ({ + type, + theme: newTheme, + className, +}: ThemeConfig) => { + if (!type) { + throw new Error('Theme `type` is required.'); + } + + // TODO: Deeply merge newTheme with light theme. + return createThemeBase(className ?? `${type}-theme`, newTheme); +}; diff --git a/src/theme/theme.ts b/src/theme/theme.ts index d6697ac..942c355 100644 --- a/src/theme/theme.ts +++ b/src/theme/theme.ts @@ -5,6 +5,7 @@ import { fonts, fontCssVariables } from './fonts'; import { mediaQueries } from './mediaQueries'; import type { CSSVariables } from './types'; +/** This theme is for backwards compatibility with our old styled-system, styled-components setup in CWA */ const theme = { breakpoints, colors, diff --git a/src/theme/types.ts b/src/theme/types.ts index 7b620e8..09f0e3a 100644 --- a/src/theme/types.ts +++ b/src/theme/types.ts @@ -1,12 +1,57 @@ +import type * as Stitches from '@stitches/react'; +import type { config, createThemeBase, theme } from './stitches.config'; + export type BreakpointNames = 'lg' | 'md' | 'sm' | 'xl'; -export type Breakpoints = readonly string[] & - { - [breakpoint in BreakpointNames]: string; - }; +export type Breakpoints = readonly string[] & { + [breakpoint in BreakpointNames]: string; +}; export type CSSVariables = Array<[cssVariableName: string, value: string]>; export type ThemeScaleObject = { [key: string]: ThemeScaleObject | string; }; + +/** Theme interface. */ +export type BaseTheme = { + [Scale in keyof T]: { + [Token in keyof T[Scale]]: T[Scale][Token] extends boolean | number | string + ? T[Scale][Token] + : boolean | number | string; + }; +} & { + borderStyles?: { [token in number | string]: boolean | number | string }; + borderWidths?: { [token in number | string]: boolean | number | string }; + colors?: { [token in number | string]: boolean | number | string }; + fontSizes?: { [token in number | string]: boolean | number | string }; + fontWeights?: { [token in number | string]: boolean | number | string }; + fonts?: { [token in number | string]: boolean | number | string }; + letterSpacings?: { [token in number | string]: boolean | number | string }; + lineHeights?: { [token in number | string]: boolean | number | string }; + radii?: { [token in number | string]: boolean | number | string }; + shadows?: { [token in number | string]: boolean | number | string }; + sizes?: { [token in number | string]: boolean | number | string }; + space?: { [token in number | string]: boolean | number | string }; + transitions?: { [token in number | string]: boolean | number | string }; + zIndices?: { [token in number | string]: boolean | number | string }; +}; + +export type ThemeType = 'light'; + +export type ThemeConfig = { + className?: string; + theme?: BaseTheme; + type?: ThemeType | string; +}; + +export type UIKitThemeContextProps = { + isDark?: boolean; + theme?: UIKitTheme; + type: ThemeType | string; +}; + +export type VariantProps = Stitches.VariantProps; +export type CSS = Stitches.CSS; +export type UIKitTheme = typeof theme; +export type CreateTheme = ReturnType; diff --git a/stitches.config.ts b/stitches.config.ts deleted file mode 100644 index 12de719..0000000 --- a/stitches.config.ts +++ /dev/null @@ -1,36 +0,0 @@ -import type * as Stitches from '@stitches/react'; -import { createStitches } from '@stitches/react'; -import { colorPrimitives } from './src/primitives/colorPrimitives'; - -export const { - styled, - css, - globalCss, - keyframes, - getCssText, - theme, - createTheme, - config, -} = createStitches({ - media: {}, - theme: { - colors: colorPrimitives, - space: { - 4: '4px', - 8: '8px', - 16: '16px', - 24: '24px', - 32: '32px', - 48: '48px', - 64: '64px', - 96: '96px', - 128: '128px', - }, - }, - utils: { - mx: (value: Stitches.ScaleValue<'space'>) => ({ - marginLeft: value, - marginRight: value, - }), - }, -});