From 12c796488c5bc42e58b905a72e7b357e5d18d369 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Tue, 3 Dec 2024 21:05:03 +0000 Subject: [PATCH 1/5] Add first pass at Grid component Signed-off-by: Charles de Dreuille --- packages/canon/docs/Home.mdx | 37 +++--- .../src/components/Grid/Grid.stories.tsx | 91 ++++++++++++++ packages/canon/src/components/Grid/Grid.tsx | 70 +++++++++++ packages/canon/src/components/Grid/index.ts | 17 +++ .../src/components/Grid/sprinkles.css.ts | 113 ++++++++++++++++++ packages/canon/src/components/Grid/styles.css | 3 + packages/canon/src/components/Grid/types.ts | 48 ++++++++ packages/canon/src/index.ts | 3 + packages/canon/src/theme/styles.css | 1 + 9 files changed, 367 insertions(+), 16 deletions(-) create mode 100644 packages/canon/src/components/Grid/Grid.stories.tsx create mode 100644 packages/canon/src/components/Grid/Grid.tsx create mode 100644 packages/canon/src/components/Grid/index.ts create mode 100644 packages/canon/src/components/Grid/sprinkles.css.ts create mode 100644 packages/canon/src/components/Grid/styles.css create mode 100644 packages/canon/src/components/Grid/types.ts diff --git a/packages/canon/docs/Home.mdx b/packages/canon/docs/Home.mdx index 3a00de5d07..51574f57a1 100644 --- a/packages/canon/docs/Home.mdx +++ b/packages/canon/docs/Home.mdx @@ -43,33 +43,38 @@ import { list } from './components/Roadmap/list'; link="/?path=/docs/components-box--docs" /> + + + + - - - - + + - - + diff --git a/packages/canon/src/components/Grid/Grid.stories.tsx b/packages/canon/src/components/Grid/Grid.stories.tsx new file mode 100644 index 0000000000..e9833a0325 --- /dev/null +++ b/packages/canon/src/components/Grid/Grid.stories.tsx @@ -0,0 +1,91 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Grid } from './Grid'; +import type { GridItemProps } from './types'; +import { Box } from '../Box/Box'; +import { argTypesSpacing, argTypesColor } from '../../../docs/utils/argTypes'; +import { Stack } from '../Stack'; + +const meta = { + title: 'Components/Grid', + component: Grid, + argTypes: { + ...argTypesSpacing, + ...argTypesColor, + children: { + control: false, + }, + className: { + control: 'text', + }, + }, + args: { + gap: 'xs', + }, +} satisfies Meta<typeof Grid>; + +export default meta; +type Story = StoryObj<typeof meta>; + +const FakeBox = () => ( + <Box + borderRadius="small" + style={{ background: '#1f47ff', color: 'white', height: '64px' }} + /> +); + +export const Default: Story = { + args: { + columns: 3, + }, + render: args => ( + <Grid {...args}> + <Grid.Item> + <FakeBox /> + </Grid.Item> + <Grid.Item> + <FakeBox /> + </Grid.Item> + <Grid.Item> + <FakeBox /> + </Grid.Item> + </Grid> + ), +}; + +export const ColumnSizes: Story = { + args: { + columns: 12, + gap: 'md', + }, + render: args => ( + <Stack gap="md"> + {Array.from({ length: 11 }, (_, i) => ( + <Grid {...args} key={i}> + <Grid.Item span={(i + 1) as GridItemProps['span']}> + <FakeBox /> + </Grid.Item> + <Grid.Item span={(11 - i) as GridItemProps['span']}> + <FakeBox /> + </Grid.Item> + </Grid> + ))} + </Stack> + ), +}; diff --git a/packages/canon/src/components/Grid/Grid.tsx b/packages/canon/src/components/Grid/Grid.tsx new file mode 100644 index 0000000000..28c49d87b1 --- /dev/null +++ b/packages/canon/src/components/Grid/Grid.tsx @@ -0,0 +1,70 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createElement } from 'react'; +import { GridItemProps, GridProps } from './types'; +import { gridItemSprinkles, gridSprinkles } from './sprinkles.css'; + +export const Grid = ({ + children, + columns = 1, + gap = 'xs', + className, + style, + ...restProps +}: GridProps) => { + const sprinklesClassName = gridSprinkles({ + ...restProps, + gap, + gridTemplateColumns: columns, + }); + + const classNames = ['grid', sprinklesClassName, className] + .filter(Boolean) + .join(' '); + + return createElement( + 'div', + { + className: classNames, + style, + }, + children, + ); +}; + +const GridItem = ({ + children, + span = 1, + start, + end, + className, + style, +}: GridItemProps) => { + const sprinklesClassName = gridItemSprinkles({ + span, + start, + end, + }); + + const classNames = ['grid-item', sprinklesClassName, className] + .filter(Boolean) + .join(' '); + + return createElement('div', { className: classNames, style }, children); +}; + +Grid.Item = GridItem; diff --git a/packages/canon/src/components/Grid/index.ts b/packages/canon/src/components/Grid/index.ts new file mode 100644 index 0000000000..b2534c6b77 --- /dev/null +++ b/packages/canon/src/components/Grid/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { Grid } from './Grid'; +export type { GridProps, GridItemProps } from './types'; diff --git a/packages/canon/src/components/Grid/sprinkles.css.ts b/packages/canon/src/components/Grid/sprinkles.css.ts new file mode 100644 index 0000000000..a2ac056d61 --- /dev/null +++ b/packages/canon/src/components/Grid/sprinkles.css.ts @@ -0,0 +1,113 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles'; +import { breakpoints } from '../../layout/properties'; +import { colorProperties, spacingProperties } from '../../layout/sprinkles.css'; + +const gridProperties = defineProperties({ + conditions: breakpoints, + defaultCondition: 'xs', + properties: { + gridTemplateColumns: { + 1: 'repeat(1, minmax(0, 1fr))', + 2: 'repeat(2, minmax(0, 1fr))', + 3: 'repeat(3, minmax(0, 1fr))', + 4: 'repeat(4, minmax(0, 1fr))', + 5: 'repeat(5, minmax(0, 1fr))', + 6: 'repeat(6, minmax(0, 1fr))', + 7: 'repeat(7, minmax(0, 1fr))', + 8: 'repeat(8, minmax(0, 1fr))', + 9: 'repeat(9, minmax(0, 1fr))', + 10: 'repeat(10, minmax(0, 1fr))', + 11: 'repeat(11, minmax(0, 1fr))', + 12: 'repeat(12, minmax(0, 1fr))', + }, + }, + shorthands: { + columns: ['gridTemplateColumns'], + }, +}); + +export const gridSprinkles = createSprinkles( + spacingProperties, + colorProperties, + gridProperties, +); + +const gridItemProperties = defineProperties({ + conditions: breakpoints, + defaultCondition: 'xs', + properties: { + gridColumn: { + 1: 'span 1 / span 1', + 2: 'span 2 / span 2', + 3: 'span 3 / span 3', + 4: 'span 4 / span 4', + 5: 'span 5 / span 5', + 6: 'span 6 / span 6', + 7: 'span 7 / span 7', + 8: 'span 8 / span 8', + 9: 'span 9 / span 9', + 10: 'span 10 / span 10', + 11: 'span 11 / span 11', + 12: 'span 12 / span 12', + full: '1 / -1', + }, + gridColumnStart: { + 1: '1', + 2: '2', + 3: '3', + 4: '4', + 5: '5', + 6: '6', + 7: '7', + 8: '8', + 9: '9', + 10: '10', + 11: '11', + 12: '12', + 13: '13', + auto: 'auto', + }, + gridColumnEnd: { + 1: '1', + 2: '2', + 3: '3', + 4: '4', + 5: '5', + 6: '6', + 7: '7', + 8: '8', + 9: '9', + 10: '10', + 11: '11', + 12: '12', + 13: '13', + auto: 'auto', + }, + }, + shorthands: { + span: ['gridColumn'], + start: ['gridColumnStart'], + end: ['gridColumnEnd'], + }, +}); + +export const gridItemSprinkles = createSprinkles( + colorProperties, + gridItemProperties, +); diff --git a/packages/canon/src/components/Grid/styles.css b/packages/canon/src/components/Grid/styles.css new file mode 100644 index 0000000000..81f8d5471d --- /dev/null +++ b/packages/canon/src/components/Grid/styles.css @@ -0,0 +1,3 @@ +.grid { + display: grid; +} diff --git a/packages/canon/src/components/Grid/types.ts b/packages/canon/src/components/Grid/types.ts new file mode 100644 index 0000000000..6432a8312c --- /dev/null +++ b/packages/canon/src/components/Grid/types.ts @@ -0,0 +1,48 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Breakpoint, ColorProps } from '../../layout/types'; +import { SpaceProps } from '../../layout/types'; + +export interface GridProps extends SpaceProps, ColorProps { + children?: React.ReactNode; + columns?: + | 1 + | 2 + | 3 + | 4 + | 5 + | 6 + | 7 + | 8 + | 9 + | 10 + | 11 + | 12 + | Partial< + Record<Breakpoint, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12> + >; + className?: string; + style?: React.CSSProperties; +} + +export interface GridItemProps { + children: React.ReactNode; + span?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 'full'; + start?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 'auto'; + end?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 'auto'; + className?: string; + style?: React.CSSProperties; +} diff --git a/packages/canon/src/index.ts b/packages/canon/src/index.ts index 198a626f06..d020041e4e 100644 --- a/packages/canon/src/index.ts +++ b/packages/canon/src/index.ts @@ -24,3 +24,6 @@ export * from './components/Button'; export * from './components/Box'; export * from './components/Icon'; export * from './layout/types'; +export * from './components/Grid'; +export * from './components/Stack'; +export * from './components/Inline'; diff --git a/packages/canon/src/theme/styles.css b/packages/canon/src/theme/styles.css index 4a31340575..65aaabe909 100644 --- a/packages/canon/src/theme/styles.css +++ b/packages/canon/src/theme/styles.css @@ -25,3 +25,4 @@ @import '../components/Button/styles.css'; @import '../components/Stack/styles.css'; @import '../components/Inline/styles.css'; +@import '../components/Grid/styles.css'; From c0fe222665603a3b852a3bdfc2097009d39c4c43 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille <charles.dedreuille@gmail.com> Date: Thu, 5 Dec 2024 10:20:58 +0000 Subject: [PATCH 2/5] Add Grid component and improve documentation Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com> --- packages/canon/docs/Home.mdx | 5 + packages/canon/docs/Layout.mdx | 7 +- .../docs/components/LayoutComponents/box.tsx | 54 +++ .../components/LayoutComponents/container.tsx | 373 ++++++++++++++++++ .../docs/components/LayoutComponents/grid.tsx | 91 +++++ .../components/LayoutComponents/index.tsx | 76 +--- .../components/LayoutComponents/inline.tsx | 92 +++++ .../LayoutComponents/layout-components.css.ts | 141 +------ .../components/LayoutComponents/stack.tsx | 82 ++++ .../docs/components/PropsTable/PropsTable.tsx | 57 +++ .../docs/components/PropsTable/getProps.ts | 43 ++ .../canon/docs/components/PropsTable/index.ts | 17 + .../canon/docs/components/Text/text.css.ts | 2 +- .../canon/docs/components/Title/title.css.ts | 4 +- packages/canon/docs/utils/argTypes.ts | 5 + packages/canon/src/components/Box/Docs.mdx | 25 +- .../src/components/Box/docs/props-table.tsx | 70 ---- .../src/components/Box/docs/spacing-table.tsx | 67 ---- packages/canon/src/components/Grid/Docs.mdx | 211 ++++++++++ .../src/components/Grid/Grid.stories.tsx | 54 ++- packages/canon/src/components/Grid/Grid.tsx | 10 +- .../src/components/Grid/sprinkles.css.ts | 19 +- packages/canon/src/components/Grid/types.ts | 26 +- packages/canon/src/components/Stack/Docs.mdx | 65 +++ 24 files changed, 1220 insertions(+), 376 deletions(-) create mode 100644 packages/canon/docs/components/LayoutComponents/box.tsx create mode 100644 packages/canon/docs/components/LayoutComponents/container.tsx create mode 100644 packages/canon/docs/components/LayoutComponents/grid.tsx create mode 100644 packages/canon/docs/components/LayoutComponents/inline.tsx create mode 100644 packages/canon/docs/components/LayoutComponents/stack.tsx create mode 100644 packages/canon/docs/components/PropsTable/PropsTable.tsx create mode 100644 packages/canon/docs/components/PropsTable/getProps.ts create mode 100644 packages/canon/docs/components/PropsTable/index.ts delete mode 100644 packages/canon/src/components/Box/docs/props-table.tsx delete mode 100644 packages/canon/src/components/Box/docs/spacing-table.tsx create mode 100644 packages/canon/src/components/Grid/Docs.mdx create mode 100644 packages/canon/src/components/Stack/Docs.mdx diff --git a/packages/canon/docs/Home.mdx b/packages/canon/docs/Home.mdx index 51574f57a1..cbe84fcfb1 100644 --- a/packages/canon/docs/Home.mdx +++ b/packages/canon/docs/Home.mdx @@ -48,6 +48,11 @@ import { list } from './components/Roadmap/list'; link="/?path=/docs/components-button--docs" /> <ComponentStatus name="Checkbox" status="notStarted" /> + <ComponentStatus + name="Container" + status="inProgress" + link="/?path=/docs/components-container--docs" + /> <ComponentStatus name="Grid" status="alpha" diff --git a/packages/canon/docs/Layout.mdx b/packages/canon/docs/Layout.mdx index ed72087cca..72344672b6 100644 --- a/packages/canon/docs/Layout.mdx +++ b/packages/canon/docs/Layout.mdx @@ -42,6 +42,11 @@ import * as Table from './components/Table'; <Title type="h2">Layout Helpers -TBD + + Sometimes you want to use global tokens dynamically outside of React + components. To help you with that we would like to provide a set of helpers + that you can use in your code. These helpers are not available just yet but we + are working on it. + diff --git a/packages/canon/docs/components/LayoutComponents/box.tsx b/packages/canon/docs/components/LayoutComponents/box.tsx new file mode 100644 index 0000000000..1749b38c6f --- /dev/null +++ b/packages/canon/docs/components/LayoutComponents/box.tsx @@ -0,0 +1,54 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; + +export const BoxSvg = () => { + return ( + + + + + + + + ); +}; diff --git a/packages/canon/docs/components/LayoutComponents/container.tsx b/packages/canon/docs/components/LayoutComponents/container.tsx new file mode 100644 index 0000000000..62fe4ce266 --- /dev/null +++ b/packages/canon/docs/components/LayoutComponents/container.tsx @@ -0,0 +1,373 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; + +export const ContainerSvg = () => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; diff --git a/packages/canon/docs/components/LayoutComponents/grid.tsx b/packages/canon/docs/components/LayoutComponents/grid.tsx new file mode 100644 index 0000000000..5527d1f3e2 --- /dev/null +++ b/packages/canon/docs/components/LayoutComponents/grid.tsx @@ -0,0 +1,91 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; + +export const GridSvg = () => { + return ( + + + + + + + + + + + + ); +}; diff --git a/packages/canon/docs/components/LayoutComponents/index.tsx b/packages/canon/docs/components/LayoutComponents/index.tsx index 9e0b039684..16a7a1726c 100644 --- a/packages/canon/docs/components/LayoutComponents/index.tsx +++ b/packages/canon/docs/components/LayoutComponents/index.tsx @@ -21,88 +21,50 @@ import { content, title, description, - whiteBox, - whiteBoxStack, - stack, - verticalDivider, - horizontalDivider, - columns, - inline, - tiles, - whiteBoxColumns, - whiteBoxInline, - whiteBoxTiles, } from './layout-components.css'; +import { BoxSvg } from './box'; +import { StackSvg } from './stack'; +import { GridSvg } from './grid'; +import { InlineSvg } from './inline'; +import { ContainerSvg } from './container'; export const LayoutComponents = () => { return (
-
+
Box
-
The most basic layout component.
+
The most basic layout component
- -
-
-
+ +
Stack
-
Arrange your components vertically.
+
Arrange your components vertically
- -
-
-
+ + -
Columns
-
Arrange your components horizontally.
+
Grid
+
Arrange your components in a grid
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
Inline
-
Arrange your components in a row.
+
Arrange your components in a row
-
-
-
-
-
-
- ); diff --git a/packages/canon/docs/components/LayoutComponents/inline.tsx b/packages/canon/docs/components/LayoutComponents/inline.tsx new file mode 100644 index 0000000000..fadb9bfc1b --- /dev/null +++ b/packages/canon/docs/components/LayoutComponents/inline.tsx @@ -0,0 +1,92 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; + +export const InlineSvg = () => { + return ( + + + + + + + + + + + + ); +}; diff --git a/packages/canon/docs/components/LayoutComponents/layout-components.css.ts b/packages/canon/docs/components/LayoutComponents/layout-components.css.ts index a8440dd01f..62fd3a634f 100644 --- a/packages/canon/docs/components/LayoutComponents/layout-components.css.ts +++ b/packages/canon/docs/components/LayoutComponents/layout-components.css.ts @@ -33,19 +33,18 @@ export const box = style({ export const content = style({ flex: 'none', - background: '#f2f2f2', + background: 'linear-gradient(180deg, #F3F3F3 0%, #FFF 100%)', borderRadius: '4px', width: '100%', height: '180px', - border: '1px solid #e0e0e0', - transition: 'border-color 0.2s ease-in-out', + transition: 'all 0.2s ease-in-out', marginBottom: '0.75rem', display: 'flex', alignItems: 'center', justifyContent: 'center', selectors: { [`${box}:hover &`]: { - borderColor: '#1f47ff', + transform: 'translateY(-4px)', }, }, }); @@ -55,11 +54,6 @@ export const title = style({ fontFamily: 'var(--canon-font-sans)', transition: 'color 0.2s ease-in-out', marginBottom: '0.25rem', - selectors: { - [`${box}:hover &`]: { - color: '#1f47ff', - }, - }, }); export const description = style({ @@ -67,132 +61,3 @@ export const description = style({ fontFamily: 'var(--canon-font-sans)', color: '#9e9e9e', }); - -export const whiteBox = style({ - background: '#fff', - width: '40px', - height: '40px', - borderRadius: '4px', - boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)', -}); - -export const whiteBoxStack = style([ - whiteBox, - { - width: '40%', - height: '28px', - }, -]); - -export const whiteBoxColumns = style([ - whiteBox, - { - width: '30%', - height: '32px', - }, -]); - -export const whiteBoxInline = style([ - whiteBox, - { - width: '32px', - height: '32px', - }, -]); - -export const whiteBoxTiles = style([ - whiteBox, - { - width: '100%', - height: '32px', - }, -]); - -export const stack = style({ - display: 'flex', - flexDirection: 'column', -}); - -export const columns = style({ - display: 'flex', - flexDirection: 'row', -}); - -export const inline = style({ - display: 'flex', - flexWrap: 'wrap', - flexDirection: 'row', - justifyContent: 'flex-start', - alignItems: 'flex-start', - gap: '0.5rem', - paddingLeft: '1rem', -}); - -export const tiles = style({ - display: 'grid', - gridTemplateColumns: 'repeat(4, 1fr)', - gap: '0.5rem', - paddingLeft: '1rem', - paddingRight: '1rem', - width: '100%', -}); - -export const verticalDivider = style({ - display: 'flex', - flexShrink: 0, - flexDirection: 'column', - position: 'relative', - height: '20px', - width: '2px', - backgroundColor: '#1f47ff', - selectors: { - '&::before': { - content: '""', - position: 'absolute', - top: 0, - left: '-9px', - width: '20px', - height: '2px', - backgroundColor: '#1f47ff', - }, - '&::after': { - content: '""', - position: 'absolute', - bottom: 0, - left: '-9px', - width: '20px', - height: '2px', - backgroundColor: '#1f47ff', - }, - }, -}); - -export const horizontalDivider = style({ - flexShrink: 0, - display: 'flex', - flexDirection: 'row', - position: 'relative', - height: '2px', - width: '20px', - backgroundColor: '#1f47ff', - selectors: { - '&::before': { - content: '""', - position: 'absolute', - left: 0, - top: '-9px', - width: '2px', - height: '20px', - backgroundColor: '#1f47ff', - }, - '&::after': { - content: '""', - position: 'absolute', - right: 0, - top: '-9px', - width: '2px', - height: '20px', - backgroundColor: '#1f47ff', - }, - }, -}); diff --git a/packages/canon/docs/components/LayoutComponents/stack.tsx b/packages/canon/docs/components/LayoutComponents/stack.tsx new file mode 100644 index 0000000000..aeda998d2e --- /dev/null +++ b/packages/canon/docs/components/LayoutComponents/stack.tsx @@ -0,0 +1,82 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; + +export const StackSvg = () => { + return ( + + + + + + + + + + + + ); +}; diff --git a/packages/canon/docs/components/PropsTable/PropsTable.tsx b/packages/canon/docs/components/PropsTable/PropsTable.tsx new file mode 100644 index 0000000000..a3dc9e271c --- /dev/null +++ b/packages/canon/docs/components/PropsTable/PropsTable.tsx @@ -0,0 +1,57 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import * as Table from '..'; +import { Chip } from '..'; + +// Modify the PropsTable component to accept a generic type +export const PropsTable = >({ + data, +}: { + data: T; +}) => { + return ( + + + + Prop + Type + Responsive + + + + {Object.keys(data).map(n => ( + + + {n} + + + {Array.isArray(data[n].type) ? ( + data[n].type.map((t: any) => {t}) + ) : ( + {data[n].type} + )} + + + {data[n].responsive ? 'Yes' : 'No'} + + + ))} + + + ); +}; diff --git a/packages/canon/docs/components/PropsTable/getProps.ts b/packages/canon/docs/components/PropsTable/getProps.ts new file mode 100644 index 0000000000..866dcb9d10 --- /dev/null +++ b/packages/canon/docs/components/PropsTable/getProps.ts @@ -0,0 +1,43 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export function getBoxProps(styles: Record) { + return Object.keys(styles).reduce( + (acc: Record, n) => { + const style = styles[n]; + + let values: string[] = []; + + if (style.values) { + // If values exist, use them + values = Object.keys(style.values); + } else if (style.mappings && style.mappings.length > 0) { + // If mappings exist, use the first mapping's values + const firstMapping = style.mappings[0]; + values = Object.keys(styles[firstMapping].values); + } else { + // Default to an empty array if neither values nor mappings exist + values = []; + } + + acc[n] = { + type: values, + responsive: true, + }; + return acc; + }, + {} as Record, + ); +} diff --git a/packages/canon/docs/components/PropsTable/index.ts b/packages/canon/docs/components/PropsTable/index.ts new file mode 100644 index 0000000000..010452ee2a --- /dev/null +++ b/packages/canon/docs/components/PropsTable/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { PropsTable } from './PropsTable'; +export { getBoxProps } from './getProps'; diff --git a/packages/canon/docs/components/Text/text.css.ts b/packages/canon/docs/components/Text/text.css.ts index 01b4cb8fc8..fbbc427362 100644 --- a/packages/canon/docs/components/Text/text.css.ts +++ b/packages/canon/docs/components/Text/text.css.ts @@ -22,7 +22,7 @@ export const textStyles = style({ lineHeight: '28px', margin: '0', fontWeight: 300, - paddingBottom: '16px', + marginBottom: '16px', }); globalStyle(`${textStyles} p`, { diff --git a/packages/canon/docs/components/Title/title.css.ts b/packages/canon/docs/components/Title/title.css.ts index 5ca0394af6..6618ad80be 100644 --- a/packages/canon/docs/components/Title/title.css.ts +++ b/packages/canon/docs/components/Title/title.css.ts @@ -28,7 +28,7 @@ export const titleStyles = recipe({ h1: { fontSize: '36px', lineHeight: '44px', - marginBottom: '32px', + marginBottom: '8px', marginTop: '0px', }, h2: { @@ -41,7 +41,7 @@ export const titleStyles = recipe({ fontSize: '20px', lineHeight: '28px', marginBottom: '12px', - marginTop: '52px', + marginTop: '40px', }, }, }, diff --git a/packages/canon/docs/utils/argTypes.ts b/packages/canon/docs/utils/argTypes.ts index ff5a159677..e6a68008f8 100644 --- a/packages/canon/docs/utils/argTypes.ts +++ b/packages/canon/docs/utils/argTypes.ts @@ -24,6 +24,11 @@ export const listResponsiveValues = ( ) => { const values = boxProperties.styles[value]; + if (!values) { + console.warn(`Value "${value}" not found in boxProperties.styles`); + return []; + } + if ('values' in values) { return Object.keys(values.values); } diff --git a/packages/canon/src/components/Box/Docs.mdx b/packages/canon/src/components/Box/Docs.mdx index dac10952cf..3f78ba3a76 100644 --- a/packages/canon/src/components/Box/Docs.mdx +++ b/packages/canon/src/components/Box/Docs.mdx @@ -2,8 +2,9 @@ import { Canvas, Meta, Unstyled } from '@storybook/blocks'; import * as BoxStories from './Box.stories'; import { Title, Text } from '../../../docs/components'; import { Padding } from './docs/padding'; -import { PropsTable } from './docs/props-table'; -import { SpacingTable } from './docs/spacing-table'; +import { PropsTable, getBoxProps } from '../../../docs/components/PropsTable'; +import { boxProperties } from './sprinkles.css'; +import { spacingProperties } from '../../layout/sprinkles.css'; @@ -16,7 +17,23 @@ import { SpacingTable } from './docs/spacing-table'; provides a consistent API for styling and layout. You'll find below a list of all the available properties. - + Padding & Margin @@ -27,6 +44,6 @@ import { SpacingTable } from './docs/spacing-table'; - + diff --git a/packages/canon/src/components/Box/docs/props-table.tsx b/packages/canon/src/components/Box/docs/props-table.tsx deleted file mode 100644 index 9979701f2e..0000000000 --- a/packages/canon/src/components/Box/docs/props-table.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2024 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React from 'react'; -import * as Table from '../../../../docs/components'; -import { Chip } from '../../../../docs/components'; -import { listResponsiveValues } from '../../../../docs/utils/argTypes'; -import { boxProperties } from '../sprinkles.css'; - -export const PropsTable = () => { - return ( - - - - Prop - Type - - - - {Object.keys(boxProperties.styles) - .filter( - n => - ![ - 'padding', - 'paddingX', - 'paddingY', - 'paddingLeft', - 'paddingRight', - 'paddingTop', - 'paddingBottom', - 'margin', - 'marginX', - 'marginY', - 'marginLeft', - 'marginRight', - 'marginTop', - 'marginBottom', - ].includes(n), - ) - .map(n => ( - - - {n} - - - {listResponsiveValues( - n as keyof typeof boxProperties.styles, - ).map(value => ( - {value} - ))} - - - ))} - - - ); -}; diff --git a/packages/canon/src/components/Box/docs/spacing-table.tsx b/packages/canon/src/components/Box/docs/spacing-table.tsx deleted file mode 100644 index 93c38457d4..0000000000 --- a/packages/canon/src/components/Box/docs/spacing-table.tsx +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2024 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React from 'react'; -import * as Table from '../../../../docs/components'; -import { Chip } from '../../../../docs/components'; -import { spacingProperties } from '../../../layout/sprinkles.css'; -import { space } from '../../../layout/properties'; - -export const SpacingTable = () => { - return ( - - - - Prop - Type - - - - {Object.keys(spacingProperties.styles) - .filter(n => - [ - 'padding', - 'paddingX', - 'paddingY', - 'paddingLeft', - 'paddingRight', - 'paddingTop', - 'paddingBottom', - 'margin', - 'marginX', - 'marginY', - 'marginLeft', - 'marginRight', - 'marginTop', - 'marginBottom', - ].includes(n), - ) - .map(n => ( - - - {n} - - - {Object.keys(space).map(value => ( - {value} - ))} - - - ))} - - - ); -}; diff --git a/packages/canon/src/components/Grid/Docs.mdx b/packages/canon/src/components/Grid/Docs.mdx new file mode 100644 index 0000000000..c37d083ef1 --- /dev/null +++ b/packages/canon/src/components/Grid/Docs.mdx @@ -0,0 +1,211 @@ +import { Canvas, Meta, Unstyled, Source } from '@storybook/blocks'; +import * as GridStories from './Grid.stories'; +import { Title, Text } from '../../../docs/components'; +import { PropsTable, getBoxProps } from '../../../docs/components/PropsTable'; +import { spacingProperties } from '../../layout/sprinkles.css'; + + + + + +Grid + + A layout component that helps to create simple column-based layouts as well as + more complex ones. + + +Installation + + +Anatomy + + The grid component is made of two parts: the grid container and the grid item. Import all parts and piece them together. + + ( + + + +);`} + language="tsx" + dark +/> + +API reference + +Grid + + This is the grid container component. It will help to define the number of + columns that will be used in the grid. You can also define the gap between the + columns. All values are responsive. + + + + + + The grid component also accepts all the spacing props from the Box component. + + + + +Grid Item + + If you need more control over the columns, you can use the grid item + component. This will give you access to `rowSpan`, `colSpan`, `start` and + `end`. All values are responsive. This component is optional, you can use any + elements directly if you prefer. + + + + +Examples + +Simple grid +This is a simple grid with 3 columns and a gap of md. + + Hello World + Hello World + Hello World + +`} + language="tsx" + dark +/> + +Complex grid + + You can also use the grid item to create more complex layouts. In this example + the first column will span 1 column and the second column will span 2 columns. + + + + + Hello World + + + Hello World + + +`} + language="tsx" + dark +/> + +Mixing rows and columns + + The grid item component also supports the `rowSpan` prop, which allows you to + span multiple rows within the grid layout. In this example, the first item + will span 2 rows to achieve a dynamic and flexible grid structure. + + + + + Hello World + + + Hello World + + + Hello World + + +`} + language="tsx" + dark +/> + +Responsive + + The grid component also supports responsive values. In this example the grid + will have 1 column on small screens and 3 on large screens, with a gap of xs + on small screens and md on large screens. + + + + Hello World + + + Hello World + + +`} + language="tsx" + dark +/> + +Start and End + + The start and end props can be used to position the item in the grid. + + + + Hello World + + +`} + language="tsx" + dark +/> + + diff --git a/packages/canon/src/components/Grid/Grid.stories.tsx b/packages/canon/src/components/Grid/Grid.stories.tsx index e9833a0325..bf1bcecfd7 100644 --- a/packages/canon/src/components/Grid/Grid.stories.tsx +++ b/packages/canon/src/components/Grid/Grid.stories.tsx @@ -51,20 +51,25 @@ const FakeBox = () => ( ); export const Default: Story = { + args: {}, + render: args => ( + + + + + + ), +}; + +export const LargeGap: Story = { args: { - columns: 3, + gap: 'lg', }, render: args => ( - - - - - - - - - + + + ), }; @@ -78,10 +83,10 @@ export const ColumnSizes: Story = { {Array.from({ length: 11 }, (_, i) => ( - + - + @@ -89,3 +94,28 @@ export const ColumnSizes: Story = { ), }; + +export const RowAndColumns: Story = { + args: { + columns: 12, + gap: 'md', + }, + render: args => ( + + + + + + + + + + + + + + ), +}; diff --git a/packages/canon/src/components/Grid/Grid.tsx b/packages/canon/src/components/Grid/Grid.tsx index 28c49d87b1..9ac23e9371 100644 --- a/packages/canon/src/components/Grid/Grid.tsx +++ b/packages/canon/src/components/Grid/Grid.tsx @@ -20,7 +20,7 @@ import { gridItemSprinkles, gridSprinkles } from './sprinkles.css'; export const Grid = ({ children, - columns = 1, + columns, gap = 'xs', className, style, @@ -29,7 +29,7 @@ export const Grid = ({ const sprinklesClassName = gridSprinkles({ ...restProps, gap, - gridTemplateColumns: columns, + gridTemplateColumns: columns ? columns : 'auto', }); const classNames = ['grid', sprinklesClassName, className] @@ -48,14 +48,16 @@ export const Grid = ({ const GridItem = ({ children, - span = 1, + rowSpan, + colSpan, start, end, className, style, }: GridItemProps) => { const sprinklesClassName = gridItemSprinkles({ - span, + rowSpan, + colSpan, start, end, }); diff --git a/packages/canon/src/components/Grid/sprinkles.css.ts b/packages/canon/src/components/Grid/sprinkles.css.ts index a2ac056d61..aff5a340ed 100644 --- a/packages/canon/src/components/Grid/sprinkles.css.ts +++ b/packages/canon/src/components/Grid/sprinkles.css.ts @@ -35,6 +35,7 @@ const gridProperties = defineProperties({ 10: 'repeat(10, minmax(0, 1fr))', 11: 'repeat(11, minmax(0, 1fr))', 12: 'repeat(12, minmax(0, 1fr))', + auto: 'repeat(auto-fit, minmax(0, 1fr))', }, }, shorthands: { @@ -67,6 +68,21 @@ const gridItemProperties = defineProperties({ 12: 'span 12 / span 12', full: '1 / -1', }, + gridRow: { + 1: 'span 1 / span 1', + 2: 'span 2 / span 2', + 3: 'span 3 / span 3', + 4: 'span 4 / span 4', + 5: 'span 5 / span 5', + 6: 'span 6 / span 6', + 7: 'span 7 / span 7', + 8: 'span 8 / span 8', + 9: 'span 9 / span 9', + 10: 'span 10 / span 10', + 11: 'span 11 / span 11', + 12: 'span 12 / span 12', + full: '1 / -1', + }, gridColumnStart: { 1: '1', 2: '2', @@ -101,7 +117,8 @@ const gridItemProperties = defineProperties({ }, }, shorthands: { - span: ['gridColumn'], + colSpan: ['gridColumn'], + rowSpan: ['gridRow'], start: ['gridColumnStart'], end: ['gridColumnEnd'], }, diff --git a/packages/canon/src/components/Grid/types.ts b/packages/canon/src/components/Grid/types.ts index 6432a8312c..8400e61830 100644 --- a/packages/canon/src/components/Grid/types.ts +++ b/packages/canon/src/components/Grid/types.ts @@ -16,33 +16,21 @@ import { Breakpoint, ColorProps } from '../../layout/types'; import { SpaceProps } from '../../layout/types'; +type Columns = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; + export interface GridProps extends SpaceProps, ColorProps { children?: React.ReactNode; - columns?: - | 1 - | 2 - | 3 - | 4 - | 5 - | 6 - | 7 - | 8 - | 9 - | 10 - | 11 - | 12 - | Partial< - Record - >; + columns?: Columns | Partial>; className?: string; style?: React.CSSProperties; } export interface GridItemProps { children: React.ReactNode; - span?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 'full'; - start?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 'auto'; - end?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 'auto'; + rowSpan?: Columns | 'full'; + colSpan?: Columns | 'full'; + start?: Columns | 'auto'; + end?: Columns | 'auto'; className?: string; style?: React.CSSProperties; } diff --git a/packages/canon/src/components/Stack/Docs.mdx b/packages/canon/src/components/Stack/Docs.mdx new file mode 100644 index 0000000000..4f63d7114e --- /dev/null +++ b/packages/canon/src/components/Stack/Docs.mdx @@ -0,0 +1,65 @@ +import { Meta, Unstyled, Source } from '@storybook/blocks'; +import * as StackStories from './Stack.stories'; +import { Title, Text } from '../../../docs/components'; +import { PropsTable } from '../../../docs/components/PropsTable'; + + + + + +Stack + + + This is the stack container component. It will help to define the number of + columns that will be used in the grid. You can also define the gap between the + columns. All values are responsive. + + + + Hello World + Hello World + Hello World +`} + language="tsx" + dark +/> + + + +How to stack horizontally? + + The Stack component only allows for stacking elements vertically. If you want + to create a column layout, please use the Grid component. + + +Responsive +TBD + +Start and End +TBD + + From 21bae49983f632859c663990efe556f9eb89e558 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Thu, 5 Dec 2024 10:52:09 +0000 Subject: [PATCH 3/5] Fix API report Signed-off-by: Charles de Dreuille --- packages/canon/report.api.md | 146 ++++++++++++++++++ packages/canon/src/components/Box/Docs.mdx | 41 ++++- packages/canon/src/components/Grid/Grid.tsx | 1 + packages/canon/src/components/Grid/index.ts | 2 +- packages/canon/src/components/Grid/types.ts | 5 +- .../canon/src/components/Inline/Inline.tsx | 1 + packages/canon/src/components/Inline/index.ts | 1 + packages/canon/src/components/Inline/types.ts | 1 + packages/canon/src/components/Stack/Stack.tsx | 1 + packages/canon/src/components/Stack/index.ts | 1 + packages/canon/src/components/Stack/types.ts | 1 + packages/canon/src/index.ts | 11 +- 12 files changed, 202 insertions(+), 10 deletions(-) diff --git a/packages/canon/report.api.md b/packages/canon/report.api.md index baa4a99d3f..9cc4035a5e 100644 --- a/packages/canon/report.api.md +++ b/packages/canon/report.api.md @@ -6,6 +6,7 @@ /// import { CSSProperties } from 'react'; +import { DetailedReactHTMLElement } from 'react'; import { DOMElement } from 'react'; import { default as React_2 } from 'react'; import { ReactNode } from 'react'; @@ -150,6 +151,9 @@ export interface ColorProps { color?: Color; } +// @public (undocumented) +export type Columns = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; + // @public (undocumented) export type DisplayProps = | 'flex' @@ -173,6 +177,69 @@ export type FlexWrapProps = // @public (undocumented) export type Gap = Space | Partial>; +// @public (undocumented) +export const Grid: { + ({ + children, + columns, + gap, + className, + style, + ...restProps + }: GridProps): DetailedReactHTMLElement< + { + className: string; + style: CSSProperties | undefined; + }, + HTMLElement + >; + Item: ({ + children, + rowSpan, + colSpan, + start, + end, + className, + style, + }: GridItemProps) => DetailedReactHTMLElement< + { + className: string; + style: CSSProperties | undefined; + }, + HTMLElement + >; +}; + +// @public (undocumented) +export interface GridItemProps { + // (undocumented) + children: React.ReactNode; + // (undocumented) + className?: string; + // (undocumented) + colSpan?: Columns | 'full'; + // (undocumented) + end?: Columns | 'auto'; + // (undocumented) + rowSpan?: Columns | 'full'; + // (undocumented) + start?: Columns | 'auto'; + // (undocumented) + style?: React.CSSProperties; +} + +// @public (undocumented) +export interface GridProps extends SpaceProps, ColorProps { + // (undocumented) + children?: React.ReactNode; + // (undocumented) + className?: string; + // (undocumented) + columns?: Columns | Partial>; + // (undocumented) + style?: React.CSSProperties; +} + // @public (undocumented) export const Icon: ({ name }: { name: IconNames }) => React_2.JSX.Element; @@ -198,6 +265,49 @@ export type IconNames = | 'plus' | 'trash'; +// @public (undocumented) +export const Inline: ({ + as, + children, + align, + alignY, + gap, + className, + style, + ...restProps +}: InlineProps) => DetailedReactHTMLElement< + { + className: string; + style: CSSProperties | undefined; + children: ReactNode; + }, + HTMLElement +>; + +// @public (undocumented) +export interface InlineProps extends SpaceProps, ColorProps { + // (undocumented) + align?: + | 'left' + | 'center' + | 'right' + | Partial>; + // (undocumented) + alignY?: + | 'top' + | 'center' + | 'bottom' + | Partial>; + // (undocumented) + as?: AsProps; + // (undocumented) + children: React.ReactNode; + // (undocumented) + className?: string; + // (undocumented) + style?: React.CSSProperties; +} + // @public (undocumented) export type JustifyContentProps = | 'stretch' @@ -309,6 +419,42 @@ export interface SpaceProps { paddingY?: PaddingY; } +// @public (undocumented) +export const Stack: ({ + as, + children, + align, + gap, + className, + style, + ...restProps +}: StackProps) => DetailedReactHTMLElement< + { + className: string; + style: CSSProperties | undefined; + children: ReactNode; + }, + HTMLElement +>; + +// @public (undocumented) +export interface StackProps extends SpaceProps, ColorProps { + // (undocumented) + align?: + | 'left' + | 'center' + | 'right' + | Partial>; + // (undocumented) + as?: AsProps; + // (undocumented) + children: React.ReactNode; + // (undocumented) + className?: string; + // (undocumented) + style?: React.CSSProperties; +} + // @public (undocumented) export type Theme = keyof typeof themes; diff --git a/packages/canon/src/components/Box/Docs.mdx b/packages/canon/src/components/Box/Docs.mdx index 3f78ba3a76..c5eec1870b 100644 --- a/packages/canon/src/components/Box/Docs.mdx +++ b/packages/canon/src/components/Box/Docs.mdx @@ -1,4 +1,4 @@ -import { Canvas, Meta, Unstyled } from '@storybook/blocks'; +import { Meta, Unstyled, Source } from '@storybook/blocks'; import * as BoxStories from './Box.stories'; import { Title, Text } from '../../../docs/components'; import { Padding } from './docs/padding'; @@ -13,8 +13,18 @@ import { spacingProperties } from '../../layout/sprinkles.css'; Box Box is the lowest-level component in Canon. We use it internally to build all - of our components. It is a wrapper around the HTML `
` element and - provides a consistent API for styling and layout. You'll find below a list of all the available properties. + of our components. It provides a consistent API for styling and layout. + + +Installation + + +API reference + +Box + + This is the Box component, our lowest-level component. Here are all the + available properties. -Padding & Margin - + Padding and margin are used to create space around your component using our predefined spacing tokens. We would recommend to use padding over margin to avoid collapsing margins but both are available. @@ -46,4 +55,26 @@ import { spacingProperties } from '../../layout/sprinkles.css'; +Examples +Here are some examples of how you can use the Box component. + +Simple example +A simple example of how to use the Box component. +Hello World`} + language="tsx" + dark +/> + +Responsive + + Most of the values can be defined per breakpoint, making it easy to create + responsive designs. + +Hello World`} + language="tsx" + dark +/> + diff --git a/packages/canon/src/components/Grid/Grid.tsx b/packages/canon/src/components/Grid/Grid.tsx index 9ac23e9371..f320d4f7f5 100644 --- a/packages/canon/src/components/Grid/Grid.tsx +++ b/packages/canon/src/components/Grid/Grid.tsx @@ -18,6 +18,7 @@ import { createElement } from 'react'; import { GridItemProps, GridProps } from './types'; import { gridItemSprinkles, gridSprinkles } from './sprinkles.css'; +/** @public */ export const Grid = ({ children, columns, diff --git a/packages/canon/src/components/Grid/index.ts b/packages/canon/src/components/Grid/index.ts index b2534c6b77..b07249241c 100644 --- a/packages/canon/src/components/Grid/index.ts +++ b/packages/canon/src/components/Grid/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ export { Grid } from './Grid'; -export type { GridProps, GridItemProps } from './types'; +export type { GridProps, GridItemProps, Columns } from './types'; diff --git a/packages/canon/src/components/Grid/types.ts b/packages/canon/src/components/Grid/types.ts index 8400e61830..87edbd75bf 100644 --- a/packages/canon/src/components/Grid/types.ts +++ b/packages/canon/src/components/Grid/types.ts @@ -16,8 +16,10 @@ import { Breakpoint, ColorProps } from '../../layout/types'; import { SpaceProps } from '../../layout/types'; -type Columns = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; +/** @public */ +export type Columns = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; +/** @public */ export interface GridProps extends SpaceProps, ColorProps { children?: React.ReactNode; columns?: Columns | Partial>; @@ -25,6 +27,7 @@ export interface GridProps extends SpaceProps, ColorProps { style?: React.CSSProperties; } +/** @public */ export interface GridItemProps { children: React.ReactNode; rowSpan?: Columns | 'full'; diff --git a/packages/canon/src/components/Inline/Inline.tsx b/packages/canon/src/components/Inline/Inline.tsx index 2d1c649e29..1adcd01b92 100644 --- a/packages/canon/src/components/Inline/Inline.tsx +++ b/packages/canon/src/components/Inline/Inline.tsx @@ -32,6 +32,7 @@ const alignToFlexAlignY = (align: InlineProps['align']) => { return undefined; }; +/** @public */ export const Inline = ({ as = 'div', children, diff --git a/packages/canon/src/components/Inline/index.ts b/packages/canon/src/components/Inline/index.ts index 77a0e51629..2cc100c02a 100644 --- a/packages/canon/src/components/Inline/index.ts +++ b/packages/canon/src/components/Inline/index.ts @@ -14,3 +14,4 @@ * limitations under the License. */ export { Inline } from './Inline'; +export type { InlineProps } from './types'; diff --git a/packages/canon/src/components/Inline/types.ts b/packages/canon/src/components/Inline/types.ts index 413f2fbbb0..3d981d0d31 100644 --- a/packages/canon/src/components/Inline/types.ts +++ b/packages/canon/src/components/Inline/types.ts @@ -17,6 +17,7 @@ import { AsProps, Breakpoint, ColorProps } from '../../layout/types'; import { SpaceProps } from '../../layout/types'; +/** @public */ export interface InlineProps extends SpaceProps, ColorProps { children: React.ReactNode; as?: AsProps; diff --git a/packages/canon/src/components/Stack/Stack.tsx b/packages/canon/src/components/Stack/Stack.tsx index f2316805b5..f2a9a3f93d 100644 --- a/packages/canon/src/components/Stack/Stack.tsx +++ b/packages/canon/src/components/Stack/Stack.tsx @@ -25,6 +25,7 @@ const alignToFlexAlign = (align: StackProps['align']) => { return undefined; }; +/** @public */ export const Stack = ({ as = 'div', children, diff --git a/packages/canon/src/components/Stack/index.ts b/packages/canon/src/components/Stack/index.ts index 2aeaba3adf..7abbc3f439 100644 --- a/packages/canon/src/components/Stack/index.ts +++ b/packages/canon/src/components/Stack/index.ts @@ -14,3 +14,4 @@ * limitations under the License. */ export { Stack } from './Stack'; +export type { StackProps } from './types'; diff --git a/packages/canon/src/components/Stack/types.ts b/packages/canon/src/components/Stack/types.ts index 81abea9999..529e92d1bd 100644 --- a/packages/canon/src/components/Stack/types.ts +++ b/packages/canon/src/components/Stack/types.ts @@ -16,6 +16,7 @@ import { AsProps, Breakpoint, ColorProps } from '../../layout/types'; import { SpaceProps } from '../../layout/types'; +/** @public */ export interface StackProps extends SpaceProps, ColorProps { children: React.ReactNode; as?: AsProps; diff --git a/packages/canon/src/index.ts b/packages/canon/src/index.ts index d020041e4e..5901f87bc0 100644 --- a/packages/canon/src/index.ts +++ b/packages/canon/src/index.ts @@ -20,10 +20,15 @@ * @packageDocumentation */ -export * from './components/Button'; -export * from './components/Box'; -export * from './components/Icon'; +// Layout types export * from './layout/types'; + +// Layout components +export * from './components/Box'; export * from './components/Grid'; export * from './components/Stack'; export * from './components/Inline'; + +// UI components +export * from './components/Button'; +export * from './components/Icon'; From 7fced762df2befd32d1c41162bf704925e743f0f Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Thu, 5 Dec 2024 11:20:35 +0000 Subject: [PATCH 4/5] Update docs for Inline Signed-off-by: Charles de Dreuille --- packages/canon/src/components/Inline/Docs.mdx | 118 ++++++++++++++++++ .../src/components/Inline/sprinkles.css.ts | 2 +- packages/canon/src/components/Stack/Docs.mdx | 92 +++++++++++--- 3 files changed, 192 insertions(+), 20 deletions(-) create mode 100644 packages/canon/src/components/Inline/Docs.mdx diff --git a/packages/canon/src/components/Inline/Docs.mdx b/packages/canon/src/components/Inline/Docs.mdx new file mode 100644 index 0000000000..fb4e664b42 --- /dev/null +++ b/packages/canon/src/components/Inline/Docs.mdx @@ -0,0 +1,118 @@ +import { Meta, Unstyled, Source } from '@storybook/blocks'; +import * as InlineStories from './Inline.stories'; +import { Title, Text } from '../../../docs/components'; +import { PropsTable, getBoxProps } from '../../../docs/components/PropsTable'; +import { spacingProperties } from '../../layout/sprinkles.css'; +import { inlineProperties } from './sprinkles.css'; + + + + + +Inline + + + The Inline component is used to create a horizontal layout of elements. By + default it uses flex and flexWrap to make sure that your content always flows + responsively. + + +Installation + + + + API reference + + + + + + The grid component also accepts all the spacing props from the Box component. + + + + +Examples + +Simple +A simple example of how to use the Inline component. + + + Hello World + Hello World + Hello World +`} + language="tsx" + dark +/> + +Responsive + + The Inline component also supports responsive values, making it easy to create + responsive designs. + + + Hello World + Hello World + Hello World +`} + language="tsx" + dark +/> + +Align + + The Inline component also supports responsive alignment, making it easy to + create responsive designs. + + + Hello World + Hello World + Hello World +`} + language="tsx" + dark +/> + +Align vertically + + The Inline component also supports responsive vertical alignment, making it + easy to create responsive designs. + + + Hello World + Hello World + Hello World +`} + language="tsx" + dark +/> + + diff --git a/packages/canon/src/components/Inline/sprinkles.css.ts b/packages/canon/src/components/Inline/sprinkles.css.ts index 1d7e95da00..ccd4126608 100644 --- a/packages/canon/src/components/Inline/sprinkles.css.ts +++ b/packages/canon/src/components/Inline/sprinkles.css.ts @@ -18,7 +18,7 @@ import { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles'; import { breakpoints } from '../../layout/properties'; import { colorProperties, spacingProperties } from '../../layout/sprinkles.css'; -const inlineProperties = defineProperties({ +export const inlineProperties = defineProperties({ conditions: breakpoints, defaultCondition: 'xs', properties: { diff --git a/packages/canon/src/components/Stack/Docs.mdx b/packages/canon/src/components/Stack/Docs.mdx index 4f63d7114e..62fd06cc62 100644 --- a/packages/canon/src/components/Stack/Docs.mdx +++ b/packages/canon/src/components/Stack/Docs.mdx @@ -1,7 +1,8 @@ import { Meta, Unstyled, Source } from '@storybook/blocks'; import * as StackStories from './Stack.stories'; import { Title, Text } from '../../../docs/components'; -import { PropsTable } from '../../../docs/components/PropsTable'; +import { PropsTable, getBoxProps } from '../../../docs/components/PropsTable'; +import { spacingProperties } from '../../layout/sprinkles.css'; @@ -15,15 +16,12 @@ import { PropsTable } from '../../../docs/components/PropsTable'; columns. All values are responsive. - - Hello World - Hello World - Hello World -`} - language="tsx" - dark -/> +Installation + + + + API reference + -How to stack horizontally? + + The grid component also accepts all the spacing props from the Box component. + + + + +Common questions + +Can I stack horizontally? The Stack component only allows for stacking elements vertically. If you want to create a column layout, please use the Grid component. -Responsive -TBD + + Hello World + Hello World + Hello World + +`} + language="tsx" + dark +/> -Start and End -TBD +Examples + +Simple + + A simple example of how to use the Stack component with a medium gap. + + + + Hello World + Hello World + Hello World +`} + language="tsx" + dark +/> + +Responsive + + The Stack component also supports responsive values, making it easy to create + responsive designs. + + + Hello World + Hello World + Hello World +`} + language="tsx" + dark +/> + +Align + + The Stack component also supports responsive alignment, making it easy to + create responsive designs. + + + Hello World + Hello World + Hello World +`} + language="tsx" + dark +/> From 9fb31370d70aa31dd2fffa5c3d1c5e349bb7cd48 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Thu, 5 Dec 2024 13:04:41 +0000 Subject: [PATCH 5/5] Cleanup API report Signed-off-by: Charles de Dreuille --- packages/canon/report.api.md | 40 ++----------------- packages/canon/src/components/Grid/Grid.tsx | 30 ++++++-------- .../canon/src/components/Inline/Inline.tsx | 22 +++++----- packages/canon/src/components/Stack/Stack.tsx | 20 +++++----- 4 files changed, 40 insertions(+), 72 deletions(-) diff --git a/packages/canon/report.api.md b/packages/canon/report.api.md index 9cc4035a5e..5a80802cc6 100644 --- a/packages/canon/report.api.md +++ b/packages/canon/report.api.md @@ -179,29 +179,14 @@ export type Gap = Space | Partial>; // @public (undocumented) export const Grid: { - ({ - children, - columns, - gap, - className, - style, - ...restProps - }: GridProps): DetailedReactHTMLElement< + (props: GridProps): DetailedReactHTMLElement< { className: string; style: CSSProperties | undefined; }, HTMLElement >; - Item: ({ - children, - rowSpan, - colSpan, - start, - end, - className, - style, - }: GridItemProps) => DetailedReactHTMLElement< + Item: (props: GridItemProps) => DetailedReactHTMLElement< { className: string; style: CSSProperties | undefined; @@ -266,16 +251,7 @@ export type IconNames = | 'trash'; // @public (undocumented) -export const Inline: ({ - as, - children, - align, - alignY, - gap, - className, - style, - ...restProps -}: InlineProps) => DetailedReactHTMLElement< +export const Inline: (props: InlineProps) => DetailedReactHTMLElement< { className: string; style: CSSProperties | undefined; @@ -420,15 +396,7 @@ export interface SpaceProps { } // @public (undocumented) -export const Stack: ({ - as, - children, - align, - gap, - className, - style, - ...restProps -}: StackProps) => DetailedReactHTMLElement< +export const Stack: (props: StackProps) => DetailedReactHTMLElement< { className: string; style: CSSProperties | undefined; diff --git a/packages/canon/src/components/Grid/Grid.tsx b/packages/canon/src/components/Grid/Grid.tsx index f320d4f7f5..8e426ff49b 100644 --- a/packages/canon/src/components/Grid/Grid.tsx +++ b/packages/canon/src/components/Grid/Grid.tsx @@ -19,14 +19,16 @@ import { GridItemProps, GridProps } from './types'; import { gridItemSprinkles, gridSprinkles } from './sprinkles.css'; /** @public */ -export const Grid = ({ - children, - columns, - gap = 'xs', - className, - style, - ...restProps -}: GridProps) => { +export const Grid = (props: GridProps) => { + const { + children, + columns, + gap = 'xs', + className, + style, + ...restProps + } = props; + const sprinklesClassName = gridSprinkles({ ...restProps, gap, @@ -47,15 +49,9 @@ export const Grid = ({ ); }; -const GridItem = ({ - children, - rowSpan, - colSpan, - start, - end, - className, - style, -}: GridItemProps) => { +const GridItem = (props: GridItemProps) => { + const { children, rowSpan, colSpan, start, end, className, style } = props; + const sprinklesClassName = gridItemSprinkles({ rowSpan, colSpan, diff --git a/packages/canon/src/components/Inline/Inline.tsx b/packages/canon/src/components/Inline/Inline.tsx index 1adcd01b92..a46d4dc948 100644 --- a/packages/canon/src/components/Inline/Inline.tsx +++ b/packages/canon/src/components/Inline/Inline.tsx @@ -33,16 +33,18 @@ const alignToFlexAlignY = (align: InlineProps['align']) => { }; /** @public */ -export const Inline = ({ - as = 'div', - children, - align = 'left', - alignY = 'top', - gap = 'xs', - className, - style, - ...restProps -}: InlineProps) => { +export const Inline = (props: InlineProps) => { + const { + as = 'div', + children, + align = 'left', + alignY = 'top', + gap = 'xs', + className, + style, + ...restProps + } = props; + // Generate the list of class names const sprinklesClassName = inlineSprinkles({ ...restProps, diff --git a/packages/canon/src/components/Stack/Stack.tsx b/packages/canon/src/components/Stack/Stack.tsx index f2a9a3f93d..85a67db05d 100644 --- a/packages/canon/src/components/Stack/Stack.tsx +++ b/packages/canon/src/components/Stack/Stack.tsx @@ -26,15 +26,17 @@ const alignToFlexAlign = (align: StackProps['align']) => { }; /** @public */ -export const Stack = ({ - as = 'div', - children, - align = 'left', - gap = 'xs', - className, - style, - ...restProps -}: StackProps) => { +export const Stack = (props: StackProps) => { + const { + as = 'div', + children, + align = 'left', + gap = 'xs', + className, + style, + ...restProps + } = props; + // Transform the align prop const flexAlign = alignToFlexAlign(align);