diff --git a/.changeset/early-peaches-allow.md b/.changeset/early-peaches-allow.md new file mode 100644 index 0000000000..b1ea2c5880 --- /dev/null +++ b/.changeset/early-peaches-allow.md @@ -0,0 +1,5 @@ +--- +'@backstage/canon': minor +--- + +**BREAKING**: Merged the Stack and Inline component into a single component called Flex. diff --git a/canon-docs/src/app/(docs)/components/button/page.mdx b/canon-docs/src/app/(docs)/components/button/page.mdx index e0b0a89f31..b1276157b6 100644 --- a/canon-docs/src/app/(docs)/components/button/page.mdx +++ b/canon-docs/src/app/(docs)/components/button/page.mdx @@ -141,9 +141,9 @@ Here's a view when buttons are full width. py={4} open preview={} - code={` + code={` -`} +`} /> ### Disabled diff --git a/canon-docs/src/app/(docs)/components/stack/page.mdx b/canon-docs/src/app/(docs)/components/flex/page.mdx similarity index 64% rename from canon-docs/src/app/(docs)/components/stack/page.mdx rename to canon-docs/src/app/(docs)/components/flex/page.mdx index 7ef25c00b7..9f2b0bb6ee 100644 --- a/canon-docs/src/app/(docs)/components/stack/page.mdx +++ b/canon-docs/src/app/(docs)/components/flex/page.mdx @@ -3,29 +3,29 @@ import { spacePropsList } from '@/utils/spaceProps'; import { Tabs } from '@/components/Tabs'; import { CodeBlock } from '@/components/CodeBlock'; import { - stackFAQ1, - stackSimple, - stackResponsive, - stackAlign, + flexFAQ1, + flexSimple, + flexResponsive, + flexAlign, } from '@/snippets/_snippets'; import { Snippet } from '@/components/Snippet'; -import { StackPreview } from '@/snippets/stack'; +import { FlexPreview } from '@/snippets/flex'; -# Stack +# Flex -This is the stack container component. It will help to define the number of +This is the flex 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. } - code={` + preview={} + code={` -`} +`} /> @@ -34,9 +34,9 @@ columns. All values are responsive. + `} /> @@ -73,29 +73,29 @@ The grid component also accepts all the spacing props from the Box component. ### Can I stack horizontally? -The Stack component only allows for stacking elements vertically. If you want +The Flex component only allows for stacking elements vertically. If you want to create a column layout, please use the Grid component. - + ## Examples ### Simple -A simple example of how to use the Stack component. +A simple example of how to use the Flex component. - + ### Responsive -The Stack component also supports responsive values, making it easy to create +The Flex component also supports responsive values, making it easy to create responsive designs. - + ### Align -The Stack component also supports responsive alignment, making it easy to +The Flex component also supports responsive alignment, making it easy to create responsive designs. - + diff --git a/canon-docs/src/app/(docs)/components/heading/page.mdx b/canon-docs/src/app/(docs)/components/heading/page.mdx index e843e131ce..f2fbe0e929 100644 --- a/canon-docs/src/app/(docs)/components/heading/page.mdx +++ b/canon-docs/src/app/(docs)/components/heading/page.mdx @@ -75,13 +75,13 @@ appearance of the heading. py={2} open preview={} - code={` + code={` Display Title 1 Title 2 Title 3 Title 4 -`} +`} /> ### Responsive diff --git a/canon-docs/src/app/(docs)/components/inline/page.mdx b/canon-docs/src/app/(docs)/components/inline/page.mdx deleted file mode 100644 index ac4d7e0401..0000000000 --- a/canon-docs/src/app/(docs)/components/inline/page.mdx +++ /dev/null @@ -1,118 +0,0 @@ -import { CodeBlock } from '@/components/CodeBlock'; -import { PropsTable } from '@/components/PropsTable'; -import { spacePropsList } from '@/utils/spaceProps'; -import { Tabs } from '@/components/Tabs'; -import { Snippet } from '@/components/Snippet'; -import { InlinePreview } from '@/snippets/inline'; - -# Inline - -The Inline component is used to create a horizontal layout of elements. - -} - code={` - - - -`} -/> - - - - Usage - - - -`} - /> - - - -## 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 -`} -/> - -### Responsive - -The Inline component also supports responsive values, making it easy to create -responsive designs. - - - Hello World - Hello World - Hello World -`} -/> - -### Align - -The Inline component also supports responsive alignment, making it easy to -create responsive designs. - - - Hello World - Hello World - Hello World -`} -/> - -### Align vertically - -The Inline component also supports responsive vertical alignment, making it -easy to create responsive designs. - - - Hello World - Hello World - Hello World -`} -/> diff --git a/canon-docs/src/app/(docs)/components/text/page.mdx b/canon-docs/src/app/(docs)/components/text/page.mdx index 6d96fc5da3..450de0f79d 100644 --- a/canon-docs/src/app/(docs)/components/text/page.mdx +++ b/canon-docs/src/app/(docs)/components/text/page.mdx @@ -83,7 +83,7 @@ appearance of the text. } - code={` + code={` A man looks at a painting in a museum and says, “Brothers and sisters I have none, but that man's father is my father's son.” Who is @@ -104,7 +104,7 @@ appearance of the text. have none, but that man's father is my father's son.” Who is in the painting? - `} + `} /> ### All weights @@ -115,7 +115,7 @@ appearance of the text. } - code={` + code={` A man looks at a painting in a museum and says, “Brothers and sisters I have none, but that man's father is my father's son.” Who is @@ -126,7 +126,7 @@ appearance of the text. have none, but that man's father is my father's son.” Who is in the painting? - `} + `} /> ### Responsive diff --git a/canon-docs/src/app/(docs)/page.mdx b/canon-docs/src/app/(docs)/page.mdx index 09d4d83ea3..35fbc482b2 100644 --- a/canon-docs/src/app/(docs)/page.mdx +++ b/canon-docs/src/app/(docs)/page.mdx @@ -45,12 +45,12 @@ import { ThemeProvider } from '@backstage/canon'; Now you can start building your plugin using the new design system. ```tsx -import { Stack, Button } from '@backstage/canon'; +import { Flex, Button, Text } from '@backstage/canon'; - + Hello World -; +; ``` ## Roadmap diff --git a/canon-docs/src/app/(docs)/theme/layout/page.mdx b/canon-docs/src/app/(docs)/theme/layout/page.mdx index dc3a5d4585..b069082b04 100644 --- a/canon-docs/src/app/(docs)/theme/layout/page.mdx +++ b/canon-docs/src/app/(docs)/theme/layout/page.mdx @@ -22,13 +22,13 @@ provide are the ones coming from the theme. + code={` Hello World Project 1 Project 2 - + `} /> diff --git a/canon-docs/src/app/(docs)/theme/typography/page.mdx b/canon-docs/src/app/(docs)/theme/typography/page.mdx index 86be4d2e19..74b3144ef6 100644 --- a/canon-docs/src/app/(docs)/theme/typography/page.mdx +++ b/canon-docs/src/app/(docs)/theme/typography/page.mdx @@ -21,13 +21,13 @@ component](?path=/docs/components-heading--docs). py={2} open preview={} - code={` + code={` Display Title 1 Title 2 Title 3 Title 4 -`} +`} /> ## Text @@ -41,7 +41,7 @@ page. } - code={` + code={` A man looks at a painting in a museum and says, “Brothers and sisters I have none, but that man's father is my father's son.” Who is @@ -62,5 +62,5 @@ page. have none, but that man's father is my father's son.” Who is in the painting? - `} + `} /> diff --git a/canon-docs/src/app/(playground)/playground/page.tsx b/canon-docs/src/app/(playground)/playground/page.tsx index 7bbdefcc95..354f07bb25 100644 --- a/canon-docs/src/app/(playground)/playground/page.tsx +++ b/canon-docs/src/app/(playground)/playground/page.tsx @@ -1,7 +1,7 @@ 'use client'; import { ReactNode } from 'react'; -import { Grid, Stack, Text } from '../../../../../packages/canon'; +import { Grid, Flex, Text } from '../../../../../packages/canon'; import { screenSizes } from '@/utils/data'; import { Frame } from '@/components/Frame'; import { usePlayground } from '@/utils/playground-context'; @@ -53,7 +53,7 @@ const Content = () => { const { selectedComponents } = usePlayground(); return ( - + {selectedComponents.find(c => c === 'button') && ( } title="Button" /> )} @@ -69,17 +69,17 @@ const Content = () => { {/* {selectedComponents.find(c => c === 'input') && ( } title="Input" /> )} */} - + ); }; const Line = ({ content, title }: { content: ReactNode; title: string }) => { return ( - - + + {title} - {content} + {content} ); }; diff --git a/canon-docs/src/components/LayoutComponents/LayoutComponents.tsx b/canon-docs/src/components/LayoutComponents/LayoutComponents.tsx index 7262b837b3..05238717f1 100644 --- a/canon-docs/src/components/LayoutComponents/LayoutComponents.tsx +++ b/canon-docs/src/components/LayoutComponents/LayoutComponents.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { BoxSvg } from './svgs/box'; -import { StackSvg } from './svgs/stack'; +import { FlexSvg } from './svgs/flex'; import { GridSvg } from './svgs/grid'; import { InlineSvg } from './svgs/inline'; import { ContainerSvg } from './svgs/container'; @@ -20,10 +20,10 @@ export const LayoutComponents = () => {
- - + + -
Stack
+
Flex
Arrange your components vertically
diff --git a/canon-docs/src/components/LayoutComponents/svgs/stack.tsx b/canon-docs/src/components/LayoutComponents/svgs/flex.tsx similarity index 98% rename from canon-docs/src/components/LayoutComponents/svgs/stack.tsx rename to canon-docs/src/components/LayoutComponents/svgs/flex.tsx index c54cba57cf..7bc3466ce8 100644 --- a/canon-docs/src/components/LayoutComponents/svgs/stack.tsx +++ b/canon-docs/src/components/LayoutComponents/svgs/flex.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; -export const StackSvg = () => { +export const FlexSvg = () => { return ( `; -export const stackFAQ1 = ` +export const flexFAQ1 = ` Hello World Hello World Hello World `; -export const stackSimple = ` +export const flexSimple = ` Hello World Hello World Hello World -`; +`; -export const stackResponsive = ` +export const flexResponsive = ` Hello World Hello World Hello World -`; +`; -export const stackAlign = ` +export const flexAlign = ` Hello World Hello World Hello World -`; +`; diff --git a/canon-docs/src/snippets/button.tsx b/canon-docs/src/snippets/button.tsx index 30ed666a6a..2ae2ab0be9 100644 --- a/canon-docs/src/snippets/button.tsx +++ b/canon-docs/src/snippets/button.tsx @@ -1,16 +1,10 @@ 'use client'; -import { - Inline, - Button, - Stack, - ButtonProps, - Text, -} from '../../../packages/canon'; +import { Button, Flex, ButtonProps, Text } from '../../../packages/canon'; export const ButtonPreview = () => { return ( - + @@ -20,40 +14,40 @@ export const ButtonPreview = () => { - + ); }; export const ButtonSizes = () => { return ( - + - + ); }; export const ButtonWithIcons = () => { return ( - + - + ); }; export const ButtonFullWidth = () => { return ( - + - + ); }; @@ -73,12 +67,12 @@ export const ButtonPlayground = () => { const variants: string[] = ['primary', 'secondary', 'tertiary']; return ( - + {variants.map(variant => ( - + {variant} {['small', 'medium'].map(size => ( - + - + ))} - + ))} - + ); }; diff --git a/canon-docs/src/snippets/checkbox.tsx b/canon-docs/src/snippets/checkbox.tsx index 88c6de4a99..fe2a5b0219 100644 --- a/canon-docs/src/snippets/checkbox.tsx +++ b/canon-docs/src/snippets/checkbox.tsx @@ -1,6 +1,6 @@ 'use client'; -import { Inline, Checkbox, Stack, Text } from '../../../packages/canon'; +import { Checkbox, Flex, Text } from '../../../packages/canon'; export const CheckboxPreview = () => { return ; @@ -8,25 +8,25 @@ export const CheckboxPreview = () => { export const CheckboxAllVariants = () => { return ( - + - + ); }; export const CheckboxPlayground = () => { return ( - + All variants - + - - + + ); }; diff --git a/canon-docs/src/snippets/stack.tsx b/canon-docs/src/snippets/flex.tsx similarity index 86% rename from canon-docs/src/snippets/stack.tsx rename to canon-docs/src/snippets/flex.tsx index 4bada6f7ba..8bfab8878e 100644 --- a/canon-docs/src/snippets/stack.tsx +++ b/canon-docs/src/snippets/flex.tsx @@ -1,6 +1,6 @@ 'use client'; -import { Stack } from '../../../packages/canon'; +import { Flex } from '../../../packages/canon'; const DecorativeBox = () => { return ( @@ -18,14 +18,14 @@ const DecorativeBox = () => { ); }; -export const StackPreview = () => { +export const FlexPreview = () => { return (
- + - +
); }; diff --git a/canon-docs/src/snippets/heading.tsx b/canon-docs/src/snippets/heading.tsx index 13eaddff30..484497e7a7 100644 --- a/canon-docs/src/snippets/heading.tsx +++ b/canon-docs/src/snippets/heading.tsx @@ -1,6 +1,6 @@ 'use client'; -import { Heading, Stack, Text } from '../../../packages/canon'; +import { Heading, Flex, Text } from '../../../packages/canon'; export const HeadingPreview = () => { return Look mum, no hands!; @@ -8,35 +8,35 @@ export const HeadingPreview = () => { export const HeadingAllVariants = () => { return ( - + Display Title 1 Title 2 Title 3 Title 4 - + ); }; export const HeadingResponsive = () => { return ( - + Responsive heading - + ); }; export const HeadingPlayground = () => { return ( - + All variants Display Title 1 Title 2 Title 3 Title 4 - + ); }; diff --git a/canon-docs/src/snippets/text.tsx b/canon-docs/src/snippets/text.tsx index d2e2020210..4d39cbf6dd 100644 --- a/canon-docs/src/snippets/text.tsx +++ b/canon-docs/src/snippets/text.tsx @@ -1,6 +1,6 @@ 'use client'; -import { Stack, Text } from '../../../packages/canon'; +import { Flex, Text } from '../../../packages/canon'; export const TextPreview = () => { return ( @@ -14,7 +14,7 @@ export const TextPreview = () => { export const TextAllVariants = () => { return ( - + A man looks at a painting in a museum and says, “Brothers and sisters I have none, but that man's father is my father's son.” Who is @@ -35,13 +35,13 @@ export const TextAllVariants = () => { have none, but that man's father is my father's son.” Who is in the painting? - + ); }; export const TextAllWeights = () => { return ( - + A man looks at a painting in a museum and says, “Brothers and sisters I have none, but that man's father is my father's son.” Who is @@ -52,7 +52,7 @@ export const TextAllWeights = () => { have none, but that man's father is my father's son.” Who is in the painting? - + ); }; @@ -64,7 +64,7 @@ export const TextResponsive = () => { export const TextPlayground = () => { return ( - + Subtitle A man looks at a painting in a museum and says, “Brothers and sisters I @@ -89,6 +89,6 @@ export const TextPlayground = () => { have none, but that man's father is my father's son.” Who is in the painting? - + ); }; diff --git a/canon-docs/src/utils/data.ts b/canon-docs/src/utils/data.ts index 1109d6fa0a..c454b76d71 100644 --- a/canon-docs/src/utils/data.ts +++ b/canon-docs/src/utils/data.ts @@ -55,13 +55,8 @@ export const layoutComponents: Page[] = [ status: 'alpha', }, { - title: 'Inline', - slug: 'inline', - status: 'alpha', - }, - { - title: 'Stack', - slug: 'stack', + title: 'Flex', + slug: 'flex', status: 'alpha', }, ]; diff --git a/packages/canon/report.api.md b/packages/canon/report.api.md index 33efa37c7d..ef59d46f68 100644 --- a/packages/canon/report.api.md +++ b/packages/canon/report.api.md @@ -283,9 +283,57 @@ export const Field: { }) => React_2.JSX.Element; }; +// @public (undocumented) +export const Flex: ForwardRefExoticComponent< + FlexProps & RefAttributes +>; + // @public (undocumented) export type FlexDirection = 'row' | 'column'; +// @public (undocumented) +export type FlexOwnProps = GetPropDefTypes; + +// @public (undocumented) +export const flexPropDefs: { + align: { + type: 'enum'; + className: string; + values: readonly ['start', 'center', 'end', 'baseline', 'stretch']; + responsive: true; + }; + direction: { + type: 'enum'; + className: string; + values: readonly ['row', 'column', 'row-reverse', 'column-reverse']; + responsive: true; + }; + justify: { + type: 'enum'; + className: string; + values: readonly ['start', 'center', 'end', 'between']; + responsive: true; + }; +}; + +// @public (undocumented) +export interface FlexProps extends SpaceProps { + // (undocumented) + align?: FlexOwnProps['align']; + // (undocumented) + children: React.ReactNode; + // (undocumented) + className?: string; + // (undocumented) + direction?: FlexOwnProps['direction']; + // (undocumented) + gap?: GapProps['gap']; + // (undocumented) + justify?: FlexOwnProps['justify']; + // (undocumented) + style?: React.CSSProperties; +} + // @public (undocumented) export type FlexWrap = 'wrap' | 'nowrap' | 'wrap-reverse'; @@ -589,37 +637,6 @@ export type IconProps = { // @public (undocumented) export const icons: IconMap; -// @public (undocumented) -export const Inline: ForwardRefExoticComponent< - InlineProps & RefAttributes ->; - -// @public (undocumented) -export interface InlineProps extends SpaceProps { - // (undocumented) - align?: - | 'left' - | 'center' - | 'right' - | Partial>; - // (undocumented) - alignY?: - | 'top' - | 'center' - | 'bottom' - | Partial>; - // (undocumented) - as?: AsProps; - // (undocumented) - children: React.ReactNode; - // (undocumented) - className?: string; - // (undocumented) - gap?: UtilityProps['gap']; - // (undocumented) - style?: React.CSSProperties; -} - // @public (undocumented) export const Input: React_2.ForwardRefExoticComponent< InputProps & React_2.RefAttributes @@ -853,39 +870,6 @@ export interface SpaceProps { py?: Responsive; } -// @public (undocumented) -export const Stack: ForwardRefExoticComponent< - StackProps & RefAttributes ->; - -// @public (undocumented) -export type StackOwnProps = GetPropDefTypes; - -// @public (undocumented) -export const stackPropDefs: { - align: { - type: 'enum'; - className: string; - values: readonly ['start', 'center', 'end', 'baseline', 'stretch']; - responsive: true; - default: 'stretch'; - }; -}; - -// @public (undocumented) -export interface StackProps extends SpaceProps { - // (undocumented) - align?: StackOwnProps['align']; - // (undocumented) - children: React.ReactNode; - // (undocumented) - className?: string; - // (undocumented) - gap?: GapProps['gap']; - // (undocumented) - style?: React.CSSProperties; -} - // @public (undocumented) export type StringPropDef = { type: 'string'; diff --git a/packages/canon/src/components/Box/Box.stories.tsx b/packages/canon/src/components/Box/Box.stories.tsx index c7fc341bf4..7b9aecca1a 100644 --- a/packages/canon/src/components/Box/Box.stories.tsx +++ b/packages/canon/src/components/Box/Box.stories.tsx @@ -17,8 +17,7 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; import { Box } from './Box'; -import { Stack } from '../Stack'; -import { Inline } from '../Inline'; +import { Flex } from '../Flex'; const meta = { title: 'Components/Box', @@ -81,8 +80,8 @@ const CardDisplay = ({ children }: { children?: React.ReactNode }) => { export const Display: Story = { render: args => ( - - + + Block @@ -92,11 +91,11 @@ export const Display: Story = { None - + Responsive - + ), }; @@ -116,8 +115,8 @@ export const Padding: Story = { }, }, render: args => ( - - + + Padding @@ -127,8 +126,8 @@ export const Padding: Story = { Padding Y - - + + Padding Top @@ -141,8 +140,8 @@ export const Padding: Story = { Padding Left - - + + ), }; @@ -156,8 +155,8 @@ export const Margin: Story = { }, }, render: args => ( - - + + Margin @@ -173,8 +172,8 @@ export const Margin: Story = { Margin Y - - + + Margin Top @@ -195,7 +194,7 @@ export const Margin: Story = { Margin Left - - + + ), }; diff --git a/packages/canon/src/components/Button/Button.stories.tsx b/packages/canon/src/components/Button/Button.stories.tsx index 8661dc927d..cd52c7fdba 100644 --- a/packages/canon/src/components/Button/Button.stories.tsx +++ b/packages/canon/src/components/Button/Button.stories.tsx @@ -17,8 +17,7 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; import { Button } from './Button'; -import { Inline } from '../Inline'; -import { Stack } from '../Stack'; +import { Flex } from '../Flex'; import { Text } from '../Text'; import { ButtonProps } from './types'; @@ -51,7 +50,7 @@ export const Variants: Story = { }, }, render: () => ( - + @@ -61,7 +60,7 @@ export const Variants: Story = { - + ), }; @@ -70,10 +69,10 @@ export const Sizes: Story = { children: 'Button', }, render: () => ( - + - + ), }; @@ -82,11 +81,11 @@ export const WithIcons: Story = { children: 'Button', }, render: args => ( - + - + ))} - + ))} - + ), }; diff --git a/packages/canon/src/components/Checkbox/Checkbox.stories.tsx b/packages/canon/src/components/Checkbox/Checkbox.stories.tsx index 574783578c..db320cb3ce 100644 --- a/packages/canon/src/components/Checkbox/Checkbox.stories.tsx +++ b/packages/canon/src/components/Checkbox/Checkbox.stories.tsx @@ -17,8 +17,7 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; import { Checkbox } from './Checkbox'; -import { Inline } from '../Inline'; -import { Stack } from '../Stack'; +import { Flex } from '../Flex'; import { Text } from '../Text'; const meta = { @@ -40,25 +39,25 @@ export const Default: Story = { export const AllVariants: Story = { render: () => ( - + - + ), }; export const Playground: Story = { render: () => ( - + All variants - + - - + + ), }; diff --git a/packages/canon/src/components/Stack/Stack.props.ts b/packages/canon/src/components/Flex/Flex.props.ts similarity index 60% rename from packages/canon/src/components/Stack/Stack.props.ts rename to packages/canon/src/components/Flex/Flex.props.ts index 5cc7300c5d..97a602b42f 100644 --- a/packages/canon/src/components/Stack/Stack.props.ts +++ b/packages/canon/src/components/Flex/Flex.props.ts @@ -17,22 +17,42 @@ import type { PropDef, GetPropDefTypes } from '../../props/prop-def'; const alignValues = ['start', 'center', 'end', 'baseline', 'stretch'] as const; +const directionValues = [ + 'row', + 'column', + 'row-reverse', + 'column-reverse', +] as const; +const justifyValues = ['start', 'center', 'end', 'between'] as const; /** @public */ -const stackPropDefs = { +const flexPropDefs = { align: { type: 'enum', className: 'cu-align', values: alignValues, responsive: true, - default: 'stretch', + }, + direction: { + type: 'enum', + className: 'cu-fd', + values: directionValues, + responsive: true, + }, + justify: { + type: 'enum', + className: 'cu-jc', + values: justifyValues, + responsive: true, }, } satisfies { align: PropDef<(typeof alignValues)[number]>; + direction: PropDef<(typeof directionValues)[number]>; + justify: PropDef<(typeof justifyValues)[number]>; }; /** @public */ -type StackOwnProps = GetPropDefTypes; +type FlexOwnProps = GetPropDefTypes; -export { stackPropDefs }; -export type { StackOwnProps }; +export { flexPropDefs }; +export type { FlexOwnProps }; diff --git a/packages/canon/src/components/Stack/Stack.stories.tsx b/packages/canon/src/components/Flex/Flex.stories.tsx similarity index 78% rename from packages/canon/src/components/Stack/Stack.stories.tsx rename to packages/canon/src/components/Flex/Flex.stories.tsx index 0b02849a91..86693274db 100644 --- a/packages/canon/src/components/Stack/Stack.stories.tsx +++ b/packages/canon/src/components/Flex/Flex.stories.tsx @@ -16,11 +16,11 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; -import { Stack } from './Stack'; +import { Flex } from './Flex'; const meta = { - title: 'Components/Stack', - component: Stack, + title: 'Components/Flex', + component: Flex, argTypes: { align: { control: 'inline-radio', @@ -38,7 +38,7 @@ const meta = { gap: '4', children: 'hello world', }, -} satisfies Meta; +} satisfies Meta; export default meta; type Story = StoryObj; @@ -65,62 +65,76 @@ export const Default: Story = { }, }; +export const ColumnDirection: Story = { + args: { + direction: 'column', + children: [, , ], + }, +}; + +export const RowDirection: Story = { + args: { + direction: 'row', + children: [, , ], + }, +}; + export const AlignLeft: Story = { render: () => ( - + - + ), }; export const AlignCenter: Story = { render: () => ( - + - + ), }; export const AlignRight: Story = { render: () => ( - + - + ), }; export const ResponsiveAlign: Story = { render: () => ( - + - + ), }; export const ResponsiveGap: Story = { render: () => ( - + - + ), }; export const LargeGap: Story = { render: () => ( - + - + ), }; diff --git a/packages/canon/src/components/Stack/Stack.tsx b/packages/canon/src/components/Flex/Flex.tsx similarity index 81% rename from packages/canon/src/components/Stack/Stack.tsx rename to packages/canon/src/components/Flex/Flex.tsx index 9080a28e11..7c84ed08f8 100644 --- a/packages/canon/src/components/Stack/Stack.tsx +++ b/packages/canon/src/components/Flex/Flex.tsx @@ -15,24 +15,24 @@ */ import { createElement, forwardRef } from 'react'; -import { StackProps } from './types'; +import { FlexProps } from './types'; import clsx from 'clsx'; -import { stackPropDefs } from './Stack.props'; +import { flexPropDefs } from './Flex.props'; import { extractProps } from '../../utils/extractProps'; import { gapPropDefs } from '../../props/gap-props'; /** @public */ -export const Stack = forwardRef((props, ref) => { +export const Flex = forwardRef((props, ref) => { const propDefs = { ...gapPropDefs, - ...stackPropDefs, + ...flexPropDefs, }; const { className, style } = extractProps(props, propDefs); return createElement('div', { ref, - className: clsx('canon-Stack', className), + className: clsx('canon-Flex', className), style, children: props.children, }); diff --git a/packages/canon/src/components/Inline/index.ts b/packages/canon/src/components/Flex/index.ts similarity index 78% rename from packages/canon/src/components/Inline/index.ts rename to packages/canon/src/components/Flex/index.ts index 2cc100c02a..033a9bec42 100644 --- a/packages/canon/src/components/Inline/index.ts +++ b/packages/canon/src/components/Flex/index.ts @@ -13,5 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { Inline } from './Inline'; -export type { InlineProps } from './types'; +export { Flex } from './Flex'; +export { flexPropDefs } from './Flex.props'; +export type { FlexProps } from './types'; +export type { FlexOwnProps } from './Flex.props'; diff --git a/packages/canon/src/components/Inline/styles.css b/packages/canon/src/components/Flex/styles.css similarity index 94% rename from packages/canon/src/components/Inline/styles.css rename to packages/canon/src/components/Flex/styles.css index d68ee9dcbd..094edffca7 100644 --- a/packages/canon/src/components/Inline/styles.css +++ b/packages/canon/src/components/Flex/styles.css @@ -14,7 +14,6 @@ * limitations under the License. */ -.canon-Inline { +.canon-Flex { display: flex; - flex-wrap: wrap; } diff --git a/packages/canon/src/components/Stack/types.ts b/packages/canon/src/components/Flex/types.ts similarity index 80% rename from packages/canon/src/components/Stack/types.ts rename to packages/canon/src/components/Flex/types.ts index 267845c48a..d449bc609a 100644 --- a/packages/canon/src/components/Stack/types.ts +++ b/packages/canon/src/components/Flex/types.ts @@ -15,14 +15,16 @@ */ import type { SpaceProps } from '../../types'; -import { StackOwnProps } from './Stack.props'; +import { FlexOwnProps } from './Flex.props'; import type { GapProps } from '../../props/gap-props'; /** @public */ -export interface StackProps extends SpaceProps { +export interface FlexProps extends SpaceProps { children: React.ReactNode; gap?: GapProps['gap']; - align?: StackOwnProps['align']; + align?: FlexOwnProps['align']; + justify?: FlexOwnProps['justify']; + direction?: FlexOwnProps['direction']; className?: string; style?: React.CSSProperties; } diff --git a/packages/canon/src/components/Grid/Grid.stories.tsx b/packages/canon/src/components/Grid/Grid.stories.tsx index ebffe29bc0..c4ac7f1849 100644 --- a/packages/canon/src/components/Grid/Grid.stories.tsx +++ b/packages/canon/src/components/Grid/Grid.stories.tsx @@ -19,7 +19,7 @@ import type { Meta, StoryObj } from '@storybook/react'; import { Grid } from './Grid'; import type { GridItemProps } from './types'; import { Box } from '../Box/Box'; -import { Stack } from '../Stack'; +import { Flex } from '../Flex'; const meta = { title: 'Components/Grid', @@ -82,7 +82,7 @@ export const ColumnSizes: Story = { columns: '12', }, render: args => ( - + {Array.from({ length: 11 }, (_, i) => ( @@ -93,7 +93,7 @@ export const ColumnSizes: Story = { ))} - + ), }; @@ -102,7 +102,7 @@ export const RowAndColumns: Story = { columns: '12', }, render: args => ( - + - + ), }; diff --git a/packages/canon/src/components/Heading/Heading.stories.tsx b/packages/canon/src/components/Heading/Heading.stories.tsx index dc74ea0e16..1357bde877 100644 --- a/packages/canon/src/components/Heading/Heading.stories.tsx +++ b/packages/canon/src/components/Heading/Heading.stories.tsx @@ -17,8 +17,9 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; import { Heading } from './Heading'; -import { Stack } from '../Stack'; +import { Flex } from '../Flex'; import { Text } from '../Text'; + const meta = { title: 'Components/Heading', component: Heading, @@ -41,13 +42,13 @@ export const Title1: Story = { export const AllVariants: Story = { render: () => ( - + Display Title 1 Title 2 Title 3 Title 4 - + ), }; @@ -69,7 +70,7 @@ export const CustomTag: Story = { export const Playground: Story = { render: () => ( - + All variants Display Title 1 @@ -77,6 +78,6 @@ export const Playground: Story = { Title 3 Title 4 Title 5 - + ), }; diff --git a/packages/canon/src/components/Inline/Inline.stories.tsx b/packages/canon/src/components/Inline/Inline.stories.tsx deleted file mode 100644 index 96833d1f64..0000000000 --- a/packages/canon/src/components/Inline/Inline.stories.tsx +++ /dev/null @@ -1,136 +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 type { Meta, StoryObj } from '@storybook/react'; -import { Inline } from './Inline'; -import { Box } from '../Box/Box'; - -const meta = { - title: 'Components/Inline', - component: Inline, - argTypes: { - align: { - control: 'inline-radio', - options: ['left', 'center', 'right'], - }, - alignY: { - control: 'inline-radio', - options: ['top', 'center', 'bottom'], - }, - children: { - control: false, - }, - as: { - control: false, - }, - className: { - control: 'text', - }, - }, - args: { - children: 'hello world', - }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -const fakeBlockList = [ - { width: 45, height: 60 }, - { width: 150, height: 75 }, - { width: 80, height: 50 }, - { width: 120, height: 70 }, - { width: 95, height: 65 }, - { width: 80, height: 32 }, - { width: 130, height: 60 }, - { width: 100, height: 80 }, - { width: 140, height: 45 }, - { width: 85, height: 70 }, - { width: 125, height: 50 }, -]; - -const FakeBox = ({ - width = 120, - height = 80, -}: { - width?: number; - height?: number; -}) => ( - -); - -export const Default: Story = { - render: () => ( - - {fakeBlockList.map((block, index) => ( - - ))} - - ), -}; - -export const AlignLeft: Story = { - args: { - align: 'left', - }, -}; - -export const AlignCenter: Story = { - args: { - align: 'center', - }, -}; - -export const AlignRight: Story = { - args: { - align: 'right', - }, -}; - -export const VerticalAlignTop: Story = { - args: { - alignY: 'top', - }, -}; - -export const VerticalAlignCenter: Story = { - args: { - alignY: 'center', - }, -}; - -export const VerticalAlignBottom: Story = { - args: { - alignY: 'bottom', - }, -}; - -export const LargeGap: Story = { - args: { - gap: 'xl', - }, -}; diff --git a/packages/canon/src/components/Inline/Inline.tsx b/packages/canon/src/components/Inline/Inline.tsx deleted file mode 100644 index 599033996c..0000000000 --- a/packages/canon/src/components/Inline/Inline.tsx +++ /dev/null @@ -1,85 +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 { createElement, forwardRef } from 'react'; -import type { InlineProps } from './types'; -import { getClassNames } from '../../utils/getClassNames'; -import { JustifyContent, Breakpoint, AlignItems } from '../../types'; -import clsx from 'clsx'; - -// Function to map align values -const mapAlignValue = (value?: InlineProps['align']) => { - if (typeof value === 'string') { - let returnedValue: JustifyContent = 'stretch'; - if (value === 'left') returnedValue = 'start'; - if (value === 'center') returnedValue = 'center'; - if (value === 'right') returnedValue = 'end'; - return returnedValue; - } else if (typeof value === 'object') { - const returnedValue: Partial> = {}; - for (const [key, val] of Object.entries(value)) { - returnedValue[key as Breakpoint] = mapAlignValue(val) as JustifyContent; - } - return returnedValue; - } - return 'stretch'; -}; - -const mapAlignYValue = (value?: InlineProps['alignY']) => { - if (typeof value === 'string') { - let returnedValue: AlignItems = 'stretch'; - if (value === 'top') returnedValue = 'start'; - if (value === 'center') returnedValue = 'center'; - if (value === 'bottom') returnedValue = 'end'; - return returnedValue; - } else if (typeof value === 'object') { - const returnedValue: Partial> = {}; - for (const [key, val] of Object.entries(value)) { - returnedValue[key as Breakpoint] = mapAlignYValue(val) as AlignItems; - } - return returnedValue; - } - return 'stretch'; -}; - -/** @public */ -export const Inline = forwardRef((props, ref) => { - const { - as = 'div', - children, - align = 'left', - alignY = 'top', - gap = 'xs', - className, - style, - ...restProps - } = props; - - // Generate utility class names - const utilityClassNames = getClassNames({ - gap, - alignItems: mapAlignYValue(alignY), - justifyContent: mapAlignValue(align), - ...restProps, - }); - - return createElement(as, { - ref, - className: clsx('canon-Inline', utilityClassNames, className), - style, - children, - }); -}); diff --git a/packages/canon/src/components/Inline/types.ts b/packages/canon/src/components/Inline/types.ts deleted file mode 100644 index c86f500018..0000000000 --- a/packages/canon/src/components/Inline/types.ts +++ /dev/null @@ -1,41 +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 type { - SpaceProps, - UtilityProps, - AsProps, - Breakpoint, -} from '../../types'; - -/** @public */ -export interface InlineProps extends SpaceProps { - children: React.ReactNode; - as?: AsProps; - gap?: UtilityProps['gap']; - align?: - | 'left' - | 'center' - | 'right' - | Partial>; - alignY?: - | 'top' - | 'center' - | 'bottom' - | Partial>; - className?: string; - style?: React.CSSProperties; -} diff --git a/packages/canon/src/components/Input/Input.stories.tsx b/packages/canon/src/components/Input/Input.stories.tsx index a215162688..c1c76ddc09 100644 --- a/packages/canon/src/components/Input/Input.stories.tsx +++ b/packages/canon/src/components/Input/Input.stories.tsx @@ -17,7 +17,7 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; import { Input } from './Input'; -import { Inline } from '../Inline'; +import { Flex } from '../Flex'; const meta = { title: 'Components/Input', @@ -33,9 +33,9 @@ export const Primary: Story = { export const Sizes: Story = { render: () => ( - + - + ), }; diff --git a/packages/canon/src/components/Stack/index.ts b/packages/canon/src/components/Stack/index.ts deleted file mode 100644 index 122d0ee57c..0000000000 --- a/packages/canon/src/components/Stack/index.ts +++ /dev/null @@ -1,19 +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. - */ -export { Stack } from './Stack'; -export { stackPropDefs } from './Stack.props'; -export type { StackProps } from './types'; -export type { StackOwnProps } from './Stack.props'; diff --git a/packages/canon/src/components/Stack/styles.css b/packages/canon/src/components/Stack/styles.css deleted file mode 100644 index 18886e3229..0000000000 --- a/packages/canon/src/components/Stack/styles.css +++ /dev/null @@ -1,20 +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. - */ - -.canon-Stack { - display: flex; - flex-direction: column; -} diff --git a/packages/canon/src/components/Text/Text.stories.tsx b/packages/canon/src/components/Text/Text.stories.tsx index b0776beee9..547b637619 100644 --- a/packages/canon/src/components/Text/Text.stories.tsx +++ b/packages/canon/src/components/Text/Text.stories.tsx @@ -17,7 +17,7 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; import { Text } from './Text'; -import { Stack } from '../Stack'; +import { Flex } from '../Flex'; const meta = { title: 'Components/Text', @@ -40,7 +40,7 @@ export const Default: Story = { export const AllVariants: Story = { render: () => ( - + A man looks at a painting in a museum and says, “Brothers and sisters I have none, but that man's father is my father's son.” Who is @@ -61,13 +61,13 @@ export const AllVariants: Story = { have none, but that man's father is my father's son.” Who is in the painting? - + ), }; export const AllWeights: Story = { render: () => ( - + A man looks at a painting in a museum and says, “Brothers and sisters I have none, but that man's father is my father's son.” Who is @@ -78,7 +78,7 @@ export const AllWeights: Story = { have none, but that man's father is my father's son.” Who is in the painting? - + ), }; @@ -93,7 +93,7 @@ export const Responsive: Story = { export const Playground: Story = { render: () => ( - + Subtitle A man looks at a painting in a museum and says, “Brothers and sisters I @@ -118,6 +118,6 @@ export const Playground: Story = { have none, but that man's father is my father's son.” Who is in the painting? - + ), }; diff --git a/packages/canon/src/css/components.css b/packages/canon/src/css/components.css index b84ce7702b..1abee6eb5d 100644 --- a/packages/canon/src/css/components.css +++ b/packages/canon/src/css/components.css @@ -17,8 +17,7 @@ /* Components */ @import '../components/Box/styles.css'; @import '../components/Button/styles.css'; -@import '../components/Stack/styles.css'; -@import '../components/Inline/styles.css'; +@import '../components/Flex/styles.css'; @import '../components/Grid/styles.css'; @import '../components/Container/styles.css'; @import '../components/Icon/styles.css'; diff --git a/packages/canon/src/css/utilities.css b/packages/canon/src/css/utilities.css index aa7136fb94..226e30722b 100644 --- a/packages/canon/src/css/utilities.css +++ b/packages/canon/src/css/utilities.css @@ -14,24 +14,6 @@ * limitations under the License. */ -/* Default utilities */ -@import './utilities/xs.css'; - -/* Min 640px */ -@import './utilities/sm.css'; - -/* Min 768px */ -@import './utilities/md.css'; - -/* Min 1024px */ -@import './utilities/lg.css'; - -/* Min 1280px */ -@import './utilities/xl.css'; - -/* Min 1536px */ -@import './utilities/2xl.css'; - /* Padding */ @import './utilities/p.css'; @import './utilities/pl.css'; diff --git a/packages/canon/src/css/utilities/2xl.css b/packages/canon/src/css/utilities/2xl.css deleted file mode 100644 index 5c152fb86f..0000000000 --- a/packages/canon/src/css/utilities/2xl.css +++ /dev/null @@ -1,164 +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. - */ - -@layer utilities { - @media (min-width: 1536px) { - .cu-2xl-block { - display: block; - } - - .cu-2xl-border-base { - border-color: var(--canon-border); - border-width: 1px; - border-style: solid; - } - - .cu-2xl-border-error { - border-color: var(--canon-border-danger); - border-width: 1px; - border-style: solid; - } - - .cu-2xl-border-none { - border-color: transparent; - border-width: 0; - } - - .cu-2xl-border-selected { - border-color: var(--canon-border-focus); - border-width: 1px; - border-style: solid; - } - - .cu-2xl-border-warning { - border-color: var(--canon-border-warning); - border-width: 1px; - border-style: solid; - } - - .cu-2xl-flex { - display: flex; - } - - .cu-2xl-flex-col { - flex-direction: column; - } - - .cu-2xl-flex-nowrap { - flex-wrap: nowrap; - } - - .cu-2xl-flex-row { - flex-direction: row; - } - - .cu-2xl-flex-wrap { - flex-wrap: wrap; - } - - .cu-2xl-flex-wrap-reverse { - flex-wrap: wrap-reverse; - } - - .cu-2xl-hidden { - display: none; - } - - .cu-2xl-inline { - display: inline; - } - - .cu-2xl-inline-block { - display: inline-block; - } - - .cu-2xl-items-center { - align-items: center; - } - - .cu-2xl-items-end { - align-items: flex-end; - } - - .cu-2xl-items-start { - align-items: flex-start; - } - - .cu-2xl-items-stretch { - align-items: stretch; - } - - .cu-2xl-justify-around { - justify-content: space-around; - } - - .cu-2xl-justify-between { - justify-content: space-between; - } - - .cu-2xl-justify-center { - justify-content: center; - } - - .cu-2xl-justify-end { - justify-content: flex-end; - } - - .cu-2xl-justify-start { - justify-content: flex-start; - } - - .cu-2xl-justify-stretch { - justify-content: stretch; - } - - .cu-2xl-rounded-2xl { - border-radius: var(--canon-radius-full); - } - - .cu-2xl-rounded-2xs { - border-radius: var(--canon-radius-1); - } - - .cu-2xl-rounded-lg { - border-radius: var(--canon-radius-5); - } - - .cu-2xl-rounded-md { - border-radius: var(--canon-radius-4); - } - - .cu-2xl-rounded-none { - border-radius: 0; - } - - .cu-2xl-rounded-sm { - border-radius: var(--canon-radius-3); - } - - .cu-2xl-rounded-xl { - border-radius: var(--canon-radius-6); - } - - .cu-2xl-rounded-xs { - border-radius: var(--canon-radius-2); - } - - .cu-2xl-wrap-reverse { - flex-wrap: wrap-reverse; - } - } -} diff --git a/packages/canon/src/css/utilities/flex.css b/packages/canon/src/css/utilities/flex.css index 209334c23d..5311aac3e8 100644 --- a/packages/canon/src/css/utilities/flex.css +++ b/packages/canon/src/css/utilities/flex.css @@ -10,6 +10,42 @@ align-items: end; } +.cu-align-stretch { + align-items: stretch; +} + +.cu-jc-start { + justify-content: start; +} + +.cu-jc-center { + justify-content: center; +} + +.cu-jc-end { + justify-content: end; +} + +.cu-jc-between { + justify-content: space-between; +} + +.cu-fd-row { + flex-direction: row; +} + +.cu-fd-column { + flex-direction: column; +} + +.cu-fd-row-reverse { + flex-direction: row-reverse; +} + +.cu-fd-column-reverse { + flex-direction: column-reverse; +} + /* Breakpoint xs */ @media (min-width: 640px) { .xs\:cu-align-start { @@ -23,6 +59,42 @@ .xs\:cu-align-end { align-items: end; } + + .xs\:cu-align-stretch { + align-items: stretch; + } + + .xs\:cu-jc-start { + justify-content: start; + } + + .xs\:cu-jc-center { + justify-content: center; + } + + .xs\:cu-jc-end { + justify-content: end; + } + + .xs\:cu-jc-between { + justify-content: space-between; + } + + .xs\:cu-fd-row { + flex-direction: row; + } + + .xs\:cu-fd-column { + flex-direction: column; + } + + .xs\:cu-fd-row-reverse { + flex-direction: row-reverse; + } + + .xs\:cu-fd-column-reverse { + flex-direction: column-reverse; + } } /* Breakpoint sm */ @@ -38,6 +110,42 @@ .sm\:cu-align-end { align-items: end; } + + .sm\:cu-align-stretch { + align-items: stretch; + } + + .sm\:cu-jc-start { + justify-content: start; + } + + .sm\:cu-jc-center { + justify-content: center; + } + + .sm\:cu-jc-end { + justify-content: end; + } + + .sm\:cu-jc-between { + justify-content: space-between; + } + + .sm\:cu-fd-row { + flex-direction: row; + } + + .sm\:cu-fd-column { + flex-direction: column; + } + + .sm\:cu-fd-row-reverse { + flex-direction: row-reverse; + } + + .sm\:cu-fd-column-reverse { + flex-direction: column-reverse; + } } /* Breakpoint md */ @@ -53,6 +161,42 @@ .md\:cu-align-end { align-items: end; } + + .md\:cu-align-stretch { + align-items: stretch; + } + + .md\:cu-jc-start { + justify-content: start; + } + + .md\:cu-jc-center { + justify-content: center; + } + + .md\:cu-jc-end { + justify-content: end; + } + + .md\:cu-jc-between { + justify-content: space-between; + } + + .md\:cu-fd-row { + flex-direction: row; + } + + .md\:cu-fd-column { + flex-direction: column; + } + + .md\:cu-fd-row-reverse { + flex-direction: row-reverse; + } + + .md\:cu-fd-column-reverse { + flex-direction: column-reverse; + } } /* Breakpoint lg */ @@ -68,6 +212,42 @@ .lg\:cu-align-end { align-items: end; } + + .lg\:cu-align-stretch { + align-items: stretch; + } + + .lg\:cu-jc-start { + justify-content: start; + } + + .lg\:cu-jc-center { + justify-content: center; + } + + .lg\:cu-jc-end { + justify-content: end; + } + + .lg\:cu-jc-between { + justify-content: space-between; + } + + .lg\:cu-fd-row { + flex-direction: row; + } + + .lg\:cu-fd-column { + flex-direction: column; + } + + .lg\:cu-fd-row-reverse { + flex-direction: row-reverse; + } + + .lg\:cu-fd-column-reverse { + flex-direction: column-reverse; + } } /* Breakpoint xl */ @@ -83,4 +263,40 @@ .xl\:cu-align-end { align-items: end; } + + .xl\:cu-align-stretch { + align-items: stretch; + } + + .xl\:cu-jc-start { + justify-content: start; + } + + .xl\:cu-jc-center { + justify-content: center; + } + + .xl\:cu-jc-end { + justify-content: end; + } + + .xl\:cu-jc-between { + justify-content: space-between; + } + + .xl\:cu-fd-row { + flex-direction: row; + } + + .xl\:cu-fd-column { + flex-direction: column; + } + + .xl\:cu-fd-row-reverse { + flex-direction: row-reverse; + } + + .xl\:cu-fd-column-reverse { + flex-direction: column-reverse; + } } diff --git a/packages/canon/src/css/utilities/lg.css b/packages/canon/src/css/utilities/lg.css deleted file mode 100644 index 179b4a83b2..0000000000 --- a/packages/canon/src/css/utilities/lg.css +++ /dev/null @@ -1,164 +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. - */ - -@layer utilities { - @media (min-width: 1024px) { - .cu-lg-block { - display: block; - } - - .cu-lg-border-base { - border-color: var(--canon-border); - border-width: 1px; - border-style: solid; - } - - .cu-lg-border-error { - border-color: var(--canon-border-danger); - border-width: 1px; - border-style: solid; - } - - .cu-lg-border-none { - border-color: transparent; - border-width: 0; - } - - .cu-lg-border-selected { - border-color: var(--canon-border-focus); - border-width: 1px; - border-style: solid; - } - - .cu-lg-border-warning { - border-color: var(--canon-border-warning); - border-width: 1px; - border-style: solid; - } - - .cu-lg-flex { - display: flex; - } - - .cu-lg-flex-col { - flex-direction: column; - } - - .cu-lg-flex-nowrap { - flex-wrap: nowrap; - } - - .cu-lg-flex-row { - flex-direction: row; - } - - .cu-lg-flex-wrap { - flex-wrap: wrap; - } - - .cu-lg-flex-wrap-reverse { - flex-wrap: wrap-reverse; - } - - .cu-lg-hidden { - display: none; - } - - .cu-lg-inline { - display: inline; - } - - .cu-lg-inline-block { - display: inline-block; - } - - .cu-lg-items-center { - align-items: center; - } - - .cu-lg-items-end { - align-items: flex-end; - } - - .cu-lg-items-start { - align-items: flex-start; - } - - .cu-lg-items-stretch { - align-items: stretch; - } - - .cu-lg-justify-around { - justify-content: space-around; - } - - .cu-lg-justify-between { - justify-content: space-between; - } - - .cu-lg-justify-center { - justify-content: center; - } - - .cu-lg-justify-end { - justify-content: flex-end; - } - - .cu-lg-justify-start { - justify-content: flex-start; - } - - .cu-lg-justify-stretch { - justify-content: stretch; - } - - .cu-lg-rounded-2xl { - border-radius: var(--canon-radius-full); - } - - .cu-lg-rounded-2xs { - border-radius: var(--canon-radius-1); - } - - .cu-lg-rounded-lg { - border-radius: var(--canon-radius-5); - } - - .cu-lg-rounded-md { - border-radius: var(--canon-radius-4); - } - - .cu-lg-rounded-none { - border-radius: 0; - } - - .cu-lg-rounded-sm { - border-radius: var(--canon-radius-3); - } - - .cu-lg-rounded-xl { - border-radius: var(--canon-radius-6); - } - - .cu-lg-rounded-xs { - border-radius: var(--canon-radius-2); - } - - .cu-lg-wrap-reverse { - flex-wrap: wrap-reverse; - } - } -} diff --git a/packages/canon/src/css/utilities/md.css b/packages/canon/src/css/utilities/md.css deleted file mode 100644 index 2cf50dc137..0000000000 --- a/packages/canon/src/css/utilities/md.css +++ /dev/null @@ -1,164 +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. - */ - -@layer utilities { - @media (min-width: 768px) { - .cu-md-block { - display: block; - } - - .cu-md-border-base { - border-color: var(--canon-border); - border-width: 1px; - border-style: solid; - } - - .cu-md-border-error { - border-color: var(--canon-border-danger); - border-width: 1px; - border-style: solid; - } - - .cu-md-border-none { - border-color: transparent; - border-width: 0; - } - - .cu-md-border-selected { - border-color: var(--canon-border-focus); - border-width: 1px; - border-style: solid; - } - - .cu-md-border-warning { - border-color: var(--canon-border-warning); - border-width: 1px; - border-style: solid; - } - - .cu-md-flex { - display: flex; - } - - .cu-md-flex-col { - flex-direction: column; - } - - .cu-md-flex-nowrap { - flex-wrap: nowrap; - } - - .cu-md-flex-row { - flex-direction: row; - } - - .cu-md-flex-wrap { - flex-wrap: wrap; - } - - .cu-md-flex-wrap-reverse { - flex-wrap: wrap-reverse; - } - - .cu-md-hidden { - display: none; - } - - .cu-md-inline { - display: inline; - } - - .cu-md-inline-block { - display: inline-block; - } - - .cu-md-items-center { - align-items: center; - } - - .cu-md-items-end { - align-items: flex-end; - } - - .cu-md-items-start { - align-items: flex-start; - } - - .cu-md-items-stretch { - align-items: stretch; - } - - .cu-md-justify-around { - justify-content: space-around; - } - - .cu-md-justify-between { - justify-content: space-between; - } - - .cu-md-justify-center { - justify-content: center; - } - - .cu-md-justify-end { - justify-content: flex-end; - } - - .cu-md-justify-start { - justify-content: flex-start; - } - - .cu-md-justify-stretch { - justify-content: stretch; - } - - .cu-md-rounded-2xl { - border-radius: var(--canon-radius-full); - } - - .cu-md-rounded-2xs { - border-radius: var(--canon-radius-1); - } - - .cu-md-rounded-lg { - border-radius: var(--canon-radius-5); - } - - .cu-md-rounded-md { - border-radius: var(--canon-radius-4); - } - - .cu-md-rounded-none { - border-radius: 0; - } - - .cu-md-rounded-sm { - border-radius: var(--canon-radius-3); - } - - .cu-md-rounded-xl { - border-radius: var(--canon-radius-6); - } - - .cu-md-rounded-xs { - border-radius: var(--canon-radius-2); - } - - .cu-md-wrap-reverse { - flex-wrap: wrap-reverse; - } - } -} diff --git a/packages/canon/src/css/utilities/xl.css b/packages/canon/src/css/utilities/xl.css deleted file mode 100644 index 0efa83e034..0000000000 --- a/packages/canon/src/css/utilities/xl.css +++ /dev/null @@ -1,164 +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. - */ - -@layer utilities { - @media (min-width: 1280px) { - .cu-xl-block { - display: block; - } - - .cu-xl-border-base { - border-color: var(--canon-border); - border-width: 1px; - border-style: solid; - } - - .cu-xl-border-error { - border-color: var(--canon-border-danger); - border-width: 1px; - border-style: solid; - } - - .cu-xl-border-none { - border-color: transparent; - border-width: 0; - } - - .cu-xl-border-selected { - border-color: var(--canon-border-focus); - border-width: 1px; - border-style: solid; - } - - .cu-xl-border-warning { - border-color: var(--canon-border-warning); - border-width: 1px; - border-style: solid; - } - - .cu-xl-flex { - display: flex; - } - - .cu-xl-flex-col { - flex-direction: column; - } - - .cu-xl-flex-nowrap { - flex-wrap: nowrap; - } - - .cu-xl-flex-row { - flex-direction: row; - } - - .cu-xl-flex-wrap { - flex-wrap: wrap; - } - - .cu-xl-flex-wrap-reverse { - flex-wrap: wrap-reverse; - } - - .cu-xl-hidden { - display: none; - } - - .cu-xl-inline { - display: inline; - } - - .cu-xl-inline-block { - display: inline-block; - } - - .cu-xl-items-center { - align-items: center; - } - - .cu-xl-items-end { - align-items: flex-end; - } - - .cu-xl-items-start { - align-items: flex-start; - } - - .cu-xl-items-stretch { - align-items: stretch; - } - - .cu-xl-justify-around { - justify-content: space-around; - } - - .cu-xl-justify-between { - justify-content: space-between; - } - - .cu-xl-justify-center { - justify-content: center; - } - - .cu-xl-justify-end { - justify-content: flex-end; - } - - .cu-xl-justify-start { - justify-content: flex-start; - } - - .cu-xl-justify-stretch { - justify-content: stretch; - } - - .cu-xl-rounded-2xl { - border-radius: var(--canon-radius-full); - } - - .cu-xl-rounded-2xs { - border-radius: var(--canon-radius-1); - } - - .cu-xl-rounded-lg { - border-radius: var(--canon-radius-5); - } - - .cu-xl-rounded-md { - border-radius: var(--canon-radius-4); - } - - .cu-xl-rounded-none { - border-radius: 0; - } - - .cu-xl-rounded-sm { - border-radius: var(--canon-radius-3); - } - - .cu-xl-rounded-xl { - border-radius: var(--canon-radius-6); - } - - .cu-xl-rounded-xs { - border-radius: var(--canon-radius-2); - } - - .cu-xl-wrap-reverse { - flex-wrap: wrap-reverse; - } - } -} diff --git a/packages/canon/src/index.ts b/packages/canon/src/index.ts index bfe796ff47..1168990966 100644 --- a/packages/canon/src/index.ts +++ b/packages/canon/src/index.ts @@ -26,8 +26,7 @@ export * from './contexts/canon'; // Layout components export * from './components/Box'; export * from './components/Grid'; -export * from './components/Stack'; -export * from './components/Inline'; +export * from './components/Flex'; export * from './components/Container'; export * from './components/Text'; export * from './components/Heading'; diff --git a/packages/canon/src/utils/getClassNames.ts b/packages/canon/src/utils/getClassNames.ts deleted file mode 100644 index 684e633027..0000000000 --- a/packages/canon/src/utils/getClassNames.ts +++ /dev/null @@ -1,206 +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 type { Breakpoint, UtilityProps } from '../types'; - -const spaceMap = (type: string) => ({ - none: `${type}-none`, - '2xs': `${type}-2xs`, - xs: `${type}-xs`, - sm: `${type}-sm`, - md: `${type}-md`, - lg: `${type}-lg`, - xl: `${type}-xl`, - '2xl': `${type}-2xl`, -}); - -const valueMap: Record> = { - alignItems: { - stretch: 'items-stretch', - start: 'items-start', - center: 'items-center', - end: 'items-end', - }, - border: { - none: 'border-none', - base: 'border-base', - error: 'border-error', - warning: 'border-warning', - selected: 'border-selected', - }, - borderRadius: { - none: 'rounded-none', - '2xs': 'rounded-2xs', - xs: 'rounded-xs', - sm: 'rounded-sm', - md: 'rounded-md', - lg: 'rounded-lg', - xl: 'rounded-xl', - '2xl': 'rounded-2xl', - }, - colEnd: { - 1: 'col-end-1', - 2: 'col-end-2', - 3: 'col-end-3', - 4: 'col-end-4', - 5: 'col-end-5', - 6: 'col-end-6', - 7: 'col-end-7', - 8: 'col-end-8', - 9: 'col-end-9', - 10: 'col-end-10', - 11: 'col-end-11', - 12: 'col-end-12', - auto: 'col-end-auto', - }, - colSpan: { - 1: 'col-span-1', - 2: 'col-span-2', - 3: 'col-span-3', - 4: 'col-span-4', - 5: 'col-span-5', - 6: 'col-span-6', - 7: 'col-span-7', - 8: 'col-span-8', - 9: 'col-span-9', - 10: 'col-span-10', - 11: 'col-span-11', - 12: 'col-span-12', - auto: 'col-span-auto', - }, - colStart: { - 1: 'col-start-1', - 2: 'col-start-2', - 3: 'col-start-3', - 4: 'col-start-4', - 5: 'col-start-5', - 6: 'col-start-6', - 7: 'col-start-7', - 8: 'col-start-8', - 9: 'col-start-9', - 10: 'col-start-10', - 11: 'col-start-11', - 12: 'col-start-12', - auto: 'col-start-auto', - }, - columns: { - 1: 'grid-cols-1', - 2: 'grid-cols-2', - 3: 'grid-cols-3', - 4: 'grid-cols-4', - 5: 'grid-cols-5', - 6: 'grid-cols-6', - 7: 'grid-cols-7', - 8: 'grid-cols-8', - 9: 'grid-cols-9', - 10: 'grid-cols-10', - 11: 'grid-cols-11', - 12: 'grid-cols-12', - auto: 'grid-cols-auto', - }, - display: { - none: 'hidden', - flex: 'flex', - block: 'block', - inline: 'inline', - }, - flexDirection: { - row: 'flex-row', - column: 'flex-col', - }, - flexWrap: { - wrap: 'flex-wrap', - nowrap: 'flex-nowrap', - 'wrap-reverse': 'flex-wrap-reverse', - }, - gap: spaceMap('gap'), - justifyContent: { - stretch: 'justify-stretch', - start: 'justify-start', - center: 'justify-center', - end: 'justify-end', - around: 'justify-around', - between: 'justify-between', - }, - margin: spaceMap('m'), - marginBottom: spaceMap('mb'), - marginLeft: spaceMap('ml'), - marginRight: spaceMap('mr'), - marginTop: spaceMap('mt'), - marginX: spaceMap('mx'), - marginY: spaceMap('my'), - padding: spaceMap('p'), - paddingBottom: spaceMap('pb'), - paddingLeft: spaceMap('pl'), - paddingRight: spaceMap('pr'), - paddingTop: spaceMap('pt'), - paddingX: spaceMap('px'), - paddingY: spaceMap('py'), - rowSpan: { - 1: 'row-span-1', - 2: 'row-span-2', - 3: 'row-span-3', - 4: 'row-span-4', - 5: 'row-span-5', - 6: 'row-span-6', - 7: 'row-span-7', - 8: 'row-span-8', - 9: 'row-span-9', - 10: 'row-span-10', - 11: 'row-span-11', - 12: 'row-span-12', - full: 'row-span-full', - }, -}; - -const generateClassNames = (propName: string, propValue: any) => { - const classNames: string[] = []; - - // If the property name is not in the valueMap, return an empty array - if (!valueMap.hasOwnProperty(propName)) { - return classNames; - } - - if (typeof propValue === 'string' || typeof propValue === 'number') { - // If the property value is a string, map it to the valueMap - const value = valueMap[propName]?.[propValue] || propValue; - classNames.push(`cu-${value}`); - } else if (typeof propValue === 'object') { - // If the property value is an object, map each key-value pair - Object.entries(propValue as Record).forEach( - ([breakpoint, value]) => { - const mappedValue = valueMap[propName]?.[value] || value; - - if (breakpoint === 'xs') { - classNames.push(`cu-${mappedValue}`); - } else { - classNames.push(`cu-${breakpoint}-${mappedValue}`); - } - }, - ); - } - return classNames; -}; - -export const getClassNames = (props: UtilityProps) => { - const classNames: string[] = []; - - Object.entries(props).forEach(([propName, propValue]) => { - classNames.push(...generateClassNames(propName, propValue)); - }); - - return classNames.filter(Boolean).join(' '); -};