Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ storybook-static
**/.DS_Store
vite.config.ts.timestamp*

# Generated TypeScript declaration files for SCSS modules
**/*.scss.d.ts
**/*.css.d.ts

.yarn/*
!.yarn/releases
!.yarn/plugins
29 changes: 21 additions & 8 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import type { StorybookConfig } from "@storybook/react-vite";
const config: StorybookConfig = {
core: {
disableTelemetry: true
disableTelemetry: true,
},
stories: [
"../src/Introduction.mdx",
"../src/components/icons/Icons.mdx",
"../src/**/*.stories.@(js|jsx|ts|tsx)",
],

addons: ["@storybook/addon-links", //"@storybook/addon-interactions",
"storybook-addon-pseudo-states", "@storybook/addon-a11y", "@storybook/addon-docs"],
addons: [
"@storybook/addon-links", //"@storybook/addon-interactions",
"storybook-addon-pseudo-states",
"@storybook/addon-a11y",
"@storybook/addon-docs",
],

framework: {
name: "@storybook/react-vite",
Expand All @@ -33,27 +37,36 @@ const config: StorybookConfig = {
},

async viteFinal(config, { configType }) {
if (config.css?.preprocessorOptions?.scss) {
config.css.preprocessorOptions.scss.api = "modern-compiler";
} else {
config.css = config.css || {};
config.css.preprocessorOptions = config.css.preprocessorOptions || {};
config.css.preprocessorOptions.scss = {
api: "modern-compiler",
};
}
// Workaround for Storybook 10.0.7 bug where MDX files generate file:// imports
// See: https://github.com/storybookjs/storybook/issues (mdx-react-shim resolution)
config.plugins = config.plugins || [];
config.plugins.push({
name: 'fix-storybook-mdx-shim',
name: "fix-storybook-mdx-shim",
resolveId(source) {
// Intercept the malformed file:// URL and resolve to the correct package
if (source.includes('mdx-react-shim')) {
return this.resolve('@mdx-js/react', undefined, { skipSelf: true });
if (source.includes("mdx-react-shim")) {
return this.resolve("@mdx-js/react", undefined, { skipSelf: true });
}
return null;
},
});

// Suppress Rollup warnings for production builds
if (configType === 'PRODUCTION') {
if (configType === "PRODUCTION") {
config.build = config.build || {};
config.build.rollupOptions = config.build.rollupOptions || {};
const originalOnWarn = config.build.rollupOptions.onwarn;
config.build.rollupOptions.onwarn = (warning, warn) => {
if (warning.message?.includes('mdx-react-shim')) return;
if (warning.message?.includes("mdx-react-shim")) return;
originalOnWarn ? originalOnWarn(warning, warn) : warn(warning);
};
}
Expand Down
21 changes: 21 additions & 0 deletions .storybook/preview.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.cuiThemeBlock {
position: absolute;
inset: 0.5rem 0 0 0; // top, right, bottom, left
height: fit-content;
overflow: auto;
padding: 1rem;
box-sizing: border-box;
background: var(--click-storybook-global-background);

&.cuiLeft {
left: 0;
}

&.cuiRight {
left: 50vw;
}

&.cuiFill {
left: 0;
}
}
89 changes: 59 additions & 30 deletions .storybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
import React from "react";
import type { Preview } from "@storybook/react-vite";
import "../src/styles/variables.css";
import "@/styles/cui-scss-theme.css";
import { Decorator } from "@storybook/react-vite";
import styled from "styled-components";
import { themes } from "storybook/theming";
import ClickUIProvider from "../src/theme/ClickUIProvider/ClickUIProvider";
import { ClickUIProvider } from "@/theme/ClickUIProvider";
import clsx from "clsx";
import styles from "./preview.module.scss";

const ThemeBlock = styled.div<{ $left?: boolean; $bfill?: boolean }>(
({ $left, $bfill: fill, theme }) => `
position: absolute;
top: 0.5rem;
left: ${$left || fill ? 0 : "50vw"};
right: 0;
height: fit-content;
bottom: 0;
overflow: auto;
padding: 1rem;
box-sizing: border-box;
background: ${theme.click.storybook.global.background};
`
interface ThemeBlockProps {
left?: boolean;
fill?: boolean;
children: React.ReactNode;
}

const ThemeBlock: React.FC<ThemeBlockProps & { theme?: string }> = ({
left,
fill,
theme = "light",
children
}) => (
<div
className={clsx(styles.cuiThemeBlock, {
[styles.cuiLeft]: left || fill,
[styles.cuiRight]: !left && !fill,
[styles.cuiFill]: fill,
})}
style={{
// Set color-scheme to make light-dark() CSS function work
colorScheme: theme,
}}
>
{children}
</div>
);

export const globalTypes = {
Expand All @@ -27,27 +40,30 @@ export const globalTypes = {
description: "Global theme for components",
defaultValue: "dark",
toolbar: {
// The icon for the toolbar item
icon: "circlehollow",
// Array of options
items: [
{ value: "dark", icon: "moon", title: "dark" },
{ value: "light", icon: "sun", title: "light" },
{ value: "light", icon: "sun", title: "Light" },
{ value: "dark", icon: "moon", title: "Dark" },
],
// Property that specifies if the name of the item will be displayed
showName: true,
dynamicTitle: true,
},
},
};
const withTheme: Decorator = (StoryFn, context) => {
const parameters = context.parameters;
const theme = parameters?.theme || context.globals.theme;
const theme = parameters?.theme || context.globals.theme || "light";

return (
<ClickUIProvider
theme={theme}
config={{ tooltip: { delayDuration: 0 } }}
key={`storybook-theme-${theme}`}
theme={theme as any}
config={{
tooltip: { delayDuration: 100 },
toast: { duration: 3000 },
}}
>
<ThemeBlock $left>
<ThemeBlock fill theme={theme}>
<StoryFn />
</ThemeBlock>
</ClickUIProvider>
Expand Down Expand Up @@ -82,12 +98,25 @@ const preview: Preview = {
},
docs: {
theme: themes.dark,
codePanel: true
codePanel: true,
},
backgrounds: {
default: "click-ui",
values: [
{
name: "click-ui",
value: "var(--click-storybook-global-background)",
},
{
name: "light",
value: "var(--click-storybook-global-background)",
},
{
name: "dark",
value: "var(--click-storybook-global-background)",
},
],
},
},
argTypes: {
// Hide children prop from docs table - it doesn't serialize well as a control
children: { table: { disable: true } },
},
};

Expand Down
44 changes: 35 additions & 9 deletions build-tokens.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,43 @@
import _ from "lodash";
import { registerTransforms, transforms } from "@tokens-studio/sd-transforms";
import StyleDictionary from "style-dictionary";

registerTransforms(StyleDictionary);
const themes = ["dark", "light"];

function generateThemeFromDictionary(dictionary, valueFunc = (value) => value) {
const setWith = (obj, path, value) => {
if (!obj || typeof obj !== "object") return obj;

const keys = Array.isArray(path)
? path
: path.replace(/\[(\d+)\]/g, ".$1").split(".");

let current = obj;

for (let i = 0; i < keys.length; i++) {
const key = keys[i];

if (i === keys.length - 1) {
// Last key → set value
current[key] = value;
} else {
// Ensure object exists
if (current[key] == null || typeof current[key] !== "object") {
current[key] = {};
}
current = current[key];
}
}

return obj;
};

const generateThemeFromDictionary = (dictionary, valueFunc = value => value) => {
const theme = {};
dictionary.allTokens.forEach((token) => {
_.setWith(theme, token.name, valueFunc(token.value), Object)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling @serdec as there's quite a lot of changes to the build-tokens.js and I don't know why.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are only using lodash increases the packages size and we are only using lodash for only here and one another place
So I was thinking like it would be better to remove these to remove dependencies and reduce the package size

dictionary.allTokens.forEach(token => {
setWith(theme, token.name, valueFunc(token.value), Object)
});
return theme;
}
};

StyleDictionary.registerTransform({
type: "name",
Expand All @@ -27,16 +53,16 @@ StyleDictionary.registerTransform({

StyleDictionary.registerFormat({
name: "ThemeFormat",
formatter: function ({ dictionary, platform, options, file }) {
formatter: ({ dictionary }) => {
const theme = generateThemeFromDictionary(dictionary);
return JSON.stringify(theme, null, 2);
}
});

StyleDictionary.registerFormat({
name: "TypescriptFormat",
formatter: function ({ dictionary, platform, options, file }) {
const theme = generateThemeFromDictionary(dictionary, (value) => typeof value);
formatter: ({ dictionary }) => {
const theme = generateThemeFromDictionary(dictionary, value => typeof value);

// Convert the theme object to a TypeScript interface string
// Prettier will format this automatically via the generate-tokens script
Expand All @@ -51,7 +77,7 @@ StyleDictionary.registerFormat({
});

StyleDictionary.extend({
source: [`./tokens/**/!(${themes.join("|*.")}).json`],
source: [`./tokens/**/*.json`],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes me a little nervous

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue I faced was missing types when the types where generated so I had to combine all the theme json to complete the complete list of the types we are using
This was identified when I worked on the scss migration branch

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could actually remove the css from being build as we are not using it at all
Also separate the logic for variable json and the types to 2 calls which would not cause any problems at all

platforms: {
css: {
transforms: [...transforms, "name/cti/kebab"],
Expand Down
13 changes: 11 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
"description": "Official ClickHouse design system react library",
"type": "module",
"license": "Apache-2.0",
"sideEffects": [
"**/*.css",
"**/*.scss"
],
"files": [
"dist"
],
Expand All @@ -17,7 +21,8 @@
"types": "./dist/index.d.ts",
"import": "./dist/click-ui.bundled.es.js",
"require": "./dist/click-ui.bundled.umd.js"
}
},
"./cui-theme.css": "./dist/cui-scss-theme.css"
},
"main": "./dist/click-ui.umd.js",
"module": "./dist/click-ui.es.js",
Expand All @@ -39,7 +44,8 @@
"build:watch": "watch 'yarn build' ./src",
"chromatic": "npx chromatic",
"dev": "vite",
"generate-tokens": "node build-tokens.js && prettier --write src/theme/tokens/types.ts",
"generate-tokens": "node build-tokens.js && prettier --write src/theme/tokens/types.ts && node scripts/generate-scss-theme.js",
"generate-scss-theme": "node scripts/generate-scss-theme.js",
"lint": "eslint src --report-unused-disable-directives --max-warnings 0",
"prettify": "prettier --write \"src/**/*.{js,jsx,ts,tsx}\" --config .prettierrc",
"prettier:check": "prettier --check \"src/**/*.{js,jsx,ts,tsx}\" --config .prettierrc",
Expand Down Expand Up @@ -68,6 +74,7 @@
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-toast": "^1.1.5",
"@radix-ui/react-tooltip": "^1.0.7",
"clsx": "^2.1.1",
"lodash": "^4.17.21",
"react-sortablejs": "^6.1.4",
"react-syntax-highlighter": "^15.5.0",
Expand All @@ -85,6 +92,7 @@
"@testing-library/react": "^15.0.7",
"@testing-library/user-event": "^14.5.2",
"@tokens-studio/sd-transforms": "^0.10.3",
"@types/lodash": "^4.17.21",
"@types/lodash-es": "^4.17.7",
"@types/node": "^24.10.1",
"@types/react": "18.3.2",
Expand All @@ -111,6 +119,7 @@
"prop-types": "^15.8.1",
"react": "18.3.1",
"react-dom": "18.3.1",
"sass-embedded": "^1.97.0",
"storybook": "^10.0.7",
"storybook-addon-pseudo-states": "^10.0.7",
"styled-components": "^6.1.11",
Expand Down
Loading