diff --git a/packages/mini-apps-ui-kit-react/README.md b/packages/mini-apps-ui-kit-react/README.md index 6902e4c7..9ab1248d 100644 --- a/packages/mini-apps-ui-kit-react/README.md +++ b/packages/mini-apps-ui-kit-react/README.md @@ -66,12 +66,32 @@ The library uses the following font **[TWK Lausanne](https://weltkern.com/typefa ## Importing Styles -To use the UI Kit components with their proper styling, you need to import the styles in your application. Add the following import statement to your application's entry point (e.g., `app/layout.tsx` for Next.js or `main.tsx` for Vite): +To use the UI Kit components with their proper styling, you need to import the styles in your application. The library provides multiple CSS files for maximum compatibility: +### **Tailwind v3 Projects (Recommended for most users)** ```typescript import "@worldcoin/mini-apps-ui-kit-react/styles.css"; +// or explicitly +import "@worldcoin/mini-apps-ui-kit-react/styles-v3.css"; ``` +### **Tailwind v4 Projects** +```typescript +import "@worldcoin/mini-apps-ui-kit-react/styles-v4.css"; +``` + +### **CSS File Differences** + +- **`styles.css`** - Backward-compatible version (same as v3, recommended for most users) +- **`styles-v3.css`** - Explicitly marked v3-compatible version +- **`styles-v4.css` - Modern v4 version with @layer directives + +### **Why Multiple Versions?** + +This library supports both Tailwind v3 and v4 to ensure maximum compatibility across different projects. The v3 versions work in any project, while the v4 version provides modern CSS features for projects that can use them. + +> **šŸ’” Tip**: If you're unsure which version to use, start with `styles.css` - it's designed to work everywhere. + ## Icons The library uses a custom set of icons built on top of [Iconoir](https://iconoir.com/). While we provide our own custom set, we highly recommend using Iconoir directly for your miniapps as it offers a comprehensive and well-maintained icon system. diff --git a/packages/mini-apps-ui-kit-react/package.json b/packages/mini-apps-ui-kit-react/package.json index cd267ef9..db82568c 100644 --- a/packages/mini-apps-ui-kit-react/package.json +++ b/packages/mini-apps-ui-kit-react/package.json @@ -16,10 +16,11 @@ "storybook": "storybook dev -p 6006", "format": "prettier --write \"**/*.{ts,tsx,md}\"", "sb:move": "mv ./storybook-static ../../storybook-static", - "dev:sb": "concurrently \"tailwindcss -i ./styles/globals.css -o ./dist/globals.css --watch\" \"pnpm storybook\"", - "build:tailwind": "tailwindcss -i ./styles/globals.css -o ./dist/globals.css --minify", - "build:sb": "pnpm build:tailwind && storybook build", - "build": "tsc -b ./tsconfig.lib.json && vite build && pnpm build:tailwind", + "dev:sb": "concurrently \"npx @tailwindcss/cli -i ./styles/globals.css -o ./dist/globals.css --watch\" \"pnpm storybook\"", + "build:sb": "vite build && storybook build", + "build": "tsc -b ./tsconfig.lib.json && vite build", + "build:css": "node scripts/build-css.js", + "build:all": "pnpm build && pnpm build:css", "lint": "eslint .", "publish:manual": "pnpm build && npm publish --access public", "generate:country-codes": "node scripts/generate-country-codes.js", @@ -37,6 +38,7 @@ }, "devDependencies": { "@chromatic-com/storybook": "^3.2.2", + "@csstools/postcss-cascade-layers": "^5.0.2", "@eslint/js": "^9.13.0", "@storybook/addon-essentials": "^8.4.7", "@storybook/addon-interactions": "^8.4.7", @@ -48,10 +50,12 @@ "@storybook/react-vite": "^8.4.7", "@storybook/test": "^8.4.7", "@storybook/theming": "^8.5.5", + "@tailwindcss/vite": "^4.1.11", "@types/glob": "^8.1.0", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "@vitejs/plugin-react": "^4.3.3", + "autoprefixer": "^10.4.21", "concurrently": "^9.1.0", "eslint": "^9.13.0", "eslint-plugin-react": "^7.37.2", @@ -60,12 +64,14 @@ "eslint-plugin-storybook": "^0.11.1", "glob": "^11.0.0", "globals": "^15.11.0", + "postcss": "^8", + "postcss-cli": "^11.0.1", "react": "^18.3.1", "react-dom": "^18.3.1", "rollup-plugin-visualizer": "^6.0.3", "rollup-preserve-directives": "^1.1.3", "storybook": "^8.4.7", - "tailwindcss": "^3.4.15", + "tailwindcss": "^4.1.11", "tailwindcss-animate": "^1.0.7", "typescript": "~5.6.2", "typescript-eslint": "^8.11.0", @@ -98,6 +104,9 @@ "import": "./dist/index.js", "require": "./dist/index.js" }, + "./styles.css": "./dist/styles.css", + "./styles-v3.css": "./dist/styles-v3.css", + "./styles-v4.css": "./dist/styles-v4.css", "./Button": { "types": "./dist/components/Button/index.d.ts", "default": "./dist/components/Button/index.js" @@ -266,7 +275,6 @@ "types": "./dist/tailwind/index.d.ts", "import": "./dist/tailwind/index.js", "require": "./dist/tailwind/index.js" - }, - "./styles.css": "./dist/globals.css" + } } } \ No newline at end of file diff --git a/packages/mini-apps-ui-kit-react/postcss-v3.config.js b/packages/mini-apps-ui-kit-react/postcss-v3.config.js new file mode 100644 index 00000000..769fe1da --- /dev/null +++ b/packages/mini-apps-ui-kit-react/postcss-v3.config.js @@ -0,0 +1,8 @@ +import removeLayersPlugin from './scripts/postcss-remove-layers.js'; + +export default { + plugins: { + autoprefixer: {}, + removeLayersPlugin: {}, + }, +}; \ No newline at end of file diff --git a/packages/mini-apps-ui-kit-react/postcss.config.js b/packages/mini-apps-ui-kit-react/postcss.config.js new file mode 100644 index 00000000..8aa97d68 --- /dev/null +++ b/packages/mini-apps-ui-kit-react/postcss.config.js @@ -0,0 +1,5 @@ +export default { + plugins: { + autoprefixer: {}, + }, +}; \ No newline at end of file diff --git a/packages/mini-apps-ui-kit-react/scripts/build-css.js b/packages/mini-apps-ui-kit-react/scripts/build-css.js new file mode 100755 index 00000000..16e01d2f --- /dev/null +++ b/packages/mini-apps-ui-kit-react/scripts/build-css.js @@ -0,0 +1,92 @@ +#!/usr/bin/env node + +import fs from 'fs'; +import path from 'path'; +import { execSync } from 'child_process'; + +console.log('šŸš€ Building CSS files for both Tailwind v3 and v4...'); + +// First, build the project using Vite (this generates the v4 CSS) +console.log('\nšŸ“¦ Building project with Vite (generates v4 CSS)...'); +try { + execSync('pnpm build', { stdio: 'inherit' }); + console.log('āœ… Vite build completed successfully'); +} catch (error) { + console.error('āŒ Failed to build project:', error.message); + process.exit(1); +} + +// Check if the v4 CSS was generated +const v4CSSPath = './dist/styles.css'; +if (!fs.existsSync(v4CSSPath)) { + console.error('āŒ V4 CSS file not found. Make sure the build completed successfully.'); + process.exit(1); +} + +// Read the v4 CSS immediately after Vite build (before any processing) +console.log('\nšŸ“¦ Reading generated v4 CSS...'); +const v4CSS = fs.readFileSync(v4CSSPath, 'utf8'); + +// Create v4 CSS file (preserve with @layer directives) +console.log('\nšŸ“¦ Creating v4 CSS file...'); +fs.writeFileSync('./dist/styles-v4.css', v4CSS); +console.log('āœ… v4 CSS file created (with @layer directives preserved)'); + +// Create v3 compatible CSS using PostCSS with @csstools/postcss-cascade-layers +console.log('\nšŸ“¦ Creating v3 compatible CSS using PostCSS...'); +try { + // Import PostCSS and the cascade layers plugin + const postcss = await import('postcss'); + const cascadeLayers = await import('@csstools/postcss-cascade-layers'); + const autoprefixer = await import('autoprefixer'); + + // Process the CSS to remove @layer directives + const result = await postcss.default([ + cascadeLayers.default({ + // This will remove all @layer directives and flatten the CSS + onRevertLayerKeyword: (layerName) => { + console.log(`Removing @layer directive: ${layerName}`); + } + }), + autoprefixer.default + ]).process(v4CSS, { + from: undefined, + to: undefined + }); + + // Write the processed CSS + fs.writeFileSync('./dist/styles-v3.css', result.css); + console.log('āœ… v3 CSS file created using @csstools/postcss-cascade-layers'); + +} catch (error) { + console.error('āŒ Failed to process CSS with PostCSS:', error.message); + console.log('šŸ”„ Falling back to regex method...'); + + // Fallback to regex method + const v3CSS = v4CSS + .replace(/@layer\s+(\w+)\s*\{([^}]*)\}/g, '$2') + .replace(/@layer\s+[^;]+;/g, '') + .replace(/@layer\s+\w+\s*\{/g, '') + .replace(/\}\s*@layer/g, '') + .replace(/\n\s*\n\s*\n/g, '\n\n') + .trim(); + + fs.writeFileSync('./dist/styles-v3.css', v3CSS); + console.log('āœ… v3 CSS file created using fallback method'); +} + +// Update the main styles.css to be v3 compatible (for backward compatibility) +console.log('\nšŸ“¦ Updating main styles.css to be v3 compatible...'); +const v3CSS = fs.readFileSync('./dist/styles-v3.css', 'utf8'); +fs.writeFileSync('./dist/styles.css', v3CSS); +console.log('āœ… Main styles.css updated for v3 compatibility'); + +console.log('\nšŸŽ‰ All CSS files built successfully!'); +console.log('\nšŸ“ Generated files:'); +console.log(' • dist/styles.css (v3 compatible, backward compatible)'); +console.log(' • dist/styles-v3.css (v3 compatible, @layer directives removed)'); +console.log(' • dist/styles-v4.css (v4 compatible, @layer directives preserved)'); +console.log('\nšŸ’” Usage:'); +console.log(' • For Tailwind v3 projects: import "styles.css" or "styles-v3.css"'); +console.log(' • For Tailwind v4 projects: import "styles-v4.css"'); +console.log('\nāš ļø Note: The v3 versions have @layer directives safely removed using @csstools/postcss-cascade-layers'); \ No newline at end of file diff --git a/packages/mini-apps-ui-kit-react/scripts/postcss-remove-layers.js b/packages/mini-apps-ui-kit-react/scripts/postcss-remove-layers.js new file mode 100644 index 00000000..8c89b45c --- /dev/null +++ b/packages/mini-apps-ui-kit-react/scripts/postcss-remove-layers.js @@ -0,0 +1,34 @@ +/** + * PostCSS plugin to remove @layer directives for Tailwind v3 compatibility + */ +export default function removeLayersPlugin() { + return { + postcssPlugin: 'postcss-remove-layers', + AtRule: { + layer(atRule) { + console.log(`Found @layer: ${atRule.name} with ${atRule.nodes?.length || 0} nodes`); + + // Remove the @layer atrule but keep its content + if (atRule.nodes && atRule.nodes.length > 0) { + // Move all child nodes to the parent + atRule.parent.insertBefore(atRule, atRule.nodes); + } + // Remove the @layer atrule itself (including standalone statements) + atRule.remove(); + } + }, + // Also handle any remaining @layer references that might not be caught + Once(root) { + // Find and remove any remaining @layer statements + root.walkAtRules('layer', (atRule) => { + console.log(`Walking found @layer: ${atRule.name}`); + if (atRule.nodes && atRule.nodes.length > 0) { + atRule.parent.insertBefore(atRule, atRule.nodes); + } + atRule.remove(); + }); + } + }; +} + +removeLayersPlugin.postcss = true; \ No newline at end of file diff --git a/packages/mini-apps-ui-kit-react/src/components/BottomBar/BottomBar.tsx b/packages/mini-apps-ui-kit-react/src/components/BottomBar/BottomBar.tsx index b266937b..970b5ec6 100644 --- a/packages/mini-apps-ui-kit-react/src/components/BottomBar/BottomBar.tsx +++ b/packages/mini-apps-ui-kit-react/src/components/BottomBar/BottomBar.tsx @@ -6,7 +6,7 @@ import { forwardRef } from "react"; const bottomBarVariants = cva("w-full gap-4", { variants: { direction: { - horizontal: "grid grid-cols-1 [&>*]:col-span-1 [&:has(>*:nth-child(2))]:grid-cols-2", + horizontal: "grid grid-cols-1 *:col-span-1 [&:has(>*:nth-child(2))]:grid-cols-2", vertical: "flex flex-col-reverse", }, }, diff --git a/packages/mini-apps-ui-kit-react/src/components/CircularIcon/CircularIcon.tsx b/packages/mini-apps-ui-kit-react/src/components/CircularIcon/CircularIcon.tsx index 03c78f02..fc084b0d 100644 --- a/packages/mini-apps-ui-kit-react/src/components/CircularIcon/CircularIcon.tsx +++ b/packages/mini-apps-ui-kit-react/src/components/CircularIcon/CircularIcon.tsx @@ -16,14 +16,14 @@ const sizeClasses: Record = { sm: "size-11", md: "size-12", lg: "size-16", - xl: "size-[5.5rem]", + xl: "size-22", }; const iconClasses: Record = { - xs: "size-[0.875rem]", - sm: "size-[1.5rem]", - md: "size-[1.625rem]", - lg: "size-[2.125rem]", + xs: "size-3.5", + sm: "size-6", + md: "size-6.5", + lg: "size-8.5", xl: "size-12", }; diff --git a/packages/mini-apps-ui-kit-react/src/components/CircularState/CircularState.tsx b/packages/mini-apps-ui-kit-react/src/components/CircularState/CircularState.tsx index f282e442..74286d46 100644 --- a/packages/mini-apps-ui-kit-react/src/components/CircularState/CircularState.tsx +++ b/packages/mini-apps-ui-kit-react/src/components/CircularState/CircularState.tsx @@ -34,7 +34,7 @@ function CircularState({ value, size, className, ...props }: CircularStateProps) "text-gray-0", size !== "xs" && "shadow-[inset_0_0_0_1px_rgba(255,255,255,0.3)]", iconClasses[value], - "bg-[radial-gradient(111.32%_111.8%_at_22.73%_0%,_rgba(255,255,255,0.2)_0%,_rgba(255,255,255,0)_100%)]", + "bg-[radial-gradient(111.32%_111.8%_at_22.73%_0%,rgba(255,255,255,0.2)_0%,rgba(255,255,255,0)_100%)]", className, )} size={size} diff --git a/packages/mini-apps-ui-kit-react/src/components/ColorPicker/ColorPicker.tsx b/packages/mini-apps-ui-kit-react/src/components/ColorPicker/ColorPicker.tsx index 72170191..84d6c69f 100644 --- a/packages/mini-apps-ui-kit-react/src/components/ColorPicker/ColorPicker.tsx +++ b/packages/mini-apps-ui-kit-react/src/components/ColorPicker/ColorPicker.tsx @@ -23,7 +23,7 @@ const ColorPickerItem = forwardRef( ( ({ children, label, description, startAdornment, endAdornment, disabled, ...props }, ref) => { return ( ); }, diff --git a/packages/mini-apps-ui-kit-react/src/components/Marble/Marble.tsx b/packages/mini-apps-ui-kit-react/src/components/Marble/Marble.tsx index 756fe8a9..8975308c 100644 --- a/packages/mini-apps-ui-kit-react/src/components/Marble/Marble.tsx +++ b/packages/mini-apps-ui-kit-react/src/components/Marble/Marble.tsx @@ -9,7 +9,7 @@ const Marble = forwardRef>((props, ref) ref={ref} alt="Marble" className={cn( - "rounded-full border-2 border-gray-100 p-[3px] aspect-square w-[7.5rem] object-cover", + "rounded-full border-2 border-gray-100 p-[3px] aspect-square w-30 object-cover", className, )} {...rest} diff --git a/packages/mini-apps-ui-kit-react/src/components/OTPField/OTPField.tsx b/packages/mini-apps-ui-kit-react/src/components/OTPField/OTPField.tsx index d68fd5c9..467b867c 100644 --- a/packages/mini-apps-ui-kit-react/src/components/OTPField/OTPField.tsx +++ b/packages/mini-apps-ui-kit-react/src/components/OTPField/OTPField.tsx @@ -16,7 +16,7 @@ import { typographyVariants } from "../Typography/Typography"; export const inputVariants = cva( cn( - "peer h-[3.5rem] w-full rounded-[0.625rem] border border-gray-100 bg-gray-100 px-4 outline-none transition duration-300", + "peer h-14 w-full rounded-[0.625rem] border border-gray-100 bg-gray-100 px-4 outline-none transition duration-300", "placeholder:text-gray-500", "focus:border-gray-300 focus:bg-gray-0 focus-visible:outline-none", "disabled:cursor-not-allowed disabled:opacity-50", @@ -121,7 +121,7 @@ const OTPField = React.forwardRef, OTPFieldPro inputMode={inputModeDictionary[mode]} pattern={pattern || patternDictionary[mode]} onChange={withHaptics(onChange)} - containerClassName="flex items-center gap-2 has-[:disabled]:opacity-50" + containerClassName="flex items-center gap-2 has-disabled:opacity-50" render={({ slots }) => ( <> {slots.map(({ isActive, char }, idx) => ( @@ -132,7 +132,7 @@ const OTPField = React.forwardRef, OTPFieldPro className={cn( inputVariants({ error }), typographyVariants({ variant: "body", level: 2 }), - "w-12 h-[4.25rem] rounded-lg flex items-center justify-center", + "w-12 h-17 rounded-lg flex items-center justify-center", (isActive || error) && "z-10 bg-gray-0", )} > diff --git a/packages/mini-apps-ui-kit-react/src/components/PhoneField/CountryListItem.tsx b/packages/mini-apps-ui-kit-react/src/components/PhoneField/CountryListItem.tsx index d961b502..309458c2 100644 --- a/packages/mini-apps-ui-kit-react/src/components/PhoneField/CountryListItem.tsx +++ b/packages/mini-apps-ui-kit-react/src/components/PhoneField/CountryListItem.tsx @@ -20,7 +20,7 @@ const CountryListItem = ({