diff --git a/README.md b/README.md
index d402661b..bdf8093b 100644
--- a/README.md
+++ b/README.md
@@ -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;
diff --git a/packages/examples/stories/Simple/Simple.mdx b/packages/examples/stories/Simple/Simple.mdx
index f0d20ffc..83fe9160 100644
--- a/packages/examples/stories/Simple/Simple.mdx
+++ b/packages/examples/stories/Simple/Simple.mdx
@@ -16,6 +16,6 @@ import { CssPropsBlock } from "@kickstartds/storybook-addon-component-tokens";
-
+
-
+
diff --git a/packages/examples/stories/Simple/Simple.stories.tsx b/packages/examples/stories/Simple/Simple.stories.tsx
index 0fa0e6f2..d7b2f755 100644
--- a/packages/examples/stories/Simple/Simple.stories.tsx
+++ b/packages/examples/stories/Simple/Simple.stories.tsx
@@ -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)" },
@@ -15,15 +15,36 @@ const cssprops = {
export default {
title: "Simple Component/CSF",
parameters: {
- cssprops,
+ cssprops: { customProperties },
docs: { page: CustomDoc },
},
component: (args) =>
Hello world!
,
} 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,
+ };
+ },
+ },
+ },
+};
diff --git a/packages/examples/stories/Simple/Simple2.stories.tsx b/packages/examples/stories/Simple/Simple2.stories.tsx
index a9ef5aa7..6543c72e 100644
--- a/packages/examples/stories/Simple/Simple2.stories.tsx
+++ b/packages/examples/stories/Simple/Simple2.stories.tsx
@@ -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: () => Lorem Ipsum
,
} as Meta;
diff --git a/packages/storybook-addon-component-tokens/src/components/CssPropsBlock.tsx b/packages/storybook-addon-component-tokens/src/components/CssPropsBlock.tsx
index 0230434d..a8c78712 100644
--- a/packages/storybook-addon-component-tokens/src/components/CssPropsBlock.tsx
+++ b/packages/storybook-addon-component-tokens/src/components/CssPropsBlock.tsx
@@ -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 = (props) => {
- let cssprops: FullExtractResult = {};
-
+export const CssPropsBlock: FC = ({
+ of = "meta",
+ ...cssprops
+}) => {
try {
- const resolvedOf = useOf(props.of || "meta");
+ const resolvedOf = useOf(of);
const { parameters = {} } =
resolvedOf.type === "meta"
? resolvedOf.csfFile.meta
@@ -25,12 +23,13 @@ export const CssPropsBlock: FC = (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) ? (
-
+ return hasEntries(cssprops.customProperties) ? (
+
) : null;
};
diff --git a/packages/storybook-addon-component-tokens/src/components/CssPropsPanel.tsx b/packages/storybook-addon-component-tokens/src/components/CssPropsPanel.tsx
index 4029eb78..d39a90af 100644
--- a/packages/storybook-addon-component-tokens/src/components/CssPropsPanel.tsx
+++ b/packages/storybook-addon-component-tokens/src/components/CssPropsPanel.tsx
@@ -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(PARAM_KEY, {});
+ const cssprops = useParameter(PARAM_KEY, {
+ customProperties: {},
+ });
- return hasEntries(cssprops) ? (
-
+ return hasEntries(cssprops.customProperties) ? (
+
) : (
);
diff --git a/packages/storybook-addon-component-tokens/src/components/CssPropsTable.tsx b/packages/storybook-addon-component-tokens/src/components/CssPropsTable.tsx
index bd1c0f39..fd536e12 100644
--- a/packages/storybook-addon-component-tokens/src/components/CssPropsTable.tsx
+++ b/packages/storybook-addon-component-tokens/src/components/CssPropsTable.tsx
@@ -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,
@@ -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 = ({
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;
@@ -54,7 +53,7 @@ export const CssPropsTable: FC = ({
argsKeys: [] as string[],
},
),
- [customPropertiesJSON],
+ [customPropertiesJSON, group],
);
const [prevProps, setPrevProps] = useState(customPropertiesJSON);
diff --git a/packages/storybook-addon-component-tokens/src/components/utils.ts b/packages/storybook-addon-component-tokens/src/components/utils.ts
index dc555e04..78e9fcc9 100644
--- a/packages/storybook-addon-component-tokens/src/components/utils.ts
+++ b/packages/storybook-addon-component-tokens/src/components/utils.ts
@@ -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 =
@@ -34,3 +36,12 @@ export const useDocument = () => {
}, []);
return docRef;
};
+
+export const groupBySelector: Group = ({
+ name,
+ media,
+ selector,
+}: FullCustomPropertyValue) => ({
+ label: `${name}${media ? ` @ ${media}` : ""}`,
+ category: selector,
+});
diff --git a/packages/storybook-addon-component-tokens/src/constants.ts b/packages/storybook-addon-component-tokens/src/constants.ts
index 054677d7..c316a787 100644
--- a/packages/storybook-addon-component-tokens/src/constants.ts
+++ b/packages/storybook-addon-component-tokens/src/constants.ts
@@ -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;
+};
diff --git a/packages/storybook-addon-component-tokens/src/index.ts b/packages/storybook-addon-component-tokens/src/index.ts
index f73a7189..8d747cc9 100644
--- a/packages/storybook-addon-component-tokens/src/index.ts
+++ b/packages/storybook-addon-component-tokens/src/index.ts
@@ -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();
diff --git a/packages/storybook-addon-component-tokens/src/register.tsx b/packages/storybook-addon-component-tokens/src/register.tsx
index 2473ffd5..60efba85 100644
--- a/packages/storybook-addon-component-tokens/src/register.tsx
+++ b/packages/storybook-addon-component-tokens/src/register.tsx
@@ -10,8 +10,8 @@ addons.register(ADDON_ID, (api: API) => {
title: getTitle,
type: types.PANEL,
paramKey: PARAM_KEY,
- render: ({ key, active }) => (
-
+ render: ({ active }) => (
+
),
diff --git a/packages/storybook-addon-component-tokens/src/title.ts b/packages/storybook-addon-component-tokens/src/title.ts
index a15cd3e6..3017f625 100644
--- a/packages/storybook-addon-component-tokens/src/title.ts
+++ b/packages/storybook-addon-component-tokens/src/title.ts
@@ -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(PARAM_KEY, {});
- const controlsCount = Object.values(cssprops).filter(
- (cssprop) => cssprop.length,
- ).length;
+ const { customProperties = {} } = useParameter(PARAM_KEY, {
+ customProperties: {},
+ });
+ const controlsCount = Object.values(customProperties).flat().length;
const suffix = controlsCount === 0 ? "" : ` (${controlsCount})`;
return `Component Tokens${suffix}`;
}