Skip to content

Commit

Permalink
feat: add customProperties & group parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
lmestel committed Feb 28, 2024
1 parent d0792ea commit 70865ad
Show file tree
Hide file tree
Showing 12 changed files with 105 additions and 57 deletions.
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,14 @@ export default {
title: "Simple Component",
parameters: {
cssprops: {
"--color-primary": [
{
value: "#ff017d",
selector: ":root"
}
]
customProperties: {
"--color-primary": [
{
value: "#ff017d",
selector: ":root"
}
]
}
}
},
} as Meta;
Expand Down
4 changes: 2 additions & 2 deletions packages/examples/stories/Simple/Simple.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ import { CssPropsBlock } from "@kickstartds/storybook-addon-component-tokens";

<CssPropsBlock />

<Canvas of={SimpleStories.DefaultStory} />
<Canvas of={SimpleStories.DefaultGroup} />

<Canvas of={SimpleStories.SecondaryStory} />
<Canvas of={SimpleStories.FlatGroup} />
29 changes: 25 additions & 4 deletions packages/examples/stories/Simple/Simple.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Meta, StoryObj } from "@storybook/react";
import CustomDoc from "./Simple.mdx";
import "./style.css";

const cssprops = {
const customProperties = {
"--color-primary": [
{ value: "#ff017d", selector: ":root" },
{ value: "blue", selector: ":root", media: "(min-width: 960px)" },
Expand All @@ -15,15 +15,36 @@ const cssprops = {
export default {
title: "Simple Component/CSF",
parameters: {
cssprops,
cssprops: { customProperties },
docs: { page: CustomDoc },
},
component: (args) => <div className={args.className}>Hello world!</div>,
} as Meta;

export const DefaultStory: StoryObj = {
export const DefaultGroup: StoryObj = {
args: {
className: "foo",
},
};
export const SecondaryStory: StoryObj = {};
export const FlatGroup: StoryObj = {
parameters: {
cssprops: {
group({ name, media, selector }) {
return { label: `${name} @ ${selector}${media ? ` ${media}` : ""}` };
},
},
},
};
export const SubcategoryGroup: StoryObj = {
parameters: {
cssprops: {
group({ name, media, selector }) {
return {
label: media || "default",
category: selector,
subcategory: name,
};
},
},
},
};
4 changes: 2 additions & 2 deletions packages/examples/stories/Simple/Simple2.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import * as React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import "./style.css";

const cssprops = {
const customProperties = {
"--width": [{ value: "100%", selector: ":root" }],
};

export default {
title: "Simple Component/CSF 2",
parameters: {
cssprops,
cssprops: { customProperties },
},
component: () => <div>Lorem Ipsum</div>,
} as Meta;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
import { FC } from "react";
import { useOf, Of } from "@storybook/addon-docs";
import { FullExtractResult } from "custom-property-extract/dist/types";
import { PARAM_KEY, CssPropsParameter } from "../constants";
import { CssPropsTable } from "./CssPropsTable";
import { hasEntries } from "./utils";

interface CssPropsBlockProps {
of?: Of;
customProperties?: FullExtractResult;
}
type CssPropsBlockProps = CssPropsParameter & { of?: Of };

/**
* For use inside Storybook Docs and MDX
*/
export const CssPropsBlock: FC<CssPropsBlockProps> = (props) => {
let cssprops: FullExtractResult = {};

export const CssPropsBlock: FC<CssPropsBlockProps> = ({
of = "meta",
...cssprops
}) => {
try {
const resolvedOf = useOf(props.of || "meta");
const resolvedOf = useOf(of);
const { parameters = {} } =
resolvedOf.type === "meta"
? resolvedOf.csfFile.meta
Expand All @@ -25,12 +23,13 @@ export const CssPropsBlock: FC<CssPropsBlockProps> = (props) => {
: resolvedOf.type === "component"
? resolvedOf.projectAnnotations
: {};
cssprops = { ...parameters.cssprops };
} catch (error) {}

cssprops = props.customProperties || cssprops;
if (parameters[PARAM_KEY]) {
cssprops = parameters[PARAM_KEY];
}
} catch (error) {}

return hasEntries(cssprops) ? (
<CssPropsTable customProperties={cssprops} inAddonPanel={false} />
return hasEntries(cssprops.customProperties) ? (
<CssPropsTable {...cssprops} inAddonPanel={false} />
) : null;
};
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { FC } from "react";
import { FullExtractResult } from "custom-property-extract/dist/types";
import { useParameter } from "@storybook/api";
import { CssPropsParameter, PARAM_KEY } from "../constants";
import { CssPropsTable } from "./CssPropsTable";
import { NoCustomPropertiesWarning } from "./NoCustomPropertiesWarning";
import { useParameter } from "@storybook/api";
import { PARAM_KEY } from "../constants";
import { hasEntries } from "./utils";

/**
* Used by the Storybook Addons Panel
*/
export const CssPropsPanel: FC = () => {
const cssprops = useParameter<FullExtractResult>(PARAM_KEY, {});
const cssprops = useParameter<CssPropsParameter>(PARAM_KEY, {
customProperties: {},
});

return hasEntries(cssprops) ? (
<CssPropsTable customProperties={cssprops} inAddonPanel={true} />
return hasEntries(cssprops.customProperties) ? (
<CssPropsTable {...cssprops} inAddonPanel={true} />
) : (
<NoCustomPropertiesWarning />
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { FC, useMemo, useState } from "react";
import { FullExtractResult } from "custom-property-extract/dist/types";
import { components, Placeholder } from "@storybook/components";
import { PureArgsTable } from "@storybook/blocks";
import { ArgTypes, Args } from "@storybook/types";
import { isValidColor } from "./utils";
import { CssPropsParameter } from "../constants";
import { isValidColor, groupBySelector } from "./utils";
import {
resetStorage,
updateStorage,
Expand All @@ -13,37 +13,36 @@ import { useInjectStyle } from "./useInjectStyle";

const ResetWrapper = components.resetwrapper;

interface CssPropsTableProps {
customProperties: FullExtractResult;
inAddonPanel?: boolean;
}
type CssPropsTableProps = CssPropsParameter & { inAddonPanel?: boolean };

export const CssPropsTable: FC<CssPropsTableProps> = ({
customProperties = {},
group = groupBySelector,
inAddonPanel,
}) => {
const customPropertiesJSON = JSON.stringify(customProperties);
const { rows, initialArgs, argsKeys } = useMemo(
() =>
Object.entries(customProperties).reduce(
(prev, [key, values]) => {
(prev, [name, values]) => {
values.forEach((item) => {
if (!item.selector) return;
const argKey = `${item.selector.trim()}/${key.trim()}${
const argKey = `${item.selector.trim()}/${name.trim()}${
item.media ? `/${item.media}` : ""
}`;
prev.argsKeys.push(argKey);

const { label, ...table } = group({ name, ...item });
prev.rows[argKey] = {
control: { type: isValidColor(item.value) ? "color" : "text" },
defaultValue: item.value,
name: `${key}${item.media ? ` @ ${item.media}` : ""}`,
table: {
category: item.selector,
},
name: label,
table,
description: item.name,
key: argKey,
type: { name: "string" },
};

prev.initialArgs[argKey] = item.value;
});
return prev;
Expand All @@ -54,7 +53,7 @@ export const CssPropsTable: FC<CssPropsTableProps> = ({
argsKeys: [] as string[],
},
),
[customPropertiesJSON],
[customPropertiesJSON, group],
);

const [prevProps, setPrevProps] = useState(customPropertiesJSON);
Expand Down
15 changes: 13 additions & 2 deletions packages/storybook-addon-component-tokens/src/components/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { useRef, useEffect } from "react";
import { FullCustomPropertyValue } from "custom-property-extract/dist/types";
import { Group } from "../constants";

export const hasEntries = (customProperties: { [key: string]: any }) =>
!!Object.keys(customProperties).length;
export const hasEntries = (customProperties?: { [key: string]: any }) =>
!!(customProperties && Object.keys(customProperties).length);

// https://www.regextester.com/103656
const colorRe =
Expand Down Expand Up @@ -34,3 +36,12 @@ export const useDocument = () => {
}, []);
return docRef;
};

export const groupBySelector: Group = ({
name,
media,
selector,
}: FullCustomPropertyValue) => ({
label: `${name}${media ? ` @ ${media}` : ""}`,
category: selector,
});
14 changes: 14 additions & 0 deletions packages/storybook-addon-component-tokens/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,16 @@
import {
FullCustomPropertyValue,
FullExtractResult,
} from "custom-property-extract/dist/types";

export const PARAM_KEY = "cssprops" as const;
export const ADDON_ID = "addon-component-tokens" as const;
export type Group = (customProperty: FullCustomPropertyValue) => {
label: string;
category?: string;
subcategory?: string;
};
export type CssPropsParameter = {
customProperties?: FullExtractResult;
group?: Group;
};
2 changes: 2 additions & 0 deletions packages/storybook-addon-component-tokens/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export { CssPropsBlock } from "./components/CssPropsBlock";
export { groupBySelector } from "./components/utils";
export type { CssPropsParameter } from "./constants";

if (module && module.hot && module.hot.decline) {
module.hot.decline();
Expand Down
4 changes: 2 additions & 2 deletions packages/storybook-addon-component-tokens/src/register.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ addons.register(ADDON_ID, (api: API) => {
title: getTitle,
type: types.PANEL,
paramKey: PARAM_KEY,
render: ({ key, active }) => (
<AddonPanel key={key} active={!!active}>
render: ({ active }) => (
<AddonPanel active={!!active}>
<CssPropsPanel />
</AddonPanel>
),
Expand Down
11 changes: 5 additions & 6 deletions packages/storybook-addon-component-tokens/src/title.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { useParameter } from "@storybook/api";
import { PARAM_KEY } from "./constants";
import { FullExtractResult } from "custom-property-extract/dist/types";
import { CssPropsParameter, PARAM_KEY } from "./constants";

export function getTitle(): string {
const cssprops = useParameter<FullExtractResult>(PARAM_KEY, {});
const controlsCount = Object.values(cssprops).filter(
(cssprop) => cssprop.length,
).length;
const { customProperties = {} } = useParameter<CssPropsParameter>(PARAM_KEY, {
customProperties: {},
});
const controlsCount = Object.values(customProperties).flat().length;
const suffix = controlsCount === 0 ? "" : ` (${controlsCount})`;
return `Component Tokens${suffix}`;
}

0 comments on commit 70865ad

Please sign in to comment.