From e9dc381c8783a42555e5822ef2524be1ecc7d339 Mon Sep 17 00:00:00 2001 From: Vitalii Dudnik Date: Tue, 30 Jun 2026 09:09:47 +0300 Subject: [PATCH 1/6] feat: expand NEUTRAL_COLORS and update type definitions to include new colors --- src/constants.js | 12 +++++++++++- src/types.ts | 12 +++++++++++- src/ui.other-theme-color-toggle/storybook/stories.ts | 4 ++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/constants.js b/src/constants.js index b70d1d438..109850ac9 100644 --- a/src/constants.js +++ b/src/constants.js @@ -76,7 +76,17 @@ export const STATE_COLORS = [ GRAYSCALE_COLOR, ]; export const LAYOUT_COLORS = ["text", "border", "bg"]; -export const NEUTRAL_COLORS = ["slate", "gray", "zinc", "neutral", "stone"]; +export const NEUTRAL_COLORS = [ + "slate", + "gray", + "zinc", + "neutral", + "stone", + "mauve", + "olive", + "mist", + "taupe", +]; export const COLOR_SHADES = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950]; export const DEFAULT_LIGHT_THEME = { diff --git a/src/types.ts b/src/types.ts index dd02bbb44..a6bb10514 100644 --- a/src/types.ts +++ b/src/types.ts @@ -235,7 +235,17 @@ export interface ColorShades { 950: string; } -export type NeutralColorName = "slate" | "gray" | "zinc" | "neutral" | "stone" | string; +export type NeutralColorName = + | "slate" + | "gray" + | "zinc" + | "neutral" + | "stone" + | "mauve" + | "olive" + | "mist" + | "taupe" + | string; export type PrimaryColorName = | "red" | "orange" diff --git a/src/ui.other-theme-color-toggle/storybook/stories.ts b/src/ui.other-theme-color-toggle/storybook/stories.ts index 5ad5a67b8..832bac372 100644 --- a/src/ui.other-theme-color-toggle/storybook/stories.ts +++ b/src/ui.other-theme-color-toggle/storybook/stories.ts @@ -55,6 +55,10 @@ export default { zinc: "bg-zinc-600", neutral: "bg-neutral-600", stone: "bg-stone-600", + mauve: "bg-mauve-600", + olive: "bg-olive-600", + mist: "bg-mist-600", + taupe: "bg-taupe-600", }, }, argTypes: { From a0c2089bd7cce1a5b6236a36e03d524179f0241b Mon Sep 17 00:00:00 2001 From: Vitalii Dudnik Date: Tue, 30 Jun 2026 13:12:35 +0300 Subject: [PATCH 2/6] feat: add eslint-plugin-tailwindcss for improved Tailwind CSS support --- eslint.config.ts | 11 +++++++- package-lock.json | 70 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/eslint.config.ts b/eslint.config.ts index d12aacbdd..16799aead 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -5,6 +5,7 @@ import prettierEslintConfig from "@vue/eslint-config-prettier"; import pluginVue from "eslint-plugin-vue"; import pluginVitest from "@vitest/eslint-plugin"; import pluginStorybook from "eslint-plugin-storybook"; +import pluginTailwindcss from "eslint-plugin-tailwindcss"; const languageOptions = { globals: { @@ -31,6 +32,15 @@ export default defineConfigWithVueTs( })), vueTsConfigs.recommended, prettierEslintConfig, + { + ...pluginTailwindcss.configs.recommended, + files: ["**/*.{js,ts,jsx,tsx,vue}"], + settings: { + tailwindcss: { + cssConfigPath: "./src/tailwind.css", + }, + }, + }, { name: "common", languageOptions, @@ -66,7 +76,6 @@ export default defineConfigWithVueTs( }, }, { - name: "vitest", files: ["src/**/tests/*"], ...pluginVitest.configs.recommended, }, diff --git a/package-lock.json b/package-lock.json index 61fbec5f5..e4f4b855b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,6 +42,7 @@ "@vueless/storybook": "^1.6.6", "eslint": "^10.2.1", "eslint-plugin-storybook": "^10.3.5", + "eslint-plugin-tailwindcss": "^4.0.0-alpha.7", "eslint-plugin-vue": "^10.9.0", "globals": "^17.5.0", "jsdom": "^29.0.2", @@ -5961,6 +5962,31 @@ "storybook": "^10.3.5" } }, + "node_modules/eslint-plugin-tailwindcss": { + "version": "4.0.0-alpha.7", + "resolved": "https://registry.npmjs.org/eslint-plugin-tailwindcss/-/eslint-plugin-tailwindcss-4.0.0-alpha.7.tgz", + "integrity": "sha512-j/bu5QdVIdHymg5nb5jJZbBgyTBBo17i+WAFtiiR7+xE7nrEOAwSvF4znoAdwHIWRh+5UO07yDucyXm/SdLh4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.37.0", + "postcss": "^8.4.4", + "postcss-nested": "^7.0.2", + "synckit": "^0.11.11", + "tailwind-api-utils": "^1.0.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "tailwindcss": "^4.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/eslint-plugin-vue": { "version": "10.9.0", "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.9.0.tgz", @@ -8647,6 +8673,32 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-nested": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-7.0.2.tgz", + "integrity": "sha512-5osppouFc0VR9/VYzYxO03VaDa3e8F23Kfd6/9qcZTUI8P58GIYlArOET2Wq0ywSl2o2PjELhYOFI4W7l5QHKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, "node_modules/postcss-selector-parser": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", @@ -9909,6 +9961,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/tailwind-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tailwind-api-utils/-/tailwind-api-utils-1.0.3.tgz", + "integrity": "sha512-KpzUHkH1ug1sq4394SLJX38ZtpeTiqQ1RVyFTTSY2XuHsNSTWUkRo108KmyyrMWdDbQrLYkSHaNKj/a3bmA4sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "enhanced-resolve": "^5.18.1", + "jiti": "^2.4.2", + "local-pkg": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/hyoban" + }, + "peerDependencies": { + "tailwindcss": "^3.3.0 || ^4.0.0 || ^4.0.0-beta" + } + }, "node_modules/tailwind-merge": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.5.0.tgz", diff --git a/package.json b/package.json index 724e5410e..2d0f07f04 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "@vueless/storybook": "^1.6.6", "eslint": "^10.2.1", "eslint-plugin-storybook": "^10.3.5", + "eslint-plugin-tailwindcss": "^4.0.0-alpha.7", "eslint-plugin-vue": "^10.9.0", "globals": "^17.5.0", "jsdom": "^29.0.2", From 4ea84f2ca956225d16f3a79c4cfdba234e9b92a4 Mon Sep 17 00:00:00 2001 From: Vitalii Dudnik Date: Tue, 30 Jun 2026 13:17:25 +0300 Subject: [PATCH 3/6] fix: add eslint-disable comments for tailwindcss rule violations in UI composables and config --- src/composables/useUI.ts | 1 + src/utils/node/vuelessConfig.js | 1 + src/utils/ui.ts | 1 + 3 files changed, 3 insertions(+) diff --git a/src/composables/useUI.ts b/src/composables/useUI.ts index 18a1d5cd6..60cceed3a 100644 --- a/src/composables/useUI.ts +++ b/src/composables/useUI.ts @@ -153,6 +153,7 @@ export function useUI(defaultConfig: T, mutatedProps?: MutatedProps, topLevel let cvaFn = cvaCache.get(key); if (!cvaFn) { + // eslint-disable-next-line tailwindcss/no-custom-classname -- CVA config object, not a class string cvaFn = cva(value); cvaCache.set(key, cvaFn); } diff --git a/src/utils/node/vuelessConfig.js b/src/utils/node/vuelessConfig.js index d9103e969..fe9961c47 100644 --- a/src/utils/node/vuelessConfig.js +++ b/src/utils/node/vuelessConfig.js @@ -58,6 +58,7 @@ const twMerge = extendTailwindMerge( */ export const { cx } = defineConfig({ hooks: { + // eslint-disable-next-line tailwindcss/no-custom-classname -- callback param, not a class string onComplete: (classNames) => twMerge(classNames).replace(NESTED_COMPONENT_PATTERN_REG_EXP, ""), }, }); diff --git a/src/utils/ui.ts b/src/utils/ui.ts index 9184013f6..da46f1c60 100644 --- a/src/utils/ui.ts +++ b/src/utils/ui.ts @@ -76,6 +76,7 @@ export const { cva: classVarianceAuthority, } = defineConfig({ hooks: { + // eslint-disable-next-line tailwindcss/no-custom-classname -- callback param, not a class string onComplete: (classNames) => twMerge(classNames), }, }); From df8a19433c904946e2a9e06e92b876712853c643 Mon Sep 17 00:00:00 2001 From: Vitalii Dudnik Date: Tue, 30 Jun 2026 18:17:44 +0300 Subject: [PATCH 4/6] refactor: remove unnecessary eslint-disable comments and update Tailwind CSS file patterns in ESLint config --- eslint.config.ts | 3 ++- src/composables/useUI.ts | 1 - src/utils/node/vuelessConfig.js | 1 - src/utils/ui.ts | 1 - 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/eslint.config.ts b/eslint.config.ts index 16799aead..0cd184644 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -34,10 +34,11 @@ export default defineConfigWithVueTs( prettierEslintConfig, { ...pluginTailwindcss.configs.recommended, - files: ["**/*.{js,ts,jsx,tsx,vue}"], + files: ["**/*.{js,ts,vue}"], settings: { tailwindcss: { cssConfigPath: "./src/tailwind.css", + functions: ["classnames", "classNames", "clsx", "ctl", "tv", "tw", "twJoin"], }, }, }, diff --git a/src/composables/useUI.ts b/src/composables/useUI.ts index 60cceed3a..18a1d5cd6 100644 --- a/src/composables/useUI.ts +++ b/src/composables/useUI.ts @@ -153,7 +153,6 @@ export function useUI(defaultConfig: T, mutatedProps?: MutatedProps, topLevel let cvaFn = cvaCache.get(key); if (!cvaFn) { - // eslint-disable-next-line tailwindcss/no-custom-classname -- CVA config object, not a class string cvaFn = cva(value); cvaCache.set(key, cvaFn); } diff --git a/src/utils/node/vuelessConfig.js b/src/utils/node/vuelessConfig.js index fe9961c47..d9103e969 100644 --- a/src/utils/node/vuelessConfig.js +++ b/src/utils/node/vuelessConfig.js @@ -58,7 +58,6 @@ const twMerge = extendTailwindMerge( */ export const { cx } = defineConfig({ hooks: { - // eslint-disable-next-line tailwindcss/no-custom-classname -- callback param, not a class string onComplete: (classNames) => twMerge(classNames).replace(NESTED_COMPONENT_PATTERN_REG_EXP, ""), }, }); diff --git a/src/utils/ui.ts b/src/utils/ui.ts index da46f1c60..9184013f6 100644 --- a/src/utils/ui.ts +++ b/src/utils/ui.ts @@ -76,7 +76,6 @@ export const { cva: classVarianceAuthority, } = defineConfig({ hooks: { - // eslint-disable-next-line tailwindcss/no-custom-classname -- callback param, not a class string onComplete: (classNames) => twMerge(classNames), }, }); From ab7ac75d3041b127f4aade6a23e84db0b31de073 Mon Sep 17 00:00:00 2001 From: Vitalii Dudnik Date: Tue, 30 Jun 2026 18:28:42 +0300 Subject: [PATCH 5/6] refactor: clear tailwindcss plugin functions list in eslint config Leave functions empty because cx, cva, and twMerge are only called with variables, not inline class strings. Parsing those helpers caused false positives from no-custom-classname while template classes remain linted. --- eslint.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eslint.config.ts b/eslint.config.ts index 0cd184644..1aa83b62e 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -38,7 +38,7 @@ export default defineConfigWithVueTs( settings: { tailwindcss: { cssConfigPath: "./src/tailwind.css", - functions: ["classnames", "classNames", "clsx", "ctl", "tv", "tw", "twJoin"], + functions: [], }, }, }, From 40d76ef87646c5e7dc22df4a4413fdcc3f4618d6 Mon Sep 17 00:00:00 2001 From: Vitalii Dudnik Date: Tue, 30 Jun 2026 19:09:10 +0300 Subject: [PATCH 6/6] refactor: add classNames function to tailwindcss plugin settings in eslint config --- eslint.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eslint.config.ts b/eslint.config.ts index 1aa83b62e..5d8ca5824 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -38,7 +38,7 @@ export default defineConfigWithVueTs( settings: { tailwindcss: { cssConfigPath: "./src/tailwind.css", - functions: [], + functions: ["classNames"], }, }, },