From 70af3a070ac8b92512cbb80a117671a86183cc36 Mon Sep 17 00:00:00 2001 From: Airike Jaska <95303654+airikej@users.noreply.github.com> Date: Tue, 10 Feb 2026 10:26:24 +0200 Subject: [PATCH 1/4] feat(theme-provider): cli command + theme provider changes #499 --- package-lock.json | 516 +++++++++++++++++- package.json | 8 +- .../theme-provider/theme-provider.tsx | 56 +- src/tedi/scripts/build-cli.ts | 19 + src/tedi/scripts/import-figma-theme.ts | 231 ++++++++ 5 files changed, 799 insertions(+), 31 deletions(-) create mode 100644 src/tedi/scripts/build-cli.ts create mode 100644 src/tedi/scripts/import-figma-theme.ts diff --git a/package-lock.json b/package-lock.json index 1604a4df..7d00238d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@tanstack/react-table": "^8.13.2", "@tedi-design-system/core": "3.0.1", "classnames": "^2.5.1", + "commander": "^14.0.3", "draft-js": "^0.11.7", "draftjs-md-converter": "^1.5.2", "formik": "^2.4.5", @@ -28,6 +29,9 @@ "what-input": "^5.2.12", "yup": "^1.4.0" }, + "bin": { + "import-figma-theme": "scripts/import-figma-theme.cjs" + }, "devDependencies": { "@avalane/storybook-addon-status": "^5.0.1", "@babel/preset-env": "^7.26.0", @@ -111,6 +115,7 @@ "ts-jest": "29.1.2", "ts-node": "^10.9.2", "tslib": "^2.3.0", + "tsx": "^4.21.0", "typescript": "5.9.2", "typescript-plugin-css-modules": "^5.1.0", "vite": "^5.4.11", @@ -3213,6 +3218,23 @@ "node": ">=18" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { "version": "0.24.2", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", @@ -11248,10 +11270,9 @@ } }, "node_modules/commander": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.1.tgz", - "integrity": "sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A==", - "dev": true, + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", "license": "MIT", "engines": { "node": ">=20" @@ -28479,6 +28500,493 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index 6fcde260..65c8cc46 100644 --- a/package.json +++ b/package.json @@ -16,10 +16,14 @@ }, "./index.css": "./index.css" }, + "bin": { + "import-figma-theme": "./scripts/import-figma-theme.cjs" + }, "scripts": { "prepare": "husky", "start": "storybook dev -p 4400 -c .storybook", - "build": "rm -rf dist && vite build --config vite.config.ts && replace-in-file //fonts//g \"./fonts/\" dist/index.css --isRegex", + "build": "rm -rf dist && vite build --config vite.config.ts && replace-in-file //fonts//g \"./fonts/\" dist/index.css --isRegex && npm run build:cli", + "build:cli": "tsx src/tedi/scripts/build-cli.ts", "build:sb": "storybook build -c .storybook -o dist/storybook-static", "lint": "npx stylelint \"src/**/*.scss\" --fix && eslint \"src/**/*.{ts,tsx}\" --no-ignore --fix", "lint:ci": "npx stylelint \"src/**/*.scss\" --quiet && npx eslint . --quiet", @@ -45,6 +49,7 @@ "@tanstack/react-table": "^8.13.2", "@tedi-design-system/core": "3.0.1", "classnames": "^2.5.1", + "commander": "^14.0.3", "draft-js": "^0.11.7", "draftjs-md-converter": "^1.5.2", "formik": "^2.4.5", @@ -145,6 +150,7 @@ "ts-jest": "29.1.2", "ts-node": "^10.9.2", "tslib": "^2.3.0", + "tsx": "^4.21.0", "typescript": "5.9.2", "typescript-plugin-css-modules": "^5.1.0", "vite": "^5.4.11", diff --git a/src/tedi/providers/theme-provider/theme-provider.tsx b/src/tedi/providers/theme-provider/theme-provider.tsx index 543cb732..d989115d 100644 --- a/src/tedi/providers/theme-provider/theme-provider.tsx +++ b/src/tedi/providers/theme-provider/theme-provider.tsx @@ -1,10 +1,10 @@ 'use client'; -import { createContext, useCallback, useContext, useEffect, useState } from 'react'; +import { createContext, useContext, useEffect, useState } from 'react'; -export type Theme = 'default' | 'dark' | 'rit' | 'muis'; +type TEDITheme = 'default' | 'dark'; +export type Theme = TEDITheme | string; -const AVAILABLE_THEMES: Theme[] = ['default', 'dark', 'rit', 'muis']; const THEME_CLASS_PREFIX = 'tedi-theme--'; const STORAGE_KEY = 'tedi-theme'; @@ -20,40 +20,44 @@ const ThemeContext = createContext({ export const useTheme = () => useContext(ThemeContext); -export const ThemeProvider = ({ theme: initialTheme, children }: { theme?: Theme; children: React.ReactNode }) => { - const [theme, setThemeState] = useState(() => { - if (initialTheme !== undefined) { - return initialTheme; - } +function getInitialTheme(initialTheme?: Theme): Theme { + if (typeof window === 'undefined') { + return initialTheme ?? 'default'; + } - if (typeof window !== 'undefined') { - const saved = localStorage.getItem(STORAGE_KEY) as Theme | null; - if (saved && AVAILABLE_THEMES.includes(saved)) { - return saved; - } - } + const fromStorage = localStorage.getItem(STORAGE_KEY); + if (fromStorage) return fromStorage; + + const cookieMatch = document.cookie + .split('; ') + .find((c) => c.startsWith(`${STORAGE_KEY}=`)) + ?.split('=')[1]; + + if (cookieMatch) return cookieMatch; + + return initialTheme ?? 'default'; +} - return 'default'; - }); +export const ThemeProvider = ({ theme: initialTheme, children }: { theme?: Theme; children: React.ReactNode }) => { + const [theme, setTheme] = useState(() => getInitialTheme(initialTheme)); useEffect(() => { if (typeof document === 'undefined') return; const root = document.documentElement; - AVAILABLE_THEMES.forEach((t) => { - root.classList.toggle(`${THEME_CLASS_PREFIX}${t}`, t === theme); - }); + for (let i = root.classList.length - 1; i >= 0; i--) { + const cls = root.classList.item(i); + if (cls?.startsWith(THEME_CLASS_PREFIX)) { + root.classList.remove(cls); + } + } + + root.classList.add(`${THEME_CLASS_PREFIX}${theme}`); localStorage.setItem(STORAGE_KEY, theme); - document.cookie = `${STORAGE_KEY}=${theme};path=/;max-age=31536000`; + document.cookie = `${STORAGE_KEY}=${theme}; path=/; max-age=31536000; SameSite=Lax`; }, [theme]); - const setTheme = useCallback((newTheme: Theme) => { - if (AVAILABLE_THEMES.includes(newTheme)) { - setThemeState(newTheme); - } - }, []); - return {children}; }; diff --git a/src/tedi/scripts/build-cli.ts b/src/tedi/scripts/build-cli.ts new file mode 100644 index 00000000..cc3b1319 --- /dev/null +++ b/src/tedi/scripts/build-cli.ts @@ -0,0 +1,19 @@ +import { build } from 'esbuild'; + +build({ + entryPoints: ['src/tedi/scripts/import-figma-theme.ts'], + outfile: 'dist/scripts/import-figma-theme.cjs', + bundle: true, + platform: 'node', + format: 'cjs', + target: 'node18', + banner: { + js: '#!/usr/bin/env node\n', + }, + external: ['commander', 'fs', 'path'], + minify: true, + sourcemap: false, +}).catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/src/tedi/scripts/import-figma-theme.ts b/src/tedi/scripts/import-figma-theme.ts new file mode 100644 index 00000000..c9d02dbe --- /dev/null +++ b/src/tedi/scripts/import-figma-theme.ts @@ -0,0 +1,231 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { Command } from 'commander'; +import fs from 'fs'; +import path from 'path'; + +const program = new Command(); +program + .name('import-figma-theme') + .description('Import base variables (primitives) — semantic vars are aliases only') + .requiredOption('--theme ', 'Theme name for output folder/class (e.g. rit, muis, tedi)') + .requiredOption('--file-key ', 'Figma file key') + .requiredOption('--token ', 'Figma personal access token') + .option('--output-dir ', 'Output directory', 'src/variables') + .option('--verbose', 'Show detailed logging', false) + .version('1.0.0') + .allowExcessArguments(false); + +program.parse(process.argv); + +const opts = program.opts(); + +const THEME_INPUT = opts.theme.trim().toLowerCase(); +const FIGMA_FILE_KEY = opts.fileKey; +const FIGMA_VARIABLE_TOKEN = opts.token; +const OUTPUT_DIR = path.resolve(process.cwd(), opts.outputDir); + +const BASE_COLLECTIONS = new Set(['Bitweb', 'Bitweb base colors', 'Bitweb dimensions']); + +const THEME_FOLDER = THEME_INPUT.replace(/\s+/g, '-'); +const THEME_SUFFIX = THEME_INPUT.replace(/\s+/g, '-'); + +function kebab(str: string): string { + return str + .replace(/[^a-zA-Z0-9]+/g, '-') + .replace(/^-+|-+$/g, '') + .toLowerCase(); +} + +function pxToRem(value: number, base = 16): string { + const rem = value / base; + return rem === Math.floor(rem) ? `${rem}rem` : `${rem.toFixed(4).replace(/\.?0+$/, '')}rem`; +} + +function getUnit(collectionName: string): 'px' | 'rem' | null { + const l = collectionName.toLowerCase(); + if (l.includes('dimension') || l.includes('container')) return 'px'; + if (l.includes('font')) return 'rem'; + return null; +} + +function shouldConvertBaseToRem(varName: string): boolean { + const lower = varName.toLowerCase(); + if (lower.includes('weight')) return false; + if (lower.includes('opacity')) return false; + if (lower.includes('z-index')) return false; + if (lower.includes('flex')) return false; + if (lower.includes('line-height')) return true; + + return ( + lower.includes('space') || + lower.includes('spacing') || + lower.includes('radius') || + lower.includes('border') || + lower.includes('size') || + lower.includes('gap') || + lower.includes('dimension') || + lower.includes('height') || + lower.includes('width') + ); +} + +function resolveValue( + raw: any, + aliasMap: Record, + unit: 'px' | 'rem' | null, + varName = '', + varId?: string +): string | null { + if (!raw) return null; + + if (raw.type === 'VARIABLE_ALIAS') { + if (raw.id === varId) { + return null; + } + + const target = aliasMap[raw.id]; + return target ? `var(${target})` : null; + } + + if ('r' in raw) { + const v = raw.value ?? raw; + const { r, g, b, a = 1 } = v; + const [rr, gg, bb] = [r, g, b].map((c: number) => Math.round(c * 255)); + return a === 1 ? `rgb(${rr}, ${gg}, ${bb})` : `rgba(${rr}, ${gg}, ${bb}, ${a})`; + } + + const value = raw.value ?? raw; + + // NUMBER + if (typeof value === 'number') { + const lowerName = varName.toLowerCase(); + + if (lowerName.includes('weight')) return value.toString(); + if (shouldConvertBaseToRem(varName)) return pxToRem(value); + + if (unit === 'px' || lowerName.includes('radius') || lowerName.includes('border')) { + return `${Math.round(value * 100) / 100}px`; + } + + if (unit === 'rem') return pxToRem(value); + + return value.toString(); + } + + return String(value); +} + +async function fetchFigmaVariables() { + const url = `https://api.figma.com/v1/files/${FIGMA_FILE_KEY}/variables/local`; + const res = await fetch(url, { headers: { 'X-Figma-Token': FIGMA_VARIABLE_TOKEN } }); + if (!res.ok) throw new Error(`Figma API error ${res.status} – ${res.statusText}`); + return await res.json(); +} + +function collectionToType(name: string): string { + const lower = name.toLowerCase(); + + if (lower.includes('color')) return 'colors'; + if (lower.includes('dimension')) return 'dimensions'; + if (lower.includes('spacing')) return 'spacing'; + if (lower.includes('typography') || lower.includes('font')) return 'typography'; + + return kebab(name.replace(/^bitweb/i, '').trim()) || 'core'; +} + +interface FigmaCollection { + name: string; + modes: { modeId: string; name: string }[]; + variableIds: string[]; + defaultModeId?: string; +} + +async function run() { + console.log(`→ Importing base primitives for theme folder: ${THEME_FOLDER}`); + console.log(`→ Output: ${OUTPUT_DIR}/themes/${THEME_FOLDER}`); + console.log(''); + + const data = await fetchFigmaVariables(); + const variables = data.meta.variables as Record; + const collections = data.meta.variableCollections as Record; + + const aliasMap: Record = {}; + for (const id in variables) { + aliasMap[id] = `--${kebab(variables[id].name)}`; + } + + let filesWritten = 0; + + for (const coll of Object.values(collections)) { + if (!BASE_COLLECTIONS.has(coll.name.trim())) continue; + + const unit = getUnit(coll.name); + const modeId = coll.defaultModeId ?? coll.modes[0]?.modeId; + + if (!modeId) { + console.warn(`No default mode for base collection: ${coll.name}`); + continue; + } + + console.log(` Processing base collection "${coll.name}" (mode ID: ${modeId})`); + + const lines: string[] = []; + + for (const varId of coll.variableIds) { + const v = variables[varId]; + if (!v) continue; + + let raw = v.valuesByMode?.[modeId]; + + if (raw === undefined && coll.defaultModeId && coll.defaultModeId !== modeId) { + raw = v.valuesByMode?.[coll.defaultModeId]; + } + + if (raw === undefined) { + continue; + } + + const resolved = resolveValue(raw, aliasMap, unit, v.name, varId); + if (!resolved) continue; + + lines.push(` ${aliasMap[varId]}: ${resolved};`); + } + + if (lines.length === 0) { + console.log(' → No values found in this base collection'); + continue; + } + + lines.sort((a, b) => a.trim().split(':')[0].localeCompare(b.trim().split(':')[0])); + + const type = collectionToType(coll.name); + const fileName = `_base-${type}__${THEME_SUFFIX}.scss`; + const dir = path.join(OUTPUT_DIR, 'themes', THEME_FOLDER); + + const css = `:root, .tedi-theme--${THEME_SUFFIX} {\n${lines.join('\n')}\n}\n`; + + fs.mkdirSync(dir, { recursive: true }); + fs.writeFileSync(path.join(dir, fileName), css); + + console.log(` → Wrote ${lines.length} base variables to ${fileName}`); + filesWritten++; + } + + console.log(''); + if (filesWritten > 0) { + console.log( + `✓ Successfully wrote base primitives for "${THEME_INPUT}" (${filesWritten} file${filesWritten === 1 ? '' : 's'})` + ); + console.log(` Location: ${path.join(OUTPUT_DIR, 'themes', THEME_FOLDER)}`); + console.log(' Semantic variables should be pure aliases — no need to export them.'); + } else { + console.warn('No base variables were written. Check:'); + console.warn(' • Collection names match ("Bitweb base colors", "Bitweb dimensions")'); + console.warn(' • Base collections have values in their default mode'); + } +} + +run().catch((err) => { + console.error('Error:', err.message || err); + process.exit(1); +}); From 017d65c2f95a09e51bd977a0dab9608d30254c4b Mon Sep 17 00:00:00 2001 From: Airike Jaska <95303654+airikej@users.noreply.github.com> Date: Mon, 9 Mar 2026 08:13:32 +0200 Subject: [PATCH 2/4] fix(theme-provider): remove unused files #499 --- package.json | 6 +- src/tedi/scripts/build-cli.ts | 19 -- src/tedi/scripts/import-figma-theme.ts | 231 ------------------------- 3 files changed, 1 insertion(+), 255 deletions(-) delete mode 100644 src/tedi/scripts/build-cli.ts delete mode 100644 src/tedi/scripts/import-figma-theme.ts diff --git a/package.json b/package.json index 65c8cc46..63c8befe 100644 --- a/package.json +++ b/package.json @@ -16,14 +16,10 @@ }, "./index.css": "./index.css" }, - "bin": { - "import-figma-theme": "./scripts/import-figma-theme.cjs" - }, "scripts": { "prepare": "husky", "start": "storybook dev -p 4400 -c .storybook", - "build": "rm -rf dist && vite build --config vite.config.ts && replace-in-file //fonts//g \"./fonts/\" dist/index.css --isRegex && npm run build:cli", - "build:cli": "tsx src/tedi/scripts/build-cli.ts", + "build": "rm -rf dist && vite build --config vite.config.ts && replace-in-file //fonts//g \"./fonts/\" dist/index.css --isRegex", "build:sb": "storybook build -c .storybook -o dist/storybook-static", "lint": "npx stylelint \"src/**/*.scss\" --fix && eslint \"src/**/*.{ts,tsx}\" --no-ignore --fix", "lint:ci": "npx stylelint \"src/**/*.scss\" --quiet && npx eslint . --quiet", diff --git a/src/tedi/scripts/build-cli.ts b/src/tedi/scripts/build-cli.ts deleted file mode 100644 index cc3b1319..00000000 --- a/src/tedi/scripts/build-cli.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { build } from 'esbuild'; - -build({ - entryPoints: ['src/tedi/scripts/import-figma-theme.ts'], - outfile: 'dist/scripts/import-figma-theme.cjs', - bundle: true, - platform: 'node', - format: 'cjs', - target: 'node18', - banner: { - js: '#!/usr/bin/env node\n', - }, - external: ['commander', 'fs', 'path'], - minify: true, - sourcemap: false, -}).catch((err) => { - console.error(err); - process.exit(1); -}); diff --git a/src/tedi/scripts/import-figma-theme.ts b/src/tedi/scripts/import-figma-theme.ts deleted file mode 100644 index c9d02dbe..00000000 --- a/src/tedi/scripts/import-figma-theme.ts +++ /dev/null @@ -1,231 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { Command } from 'commander'; -import fs from 'fs'; -import path from 'path'; - -const program = new Command(); -program - .name('import-figma-theme') - .description('Import base variables (primitives) — semantic vars are aliases only') - .requiredOption('--theme ', 'Theme name for output folder/class (e.g. rit, muis, tedi)') - .requiredOption('--file-key ', 'Figma file key') - .requiredOption('--token ', 'Figma personal access token') - .option('--output-dir ', 'Output directory', 'src/variables') - .option('--verbose', 'Show detailed logging', false) - .version('1.0.0') - .allowExcessArguments(false); - -program.parse(process.argv); - -const opts = program.opts(); - -const THEME_INPUT = opts.theme.trim().toLowerCase(); -const FIGMA_FILE_KEY = opts.fileKey; -const FIGMA_VARIABLE_TOKEN = opts.token; -const OUTPUT_DIR = path.resolve(process.cwd(), opts.outputDir); - -const BASE_COLLECTIONS = new Set(['Bitweb', 'Bitweb base colors', 'Bitweb dimensions']); - -const THEME_FOLDER = THEME_INPUT.replace(/\s+/g, '-'); -const THEME_SUFFIX = THEME_INPUT.replace(/\s+/g, '-'); - -function kebab(str: string): string { - return str - .replace(/[^a-zA-Z0-9]+/g, '-') - .replace(/^-+|-+$/g, '') - .toLowerCase(); -} - -function pxToRem(value: number, base = 16): string { - const rem = value / base; - return rem === Math.floor(rem) ? `${rem}rem` : `${rem.toFixed(4).replace(/\.?0+$/, '')}rem`; -} - -function getUnit(collectionName: string): 'px' | 'rem' | null { - const l = collectionName.toLowerCase(); - if (l.includes('dimension') || l.includes('container')) return 'px'; - if (l.includes('font')) return 'rem'; - return null; -} - -function shouldConvertBaseToRem(varName: string): boolean { - const lower = varName.toLowerCase(); - if (lower.includes('weight')) return false; - if (lower.includes('opacity')) return false; - if (lower.includes('z-index')) return false; - if (lower.includes('flex')) return false; - if (lower.includes('line-height')) return true; - - return ( - lower.includes('space') || - lower.includes('spacing') || - lower.includes('radius') || - lower.includes('border') || - lower.includes('size') || - lower.includes('gap') || - lower.includes('dimension') || - lower.includes('height') || - lower.includes('width') - ); -} - -function resolveValue( - raw: any, - aliasMap: Record, - unit: 'px' | 'rem' | null, - varName = '', - varId?: string -): string | null { - if (!raw) return null; - - if (raw.type === 'VARIABLE_ALIAS') { - if (raw.id === varId) { - return null; - } - - const target = aliasMap[raw.id]; - return target ? `var(${target})` : null; - } - - if ('r' in raw) { - const v = raw.value ?? raw; - const { r, g, b, a = 1 } = v; - const [rr, gg, bb] = [r, g, b].map((c: number) => Math.round(c * 255)); - return a === 1 ? `rgb(${rr}, ${gg}, ${bb})` : `rgba(${rr}, ${gg}, ${bb}, ${a})`; - } - - const value = raw.value ?? raw; - - // NUMBER - if (typeof value === 'number') { - const lowerName = varName.toLowerCase(); - - if (lowerName.includes('weight')) return value.toString(); - if (shouldConvertBaseToRem(varName)) return pxToRem(value); - - if (unit === 'px' || lowerName.includes('radius') || lowerName.includes('border')) { - return `${Math.round(value * 100) / 100}px`; - } - - if (unit === 'rem') return pxToRem(value); - - return value.toString(); - } - - return String(value); -} - -async function fetchFigmaVariables() { - const url = `https://api.figma.com/v1/files/${FIGMA_FILE_KEY}/variables/local`; - const res = await fetch(url, { headers: { 'X-Figma-Token': FIGMA_VARIABLE_TOKEN } }); - if (!res.ok) throw new Error(`Figma API error ${res.status} – ${res.statusText}`); - return await res.json(); -} - -function collectionToType(name: string): string { - const lower = name.toLowerCase(); - - if (lower.includes('color')) return 'colors'; - if (lower.includes('dimension')) return 'dimensions'; - if (lower.includes('spacing')) return 'spacing'; - if (lower.includes('typography') || lower.includes('font')) return 'typography'; - - return kebab(name.replace(/^bitweb/i, '').trim()) || 'core'; -} - -interface FigmaCollection { - name: string; - modes: { modeId: string; name: string }[]; - variableIds: string[]; - defaultModeId?: string; -} - -async function run() { - console.log(`→ Importing base primitives for theme folder: ${THEME_FOLDER}`); - console.log(`→ Output: ${OUTPUT_DIR}/themes/${THEME_FOLDER}`); - console.log(''); - - const data = await fetchFigmaVariables(); - const variables = data.meta.variables as Record; - const collections = data.meta.variableCollections as Record; - - const aliasMap: Record = {}; - for (const id in variables) { - aliasMap[id] = `--${kebab(variables[id].name)}`; - } - - let filesWritten = 0; - - for (const coll of Object.values(collections)) { - if (!BASE_COLLECTIONS.has(coll.name.trim())) continue; - - const unit = getUnit(coll.name); - const modeId = coll.defaultModeId ?? coll.modes[0]?.modeId; - - if (!modeId) { - console.warn(`No default mode for base collection: ${coll.name}`); - continue; - } - - console.log(` Processing base collection "${coll.name}" (mode ID: ${modeId})`); - - const lines: string[] = []; - - for (const varId of coll.variableIds) { - const v = variables[varId]; - if (!v) continue; - - let raw = v.valuesByMode?.[modeId]; - - if (raw === undefined && coll.defaultModeId && coll.defaultModeId !== modeId) { - raw = v.valuesByMode?.[coll.defaultModeId]; - } - - if (raw === undefined) { - continue; - } - - const resolved = resolveValue(raw, aliasMap, unit, v.name, varId); - if (!resolved) continue; - - lines.push(` ${aliasMap[varId]}: ${resolved};`); - } - - if (lines.length === 0) { - console.log(' → No values found in this base collection'); - continue; - } - - lines.sort((a, b) => a.trim().split(':')[0].localeCompare(b.trim().split(':')[0])); - - const type = collectionToType(coll.name); - const fileName = `_base-${type}__${THEME_SUFFIX}.scss`; - const dir = path.join(OUTPUT_DIR, 'themes', THEME_FOLDER); - - const css = `:root, .tedi-theme--${THEME_SUFFIX} {\n${lines.join('\n')}\n}\n`; - - fs.mkdirSync(dir, { recursive: true }); - fs.writeFileSync(path.join(dir, fileName), css); - - console.log(` → Wrote ${lines.length} base variables to ${fileName}`); - filesWritten++; - } - - console.log(''); - if (filesWritten > 0) { - console.log( - `✓ Successfully wrote base primitives for "${THEME_INPUT}" (${filesWritten} file${filesWritten === 1 ? '' : 's'})` - ); - console.log(` Location: ${path.join(OUTPUT_DIR, 'themes', THEME_FOLDER)}`); - console.log(' Semantic variables should be pure aliases — no need to export them.'); - } else { - console.warn('No base variables were written. Check:'); - console.warn(' • Collection names match ("Bitweb base colors", "Bitweb dimensions")'); - console.warn(' • Base collections have values in their default mode'); - } -} - -run().catch((err) => { - console.error('Error:', err.message || err); - process.exit(1); -}); From f45d59b79eb76bce09be03045fd0ac05f5b541de Mon Sep 17 00:00:00 2001 From: Airike Jaska <95303654+airikej@users.noreply.github.com> Date: Mon, 9 Mar 2026 08:20:36 +0200 Subject: [PATCH 3/4] fix(theme-provider): remove currently unused packages #499 --- package-lock.json | 510 +--------------------------------------------- package.json | 2 - 2 files changed, 1 insertion(+), 511 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7d00238d..cb6faa6f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,6 @@ "@tanstack/react-table": "^8.13.2", "@tedi-design-system/core": "3.0.1", "classnames": "^2.5.1", - "commander": "^14.0.3", "draft-js": "^0.11.7", "draftjs-md-converter": "^1.5.2", "formik": "^2.4.5", @@ -29,9 +28,6 @@ "what-input": "^5.2.12", "yup": "^1.4.0" }, - "bin": { - "import-figma-theme": "scripts/import-figma-theme.cjs" - }, "devDependencies": { "@avalane/storybook-addon-status": "^5.0.1", "@babel/preset-env": "^7.26.0", @@ -115,7 +111,6 @@ "ts-jest": "29.1.2", "ts-node": "^10.9.2", "tslib": "^2.3.0", - "tsx": "^4.21.0", "typescript": "5.9.2", "typescript-plugin-css-modules": "^5.1.0", "vite": "^5.4.11", @@ -3218,23 +3213,6 @@ "node": ">=18" } }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", - "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, "node_modules/@esbuild/sunos-x64": { "version": "0.24.2", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", @@ -11273,6 +11251,7 @@ "version": "14.0.3", "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "dev": true, "license": "MIT", "engines": { "node": ">=20" @@ -28500,493 +28479,6 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, - "node_modules/tsx": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", - "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.27.0", - "get-tsconfig": "^4.7.5" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", - "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", - "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", - "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", - "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", - "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/darwin-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", - "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", - "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", - "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", - "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", - "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", - "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-loong64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", - "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", - "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", - "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", - "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-s390x": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", - "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", - "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", - "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", - "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", - "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", - "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/sunos-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", - "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", - "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", - "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", - "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/esbuild": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", - "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.2", - "@esbuild/android-arm": "0.27.2", - "@esbuild/android-arm64": "0.27.2", - "@esbuild/android-x64": "0.27.2", - "@esbuild/darwin-arm64": "0.27.2", - "@esbuild/darwin-x64": "0.27.2", - "@esbuild/freebsd-arm64": "0.27.2", - "@esbuild/freebsd-x64": "0.27.2", - "@esbuild/linux-arm": "0.27.2", - "@esbuild/linux-arm64": "0.27.2", - "@esbuild/linux-ia32": "0.27.2", - "@esbuild/linux-loong64": "0.27.2", - "@esbuild/linux-mips64el": "0.27.2", - "@esbuild/linux-ppc64": "0.27.2", - "@esbuild/linux-riscv64": "0.27.2", - "@esbuild/linux-s390x": "0.27.2", - "@esbuild/linux-x64": "0.27.2", - "@esbuild/netbsd-arm64": "0.27.2", - "@esbuild/netbsd-x64": "0.27.2", - "@esbuild/openbsd-arm64": "0.27.2", - "@esbuild/openbsd-x64": "0.27.2", - "@esbuild/openharmony-arm64": "0.27.2", - "@esbuild/sunos-x64": "0.27.2", - "@esbuild/win32-arm64": "0.27.2", - "@esbuild/win32-ia32": "0.27.2", - "@esbuild/win32-x64": "0.27.2" - } - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index 63c8befe..6fcde260 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,6 @@ "@tanstack/react-table": "^8.13.2", "@tedi-design-system/core": "3.0.1", "classnames": "^2.5.1", - "commander": "^14.0.3", "draft-js": "^0.11.7", "draftjs-md-converter": "^1.5.2", "formik": "^2.4.5", @@ -146,7 +145,6 @@ "ts-jest": "29.1.2", "ts-node": "^10.9.2", "tslib": "^2.3.0", - "tsx": "^4.21.0", "typescript": "5.9.2", "typescript-plugin-css-modules": "^5.1.0", "vite": "^5.4.11", From a44dda33916ba7412bc49594183d94824653d8fe Mon Sep 17 00:00:00 2001 From: Airike Jaska <95303654+airikej@users.noreply.github.com> Date: Mon, 9 Mar 2026 08:25:07 +0200 Subject: [PATCH 4/4] fix(theme-provider): fix tests #499 --- .../theme-provider/theme-provider.spec.tsx | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/tedi/providers/theme-provider/theme-provider.spec.tsx b/src/tedi/providers/theme-provider/theme-provider.spec.tsx index 51d73f42..9afd382b 100644 --- a/src/tedi/providers/theme-provider/theme-provider.spec.tsx +++ b/src/tedi/providers/theme-provider/theme-provider.spec.tsx @@ -18,6 +18,7 @@ describe('ThemeProvider', () => { const TestComponent = () => { const { theme, setTheme } = useTheme(); + return (

