diff --git a/packages/canon/docs/Home.mdx b/packages/canon/docs/Home.mdx index 479834303a..3a00de5d07 100644 --- a/packages/canon/docs/Home.mdx +++ b/packages/canon/docs/Home.mdx @@ -1,5 +1,13 @@ import { Unstyled } from '@storybook/blocks'; -import { Columns, Text, ComponentStatus, Banner, Title } from './components'; +import { + Columns, + Text, + ComponentStatus, + Banner, + Title, + Roadmap, +} from './components'; +import { list } from './components/Roadmap/list'; @@ -19,7 +27,7 @@ import { Columns, Text, ComponentStatus, Banner, Title } from './components'; - Project Status + Component Status We are still in the process of documenting the API and building the @@ -29,51 +37,45 @@ import { Columns, Text, ComponentStatus, Banner, Title } from './components'; - - - - - + - - - - - - - - + + + + + + + + + + Roadmap + + + + diff --git a/packages/canon/docs/components/Columns/columns.css.ts b/packages/canon/docs/components/Columns/columns.css.ts index 6efe97c349..0b5ec18aef 100644 --- a/packages/canon/docs/components/Columns/columns.css.ts +++ b/packages/canon/docs/components/Columns/columns.css.ts @@ -18,7 +18,7 @@ import { style } from '@vanilla-extract/css'; export const styles = style({ display: 'grid', - gridTemplateColumns: 'repeat(2, 1fr)', + gridTemplateColumns: 'repeat(3, 1fr)', rowGap: '20px', columnGap: '80px', }); diff --git a/packages/canon/docs/components/ComponentStatus/component-status.css.ts b/packages/canon/docs/components/ComponentStatus/component-status.css.ts index eeb58865ff..5cce5adb5d 100644 --- a/packages/canon/docs/components/ComponentStatus/component-status.css.ts +++ b/packages/canon/docs/components/ComponentStatus/component-status.css.ts @@ -57,7 +57,17 @@ export const pill = recipe({ borderColor: '#FFD000', color: '#D79927', }, - done: { + alpha: { + backgroundColor: '#D7F9D7', + borderColor: '#4ED14A', + color: '#3A9837', + }, + beta: { + backgroundColor: '#D7F9D7', + borderColor: '#4ED14A', + color: '#3A9837', + }, + stable: { backgroundColor: '#D7F9D7', borderColor: '#4ED14A', color: '#3A9837', diff --git a/packages/canon/docs/components/ComponentStatus/index.tsx b/packages/canon/docs/components/ComponentStatus/index.tsx index 2444fcdc16..64d552ea97 100644 --- a/packages/canon/docs/components/ComponentStatus/index.tsx +++ b/packages/canon/docs/components/ComponentStatus/index.tsx @@ -24,7 +24,7 @@ export const ComponentStatus = ({ link, }: { name: string; - status: 'notStarted' | 'inProgress' | 'done'; + status: 'notStarted' | 'inProgress' | 'alpha' | 'beta' | 'stable'; style?: React.CSSProperties; link?: string; }) => { @@ -40,7 +40,9 @@ export const ComponentStatus = ({ {status === 'notStarted' && 'Not Started'} {status === 'inProgress' && 'In Progress'} - {status === 'done' && 'Done'} + {status === 'alpha' && 'Alpha'} + {status === 'beta' && 'Beta'} + {status === 'stable' && 'Stable'} ); diff --git a/packages/canon/docs/components/Roadmap/index.tsx b/packages/canon/docs/components/Roadmap/index.tsx new file mode 100644 index 0000000000..2177ea558f --- /dev/null +++ b/packages/canon/docs/components/Roadmap/index.tsx @@ -0,0 +1,53 @@ +/* + * 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 { RoadmapItem } from './list'; + +export const Roadmap = ({ list }: { list: RoadmapItem[] }) => { + const orderList = ['inProgress', 'notStarted', 'completed']; + return ( +
+ {list + .sort( + (a, b) => orderList.indexOf(a.status) - orderList.indexOf(b.status), + ) + .map(Item)} +
+ ); +}; + +const Item = ({ + title, + status = 'notStarted', +}: { + title: string; + status: 'notStarted' | 'inProgress' | 'inReview' | 'completed'; +}) => { + return ( +
+
+
+
{title}
+
+ + {status === 'notStarted' && 'Not Started'} + {status === 'inProgress' && 'In Progress'} + {status === 'inReview' && 'Ready for Review'} + {status === 'completed' && 'Completed'} + +
+ ); +}; diff --git a/packages/canon/docs/components/Roadmap/list.ts b/packages/canon/docs/components/Roadmap/list.ts new file mode 100644 index 0000000000..d5f436281a --- /dev/null +++ b/packages/canon/docs/components/Roadmap/list.ts @@ -0,0 +1,62 @@ +/* + * 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 type RoadmapItem = { + title: string; + status: 'notStarted' | 'inProgress' | 'inReview' | 'completed'; +}; + +export const list: RoadmapItem[] = [ + { + title: 'Remove Vanilla Extract and use pure CSS instead', + status: 'inProgress', + }, + { + title: 'Add collapsing across breakpoints for the Inline component', + status: 'notStarted', + }, + { + title: 'Add reversing the order for the Inline component', + status: 'notStarted', + }, + { + title: 'Set up Storybook', + status: 'completed', + }, + { + title: 'Set up iconography', + status: 'completed', + }, + { + title: 'Set up global tokens', + status: 'inProgress', + }, + { + title: 'Set up theming system', + status: 'inProgress', + }, + { + title: 'Create first pass at box component', + status: 'completed', + }, + { + title: 'Create first pass at stack component', + status: 'completed', + }, + { + title: 'Create first pass at inline component', + status: 'completed', + }, +]; diff --git a/packages/canon/docs/components/Roadmap/styles.css b/packages/canon/docs/components/Roadmap/styles.css new file mode 100644 index 0000000000..e47aecf7fa --- /dev/null +++ b/packages/canon/docs/components/Roadmap/styles.css @@ -0,0 +1,102 @@ +.roadmap { + display: flex; + flex-direction: column; +} + +.roadmap .roadmap-item { + font-family: 'Geist', sans-serif; + display: flex; + align-items: center; + justify-content: space-between; + border-bottom: 1px solid #e0e0e0; + padding: 8px 0px; +} + +.roadmap .roadmap-item .left { + display: flex; + align-items: center; + padding-left: 12px; + gap: 12px; +} + +.roadmap .roadmap-item .dot { + width: 8px; + height: 8px; + border-radius: 50%; + background-color: #e0e0e0; +} + +.roadmap .roadmap-item.notStarted { + color: #000; +} + +.roadmap .roadmap-item.inProgress { + color: #000; +} + +.roadmap .roadmap-item.inReview { + color: #000; +} + +.roadmap .roadmap-item.completed .title { + color: #a2a2a2; + text-decoration: line-through; +} + +.roadmap .roadmap-item.notStarted .dot { + background-color: #d1d1d1; +} + +.roadmap .roadmap-item.inProgress .dot { + background-color: #ffd000; +} + +.roadmap .roadmap-item.inReview .dot { + background-color: #4ed14a; +} + +.roadmap .roadmap-item.completed .dot { + background-color: #4ed14a; +} + +.roadmap .roadmap-item .title { + font-weight: 300; + font-size: 16px; +} + +.roadmap .roadmap-item .pill { + display: inline-flex; + align-items: center; + height: 24px; + padding: 0px 8px; + border-radius: 40px; + font-size: 12px; + font-weight: 600; + margin-left: 8px; + border-style: solid; + border-width: 1px; +} + +.roadmap .roadmap-item.notStarted .pill { + background-color: #f2f2f2; + border-color: #cdcdcd; + color: #888888; +} + +.roadmap .roadmap-item.inProgress .pill { + background-color: #fff2b9; + border-color: #ffd000; + color: #d79927; +} + +.roadmap .roadmap-item.inReview .pill { + background-color: #d7f9d7; + border-color: #4ed14a; + color: #3a9837; +} + +.roadmap .roadmap-item.completed .pill { + background-color: #d7f9d7; + border-color: #4ed14a; + color: #3a9837; +} diff --git a/packages/canon/docs/components/index.ts b/packages/canon/docs/components/index.ts index 88a8cb0391..7ad07bec6a 100644 --- a/packages/canon/docs/components/index.ts +++ b/packages/canon/docs/components/index.ts @@ -23,3 +23,4 @@ export * from './ComponentStatus'; export * from './LayoutComponents'; export * from './Banner'; export * from './IconLibrary'; +export * from './Roadmap'; diff --git a/packages/canon/docs/components/styles.css b/packages/canon/docs/components/styles.css index 63df601609..698085ad19 100644 --- a/packages/canon/docs/components/styles.css +++ b/packages/canon/docs/components/styles.css @@ -1 +1,2 @@ @import './IconLibrary/styles.css'; +@import './Roadmap/styles.css'; diff --git a/packages/canon/src/utils/list-values.ts b/packages/canon/docs/utils/argTypes.ts similarity index 55% rename from packages/canon/src/utils/list-values.ts rename to packages/canon/docs/utils/argTypes.ts index 9e3464a4f5..ff5a159677 100644 --- a/packages/canon/src/utils/list-values.ts +++ b/packages/canon/docs/utils/argTypes.ts @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +import { boxProperties } from '../../src/components/Box/sprinkles.css'; import { - responsiveProperties, colorProperties, -} from '../components/Box/sprinkles.css'; + spacingProperties, +} from '../../src/layout/sprinkles.css'; export const listResponsiveValues = ( - value: keyof typeof responsiveProperties.styles, + value: keyof typeof boxProperties.styles, ) => { - const values = responsiveProperties.styles[value]; + const values = boxProperties.styles[value]; if ('values' in values) { return Object.keys(values.values); @@ -40,3 +40,25 @@ export const listColorValues = (value: keyof typeof colorProperties.styles) => { return []; }; + +export const argTypesSpacing = Object.keys(spacingProperties.styles).reduce< + Record +>((acc, n) => { + acc[n] = { + control: 'inline-radio', + options: ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'], + }; + return acc; +}, {}); + +export const argTypesColor = Object.keys(colorProperties.styles).reduce< + Record +>((acc, n) => { + acc[n as keyof typeof colorProperties.styles] = { + control: 'select', + options: Object.keys( + colorProperties.styles[n as keyof typeof colorProperties.styles].values, + ), + }; + return acc; +}, {}); diff --git a/packages/canon/report.api.md b/packages/canon/report.api.md index 723e08859b..e98d57a13d 100644 --- a/packages/canon/report.api.md +++ b/packages/canon/report.api.md @@ -6,12 +6,12 @@ /// import { CSSProperties } from 'react'; -import { JSXElementConstructor } from 'react'; +import { DOMElement } from 'react'; import { default as React_2 } from 'react'; -import { ReactElement } from 'react'; +import { ReactNode } from 'react'; // @public (undocumented) -export type AlignItems = +export type AlignItemsProps = | 'stretch' | 'flex-start' | 'center' @@ -20,6 +20,25 @@ export type AlignItems = Record >; +// @public (undocumented) +export type AsProps = + | 'div' + | 'span' + | 'p' + | 'article' + | 'section' + | 'main' + | 'nav' + | 'aside' + | 'ul' + | 'ol' + | 'li' + | 'details' + | 'summary' + | 'dd' + | 'dl' + | 'dt'; + // @public (undocumented) export type Background = | 'background' @@ -31,7 +50,7 @@ export type Background = >; // @public (undocumented) -export type BorderRadius = +export type BorderRadiusProps = | 'none' | 'small' | 'medium' @@ -39,68 +58,35 @@ export type BorderRadius = | Partial>; // @public (undocumented) -export const Box: (props: BoxProps) => ReactElement< +export const Box: (props: BoxProps) => DOMElement< { className: string; style: CSSProperties | undefined; + children: ReactNode; }, - string | JSXElementConstructor + Element >; // @public (undocumented) -export interface BoxProps { +export interface BoxProps extends SpaceProps, ColorProps { // (undocumented) - alignItems?: AlignItems; + alignItems?: AlignItemsProps; // (undocumented) as?: keyof JSX.IntrinsicElements; // (undocumented) - background?: Background; - // (undocumented) - borderRadius?: BorderRadius; + borderRadius?: BorderRadiusProps; // (undocumented) children?: React.ReactNode; // (undocumented) className?: string; // (undocumented) - color?: Color; + display?: DisplayProps; // (undocumented) - display?: Display; + flexDirection?: FlexDirectionProps; // (undocumented) - flexDirection?: FlexDirection; + flexWrap?: FlexWrapProps; // (undocumented) - flexWrap?: FlexWrap; - // (undocumented) - gap?: Gap; - // (undocumented) - justifyContent?: JustifyContent; - // (undocumented) - margin?: Margin; - // (undocumented) - marginBottom?: MarginBottom; - // (undocumented) - marginLeft?: MarginLeft; - // (undocumented) - marginRight?: MarginRight; - // (undocumented) - marginTop?: MarginTop; - // (undocumented) - marginX?: MarginX; - // (undocumented) - marginY?: MarginY; - // (undocumented) - padding?: Padding; - // (undocumented) - paddingBottom?: PaddingBottom; - // (undocumented) - paddingLeft?: PaddingLeft; - // (undocumented) - paddingRight?: PaddingRight; - // (undocumented) - paddingTop?: PaddingTop; - // (undocumented) - paddingX?: PaddingX; - // (undocumented) - paddingY?: PaddingY; + justifyContent?: JustifyContentProps; // (undocumented) style?: React.CSSProperties; } @@ -163,7 +149,15 @@ export type Color = | Partial>; // @public (undocumented) -export type Display = +export interface ColorProps { + // (undocumented) + background?: Background; + // (undocumented) + color?: Color; +} + +// @public (undocumented) +export type DisplayProps = | 'flex' | 'none' | 'inline' @@ -171,13 +165,13 @@ export type Display = | Partial>; // @public (undocumented) -export type FlexDirection = +export type FlexDirectionProps = | 'row' | 'column' | Partial>; // @public (undocumented) -export type FlexWrap = +export type FlexWrapProps = | 'wrap' | 'nowrap' | Partial>; @@ -203,7 +197,7 @@ export type IconNames = | 'trash'; // @public (undocumented) -export type JustifyContent = +export type JustifyContentProps = | 'stretch' | 'flex-start' | 'center' @@ -279,6 +273,40 @@ export const space: { xxl: string; }; +// @public (undocumented) +export interface SpaceProps { + // (undocumented) + gap?: Gap; + // (undocumented) + margin?: Margin; + // (undocumented) + marginBottom?: MarginBottom; + // (undocumented) + marginLeft?: MarginLeft; + // (undocumented) + marginRight?: MarginRight; + // (undocumented) + marginTop?: MarginTop; + // (undocumented) + marginX?: MarginX; + // (undocumented) + marginY?: MarginY; + // (undocumented) + padding?: Padding; + // (undocumented) + paddingBottom?: PaddingBottom; + // (undocumented) + paddingLeft?: PaddingLeft; + // (undocumented) + paddingRight?: PaddingRight; + // (undocumented) + paddingTop?: PaddingTop; + // (undocumented) + paddingX?: PaddingX; + // (undocumented) + paddingY?: PaddingY; +} + // @public (undocumented) export type Theme = keyof typeof themes; diff --git a/packages/canon/src/components/Box/Box.stories.tsx b/packages/canon/src/components/Box/Box.stories.tsx index 8b8a2d7c56..6f15d984e1 100644 --- a/packages/canon/src/components/Box/Box.stories.tsx +++ b/packages/canon/src/components/Box/Box.stories.tsx @@ -17,87 +17,41 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; import { Box } from './Box'; -import { listResponsiveValues } from '../../utils/list-values'; -import { responsiveProperties, colorProperties } from './sprinkles.css'; +import { + listResponsiveValues, + argTypesSpacing, + argTypesColor, +} from '../../../docs/utils/argTypes'; +import { boxProperties } from './sprinkles.css'; -const argTypesResponsive = Object.keys(responsiveProperties.styles).reduce< +const argTypesBox = Object.keys(boxProperties.styles).reduce< Record >((acc, n) => { - if ( - [ - 'margin', - 'marginBottom', - 'marginLeft', - 'marginRight', - 'marginTop', - 'marginX', - 'marginY', - 'padding', - 'paddingBottom', - 'paddingLeft', - 'paddingRight', - 'paddingTop', - 'paddingX', - 'paddingY', - ].includes(n) - ) { - acc[n] = { - control: 'select', - options: ['xs', 'sm', 'md', 'lg', 'xl', '2xl'], - }; - } else { - acc[n] = { - control: 'select', - options: listResponsiveValues( - n as keyof typeof responsiveProperties.styles, - ), - }; - } - return acc; -}, {}); - -const argTypesColor = Object.keys(colorProperties.styles).reduce< - Record ->((acc, n) => { - acc[n as keyof typeof colorProperties.styles] = { + acc[n] = { control: 'select', - options: Object.keys( - colorProperties.styles[n as keyof typeof colorProperties.styles].values, - ), + options: listResponsiveValues(n as keyof typeof boxProperties.styles), }; return acc; }, {}); -const argTypes = { - ...argTypesResponsive, - ...argTypesColor, -}; - -// Sort the resulting object keys alphabetically -const sortedArgTypes = Object.keys(argTypes) - .sort() - .reduce((acc, key) => { - acc[key] = argTypes[key]; - return acc; - }, {} as Record); - -// Add 'as' and 'children' to the sortedArgTypes -sortedArgTypes['as'] = { - control: 'select', - options: ['div', 'span', 'article', 'section'], -}; - -sortedArgTypes['children'] = { - control: 'text', -}; - const meta = { title: 'Components/Box', component: Box, parameters: { layout: 'centered', }, - argTypes: sortedArgTypes, + argTypes: { + ...argTypesSpacing, + ...argTypesColor, + ...argTypesBox, + as: { + control: { type: 'select' }, + options: ['div', 'span', 'article', 'section'], + }, + children: { + control: false, + }, + }, args: { as: 'div', background: 'elevation1', diff --git a/packages/canon/src/components/Box/Box.tsx b/packages/canon/src/components/Box/Box.tsx index 960220a949..d134abff35 100644 --- a/packages/canon/src/components/Box/Box.tsx +++ b/packages/canon/src/components/Box/Box.tsx @@ -21,30 +21,19 @@ import { BoxProps } from './types'; /** @public */ export const Box = (props: BoxProps) => { - const { as = 'div', className, style, ...rest } = props; - const boxSprinklesProps: Record = {}; - const nativeProps: Record = {}; + const { as = 'div', className, style, children, ...restProps } = props; - // Split props between sprinkles and native HTML props - Object.entries(rest).forEach(([key, value]) => { - if (value === undefined) return; + // Generate the list of class names + const sprinklesClassName = boxSprinkles(restProps); - if ( - boxSprinkles.properties.has( - key as keyof Parameters[0], - ) - ) { - boxSprinklesProps[key] = value; - } else { - nativeProps[key] = value; - } - }); - - const sprinklesClassName = boxSprinkles(boxSprinklesProps); + // Combine the base class name, the sprinkles class name, and any additional class names + const classNames = [base, sprinklesClassName, className] + .filter(Boolean) + .join(' '); return createElement(as, { - className: [base, sprinklesClassName, className].filter(Boolean).join(' '), + className: classNames, style, - ...nativeProps, + children, }); }; diff --git a/packages/canon/src/components/Box/Docs.mdx b/packages/canon/src/components/Box/Docs.mdx index a3ce48b06d..dac10952cf 100644 --- a/packages/canon/src/components/Box/Docs.mdx +++ b/packages/canon/src/components/Box/Docs.mdx @@ -1,13 +1,7 @@ import { Canvas, Meta, Unstyled } from '@storybook/blocks'; import * as BoxStories from './Box.stories'; -import { Chip } from '../../../docs/components/Chip'; -import * as Table from '../../../docs/components/Table'; -import { Box } from './Box'; -import { Stack } from '../Stack'; import { Title, Text } from '../../../docs/components'; import { Padding } from './docs/padding'; -import { listResponsiveValues, listColorValues } from '../../utils/list-values'; -import { responsiveProperties } from './sprinkles.css'; import { PropsTable } from './docs/props-table'; import { SpacingTable } from './docs/spacing-table'; diff --git a/packages/canon/src/components/Box/docs/padding.tsx b/packages/canon/src/components/Box/docs/padding.tsx index 3f78f56692..86a7c801a2 100644 --- a/packages/canon/src/components/Box/docs/padding.tsx +++ b/packages/canon/src/components/Box/docs/padding.tsx @@ -15,7 +15,6 @@ */ import React from 'react'; -import { Stack } from '../../Stack'; import { Inline } from '../../Inline'; import { Box } from '../Box'; @@ -32,74 +31,77 @@ const FakeBox = ({ children }: { children: string }) => ( export const Padding = () => { return ( - - - + padding - - + paddingX - - + paddingY - + - - + paddingTop - - + paddingBottom - - + paddingLeft - - + paddingRight - + - + ); }; diff --git a/packages/canon/src/components/Box/docs/props-table.tsx b/packages/canon/src/components/Box/docs/props-table.tsx index bcdda93f2a..9979701f2e 100644 --- a/packages/canon/src/components/Box/docs/props-table.tsx +++ b/packages/canon/src/components/Box/docs/props-table.tsx @@ -17,8 +17,8 @@ import React from 'react'; import * as Table from '../../../../docs/components'; import { Chip } from '../../../../docs/components'; -import { listResponsiveValues } from '../../../utils/list-values'; -import { responsiveProperties } from '../sprinkles.css'; +import { listResponsiveValues } from '../../../../docs/utils/argTypes'; +import { boxProperties } from '../sprinkles.css'; export const PropsTable = () => { return ( @@ -30,7 +30,7 @@ export const PropsTable = () => { - {Object.keys(responsiveProperties.styles) + {Object.keys(boxProperties.styles) .filter( n => ![ @@ -57,7 +57,7 @@ export const PropsTable = () => { {listResponsiveValues( - n as keyof typeof responsiveProperties.styles, + 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 index 32b1eac1b9..93c38457d4 100644 --- a/packages/canon/src/components/Box/docs/spacing-table.tsx +++ b/packages/canon/src/components/Box/docs/spacing-table.tsx @@ -17,8 +17,8 @@ import React from 'react'; import * as Table from '../../../../docs/components'; import { Chip } from '../../../../docs/components'; -import { listResponsiveValues } from '../../../utils/list-values'; -import { responsiveProperties } from '../sprinkles.css'; +import { spacingProperties } from '../../../layout/sprinkles.css'; +import { space } from '../../../layout/properties'; export const SpacingTable = () => { return ( @@ -30,7 +30,7 @@ export const SpacingTable = () => { - {Object.keys(responsiveProperties.styles) + {Object.keys(spacingProperties.styles) .filter(n => [ 'padding', @@ -55,9 +55,7 @@ export const SpacingTable = () => { {n} - {listResponsiveValues( - 'paddingTop' as keyof typeof responsiveProperties.styles, - ).map(value => ( + {Object.keys(space).map(value => ( {value} ))} diff --git a/packages/canon/src/components/Box/index.tsx b/packages/canon/src/components/Box/index.tsx index f275aa352c..e4f1867edc 100644 --- a/packages/canon/src/components/Box/index.tsx +++ b/packages/canon/src/components/Box/index.tsx @@ -15,4 +15,4 @@ */ export { Box } from './Box'; export type * from './types'; -export { breakpoints, space, themes } from './properties'; +export { breakpoints, space, themes } from '../../layout/properties'; diff --git a/packages/canon/src/components/Box/sprinkles.css.ts b/packages/canon/src/components/Box/sprinkles.css.ts index 36904cb2ab..df5664029b 100644 --- a/packages/canon/src/components/Box/sprinkles.css.ts +++ b/packages/canon/src/components/Box/sprinkles.css.ts @@ -14,16 +14,11 @@ * limitations under the License. */ -import { - defineProperties, - createSprinkles, - RequiredConditionalValue, - ConditionalValue, - createMapValueFn, -} from '@vanilla-extract/sprinkles'; -import { breakpoints, space } from './properties'; +import { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles'; +import { breakpoints } from '../../layout/properties'; +import { colorProperties, spacingProperties } from '../../layout/sprinkles.css'; -export const responsiveProperties = defineProperties({ +export const boxProperties = defineProperties({ conditions: breakpoints, defaultCondition: 'xs', responsiveArray: ['xs', 'sm', 'md', 'lg', 'xl', '2xl'], @@ -55,57 +50,12 @@ export const responsiveProperties = defineProperties({ error: '1px solid var(--canon-error)', }, display: ['none', 'flex', 'block', 'inline'], - paddingTop: space, - paddingBottom: space, - paddingLeft: space, - paddingRight: space, - marginTop: space, - marginBottom: space, - marginLeft: space, - marginRight: space, - gap: space, flexWrap: ['wrap', 'nowrap'], }, - shorthands: { - padding: ['paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight'], - paddingX: ['paddingLeft', 'paddingRight'], - paddingY: ['paddingTop', 'paddingBottom'], - margin: ['marginTop', 'marginBottom', 'marginLeft', 'marginRight'], - marginX: ['marginLeft', 'marginRight'], - marginY: ['marginTop', 'marginBottom'], - }, -}); - -export const colorProperties = defineProperties({ - conditions: { - light: { selector: '[data-theme="light"] &' }, - dark: { selector: '[data-theme="dark"] &' }, - }, - defaultCondition: ['light', 'dark'], - properties: { - color: { - primary: 'var(--canon-text-primary)', - secondary: 'var(--canon-text-secondary)', - error: 'var(--canon-error)', - }, - background: { - background: 'var(--canon-background)', - elevation1: 'var(--canon-surface-1)', - elevation2: 'var(--canon-surface-2)', - transparent: 'transparent', - }, - }, }); export const boxSprinkles = createSprinkles( - responsiveProperties, + spacingProperties, + boxProperties, colorProperties, ); - -export type OptionalResponsiveValue = - ConditionalValue; - -export type RequiredResponsiveValue = - RequiredConditionalValue; - -export const mapResponsiveValue = createMapValueFn(responsiveProperties); diff --git a/packages/canon/src/components/Box/types.ts b/packages/canon/src/components/Box/types.ts index 3f307bf2eb..2ba5929fdd 100644 --- a/packages/canon/src/components/Box/types.ts +++ b/packages/canon/src/components/Box/types.ts @@ -13,19 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { breakpoints, space, themes } from './properties'; + +import { Breakpoint, SpaceProps, ColorProps } from '../../layout/types'; /** @public */ -export type Breakpoint = keyof typeof breakpoints; - -/** @public */ -export type Space = keyof typeof space; - -/** @public */ -export type Theme = keyof typeof themes; - -/** @public */ -export type Display = +export type DisplayProps = | 'flex' | 'none' | 'inline' @@ -33,19 +25,19 @@ export type Display = | Partial>; /** @public */ -export type FlexDirection = +export type FlexDirectionProps = | 'row' | 'column' | Partial>; /** @public */ -export type FlexWrap = +export type FlexWrapProps = | 'wrap' | 'nowrap' | Partial>; /** @public */ -export type JustifyContent = +export type JustifyContentProps = | 'stretch' | 'flex-start' | 'center' @@ -65,7 +57,7 @@ export type JustifyContent = >; /** @public */ -export type AlignItems = +export type AlignItemsProps = | 'stretch' | 'flex-start' | 'center' @@ -75,7 +67,7 @@ export type AlignItems = >; /** @public */ -export type BorderRadius = +export type BorderRadiusProps = | 'none' | 'small' | 'medium' @@ -83,94 +75,15 @@ export type BorderRadius = | Partial>; /** @public */ -export type Gap = Space | Partial>; - -/** @public */ -export type PaddingLeft = Space | Partial>; - -/** @public */ -export type PaddingRight = Space | Partial>; - -/** @public */ -export type PaddingTop = Space | Partial>; - -/** @public */ -export type PaddingBottom = Space | Partial>; - -/** @public */ -export type Padding = Space | Partial>; - -/** @public */ -export type PaddingX = Space | Partial>; - -/** @public */ -export type PaddingY = Space | Partial>; - -/** @public */ -export type MarginLeft = Space | Partial>; - -/** @public */ -export type MarginRight = Space | Partial>; - -/** @public */ -export type MarginTop = Space | Partial>; - -/** @public */ -export type MarginBottom = Space | Partial>; - -/** @public */ -export type Margin = Space | Partial>; - -/** @public */ -export type MarginX = Space | Partial>; - -/** @public */ -export type MarginY = Space | Partial>; - -/** @public */ -export type Background = - | 'background' - | 'elevation1' - | 'elevation2' - | 'transparent' - | Partial< - Record - >; - -/** @public */ -export type Color = - | 'primary' - | 'secondary' - | 'error' - | Partial>; - -/** @public */ -export interface BoxProps { +export interface BoxProps extends SpaceProps, ColorProps { as?: keyof JSX.IntrinsicElements; - background?: Background; children?: React.ReactNode; - color?: Color; - display?: Display; - flexDirection?: FlexDirection; - flexWrap?: FlexWrap; - justifyContent?: JustifyContent; - alignItems?: AlignItems; - borderRadius?: BorderRadius; - gap?: Gap; - padding?: Padding; - paddingLeft?: PaddingLeft; - paddingRight?: PaddingRight; - paddingTop?: PaddingTop; - paddingBottom?: PaddingBottom; - paddingX?: PaddingX; - paddingY?: PaddingY; - margin?: Margin; - marginLeft?: MarginLeft; - marginRight?: MarginRight; - marginTop?: MarginTop; - marginBottom?: MarginBottom; - marginX?: MarginX; - marginY?: MarginY; + display?: DisplayProps; + flexDirection?: FlexDirectionProps; + flexWrap?: FlexWrapProps; + justifyContent?: JustifyContentProps; + alignItems?: AlignItemsProps; + borderRadius?: BorderRadiusProps; className?: string; style?: React.CSSProperties; } diff --git a/packages/canon/src/components/Inline/Inline.stories.tsx b/packages/canon/src/components/Inline/Inline.stories.tsx index d098fa71a3..613fd68c68 100644 --- a/packages/canon/src/components/Inline/Inline.stories.tsx +++ b/packages/canon/src/components/Inline/Inline.stories.tsx @@ -18,38 +18,108 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; import { Inline } from './Inline'; import { Box } from '../Box/Box'; +import { argTypesSpacing, argTypesColor } from '../../../docs/utils/argTypes'; const meta = { title: 'Components/Inline', component: Inline, + argTypes: { + ...argTypesSpacing, + ...argTypesColor, + 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', + }, + }, } satisfies Meta; export default meta; type Story = StoryObj; -const FakeBox = () => ( +const FakeBox = ({ + width = 120, + height = 80, +}: { + width?: number; + height?: number; +}) => ( - Fake Box - + style={{ background: '#1f47ff', color: 'white', width, height }} + /> ); export const Default: Story = { args: { children: ( <> - - - + {Array.from({ length: 32 }).map((_, index) => ( + + ))} ), }, }; +export const AlignLeft: Story = { + args: { + ...Default.args, + align: 'left', + }, +}; + +export const AlignCenter: Story = { + args: { + ...Default.args, + align: 'center', + }, +}; + +export const AlignRight: Story = { + args: { + ...Default.args, + align: 'right', + }, +}; + +export const VerticalAlignTop: Story = { + args: { + ...Default.args, + alignY: 'top', + }, +}; + +export const VerticalAlignCenter: Story = { + args: { + ...Default.args, + alignY: 'center', + }, +}; + +export const VerticalAlignBottom: Story = { + args: { + ...Default.args, + alignY: 'bottom', + }, +}; + export const LargeGap: Story = { args: { ...Default.args, diff --git a/packages/canon/src/components/Inline/Inline.tsx b/packages/canon/src/components/Inline/Inline.tsx index db9f4bd9c3..2d1c649e29 100644 --- a/packages/canon/src/components/Inline/Inline.tsx +++ b/packages/canon/src/components/Inline/Inline.tsx @@ -14,46 +14,50 @@ * limitations under the License. */ -import React from 'react'; -import { Box } from '../Box/Box'; -import { alignToFlexAlign } from '../../utils/align'; -import type { BoxProps } from '../Box/types'; +import { createElement } from 'react'; +import { inlineSprinkles } from './sprinkles.css'; +import type { InlineProps } from './types'; -export const validInlineComponents = [ - 'div', - 'span', - 'p', - 'nav', - 'ul', - 'ol', - 'li', -] as const; +const alignYToFlexAlign = (alignY: InlineProps['alignY']) => { + if (alignY === 'top') return 'flex-start'; + if (alignY === 'center') return 'center'; + if (alignY === 'bottom') return 'flex-end'; + return undefined; +}; -export interface InlineProps extends Omit { - as?: (typeof validInlineComponents)[number]; - children: React.ReactNode; - align?: 'left' | 'center' | 'right'; - gap?: BoxProps['gap']; -} +const alignToFlexAlignY = (align: InlineProps['align']) => { + if (align === 'left') return 'flex-start'; + if (align === 'center') return 'center'; + if (align === 'right') return 'flex-end'; + return undefined; +}; export const Inline = ({ - align, as = 'div', children, + align = 'left', + alignY = 'top', gap = 'xs', + className, + style, ...restProps }: InlineProps) => { - return ( - - {children} - - ); + // Generate the list of class names + const sprinklesClassName = inlineSprinkles({ + ...restProps, + gap, + alignItems: alignYToFlexAlign(alignY), + justifyContent: alignToFlexAlignY(align), + }); + + // Combine the base class name, the sprinkles class name, and any additional class names + const classNames = ['inline', sprinklesClassName, className] + .filter(Boolean) + .join(' '); + + return createElement(as, { + className: classNames, + style, + children, + }); }; diff --git a/packages/canon/src/components/Inline/sprinkles.css.ts b/packages/canon/src/components/Inline/sprinkles.css.ts new file mode 100644 index 0000000000..1d7e95da00 --- /dev/null +++ b/packages/canon/src/components/Inline/sprinkles.css.ts @@ -0,0 +1,34 @@ +/* + * 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 inlineProperties = defineProperties({ + conditions: breakpoints, + defaultCondition: 'xs', + properties: { + alignItems: ['flex-start', 'center', 'flex-end'], + justifyContent: ['flex-start', 'center', 'flex-end'], + }, +}); + +export const inlineSprinkles = createSprinkles( + spacingProperties, + colorProperties, + inlineProperties, +); diff --git a/packages/canon/src/components/Inline/styles.css b/packages/canon/src/components/Inline/styles.css new file mode 100644 index 0000000000..fb9b1c3825 --- /dev/null +++ b/packages/canon/src/components/Inline/styles.css @@ -0,0 +1,4 @@ +.inline { + display: flex; + flex-wrap: wrap; +} diff --git a/packages/canon/src/components/Inline/types.ts b/packages/canon/src/components/Inline/types.ts new file mode 100644 index 0000000000..413f2fbbb0 --- /dev/null +++ b/packages/canon/src/components/Inline/types.ts @@ -0,0 +1,35 @@ +/* + * 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 { AsProps, Breakpoint, ColorProps } from '../../layout/types'; +import { SpaceProps } from '../../layout/types'; + +export interface InlineProps extends SpaceProps, ColorProps { + children: React.ReactNode; + as?: AsProps; + align?: + | 'left' + | 'center' + | 'right' + | Partial>; + alignY?: + | 'top' + | 'center' + | 'bottom' + | Partial>; + className?: string; + style?: React.CSSProperties; +} diff --git a/packages/canon/src/components/Stack/Stack.stories.tsx b/packages/canon/src/components/Stack/Stack.stories.tsx index 9d01238ae7..601f6b847f 100644 --- a/packages/canon/src/components/Stack/Stack.stories.tsx +++ b/packages/canon/src/components/Stack/Stack.stories.tsx @@ -18,10 +18,32 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; import { Stack } from './Stack'; import { Box } from '../Box/Box'; +import { argTypesSpacing, argTypesColor } from '../../../docs/utils/argTypes'; const meta = { title: 'Components/Stack', component: Stack, + argTypes: { + ...argTypesSpacing, + ...argTypesColor, + align: { + control: 'inline-radio', + options: ['left', 'center', 'right'], + }, + children: { + control: false, + }, + as: { + control: false, + }, + className: { + control: 'text', + }, + }, + args: { + align: 'left', + gap: 'xs', + }, } satisfies Meta; export default meta; @@ -50,6 +72,49 @@ export const Default: Story = { }, }; +export const AlignLeft: Story = { + args: { + ...Default.args, + align: 'left', + }, +}; + +export const AlignCenter: Story = { + args: { + ...Default.args, + align: 'center', + }, +}; + +export const AlignRight: Story = { + args: { + ...Default.args, + align: 'right', + }, +}; + +export const ResponsiveAlign: Story = { + args: { + ...Default.args, + align: { + xs: 'left', + md: 'center', + lg: 'right', + }, + }, +}; + +export const ResponsiveGap: Story = { + args: { + ...Default.args, + gap: { + xs: 'xs', + md: 'md', + lg: 'xxl', + }, + }, +}; + export const LargeGap: Story = { args: { ...Default.args, diff --git a/packages/canon/src/components/Stack/Stack.tsx b/packages/canon/src/components/Stack/Stack.tsx index 121ab1b176..f2316805b5 100644 --- a/packages/canon/src/components/Stack/Stack.tsx +++ b/packages/canon/src/components/Stack/Stack.tsx @@ -14,61 +14,44 @@ * limitations under the License. */ -import React from 'react'; -import { Box } from '../Box/Box'; -import { alignToFlexAlign } from '../../utils/align'; -import type { BoxProps } from '../Box/types'; -const validStackComponents = [ - 'div', - 'span', - 'p', - 'article', - 'section', - 'main', - 'nav', - 'aside', - 'ul', - 'ol', - 'li', - 'details', - 'summary', - 'dd', - 'dl', - 'dt', -] as const; +import { createElement } from 'react'; +import { StackProps } from './types'; +import { stackSprinkles } from './sprinkles.css'; -export interface StackProps extends Omit { - children: React.ReactNode; - as?: (typeof validStackComponents)[number]; - align?: 'left' | 'center' | 'right'; - gap?: BoxProps['gap']; -} +const alignToFlexAlign = (align: StackProps['align']) => { + if (align === 'left') return 'stretch'; + if (align === 'center') return 'center'; + if (align === 'right') return 'flex-end'; + return undefined; +}; export const Stack = ({ as = 'div', children, - align: alignProp, + align = 'left', gap = 'xs', + className, + style, ...restProps }: StackProps) => { - /** - * Creating a seam between the provided prop and the default value - * to enable only setting the text alignment when the `align` prop - * is provided — not when it's defaulted. - */ - const align = alignProp || 'left'; + // Transform the align prop + const flexAlign = alignToFlexAlign(align); - return ( - - {children} - - ); + // Generate the list of class names + const sprinklesClassName = stackSprinkles({ + ...restProps, + gap, + alignItems: flexAlign, + }); + + // Combine the base class name, the sprinkles class name, and any additional class names + const classNames = ['stack', sprinklesClassName, className] + .filter(Boolean) + .join(' '); + + return createElement(as, { + className: classNames, + style, + children, + }); }; diff --git a/packages/canon/src/components/Stack/sprinkles.css.ts b/packages/canon/src/components/Stack/sprinkles.css.ts index 461f38fcde..85c8f83a71 100644 --- a/packages/canon/src/components/Stack/sprinkles.css.ts +++ b/packages/canon/src/components/Stack/sprinkles.css.ts @@ -13,74 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles'; -import { breakpoints, space } from '../Box/properties'; -import { colorProperties } from '../Box/sprinkles.css'; -const responsiveProperties = defineProperties({ +import { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles'; +import { breakpoints } from '../../layout/properties'; +import { colorProperties, spacingProperties } from '../../layout/sprinkles.css'; + +const stackProperties = defineProperties({ conditions: breakpoints, defaultCondition: 'xs', properties: { - flexDirection: ['row', 'column'], - justifyContent: [ - 'stretch', - 'flex-start', - 'center', - 'flex-end', - 'space-around', - 'space-between', - ], alignItems: ['stretch', 'flex-start', 'center', 'flex-end'], - borderRadius: { - none: 0, - small: '4px', - medium: '8px', - full: '9999px', - }, - boxShadow: { - small: 'var(--canon-box-shadow-small)', - medium: 'var(--canon-box-shadow-medium)', - large: 'var(--canon-box-shadow-large)', - }, - border: { - none: 'none', - thin: '1px solid var(--canon-outline)', - error: '1px solid var(--canon-error)', - }, - display: ['none', 'flex', 'block', 'inline'], - paddingTop: space, - paddingBottom: space, - paddingLeft: space, - paddingRight: space, - marginTop: space, - marginBottom: space, - marginLeft: space, - marginRight: space, - gap: space, - flexWrap: ['wrap', 'nowrap'], - }, - shorthands: { - p: ['paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight'], - pt: ['paddingTop'], - pr: ['paddingRight'], - pb: ['paddingBottom'], - pl: ['paddingLeft'], - px: ['paddingLeft', 'paddingRight'], - py: ['paddingTop', 'paddingBottom'], - m: ['marginTop', 'marginBottom', 'marginLeft', 'marginRight'], - mt: ['marginTop'], - mr: ['marginRight'], - mb: ['marginBottom'], - ml: ['marginLeft'], - mx: ['marginLeft', 'marginRight'], - my: ['marginTop', 'marginBottom'], - direction: ['flexDirection'], - items: ['alignItems'], - justify: ['justifyContent'], }, }); -export const sprinkles = createSprinkles(responsiveProperties, colorProperties); - -// It's a good idea to export the Sprinkles type too -export type Sprinkles = Parameters[0]; +export const stackSprinkles = createSprinkles( + spacingProperties, + colorProperties, + stackProperties, +); diff --git a/packages/canon/src/components/Stack/styles.css b/packages/canon/src/components/Stack/styles.css new file mode 100644 index 0000000000..784fd3b1ab --- /dev/null +++ b/packages/canon/src/components/Stack/styles.css @@ -0,0 +1,4 @@ +.stack { + display: flex; + flex-direction: column; +} diff --git a/packages/canon/src/components/Stack/types.ts b/packages/canon/src/components/Stack/types.ts new file mode 100644 index 0000000000..81abea9999 --- /dev/null +++ b/packages/canon/src/components/Stack/types.ts @@ -0,0 +1,29 @@ +/* + * 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 { AsProps, Breakpoint, ColorProps } from '../../layout/types'; +import { SpaceProps } from '../../layout/types'; + +export interface StackProps extends SpaceProps, ColorProps { + children: React.ReactNode; + as?: AsProps; + align?: + | 'left' + | 'center' + | 'right' + | Partial>; + className?: string; + style?: React.CSSProperties; +} diff --git a/packages/canon/src/index.ts b/packages/canon/src/index.ts index 2bd3f11f48..198a626f06 100644 --- a/packages/canon/src/index.ts +++ b/packages/canon/src/index.ts @@ -23,3 +23,4 @@ export * from './components/Button'; export * from './components/Box'; export * from './components/Icon'; +export * from './layout/types'; diff --git a/packages/canon/src/components/Box/properties.ts b/packages/canon/src/layout/properties.ts similarity index 100% rename from packages/canon/src/components/Box/properties.ts rename to packages/canon/src/layout/properties.ts diff --git a/packages/canon/src/layout/sprinkles.css.ts b/packages/canon/src/layout/sprinkles.css.ts new file mode 100644 index 0000000000..7e85487fe3 --- /dev/null +++ b/packages/canon/src/layout/sprinkles.css.ts @@ -0,0 +1,63 @@ +/* + * 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 } from '@vanilla-extract/sprinkles'; +import { breakpoints, space } from './properties'; + +export const spacingProperties = defineProperties({ + conditions: breakpoints, + defaultCondition: 'xs', + responsiveArray: ['xs', 'sm', 'md', 'lg', 'xl', '2xl'], + properties: { + paddingTop: space, + paddingBottom: space, + paddingLeft: space, + paddingRight: space, + marginTop: space, + marginBottom: space, + marginLeft: space, + marginRight: space, + gap: space, + }, + shorthands: { + padding: ['paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight'], + paddingX: ['paddingLeft', 'paddingRight'], + paddingY: ['paddingTop', 'paddingBottom'], + margin: ['marginTop', 'marginBottom', 'marginLeft', 'marginRight'], + marginX: ['marginLeft', 'marginRight'], + marginY: ['marginTop', 'marginBottom'], + }, +}); + +export const colorProperties = defineProperties({ + conditions: { + light: { selector: '[data-theme="light"] &' }, + dark: { selector: '[data-theme="dark"] &' }, + }, + defaultCondition: ['light', 'dark'], + properties: { + color: { + primary: 'var(--canon-text-primary)', + secondary: 'var(--canon-text-secondary)', + error: 'var(--canon-error)', + }, + background: { + background: 'var(--canon-background)', + elevation1: 'var(--canon-surface-1)', + elevation2: 'var(--canon-surface-2)', + transparent: 'transparent', + }, + }, +}); diff --git a/packages/canon/src/layout/types.ts b/packages/canon/src/layout/types.ts new file mode 100644 index 0000000000..c051dacb44 --- /dev/null +++ b/packages/canon/src/layout/types.ts @@ -0,0 +1,131 @@ +/* + * 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 { breakpoints, space, themes } from './properties'; + +/** @public */ +export type Breakpoint = keyof typeof breakpoints; + +/** @public */ +export type Space = keyof typeof space; + +/** @public */ +export type Theme = keyof typeof themes; + +/** @public */ +export type Gap = Space | Partial>; + +/** @public */ +export type PaddingLeft = Space | Partial>; + +/** @public */ +export type PaddingRight = Space | Partial>; + +/** @public */ +export type PaddingTop = Space | Partial>; + +/** @public */ +export type PaddingBottom = Space | Partial>; + +/** @public */ +export type Padding = Space | Partial>; + +/** @public */ +export type PaddingX = Space | Partial>; + +/** @public */ +export type PaddingY = Space | Partial>; + +/** @public */ +export type MarginLeft = Space | Partial>; + +/** @public */ +export type MarginRight = Space | Partial>; + +/** @public */ +export type MarginTop = Space | Partial>; + +/** @public */ +export type MarginBottom = Space | Partial>; + +/** @public */ +export type Margin = Space | Partial>; + +/** @public */ +export type MarginX = Space | Partial>; + +/** @public */ +export type MarginY = Space | Partial>; + +/** @public */ +export interface SpaceProps { + gap?: Gap; + padding?: Padding; + paddingLeft?: PaddingLeft; + paddingRight?: PaddingRight; + paddingTop?: PaddingTop; + paddingBottom?: PaddingBottom; + paddingX?: PaddingX; + paddingY?: PaddingY; + margin?: Margin; + marginLeft?: MarginLeft; + marginRight?: MarginRight; + marginTop?: MarginTop; + marginBottom?: MarginBottom; + marginX?: MarginX; + marginY?: MarginY; +} + +/** @public */ +export type Background = + | 'background' + | 'elevation1' + | 'elevation2' + | 'transparent' + | Partial< + Record + >; + +/** @public */ +export type Color = + | 'primary' + | 'secondary' + | 'error' + | Partial>; + +/** @public */ +export type AsProps = + | 'div' + | 'span' + | 'p' + | 'article' + | 'section' + | 'main' + | 'nav' + | 'aside' + | 'ul' + | 'ol' + | 'li' + | 'details' + | 'summary' + | 'dd' + | 'dl' + | 'dt'; + +/** @public */ +export interface ColorProps { + color?: Color; + background?: Background; +} diff --git a/packages/canon/src/theme/styles.css b/packages/canon/src/theme/styles.css index fa5ed2ba4d..4a31340575 100644 --- a/packages/canon/src/theme/styles.css +++ b/packages/canon/src/theme/styles.css @@ -23,3 +23,5 @@ /* Components */ @import '../components/Button/styles.css'; +@import '../components/Stack/styles.css'; +@import '../components/Inline/styles.css'; diff --git a/packages/canon/src/utils/align.ts b/packages/canon/src/utils/align.ts deleted file mode 100644 index f4d7b5932e..0000000000 --- a/packages/canon/src/utils/align.ts +++ /dev/null @@ -1,49 +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 OptionalResponsiveValue, - mapResponsiveValue, -} from '../components/Box/sprinkles.css'; - -export type Align = 'left' | 'center' | 'right'; -export type AlignY = 'top' | 'center' | 'bottom'; - -const alignToFlexAlignLookup = { - left: 'flex-start', - center: 'center', - right: 'flex-end', -} as const; - -export const alignToFlexAlign = ( - align: OptionalResponsiveValue | undefined, -) => - align - ? mapResponsiveValue(align, value => alignToFlexAlignLookup[value]) - : undefined; - -const alignYToFlexAlignLookup = { - top: 'flex-start', - center: 'center', - bottom: 'flex-end', -} as const; - -export const alignYToFlexAlign = ( - alignY: OptionalResponsiveValue | undefined, -) => - alignY - ? mapResponsiveValue(alignY, value => alignYToFlexAlignLookup[value]) - : undefined;