From 5f0dbf37dc65af4ad668520a1058f20e70c9f070 Mon Sep 17 00:00:00 2001 From: Joonas Tiala Date: Fri, 26 Jan 2024 00:12:02 +0200 Subject: [PATCH] feat: add Storybook utils --- apps/docs/utils/ExampleGrid.tsx | 27 ++++++++ apps/docs/utils/ExampleItem.tsx | 36 ++++++++++ apps/docs/utils/ExampleStack.tsx | 37 ++++++++++ apps/docs/utils/ExampleTitle.tsx | 13 ++++ apps/docs/utils/SizeElement.tsx | 43 ++++++++++++ apps/docs/utils/decorators.tsx | 84 +++++++++++++++++++++++ apps/docs/utils/index.ts | 6 ++ packages/typescript-config/storybook.json | 3 +- 8 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 apps/docs/utils/ExampleGrid.tsx create mode 100644 apps/docs/utils/ExampleItem.tsx create mode 100644 apps/docs/utils/ExampleStack.tsx create mode 100644 apps/docs/utils/ExampleTitle.tsx create mode 100644 apps/docs/utils/SizeElement.tsx create mode 100644 apps/docs/utils/decorators.tsx create mode 100644 apps/docs/utils/index.ts diff --git a/apps/docs/utils/ExampleGrid.tsx b/apps/docs/utils/ExampleGrid.tsx new file mode 100644 index 0000000..fcc6341 --- /dev/null +++ b/apps/docs/utils/ExampleGrid.tsx @@ -0,0 +1,27 @@ +import { ReactNode } from "react"; + +export function ExampleGrid({ + columns, + gap = 32, + centered, + children, +}: { + columns: number; + gap?: number; + centered?: boolean; + children: ReactNode; +}) { + return ( +
+ {children} +
+ ); +} diff --git a/apps/docs/utils/ExampleItem.tsx b/apps/docs/utils/ExampleItem.tsx new file mode 100644 index 0000000..74237d6 --- /dev/null +++ b/apps/docs/utils/ExampleItem.tsx @@ -0,0 +1,36 @@ +import { ReactNode } from "react"; +import { ExampleTitle } from "./ExampleTitle"; + +export function ExampleItem({ + title, + direction = "vertical", + centered, + children, +}: { + title: string; + direction?: "vertical" | "horizontal" | "vertical-reverse"; + centered?: boolean; + children: ReactNode; +}) { + return ( +
+ {`${title}${ + direction === "horizontal" ? ":" : "" + }`} + + {children} +
+ ); +} diff --git a/apps/docs/utils/ExampleStack.tsx b/apps/docs/utils/ExampleStack.tsx new file mode 100644 index 0000000..3735551 --- /dev/null +++ b/apps/docs/utils/ExampleStack.tsx @@ -0,0 +1,37 @@ +import { ReactNode } from "react"; +import { SizeElement } from "./SizeElement"; + +export function ExampleStack({ + gap = 32, + children, +}: { + gap?: number; + children?: ReactNode; +}) { + return ( +
+ {children} +
+ ); +} + +function getDefaultElement(elementNumber: number = 0) { + return ; +} + +export function getStackedElements( + numberOfElements: number, + getElement: (elementNumber: number) => JSX.Element = getDefaultElement, +) { + return ( + + {[...Array(numberOfElements).keys()].map((n) => getElement(n))} + + ); +} diff --git a/apps/docs/utils/ExampleTitle.tsx b/apps/docs/utils/ExampleTitle.tsx new file mode 100644 index 0000000..131e3eb --- /dev/null +++ b/apps/docs/utils/ExampleTitle.tsx @@ -0,0 +1,13 @@ +import { ReactNode } from "react"; + +export function ExampleTitle({ children }: { children: ReactNode }) { + return ( + + {children} + + ); +} diff --git a/apps/docs/utils/SizeElement.tsx b/apps/docs/utils/SizeElement.tsx new file mode 100644 index 0000000..8cd9cf6 --- /dev/null +++ b/apps/docs/utils/SizeElement.tsx @@ -0,0 +1,43 @@ +import { CSSProperties, useEffect, useRef, useState } from "react"; + +export function SizeElement({ styles }: { styles?: CSSProperties }) { + const ref = useRef(null); + + const [size, setSize] = useState({ + width: 0, + height: 0, + }); + + useEffect(() => { + const handleResize = () => { + if (ref && "current" in ref && ref.current) { + const { clientWidth: width, clientHeight: height } = ref.current; + setSize({ width, height }); + } + }; + + handleResize(); + + window.addEventListener("resize", handleResize); + + return () => { + window.removeEventListener("resize", handleResize); + }; + }, [ref]); + + return ( +
+ + {size.width}x{size.height} + +
+ ); +} diff --git a/apps/docs/utils/decorators.tsx b/apps/docs/utils/decorators.tsx new file mode 100644 index 0000000..5289477 --- /dev/null +++ b/apps/docs/utils/decorators.tsx @@ -0,0 +1,84 @@ +import { Decorator } from "@storybook/react"; +import { useEffect, useState } from "react"; + +export const marginDecorator: ( + margin: + | { + top?: string; + left?: string; + bottom?: string; + right?: string; + } + | string, +) => Decorator = (margin) => { + const decorator: Decorator = (Story) => ( +
+ +
+ ); + + return decorator; +}; + +export const viewportSizeDecorator: () => Decorator = () => { + const Decorator: Decorator = (Story) => { + const [size, setSize] = useState({ + width: window.innerWidth, + height: window.innerHeight, + }); + + useEffect(() => { + const handleResize = () => { + setSize({ width: window.innerWidth, height: window.innerHeight }); + }; + + window.addEventListener("resize", handleResize); + + return () => { + window.removeEventListener("resize", handleResize); + }; + }, []); + + // These values should match the ones in `breakpoints.css` + const viewport = + size.width < 640 + ? "xs" + : size.width < 768 + ? "sm" + : size.width < 1024 + ? "md" + : size.width < 1280 + ? "lg" + : size.width < 1536 + ? "xl" + : "xxl"; + + return ( +
+ + viewport: {viewport} ({size.width}x{size.height}) + + +
+ ); + }; + + return Decorator; +}; diff --git a/apps/docs/utils/index.ts b/apps/docs/utils/index.ts new file mode 100644 index 0000000..f65f19f --- /dev/null +++ b/apps/docs/utils/index.ts @@ -0,0 +1,6 @@ +export * from "./ExampleGrid"; +export * from "./ExampleItem"; +export * from "./ExampleStack"; +export * from "./ExampleTitle"; +export * from "./SizeElement"; +export * from "./decorators"; diff --git a/packages/typescript-config/storybook.json b/packages/typescript-config/storybook.json index 4ce4b13..ab79f8e 100644 --- a/packages/typescript-config/storybook.json +++ b/packages/typescript-config/storybook.json @@ -3,6 +3,7 @@ "extends": "./base.json", "compilerOptions": { "jsx": "react-jsx", - "noEmit": true + "noEmit": true, + "target": "ESNext" } }