{theme}

@@ -53,7 +54,7 @@ describe('ThemeProvider', () => { expect(document.cookie).toContain('tedi-theme=default'); }); - it('ignores existing localStorage theme and uses provided prop theme instead', () => { + it('uses theme from localStorage over provided prop theme', () => { localStorage.setItem('tedi-theme', 'dark'); render( @@ -62,11 +63,10 @@ describe('ThemeProvider', () => { ); - // Provider should still use "default" because prop theme overrides storage - expect(screen.getByTestId('theme')).toHaveTextContent('default'); - expect(document.documentElement).toHaveClass('tedi-theme--default'); - expect(localStorage.getItem('tedi-theme')).toBe('default'); - expect(document.cookie).toContain('tedi-theme=default'); + expect(screen.getByTestId('theme')).toHaveTextContent('dark'); + expect(document.documentElement).toHaveClass('tedi-theme--dark'); + expect(localStorage.getItem('tedi-theme')).toBe('dark'); + expect(document.cookie).toContain('tedi-theme=dark'); }); it('updates theme and document classes when setTheme is called', () => { @@ -76,10 +76,8 @@ describe('ThemeProvider', () => { ); - const button = screen.getByText('Set Dark'); - act(() => { - button.click(); + screen.getByText('Set Dark').click(); }); expect(screen.getByTestId('theme')).toHaveTextContent('dark'); @@ -133,29 +131,31 @@ describe('ThemeProvider', () => { expect(document.cookie).toContain('tedi-theme=rit'); }); - it('does not set theme if invalid theme is provided', () => { - const TestComponentWithInvalidTheme = () => { + it('allows custom theme values', () => { + const TestComponentWithCustomTheme = () => { const { theme, setTheme } = useTheme(); + return (

{theme}

- +
); }; render( - + ); act(() => { - screen.getByText('Set Invalid').click(); + screen.getByText('Set Custom').click(); }); - expect(screen.getByTestId('theme')).toHaveTextContent('default'); - expect(document.documentElement).toHaveClass('tedi-theme--default'); - expect(localStorage.getItem('tedi-theme')).toBe('default'); + expect(screen.getByTestId('theme')).toHaveTextContent('invalid'); + expect(document.documentElement).toHaveClass('tedi-theme--invalid'); + expect(localStorage.getItem('tedi-theme')).toBe('invalid'); + expect(document.cookie).toContain('tedi-theme=invalid'); }); });