Skip to content

Commit dcadb62

Browse files
authored
Add createStyleContext helper (#40)
* feat: add context providers and update component structures / recipes * fix: update Modal exports * ci(changesets): add appropriate changesets
1 parent d1972e3 commit dcadb62

File tree

12 files changed

+317
-241
lines changed

12 files changed

+317
-241
lines changed

.changeset/cuddly-gorillas-study.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@hobbescodes/tigris-ui": minor
3+
---
4+
5+
Update components to use `colorPalette` to allow for virtual color overrides

.changeset/kind-balloons-shave.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@hobbescodes/tigris-ui": patch
3+
---
4+
5+
Use `createStyleContext` helper to structure components

src/components/Button/Button.stories.tsx

+42-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useState } from "react";
22

33
import { buttonState } from "./Button.spec";
44
import { Button } from "components";
5+
import { Flex } from "generated/panda/jsx";
56

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

@@ -23,11 +24,6 @@ export const Example: Story = {
2324
control: { type: "radio" },
2425
defaultValue: { summary: "md" },
2526
},
26-
colorScheme: {
27-
options: ["primary", "secondary", "tertiary"],
28-
control: { type: "radio" },
29-
defaultValue: { summary: "primary" },
30-
},
3127
variant: {
3228
options: ["primary", "outline", "ghost", "rounded"],
3329
control: { type: "radio" },
@@ -37,6 +33,47 @@ export const Example: Story = {
3733
name: "Button",
3834
};
3935

36+
export const Brand: Story = {
37+
render: () => (
38+
<Flex direction="column" gap={2}>
39+
<Flex gap={1}>
40+
<Button variant="primary">Primary</Button>
41+
<Button variant="outline">Outline</Button>
42+
<Button variant="ghost">Ghost</Button>
43+
<Button variant="rounded">Rounded</Button>
44+
</Flex>
45+
<Flex gap={1}>
46+
<Button colorPalette="brand.secondary" variant="primary">
47+
Primary
48+
</Button>
49+
<Button colorPalette="brand.secondary" variant="outline">
50+
Outline
51+
</Button>
52+
<Button colorPalette="brand.secondary" variant="ghost">
53+
Ghost
54+
</Button>
55+
<Button colorPalette="brand.secondary" variant="rounded">
56+
Rounded
57+
</Button>
58+
</Flex>
59+
<Flex gap={1}>
60+
<Button colorPalette="brand.tertiary" variant="primary">
61+
Primary
62+
</Button>
63+
<Button colorPalette="brand.tertiary" variant="outline">
64+
Outline
65+
</Button>
66+
<Button colorPalette="brand.tertiary" variant="ghost">
67+
Ghost
68+
</Button>
69+
<Button colorPalette="brand.tertiary" variant="rounded">
70+
Rounded
71+
</Button>
72+
</Flex>
73+
</Flex>
74+
),
75+
};
76+
4077
export const ButtonState: Story = {
4178
render: () => <ButtonTest />,
4279
play: buttonState,

src/components/Drawer/Drawer.tsx

+85-75
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,62 @@
1-
import {
2-
ark,
3-
Dialog,
4-
DialogBackdrop,
5-
DialogCloseTrigger,
6-
DialogContent,
7-
DialogDescription,
8-
DialogPositioner,
9-
DialogTitle,
10-
DialogTrigger,
11-
} from "@ark-ui/react";
1+
import { ark, Dialog as ArkDialog } from "@ark-ui/react";
122
import { FiX as CloseIcon } from "react-icons/fi";
133

144
import Icon from "components/Icon/Icon";
155
import { Flex, panda } from "generated/panda/jsx";
166
import { drawer } from "generated/panda/recipes";
17-
import { getContextualChildren } from "lib/util";
7+
import { createStyleContext, getContextualChildren } from "lib/util";
188

199
import type { DialogProps } from "@ark-ui/react";
2010
import type { DialogContext } from "@ark-ui/react/dialog/dialog-context";
2111
import type { DrawerVariantProps } from "generated/panda/recipes";
22-
import type { ReactNode } from "react";
12+
import type { ComponentPropsWithoutRef, ReactNode } from "react";
13+
14+
const { withProvider, withContext } = createStyleContext(drawer);
2315

2416
export interface DrawerProps extends DialogProps, DrawerVariantProps {
2517
trigger?: ReactNode;
2618
title?: string;
2719
description?: string;
2820
headerAddon?: ReactNode;
2921
footer?: ReactNode | ((props: DialogContext) => ReactNode);
22+
/** Drawer content (body) container props. */
23+
contentProps?: ComponentPropsWithoutRef<typeof DrawerContent>;
3024
}
3125

26+
export const DrawerRoot = withProvider(panda(ArkDialog.Root), "root");
27+
28+
export const DrawerTrigger = withContext(panda(ArkDialog.Trigger), "trigger");
29+
30+
export const DrawerBackdrop = withContext(
31+
panda(ArkDialog.Backdrop),
32+
"backdrop"
33+
);
34+
35+
export const DrawerCloseTrigger = withContext(
36+
panda(ArkDialog.CloseTrigger),
37+
"closeTrigger"
38+
);
39+
40+
export const DrawerPositioner = withContext(
41+
panda(ArkDialog.Positioner),
42+
"positioner"
43+
);
44+
45+
export const DrawerContent = withContext(panda(ArkDialog.Content), "content");
46+
47+
export const DrawerTitle = withContext(panda(ArkDialog.Title), "title");
48+
49+
export const DrawerDescription = withContext(
50+
panda(ArkDialog.Description),
51+
"description"
52+
);
53+
54+
export const DrawerHeader = withContext(panda(ark.div), "header");
55+
56+
export const DrawerBody = withContext(panda(ark.div), "body");
57+
58+
export const DrawerFooter = withContext(panda(ark.div), "footer");
59+
3260
/**
3361
* A panel that slides in from the edge of the screen.
3462
*/
@@ -38,69 +66,51 @@ const Drawer = ({
3866
description,
3967
headerAddon,
4068
footer,
69+
contentProps,
4170
children,
42-
alignment,
43-
placement,
4471
...rest
45-
}: DrawerProps) => {
46-
const classes = drawer({ alignment, placement });
47-
48-
const PandaContainer = panda(ark.div);
49-
50-
return (
51-
<Dialog lazyMount unmountOnExit {...rest}>
52-
{(ctx) => (
53-
<>
54-
{trigger && (
55-
<DialogTrigger className={classes.trigger} asChild>
56-
{trigger}
57-
</DialogTrigger>
58-
)}
59-
60-
<DialogBackdrop className={classes.backdrop} />
61-
62-
<DialogPositioner className={classes.positioner}>
63-
<DialogContent className={classes.content}>
64-
<PandaContainer className={classes.header}>
65-
{headerAddon && headerAddon}
66-
67-
<Flex direction="column" gap={1}>
68-
{title && (
69-
<DialogTitle className={classes.title}>{title}</DialogTitle>
70-
)}
71-
72-
{description && (
73-
<DialogDescription className={classes.description}>
74-
{description}
75-
</DialogDescription>
76-
)}
77-
</Flex>
78-
79-
<DialogCloseTrigger
80-
aria-label="close button"
81-
className={classes.closeTrigger}
82-
>
83-
<Icon color="fg.primary">
84-
<CloseIcon />
85-
</Icon>
86-
</DialogCloseTrigger>
87-
</PandaContainer>
88-
89-
<PandaContainer className={classes.body} asChild>
90-
{getContextualChildren({ ctx, children })}
91-
</PandaContainer>
92-
93-
{footer && (
94-
<PandaContainer className={classes.footer} asChild>
95-
{getContextualChildren({ ctx, children: footer })}
96-
</PandaContainer>
97-
)}
98-
</DialogContent>
99-
</DialogPositioner>
100-
</>
101-
)}
102-
</Dialog>
103-
);
104-
};
72+
}: DrawerProps) => (
73+
<DrawerRoot lazyMount unmountOnExit {...rest}>
74+
{(ctx) => (
75+
<>
76+
{trigger && <DrawerTrigger asChild>{trigger}</DrawerTrigger>}
77+
78+
<DrawerBackdrop />
79+
80+
<DrawerPositioner>
81+
<DrawerContent {...contentProps}>
82+
<DrawerHeader>
83+
{headerAddon && headerAddon}
84+
85+
<Flex direction="column" gap={1}>
86+
{title && <DrawerTitle>{title}</DrawerTitle>}
87+
88+
{description && (
89+
<DrawerDescription>{description}</DrawerDescription>
90+
)}
91+
</Flex>
92+
93+
<DrawerCloseTrigger aria-label="close button">
94+
<Icon color="fg.primary">
95+
<CloseIcon />
96+
</Icon>
97+
</DrawerCloseTrigger>
98+
</DrawerHeader>
99+
100+
<DrawerBody asChild>
101+
{getContextualChildren({ ctx, children })}
102+
</DrawerBody>
103+
104+
{footer && (
105+
<DrawerFooter asChild>
106+
{getContextualChildren({ ctx, children: footer })}
107+
</DrawerFooter>
108+
)}
109+
</DrawerContent>
110+
</DrawerPositioner>
111+
</>
112+
)}
113+
</DrawerRoot>
114+
);
105115

106116
export default Drawer;

src/components/Modal/Modal.stories.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { Meta, StoryObj } from "@storybook/react";
66

77
type Story = StoryObj<typeof Modal>;
88

9-
export const Default: Story = {
9+
export const Example: Story = {
1010
args: {
1111
trigger: <Button>Open Modal</Button>,
1212
title: "Modal Title",
@@ -23,7 +23,7 @@ export const Default: Story = {
2323

2424
export const WithContext: Story = {
2525
args: {
26-
...Default.args,
26+
...Example.args,
2727
children: ({ isOpen }) => (
2828
<panda.p mt={2} color="fg.primary">
2929
Open: {String(isOpen)}
@@ -33,7 +33,7 @@ export const WithContext: Story = {
3333
};
3434

3535
export const ModalState: Story = {
36-
...Default,
36+
...Example,
3737
play: modalState,
3838
name: "[TEST] Modal State",
3939
tags: ["test"],

0 commit comments

Comments
 (0)