diff --git a/packages/canon/.storybook/main.ts b/packages/canon/.storybook/main.ts index b1e87159a3..86dc3ec87f 100644 --- a/packages/canon/.storybook/main.ts +++ b/packages/canon/.storybook/main.ts @@ -1,5 +1,5 @@ import type { StorybookConfig } from '@storybook/react-webpack5'; -const { VanillaExtractPlugin } = require('@vanilla-extract/webpack-plugin'); +import { VanillaExtractPlugin } from '@vanilla-extract/webpack-plugin'; import { merge } from 'webpack-merge'; import { join, dirname } from 'path'; @@ -20,11 +20,10 @@ const config: StorybookConfig = { staticDirs: ['../static'], addons: [ getAbsolutePath('@storybook/addon-webpack5-compiler-swc'), - getAbsolutePath('@storybook/addon-onboarding'), getAbsolutePath('@storybook/addon-essentials'), getAbsolutePath('@chromatic-com/storybook'), getAbsolutePath('@storybook/addon-interactions'), - // getAbsolutePath("@storybook/addon-styling-webpack") + getAbsolutePath('@storybook/addon-themes'), ], framework: { name: getAbsolutePath('@storybook/react-webpack5'), diff --git a/packages/canon/.storybook/preview.tsx b/packages/canon/.storybook/preview.tsx index 05eea4b8ec..4e82cbb8a0 100644 --- a/packages/canon/.storybook/preview.tsx +++ b/packages/canon/.storybook/preview.tsx @@ -1,9 +1,6 @@ import React from 'react'; import type { Preview, ReactRenderer } from '@storybook/react'; -import { - withThemeByClassName, - withThemeByDataAttribute, -} from '@storybook/addon-themes'; +import { withThemeByDataAttribute } from '@storybook/addon-themes'; import '../src/theme/styles.css'; diff --git a/packages/canon/package.json b/packages/canon/package.json index cf818a230d..eafd752a83 100644 --- a/packages/canon/package.json +++ b/packages/canon/package.json @@ -47,16 +47,15 @@ "@backstage/cli": "workspace:^", "@chromatic-com/storybook": "^3.2.2", "@eslint/js": "^9.13.0", - "@storybook/addon-essentials": "^8.4.4", - "@storybook/addon-interactions": "^8.4.4", - "@storybook/addon-onboarding": "^8.4.4", + "@storybook/addon-essentials": "^8.4.5", + "@storybook/addon-interactions": "^8.4.5", "@storybook/addon-styling-webpack": "^1.0.1", - "@storybook/addon-themes": "^8.4.4", + "@storybook/addon-themes": "^8.4.5", "@storybook/addon-webpack5-compiler-swc": "^1.0.5", - "@storybook/blocks": "^8.4.4", - "@storybook/react": "^8.4.4", - "@storybook/react-webpack5": "^8.4.4", - "@storybook/test": "^8.4.4", + "@storybook/blocks": "^8.4.5", + "@storybook/react": "^8.4.5", + "@storybook/react-webpack5": "^8.4.5", + "@storybook/test": "^8.4.5", "@testing-library/jest-dom": "^6.0.0", "@types/react": "^18.3.11", "@types/react-dom": "^18.3.1", @@ -65,10 +64,10 @@ "eslint": "^9.13.0", "eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-react-refresh": "^0.4.13", - "eslint-plugin-storybook": "^0.11.0", + "eslint-plugin-storybook": "^0.11.1", "globals": "^15.11.0", "mini-css-extract-plugin": "^2.9.2", - "storybook": "^8.4.4", + "storybook": "^8.4.5", "typescript": "~5.6.2", "typescript-eslint": "^8.10.0", "webpack-merge": "^6.0.1" diff --git a/packages/canon/src/components/box/box.mdx b/packages/canon/src/components/box/box.mdx index 6b2264db6f..e827d8fcfd 100644 --- a/packages/canon/src/components/box/box.mdx +++ b/packages/canon/src/components/box/box.mdx @@ -1,59 +1,231 @@ import { Canvas, Meta, Unstyled } from '@storybook/blocks'; import * as BoxStories from './box.stories'; -import { PropsTable } from '../../storybook/props-table'; import { Chip } from '../../storybook/chip'; import * as Table from '../../storybook/table'; +import { Box } from './box'; +import { Stack } from '../stack/stack'; +import { Title, Text } from '../../storybook'; +import { + alignItems, + backgroundColors, + boxShadows, + borderRadius, + display, +} from './properties'; -# Box - -Box is the lowest-level component in Canon. We use it internally to build all of our components. - - - +Box + + Box is the lowest-level component in Canon. We use it internally to build all + of our components. + + + + + + + padding + + + + + paddingX + + + + + paddingY + + + + + + + paddingTop + + + + + paddingBottom + + + + + paddingLeft + + + + + paddingRight + + + + + Prop Type Default - Description - background + alignItems - string + {alignItems.map(n => ( + {n} + ))} + + + stretch + + + + + background + + + {Object.keys(backgroundColors).map(n => ( + {n} + ))} transparent - The background color of the box. - display + borderRadius - block - flex - inline-block - inline-flex + {Object.keys(borderRadius).map(n => ( + {n} + ))} + + + none + + + + + boxShadow + + + {Object.keys(boxShadows).map(n => ( + {n} + ))} + + + + + display + + + {display.map(n => ( + {n} + ))} block - The display property of the box. - padding + padding + p number @@ -61,11 +233,11 @@ Box is the lowest-level component in Canon. We use it internally to build all of 0 - The padding of the box. - paddingX + paddingX + px number @@ -73,11 +245,11 @@ Box is the lowest-level component in Canon. We use it internally to build all of 0 - The horizontal padding of the box. - paddingY + paddingY + py number @@ -85,11 +257,11 @@ Box is the lowest-level component in Canon. We use it internally to build all of 0 - The vertical padding of the box. - paddingLeft + paddingLeft + pl number @@ -97,11 +269,71 @@ Box is the lowest-level component in Canon. We use it internally to build all of 0 - The left padding of the box. - paddingRight + paddingRight + pr + + + number + + + 0 + + + + + margin + m + + + number + + + 0 + + + + + marginX + mx + + + number + + + 0 + + + + + marginY + my + + + number + + + 0 + + + + + marginLeft + ml + + + number + + + 0 + + + + + marginRight + mr number @@ -109,7 +341,6 @@ Box is the lowest-level component in Canon. We use it internally to build all of 0 - The right padding of the box. diff --git a/packages/canon/src/components/box/box.stories.tsx b/packages/canon/src/components/box/box.stories.tsx index 6de85ca178..fa78813a73 100644 --- a/packages/canon/src/components/box/box.stories.tsx +++ b/packages/canon/src/components/box/box.stories.tsx @@ -18,7 +18,7 @@ import type { Meta, StoryObj } from '@storybook/react'; import { Box } from './box'; const meta = { - title: 'Components/Box', + title: 'Layout/Box', component: Box, parameters: { layout: 'centered', @@ -31,7 +31,13 @@ type Story = StoryObj; export const Basic: Story = { render: () => ( - + Basic Box ), diff --git a/packages/canon/src/components/box/box.tsx b/packages/canon/src/components/box/box.tsx index 561bf2c0f1..1dd722d3ad 100644 --- a/packages/canon/src/components/box/box.tsx +++ b/packages/canon/src/components/box/box.tsx @@ -22,7 +22,7 @@ type HTMLProperties = Omit< keyof Sprinkles >; -type BoxProps = Sprinkles & +export type BoxProps = Sprinkles & HTMLProperties & { as?: keyof JSX.IntrinsicElements; }; diff --git a/packages/canon/src/components/box/properties.ts b/packages/canon/src/components/box/properties.ts new file mode 100644 index 0000000000..5d4e851a0e --- /dev/null +++ b/packages/canon/src/components/box/properties.ts @@ -0,0 +1,64 @@ +export const alignItems = ['stretch', 'flex-start', 'center', 'flex-end']; + +export const breakpoints = { + xs: {}, + 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)' }, + '2xl': { '@media': 'screen and (min-width: 1536px)' }, +}; + +export const borderRadius = { + none: 0, + small: '4px', + medium: '8px', + full: '9999px', +}; + +export const backgroundColors = { + background: 'var(--canon-color-background)', + elevation1: 'var(--canon-color-elevation1)', + elevation2: 'var(--canon-color-elevation2)', + transparent: 'transparent', +}; + +export const border = { + none: 'none', + thin: '1px solid var(--canon-outline)', + error: '1px solid var(--canon-error)', +}; + +export const boxShadows = { + small: 'var(--canon-box-shadow-small)', + medium: 'var(--canon-box-shadow-medium)', + large: 'var(--canon-box-shadow-large)', +}; + +export const colors = { + background: '#eff6ff', +}; + +export const display = ['none', 'flex', 'block', 'inline']; + +export const flexDirection = ['row', 'column'] as const; + +export const justifyContent = [ + 'stretch', + 'flex-start', + 'center', + 'flex-end', + 'space-around', + 'space-between', +]; + +export const space = { + none: 0, + xxs: 'var(--space-xxs)', + xs: 'var(--space-xs)', + sm: 'var(--space-sm)', + md: 'var(--space-md)', + lg: 'var(--space-lg)', + xl: 'var(--space-xl)', + xxl: 'var(--space-xxl)', +}; diff --git a/packages/canon/src/components/box/sprinkles.css.ts b/packages/canon/src/components/box/sprinkles.css.ts index 30ce3e0cdf..e8e912fef4 100644 --- a/packages/canon/src/components/box/sprinkles.css.ts +++ b/packages/canon/src/components/box/sprinkles.css.ts @@ -14,66 +14,83 @@ * limitations under the License. */ import { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles'; +import { + alignItems, + borderRadius, + breakpoints, + colors, + backgroundColors, + display, + flexDirection, + justifyContent, + space, + boxShadows, + border, +} from './properties'; -const space = { - none: 0, - small: '4px', - medium: '8px', - large: '16px', - // etc. +export const commonProperties = { + flexDirection, + justifyContent, + alignItems, + borderRadius, + boxShadow: boxShadows, + border, + paddingTop: space, + paddingBottom: space, + paddingLeft: space, + paddingRight: space, + marginTop: space, + marginBottom: space, + marginLeft: space, + marginRight: space, + gap: space, }; -const colors = { - background: '#eff6ff', +export const boxShorthands: Record = { + padding: ['paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight'], + paddingX: ['paddingLeft', 'paddingRight'], + paddingY: ['paddingTop', 'paddingBottom'], + p: ['paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight'], + pt: ['paddingTop'], + pr: ['paddingRight'], + pb: ['paddingBottom'], + pl: ['paddingLeft'], + px: ['paddingLeft', 'paddingRight'], + py: ['paddingTop', 'paddingBottom'], + margin: ['marginTop', 'marginBottom', 'marginLeft', 'marginRight'], + marginX: ['marginLeft', 'marginRight'], + marginY: ['marginTop', 'marginBottom'], + m: ['marginTop', 'marginBottom', 'marginLeft', 'marginRight'], + mt: ['marginTop'], + mr: ['marginRight'], + mb: ['marginBottom'], + ml: ['marginLeft'], + mx: ['marginLeft', 'marginRight'], + my: ['marginTop', 'marginBottom'], }; const responsiveProperties = defineProperties({ - conditions: { - xs: {}, - 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)' }, - '2xl': { '@media': 'screen and (min-width: 1536px)' }, - }, + conditions: breakpoints, defaultCondition: 'xs', properties: { - display: ['none', 'flex', 'block', 'inline'], - flexDirection: ['row', 'column'], - justifyContent: [ - 'stretch', - 'flex-start', - 'center', - 'flex-end', - 'space-around', - 'space-between', - ], - alignItems: ['stretch', 'flex-start', 'center', 'flex-end'], - paddingTop: space, - paddingBottom: space, - paddingLeft: space, - paddingRight: space, - // fontFamily: font, - gap: space, - // etc. + ...commonProperties, + display, }, shorthands: { - padding: ['paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight'], - paddingX: ['paddingLeft', 'paddingRight'], - paddingY: ['paddingTop', 'paddingBottom'], + ...boxShorthands, placeItems: ['justifyContent', 'alignItems'], }, }); const colorProperties = defineProperties({ conditions: { - lightMode: {}, - darkMode: { '@media': '(prefers-color-scheme: dark)' }, + light: { selector: '[data-theme="light"] &' }, + dark: { selector: '[data-theme="dark"] &' }, }, - defaultCondition: 'lightMode', + defaultCondition: ['light', 'dark'], properties: { color: colors, - background: colors, + background: backgroundColors, }, }); diff --git a/packages/canon/src/components/button/button.css.ts b/packages/canon/src/components/button/button.css.ts index 8ab3b663ae..e3882831f6 100644 --- a/packages/canon/src/components/button/button.css.ts +++ b/packages/canon/src/components/button/button.css.ts @@ -19,7 +19,8 @@ import { recipe } from '@vanilla-extract/recipes'; export const button = recipe({ base: { all: 'unset', - display: 'inline-block', + display: 'inline-flex', + alignItems: 'center', userSelect: 'none', fontFamily: 'var(--canon-font-sans)', fontWeight: 600, diff --git a/packages/canon/src/components/button/button.stories.tsx b/packages/canon/src/components/button/button.stories.tsx index 8a9d7f3845..b979b92022 100644 --- a/packages/canon/src/components/button/button.stories.tsx +++ b/packages/canon/src/components/button/button.stories.tsx @@ -16,6 +16,7 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; import { Button } from './button'; +import { Box } from '../box/box'; const meta = { title: 'Components/Button', @@ -63,6 +64,32 @@ export const Sizes: Story = { ), }; +export const WithIcons: Story = { + args: { + children: 'Button', + }, + render: args => ( +
+
+ ), +}; + +export const FullWidth: Story = { + args: { + children: 'Button', + }, + render: args => ( + +