Skip to content

Commit

Permalink
Add createStyleContext helper (#40)
Browse files Browse the repository at this point in the history
* feat: add context providers and update component structures / recipes

* fix: update Modal exports

* ci(changesets): add appropriate changesets
  • Loading branch information
hobbescodes authored Jan 1, 2024
1 parent d1972e3 commit dcadb62
Show file tree
Hide file tree
Showing 12 changed files with 317 additions and 241 deletions.
5 changes: 5 additions & 0 deletions .changeset/cuddly-gorillas-study.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hobbescodes/tigris-ui": minor
---

Update components to use `colorPalette` to allow for virtual color overrides
5 changes: 5 additions & 0 deletions .changeset/kind-balloons-shave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hobbescodes/tigris-ui": patch
---

Use `createStyleContext` helper to structure components
47 changes: 42 additions & 5 deletions src/components/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useState } from "react";

import { buttonState } from "./Button.spec";
import { Button } from "components";
import { Flex } from "generated/panda/jsx";

import type { Meta, StoryObj } from "@storybook/react";

Expand All @@ -23,11 +24,6 @@ export const Example: Story = {
control: { type: "radio" },
defaultValue: { summary: "md" },
},
colorScheme: {
options: ["primary", "secondary", "tertiary"],
control: { type: "radio" },
defaultValue: { summary: "primary" },
},
variant: {
options: ["primary", "outline", "ghost", "rounded"],
control: { type: "radio" },
Expand All @@ -37,6 +33,47 @@ export const Example: Story = {
name: "Button",
};

export const Brand: Story = {
render: () => (
<Flex direction="column" gap={2}>
<Flex gap={1}>
<Button variant="primary">Primary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="rounded">Rounded</Button>
</Flex>
<Flex gap={1}>
<Button colorPalette="brand.secondary" variant="primary">
Primary
</Button>
<Button colorPalette="brand.secondary" variant="outline">
Outline
</Button>
<Button colorPalette="brand.secondary" variant="ghost">
Ghost
</Button>
<Button colorPalette="brand.secondary" variant="rounded">
Rounded
</Button>
</Flex>
<Flex gap={1}>
<Button colorPalette="brand.tertiary" variant="primary">
Primary
</Button>
<Button colorPalette="brand.tertiary" variant="outline">
Outline
</Button>
<Button colorPalette="brand.tertiary" variant="ghost">
Ghost
</Button>
<Button colorPalette="brand.tertiary" variant="rounded">
Rounded
</Button>
</Flex>
</Flex>
),
};

export const ButtonState: Story = {
render: () => <ButtonTest />,
play: buttonState,
Expand Down
160 changes: 85 additions & 75 deletions src/components/Drawer/Drawer.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,62 @@
import {
ark,
Dialog,
DialogBackdrop,
DialogCloseTrigger,
DialogContent,
DialogDescription,
DialogPositioner,
DialogTitle,
DialogTrigger,
} from "@ark-ui/react";
import { ark, Dialog as ArkDialog } from "@ark-ui/react";
import { FiX as CloseIcon } from "react-icons/fi";

import Icon from "components/Icon/Icon";
import { Flex, panda } from "generated/panda/jsx";
import { drawer } from "generated/panda/recipes";
import { getContextualChildren } from "lib/util";
import { createStyleContext, getContextualChildren } from "lib/util";

import type { DialogProps } from "@ark-ui/react";
import type { DialogContext } from "@ark-ui/react/dialog/dialog-context";
import type { DrawerVariantProps } from "generated/panda/recipes";
import type { ReactNode } from "react";
import type { ComponentPropsWithoutRef, ReactNode } from "react";

const { withProvider, withContext } = createStyleContext(drawer);

export interface DrawerProps extends DialogProps, DrawerVariantProps {
trigger?: ReactNode;
title?: string;
description?: string;
headerAddon?: ReactNode;
footer?: ReactNode | ((props: DialogContext) => ReactNode);
/** Drawer content (body) container props. */
contentProps?: ComponentPropsWithoutRef<typeof DrawerContent>;
}

export const DrawerRoot = withProvider(panda(ArkDialog.Root), "root");

export const DrawerTrigger = withContext(panda(ArkDialog.Trigger), "trigger");

export const DrawerBackdrop = withContext(
panda(ArkDialog.Backdrop),
"backdrop"
);

export const DrawerCloseTrigger = withContext(
panda(ArkDialog.CloseTrigger),
"closeTrigger"
);

export const DrawerPositioner = withContext(
panda(ArkDialog.Positioner),
"positioner"
);

export const DrawerContent = withContext(panda(ArkDialog.Content), "content");

export const DrawerTitle = withContext(panda(ArkDialog.Title), "title");

export const DrawerDescription = withContext(
panda(ArkDialog.Description),
"description"
);

export const DrawerHeader = withContext(panda(ark.div), "header");

export const DrawerBody = withContext(panda(ark.div), "body");

export const DrawerFooter = withContext(panda(ark.div), "footer");

/**
* A panel that slides in from the edge of the screen.
*/
Expand All @@ -38,69 +66,51 @@ const Drawer = ({
description,
headerAddon,
footer,
contentProps,
children,
alignment,
placement,
...rest
}: DrawerProps) => {
const classes = drawer({ alignment, placement });

const PandaContainer = panda(ark.div);

return (
<Dialog lazyMount unmountOnExit {...rest}>
{(ctx) => (
<>
{trigger && (
<DialogTrigger className={classes.trigger} asChild>
{trigger}
</DialogTrigger>
)}

<DialogBackdrop className={classes.backdrop} />

<DialogPositioner className={classes.positioner}>
<DialogContent className={classes.content}>
<PandaContainer className={classes.header}>
{headerAddon && headerAddon}

<Flex direction="column" gap={1}>
{title && (
<DialogTitle className={classes.title}>{title}</DialogTitle>
)}

{description && (
<DialogDescription className={classes.description}>
{description}
</DialogDescription>
)}
</Flex>

<DialogCloseTrigger
aria-label="close button"
className={classes.closeTrigger}
>
<Icon color="fg.primary">
<CloseIcon />
</Icon>
</DialogCloseTrigger>
</PandaContainer>

<PandaContainer className={classes.body} asChild>
{getContextualChildren({ ctx, children })}
</PandaContainer>

{footer && (
<PandaContainer className={classes.footer} asChild>
{getContextualChildren({ ctx, children: footer })}
</PandaContainer>
)}
</DialogContent>
</DialogPositioner>
</>
)}
</Dialog>
);
};
}: DrawerProps) => (
<DrawerRoot lazyMount unmountOnExit {...rest}>
{(ctx) => (
<>
{trigger && <DrawerTrigger asChild>{trigger}</DrawerTrigger>}

<DrawerBackdrop />

<DrawerPositioner>
<DrawerContent {...contentProps}>
<DrawerHeader>
{headerAddon && headerAddon}

<Flex direction="column" gap={1}>
{title && <DrawerTitle>{title}</DrawerTitle>}

{description && (
<DrawerDescription>{description}</DrawerDescription>
)}
</Flex>

<DrawerCloseTrigger aria-label="close button">
<Icon color="fg.primary">
<CloseIcon />
</Icon>
</DrawerCloseTrigger>
</DrawerHeader>

<DrawerBody asChild>
{getContextualChildren({ ctx, children })}
</DrawerBody>

{footer && (
<DrawerFooter asChild>
{getContextualChildren({ ctx, children: footer })}
</DrawerFooter>
)}
</DrawerContent>
</DrawerPositioner>
</>
)}
</DrawerRoot>
);

export default Drawer;
6 changes: 3 additions & 3 deletions src/components/Modal/Modal.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { Meta, StoryObj } from "@storybook/react";

type Story = StoryObj<typeof Modal>;

export const Default: Story = {
export const Example: Story = {
args: {
trigger: <Button>Open Modal</Button>,
title: "Modal Title",
Expand All @@ -23,7 +23,7 @@ export const Default: Story = {

export const WithContext: Story = {
args: {
...Default.args,
...Example.args,
children: ({ isOpen }) => (
<panda.p mt={2} color="fg.primary">
Open: {String(isOpen)}
Expand All @@ -33,7 +33,7 @@ export const WithContext: Story = {
};

export const ModalState: Story = {
...Default,
...Example,
play: modalState,
name: "[TEST] Modal State",
tags: ["test"],
Expand Down
Loading

0 comments on commit dcadb62

Please sign in to comment.