Skip to content
Merged
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
22 changes: 22 additions & 0 deletions .changeset/free-turkeys-lick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
"flowbite-react": patch
---

Use CSS variables for `tailwindcss@v4` instead of inline colors.

### Changes

- [x] automatically generate `tailwindcss@v4` config file
- [x] use css variables for the `v4` config

### Breaking changes

Only applicable to `tailwindcss@v4`:

before
`@plugin "flowbite-react/plugins/tailwindcss"` - this points to the legacy JS plugin (that uses inline colors)

after
`@import "flowbite-react/plugins/tailwindcss"` - this points to the CSS-based plugin (that uses CSS variables)

The breaking change is self-managed once upgrading `flowbite-react` and starting/building the app, which runs the `flowbite-react dev` or respectively `flowbite-react build` command that triggers the patch/fix/migration automatically.
1 change: 1 addition & 0 deletions bun.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "root",
Expand Down
1 change: 1 addition & 0 deletions packages/ui/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
coverage
dist
src/metadata
src/plugin/tailwindcss/index.css
6 changes: 4 additions & 2 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@
"require": {
"types": "./dist/plugin/tailwindcss/index.d.cts",
"default": "./dist/plugin/tailwindcss/index.cjs"
}
},
"style": "./dist/plugin/tailwindcss/index.css"
},
"./plugin/tailwindcss/*": {
"import": {
Expand Down Expand Up @@ -252,10 +253,11 @@
"format": "prettier . --write",
"format:check": "prettier . --check",
"generate-metadata": "bun scripts/generate-metadata.ts",
"generate-tailwind-plugin-css-file": "bun scripts/generate-tailwind-plugin-css-file.ts",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"prepack": "clean-package",
"prepare": "bun run generate-metadata",
"prepare": "bun run generate-metadata && bun run generate-tailwind-plugin-css-file",
"prepublishOnly": "bun run build",
"test": "bun test scripts src/cli src/helpers && vitest",
"test:coverage": "vitest run --coverage",
Expand Down
24 changes: 23 additions & 1 deletion packages/ui/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import esbuild from "rollup-plugin-esbuild";
import { rollupPluginUseClient } from "rollup-plugin-use-client";
import packageJson from "./package.json";

const tailwindPluginCssFile = "plugin/tailwindcss/index.css";

let entries = await Array.fromAsync(new Glob("src/**/*").scan());
entries = entries.filter((path) => !path.includes(".test.")).sort();
entries = entries.filter((path) => !path.includes(".test.") && !path.includes(tailwindPluginCssFile)).sort();

const external = [
"ast-types",
Expand Down Expand Up @@ -53,10 +55,12 @@ export default {
plugins: [
cleanOutputDir(),
generateMetadata(),
generateTailwindPluginCssFile(),
esbuild({
sourceMap: false,
}),
rollupPluginUseClient(),
copyTailwindPluginCssFile(),
generateDts(),
generateRspackPlugin(),
],
Expand Down Expand Up @@ -90,6 +94,24 @@ function generateMetadata() {
};
}

function generateTailwindPluginCssFile() {
return {
name: "generate-tailwind-plugin-css-file",
async buildStart() {
await $`bun run generate-tailwind-plugin-css-file`;
},
};
}

function copyTailwindPluginCssFile() {
return {
name: "copy-tailwind-plugin-css-file",
async buildEnd() {
await Bun.write(`${outputDir}/${tailwindPluginCssFile}`, await Bun.file(`src/${tailwindPluginCssFile}`).text());
},
};
}

function generateDts() {
return {
name: "generate-dts",
Expand Down
60 changes: 60 additions & 0 deletions packages/ui/scripts/generate-tailwind-plugin-css-file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import prettier from "prettier";
import { colors } from "../src/plugin/tailwindcss/colors";
import { backgroundImage, boxShadow } from "../src/plugin/tailwindcss/theme";

let VARS = "";
let COLORS = "";

for (const colorName in colors) {
const colorShades = colors[colorName as keyof typeof colors];

for (const shade in colorShades) {
VARS += `--${colorName}-${shade}: ${colorShades[shade as unknown as keyof typeof colorShades]};\n`;
}
VARS += `\n`;

for (const shade in colorShades) {
COLORS += `--color-${colorName}-${shade}: var(--${colorName}-${shade});\n`;
}
COLORS += `\n`;
}

const BACKGROUND_IMAGES = Object.entries(backgroundImage)
.map(([name, value]) => `--background-image-${name}: ${value};`)
.join("\n");

const SHADOWS = Object.entries(boxShadow)
.map(([name, value]) => `--shadow-${name}: ${value};`)
.join("\n");

const content = `
:root {
${VARS}
}

@theme inline {
${COLORS}
}

@theme {
${BACKGROUND_IMAGES}
}

@theme {
${SHADOWS}
}
`;

const outputFile = "src/plugin/tailwindcss/index.css";

try {
await Bun.write(
outputFile,
await prettier.format(content, {
parser: "css",
}),
);
console.log(`Tailwind plugin CSS file generated successfully: ${outputFile}`);
} catch (error) {
console.error(`Failed generating Tailwind plugin CSS file: ${outputFile}`, error);
}
2 changes: 2 additions & 0 deletions packages/ui/src/cli/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import { findFiles } from "../utils/find-files";
import { getConfig } from "../utils/get-config";
import { setupInit } from "./setup-init";
import { setupOutputDirectory } from "./setup-output-directory";
import { setupTailwind } from "./setup-tailwind";

export async function build() {
await setupOutputDirectory();

try {
const config = await getConfig();
await setupInit(config);
await setupTailwind();
const initLogger = createInitLogger(config);

const importedComponents: string[] = [];
Expand Down
2 changes: 2 additions & 0 deletions packages/ui/src/cli/commands/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ import { getConfig } from "../utils/get-config";
import { setupGitIgnore } from "./setup-gitignore";
import { setupInit } from "./setup-init";
import { setupOutputDirectory } from "./setup-output-directory";
import { setupTailwind } from "./setup-tailwind";

export async function dev() {
await setupOutputDirectory();
let config = await getConfig();
await setupInit(config);
await setupTailwind();
const initLogger = createInitLogger(config);

if (config.components.length) {
Expand Down
16 changes: 14 additions & 2 deletions packages/ui/src/cli/commands/setup-tailwind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,23 +74,35 @@ async function setupTailwindV4() {
.join(path.relative(path.dirname(file), process.cwd()), classListFilePath)
.replace(/\\/g, "/");

const pluginRegex = new RegExp(
const pluginRegex_OLD = new RegExp(
`@plugin\\s+['"](${pluginDirectivePath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})['"](;|\\s|$)`,
);
const pluginRegex = new RegExp(
`@import\\s+['"](${pluginDirectivePath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})['"](;|\\s|$)`,
);
const sourceRegex = new RegExp(
`@source\\s+['"](${sourceDirectivePath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})['"](;|\\s|$)`,
);

const hasPluginDirective_OLD = pluginRegex_OLD.test(content);
const hasPluginDirective = pluginRegex.test(content);
const hasSourceDirective = sourceRegex.test(content);

if (hasPluginDirective && hasSourceDirective) {
continue;
}

if (hasPluginDirective_OLD) {
const pluginImportIndex = lines.findIndex((line) => pluginRegex_OLD.test(line));
if (pluginImportIndex !== -1) {
console.log(`Removing old flowbite-react plugin import directive from ${file}...`);
lines.splice(pluginImportIndex, 1);
}
}

const directivesToAdd = [];
if (!hasPluginDirective) {
const pluginDirective = `@plugin ${quoteType}${pluginDirectivePath}${quoteType};`;
const pluginDirective = `@import ${quoteType}${pluginDirectivePath}${quoteType};`;
directivesToAdd.push(pluginDirective);
}
if (!hasSourceDirective) {
Expand Down
Loading