From cafeb1d3c508082cc03b04ba5cfe0a6336cb04eb Mon Sep 17 00:00:00 2001 From: Adrian Smijulj Date: Thu, 21 Nov 2024 10:02:16 +0100 Subject: [PATCH] feat: create `Grid` / `Column` components (#4252) --- .../admin-ui/src/Button/Button.stories.tsx | 1 - packages/admin-ui/src/Card/Card.stories.tsx | 3 - packages/admin-ui/src/Grid/Grid.stories.tsx | 89 ++++++++++++++ packages/admin-ui/src/Grid/Grid.tsx | 111 ++++++++++++++++++ packages/admin-ui/src/Grid/index.ts | 1 + packages/admin-ui/src/Heading/Heading.tsx | 2 +- packages/admin-ui/src/Icon/Icon.stories.tsx | 2 - packages/admin-ui/src/Text/Text.tsx | 2 +- packages/admin-ui/src/index.ts | 1 + packages/ui/src/Elevation/Elevation.tsx | 9 +- packages/ui/src/Grid/Grid.tsx | 52 +++++--- yarn.lock | 15 +-- 12 files changed, 248 insertions(+), 40 deletions(-) create mode 100644 packages/admin-ui/src/Grid/Grid.stories.tsx create mode 100644 packages/admin-ui/src/Grid/Grid.tsx create mode 100644 packages/admin-ui/src/Grid/index.ts diff --git a/packages/admin-ui/src/Button/Button.stories.tsx b/packages/admin-ui/src/Button/Button.stories.tsx index 9c535ea5b36..8693a006fb6 100644 --- a/packages/admin-ui/src/Button/Button.stories.tsx +++ b/packages/admin-ui/src/Button/Button.stories.tsx @@ -26,7 +26,6 @@ const meta: Meta = { export default meta; type Story = StoryObj; -// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args export const Primary: Story = { args: { variant: "primary", diff --git a/packages/admin-ui/src/Card/Card.stories.tsx b/packages/admin-ui/src/Card/Card.stories.tsx index 6fe48c8112b..160d1039bee 100644 --- a/packages/admin-ui/src/Card/Card.stories.tsx +++ b/packages/admin-ui/src/Card/Card.stories.tsx @@ -3,11 +3,9 @@ import type { Meta, StoryObj } from "@storybook/react"; import { Card, CardContent, CardFooter, CardHeader } from "./Card"; -// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export const meta: Meta = { title: "Components/Card", component: Card, - // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs tags: ["autodocs"] }; @@ -21,7 +19,6 @@ const defaultContentProps = { footer: }; -// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args export const Default: Story = { args: { ...defaultContentProps, diff --git a/packages/admin-ui/src/Grid/Grid.stories.tsx b/packages/admin-ui/src/Grid/Grid.stories.tsx new file mode 100644 index 00000000000..706fc779c39 --- /dev/null +++ b/packages/admin-ui/src/Grid/Grid.stories.tsx @@ -0,0 +1,89 @@ +import React from "react"; +import type { Meta, StoryObj } from "@storybook/react"; + +import { Grid } from "./Grid"; + +const meta: Meta = { + title: "Components/Grid", + component: Grid, + tags: ["autodocs"] +}; + +export default meta; + +type Story = StoryObj; + +const StyledColumn = ({ ...props }) => ( + +); + +export const Default: Story = { + args: { + className: "bg-neutral-light p-4", + children: ( + <> + Col 1 + + Col 2 (span: 3) + + Col 3 + Col 4 + Col 5 + Col 6 + + Col 7 (span: 2) + + Col 8 + Col 9 + + ) + } +}; + +export const SpaciousGap: Story = { + args: { + ...Default.args, + gap: "spacious" + } +}; + +export const WithOffset: Story = { + parameters: { + layout: "padded" + }, + decorators: [ + Story => ( +
+ +
+ ) + ], + args: { + ...Default.args, + children: ( + <> + {/* Row 1 */} + + Col (span: 8, offset: 2) + + + + {/* Row 2 */} + + Col (span: 8, offset: 4) + + + {/* Row 3 */} + + Col (span: 10, offset: 1) + + + + {/* Row 4 */} + + Col (span: 12) + + + ) + } +}; diff --git a/packages/admin-ui/src/Grid/Grid.tsx b/packages/admin-ui/src/Grid/Grid.tsx new file mode 100644 index 00000000000..9a48a519771 --- /dev/null +++ b/packages/admin-ui/src/Grid/Grid.tsx @@ -0,0 +1,111 @@ +import React from "react"; +import { makeDecoratable } from "@webiny/react-composition"; +import { cva, type VariantProps } from "class-variance-authority"; +import { cn, withStaticProps } from "~/utils"; + +const columnVariants = cva("", { + variants: { + span: { + auto: "col-auto", + 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" + }, + offset: { + 1: "col-start-2", + 2: "col-start-3", + 3: "col-start-4", + 4: "col-start-5", + 5: "col-start-6", + 6: "col-start-7", + 7: "col-start-8", + 8: "col-start-9", + 9: "col-start-10", + 10: "col-start-11", + 11: "col-start-12" + }, + align: { + top: "self-start", + middle: "self-center", + bottom: "self-end" + } + }, + defaultVariants: { + span: "auto" + } +}); + +interface ColumnProps + extends React.HTMLAttributes, + VariantProps { + children?: React.ReactNode; +} + +const ColumnBase = React.forwardRef( + ({ span, align, children, className, offset, ...props }, ref) => { + return ( +
+ {children} +
+ ); + } +); + +ColumnBase.displayName = "Column"; + +const Column = makeDecoratable("Column", ColumnBase); + +const gridVariants = cva("grid", { + variants: { + gap: { + comfortable: "gap-lg", + spacious: "gap-xl" + } + }, + defaultVariants: { + gap: "comfortable" + } +}); + +interface GridProps + extends React.HTMLAttributes, + VariantProps { + children: + | React.ReactElement + | Array>; +} + +const GridBase = React.forwardRef( + ({ gap, children, className, ...props }, ref) => { + return ( +
+ {children} +
+ ); + } +); + +GridBase.displayName = "Grid"; + +const DecoratableGrid = makeDecoratable("Grid", GridBase); + +const Grid = withStaticProps(DecoratableGrid, { Column }); + +export { Grid, type GridProps, type ColumnProps }; diff --git a/packages/admin-ui/src/Grid/index.ts b/packages/admin-ui/src/Grid/index.ts new file mode 100644 index 00000000000..f2b81475d2c --- /dev/null +++ b/packages/admin-ui/src/Grid/index.ts @@ -0,0 +1 @@ +export * from "./Grid"; diff --git a/packages/admin-ui/src/Heading/Heading.tsx b/packages/admin-ui/src/Heading/Heading.tsx index 2dae7b34e68..44196de36f8 100644 --- a/packages/admin-ui/src/Heading/Heading.tsx +++ b/packages/admin-ui/src/Heading/Heading.tsx @@ -16,7 +16,7 @@ const TAG_MAP: Record = { 6: "h6" }; -const headingVariants = cva("font-sans font-semibold", { +const headingVariants = cva("font-sans", { variants: { level: { 1: "text-h1", diff --git a/packages/admin-ui/src/Icon/Icon.stories.tsx b/packages/admin-ui/src/Icon/Icon.stories.tsx index b5f03acc0bd..52f97dd7e35 100644 --- a/packages/admin-ui/src/Icon/Icon.stories.tsx +++ b/packages/admin-ui/src/Icon/Icon.stories.tsx @@ -3,11 +3,9 @@ import type { Meta, StoryObj } from "@storybook/react"; import { ReactComponent as XIcon } from "@material-design-icons/svg/filled/close.svg"; import { Icon } from "./Icon"; -// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export const meta: Meta = { title: "Components/Icon", component: Icon, - // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs tags: ["autodocs"] }; diff --git a/packages/admin-ui/src/Text/Text.tsx b/packages/admin-ui/src/Text/Text.tsx index cb59ddf49db..76fb0c7d4b3 100644 --- a/packages/admin-ui/src/Text/Text.tsx +++ b/packages/admin-ui/src/Text/Text.tsx @@ -5,7 +5,7 @@ import { cn } from "~/utils"; type TextTags = "span" | "div"; -const textVariants = cva("font-sans font-normal", { +const textVariants = cva("font-sans", { variants: { size: { xl: "text-xl", diff --git a/packages/admin-ui/src/index.ts b/packages/admin-ui/src/index.ts index 0c4310b773c..30810051eb0 100644 --- a/packages/admin-ui/src/index.ts +++ b/packages/admin-ui/src/index.ts @@ -2,6 +2,7 @@ export * from "./Alert"; export * from "./Avatar"; export * from "./Button"; export * from "./Card"; +export * from "./Grid"; export * from "./Heading"; export * from "./Input"; export * from "./Label"; diff --git a/packages/ui/src/Elevation/Elevation.tsx b/packages/ui/src/Elevation/Elevation.tsx index 077e7a170e9..51f3bfda692 100644 --- a/packages/ui/src/Elevation/Elevation.tsx +++ b/packages/ui/src/Elevation/Elevation.tsx @@ -1,4 +1,5 @@ import React from "react"; +import cn from "classnames"; export type ElevationProps = { // Any element that needs to be highlighted. @@ -21,8 +22,12 @@ export type ElevationProps = { * @deprecated This component is deprecated and will be removed in future releases. * Please use the `Card` component from the `@webiny/admin-ui` package instead. */ -const Elevation = (props: ElevationProps) => { - return
{props.children}
; +const Elevation = ({ className, ...props }: ElevationProps) => { + return ( +
+ {props.children} +
+ ); }; Elevation.displayName = "Elevation"; diff --git a/packages/ui/src/Grid/Grid.tsx b/packages/ui/src/Grid/Grid.tsx index bf130d81d87..c2bb18da4f9 100644 --- a/packages/ui/src/Grid/Grid.tsx +++ b/packages/ui/src/Grid/Grid.tsx @@ -1,13 +1,10 @@ import React from "react"; -import { - Grid as RmwcGrid, - GridCell as RmwcGridCell, - GridRow as RmwcGridInner, - GridCellProps as RmwcGridCellProps, - GridProps as RmwcGridProps -} from "@rmwc/grid"; +import cn from "classnames"; +import { GridCellProps as RmwcGridCellProps, GridProps as RmwcGridProps } from "@rmwc/grid"; import { CSSProperties } from "react"; +import { Grid as AdminUiGrid, ColumnProps as AdminUiColumnProps } from "@webiny/admin-ui"; + export type CellProps = RmwcGridCellProps & { // One or more Cell components. children?: React.ReactNode; @@ -18,16 +15,21 @@ export type CellProps = RmwcGridCellProps & { style?: { [key: string]: any }; }; -export type GridProps = RmwcGridProps & { - className?: string; - style?: CSSProperties; -}; - /** * Cell must be direct children of Grid component. */ export const Cell = (props: CellProps) => { - return {props.children}; + const { children, style, className, align } = props; + return ( + + {children} + + ); }; export type GridInnerProps = { @@ -40,15 +42,33 @@ export type GridInnerProps = { className?: string; }; -export const GridInner = (props: GridInnerProps) => { - return {props.children}; +export const GridInner = ({ className, ...props }: GridInnerProps) => { + return ( +
+ {props.children} +
+ ); }; GridInner.displayName = "GridInner"; +export type GridProps = RmwcGridProps & { + className?: string; + style?: CSSProperties; +}; + /** * Use Grid component to display a list of choices, once the handler is triggered. */ export const Grid = (props: GridProps) => { - return {props.children}; + const { children, style, className } = props; + + return ( + + {children as React.ReactElement} + + ); }; diff --git a/yarn.lock b/yarn.lock index 95cf46c1abc..68c4cb20fe0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2414,20 +2414,7 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.23.0": - version: 7.26.2 - resolution: "@babel/generator@npm:7.26.2" - dependencies: - "@babel/parser": ^7.26.2 - "@babel/types": ^7.26.0 - "@jridgewell/gen-mapping": ^0.3.5 - "@jridgewell/trace-mapping": ^0.3.25 - jsesc: ^3.0.2 - checksum: 6ff850b7d6082619f8c2f518d993cf7254cfbaa20b026282cbef5c9b2197686d076a432b18e36c4d1a42721c016df4f77a8f62c67600775d9683621d534b91b4 - languageName: node - linkType: hard - -"@babel/generator@npm:^7.25.9, @babel/generator@npm:^7.26.0": +"@babel/generator@npm:^7.23.0, @babel/generator@npm:^7.25.9, @babel/generator@npm:^7.26.0": version: 7.26.2 resolution: "@babel/generator@npm:7.26.2" dependencies: