Skip to content

Commit

Permalink
feat: create Grid / Column components (#4252)
Browse files Browse the repository at this point in the history
  • Loading branch information
adrians5j authored Nov 21, 2024
1 parent aa01bc1 commit cafeb1d
Show file tree
Hide file tree
Showing 12 changed files with 248 additions and 40 deletions.
1 change: 0 additions & 1 deletion packages/admin-ui/src/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ const meta: Meta<typeof Button> = {
export default meta;
type Story = StoryObj<typeof Button>;

// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Primary: Story = {
args: {
variant: "primary",
Expand Down
3 changes: 0 additions & 3 deletions packages/admin-ui/src/Card/Card.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof Card> = {
title: "Components/Card",
component: Card,
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
tags: ["autodocs"]
};

Expand All @@ -21,7 +19,6 @@ const defaultContentProps = {
footer: <CardFooter content={"This is card footer. Anything can go in here."} />
};

// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Default: Story = {
args: {
...defaultContentProps,
Expand Down
89 changes: 89 additions & 0 deletions packages/admin-ui/src/Grid/Grid.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";

import { Grid } from "./Grid";

const meta: Meta<typeof Grid> = {
title: "Components/Grid",
component: Grid,
tags: ["autodocs"]
};

export default meta;

type Story = StoryObj<typeof Grid>;

const StyledColumn = ({ ...props }) => (
<Grid.Column className="bg-primary text-neutral-light p-2 text-md rounded-sm" {...props} />
);

export const Default: Story = {
args: {
className: "bg-neutral-light p-4",
children: (
<>
<StyledColumn>Col 1</StyledColumn>
<StyledColumn span={3}>
Col 2 (<code>span: 3</code>)
</StyledColumn>
<StyledColumn>Col 3</StyledColumn>
<StyledColumn>Col 4</StyledColumn>
<StyledColumn>Col 5</StyledColumn>
<StyledColumn>Col 6</StyledColumn>
<StyledColumn span={2}>
Col 7 (<code>span: 2</code>)
</StyledColumn>
<StyledColumn>Col 8</StyledColumn>
<StyledColumn>Col 9</StyledColumn>
</>
)
}
};

export const SpaciousGap: Story = {
args: {
...Default.args,
gap: "spacious"
}
};

export const WithOffset: Story = {
parameters: {
layout: "padded"
},
decorators: [
Story => (
<div className="w-full">
<Story />
</div>
)
],
args: {
...Default.args,
children: (
<>
{/* Row 1 */}
<StyledColumn span={8} offset={2}>
Col (<code>span: 8</code>, <code>offset: 2</code>)
</StyledColumn>
<Grid.Column span={2} />

{/* Row 2 */}
<StyledColumn span={8} offset={4}>
Col (<code>span: 8</code>, <code>offset: 4</code>)
</StyledColumn>

{/* Row 3 */}
<StyledColumn span={10} offset={1}>
Col (<code>span: 10</code>, <code>offset: 1</code>)
</StyledColumn>
<Grid.Column span={1} />

{/* Row 4 */}
<StyledColumn span={12}>
Col (<code>span: 12</code>)
</StyledColumn>
</>
)
}
};
111 changes: 111 additions & 0 deletions packages/admin-ui/src/Grid/Grid.tsx
Original file line number Diff line number Diff line change
@@ -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<HTMLDivElement>,
VariantProps<typeof columnVariants> {
children?: React.ReactNode;
}

const ColumnBase = React.forwardRef<HTMLDivElement, ColumnProps>(
({ span, align, children, className, offset, ...props }, ref) => {
return (
<div
{...props}
className={cn(columnVariants({ span, offset, align, className }))}
ref={ref}
>
{children}
</div>
);
}
);

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<HTMLDivElement>,
VariantProps<typeof gridVariants> {
children:
| React.ReactElement<ColumnProps, typeof Column>
| Array<React.ReactElement<ColumnProps, typeof Column>>;
}

const GridBase = React.forwardRef<HTMLDivElement, GridProps>(
({ gap, children, className, ...props }, ref) => {
return (
<div
{...props}
className={cn("grid-cols-12", gridVariants({ gap }), className)}
ref={ref}
>
{children}
</div>
);
}
);

GridBase.displayName = "Grid";

const DecoratableGrid = makeDecoratable("Grid", GridBase);

const Grid = withStaticProps(DecoratableGrid, { Column });

export { Grid, type GridProps, type ColumnProps };
1 change: 1 addition & 0 deletions packages/admin-ui/src/Grid/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./Grid";
2 changes: 1 addition & 1 deletion packages/admin-ui/src/Heading/Heading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const TAG_MAP: Record<HeadingLevels, HeadingTags> = {
6: "h6"
};

const headingVariants = cva("font-sans font-semibold", {
const headingVariants = cva("font-sans", {
variants: {
level: {
1: "text-h1",
Expand Down
2 changes: 0 additions & 2 deletions packages/admin-ui/src/Icon/Icon.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof Icon> = {
title: "Components/Icon",
component: Icon,
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
tags: ["autodocs"]
};

Expand Down
2 changes: 1 addition & 1 deletion packages/admin-ui/src/Text/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
1 change: 1 addition & 0 deletions packages/admin-ui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
9 changes: 7 additions & 2 deletions packages/ui/src/Elevation/Elevation.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from "react";
import cn from "classnames";

export type ElevationProps = {
// Any element that needs to be highlighted.
Expand All @@ -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 <div className={"bg-white shadow-md p-4"}>{props.children}</div>;
const Elevation = ({ className, ...props }: ElevationProps) => {
return (
<div {...props} className={cn("bg-white shadow-md p-4", className)}>
{props.children}
</div>
);
};

Elevation.displayName = "Elevation";
Expand Down
52 changes: 36 additions & 16 deletions packages/ui/src/Grid/Grid.tsx
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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 <RmwcGridCell {...props}>{props.children}</RmwcGridCell>;
const { children, style, className, align } = props;
return (
<AdminUiGrid.Column
className={className}
style={style}
span={props.span as AdminUiColumnProps["span"]}
align={align}
>
{children}
</AdminUiGrid.Column>
);
};

export type GridInnerProps = {
Expand All @@ -40,15 +42,33 @@ export type GridInnerProps = {
className?: string;
};

export const GridInner = (props: GridInnerProps) => {
return <RmwcGridInner {...props}>{props.children}</RmwcGridInner>;
export const GridInner = ({ className, ...props }: GridInnerProps) => {
return (
<div
{...props}
className={cn("grid grid-cols-12 gap-6 m-0 flex flex-wrap items-stretch", className)}
>
{props.children}
</div>
);
};

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 <RmwcGrid {...props}>{props.children}</RmwcGrid>;
const { children, style, className } = props;

return (
<AdminUiGrid className={className} style={style}>
{children as React.ReactElement<AdminUiColumnProps, typeof AdminUiGrid.Column>}
</AdminUiGrid>
);
};
15 changes: 1 addition & 14 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down

0 comments on commit cafeb1d

Please sign in to comment.