diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 8c577ed58..4768369bb 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -147,7 +147,7 @@ module.exports = { extends: [ '@theguild', '@theguild/eslint-config/react', - 'plugin:tailwindcss/recommended', + 'plugin:better-tailwindcss/legacy-recommended', 'plugin:@next/next/recommended', ], settings: { @@ -159,13 +159,12 @@ module.exports = { }, rules: { // conflicts with official prettier-plugin-tailwindcss and tailwind v3 - 'tailwindcss/classnames-order': 'off', - 'tailwindcss/no-unnecessary-arbitrary-value': 'off', - // set more strict to highlight in editor - 'tailwindcss/enforces-shorthand': 'error', - 'tailwindcss/no-custom-classname': 'error', - 'tailwindcss/migration-from-tailwind-2': 'error', - 'tailwindcss/no-contradicting-classname': 'error', + 'better-tailwindcss/enforce-consistent-class-order': 'off', + 'better-tailwindcss/enforce-canonical-classes': 'warn', + // keeping classes in one line helps prettier-plugin-tailwindcss + // enable wrapping in text editors to make classes human readable + 'better-tailwindcss/enforce-consistent-line-wrapping': 'off', + 'better-tailwindcss/enforce-shorthand-classes': 'off', 'react/display-name': 'off', 'react/prop-types': 'off', 'react/no-unknown-property': 'off', @@ -198,13 +197,55 @@ module.exports = { { files: ['packages/web/app/**'], settings: { - tailwindcss: { + 'better-tailwindcss': { + // tailwindcss 4: the path to the entry file of the css based tailwind config (eg: `src/global.css`) + entryPoint: 'packages/web/app/src/index.css', callees: tailwindCallees, - config: path.join(__dirname, './packages/web/app/tailwind.config.ts'), - whitelist: ['drag-none'], - cssFiles: ['packages/web/app/src/index.css', 'node_modules/graphiql/dist/style.css'], }, }, + rules: { + // better-tailwindcss assumes you're using v4...we're being explicit here due to our dual tailwind setups + 'better-tailwindcss/no-deprecated-classes': 'error', + // Tailwind v4 uses CSS variables without var() syntax + 'better-tailwindcss/enforce-consistent-variable-syntax': 'off', + 'better-tailwindcss/no-unknown-classes': [ + 'error', + { + ignore: [ + 'drag-none', + // Tailwind v4 semantic colors from @theme in index.css + // Regex patterns to match all utility variants (bg-*, text-*, border-*, etc.) + // Includes optional opacity modifier (/40, /60, etc.) + '(bg|text|border|ring|outline|shadow|from|via|to|fill|stroke|caret|accent|divide|placeholder)-(background|foreground|card|card-foreground|popover|popover-foreground|primary|primary-foreground|secondary|secondary-foreground|muted|muted-foreground|accent|accent-foreground|destructive|destructive-foreground|border|input|ring|sidebar|sidebar-background|sidebar-foreground|sidebar-primary|sidebar-primary-foreground|sidebar-accent|sidebar-accent-foreground|sidebar-border|sidebar-ring|chart-1|chart-2)(/.*)?', + // Animation utilities (from index.css, replaces tailwindcss-animate) + 'animate-in', + 'animate-out', + 'fade-in-.*', + 'fade-out-.*', + 'zoom-in-.*', + 'zoom-out-.*', + 'slide-in-from-.*', + 'slide-out-to-.*', + // Custom radius from @theme + 'rounded-xs', + // ring-offset with semantic colors + 'ring-offset-.*', + // Data attribute variants with custom animations (for Radix UI components) + 'data-\\[side=(top|right|bottom|left)\\]:animate-slide-(up|down|left|right)-fade', + // GraphiQL classes + 'graphiql-.*', + // hive classes + 'hive-.*', + // Schema diff custom classes (defined in index.css) + 'schema-doc-row-.*', + // No scrollbar utility (defined in index.css) + 'no-scrollbar', + // Tailwind v4 CSS variable syntax with parentheses + '.*-\\(--.*\\)', + ], + }, + ], + }, }, { files: ['packages/web/app/**/*.stories.tsx', 'packages/web/docs/**'], @@ -218,23 +259,38 @@ module.exports = { next: { rootDir: 'packages/web/docs', }, - tailwindcss: { + 'better-tailwindcss': { + // tailwindcss 3: the path to the tailwind config file (eg: `tailwind.config.js`) + tailwindConfig: 'packages/web/docs/tailwind.config.ts', callees: tailwindCallees, - whitelist: [ - 'light', - 'hive-focus', - 'hive-focus-within', - 'nextra-scrollbar', - 'no-scrollbar', // from Nextra - 'hive-slider', - 'hive-prose', - 'subheader', - ], - config: path.join(__dirname, './packages/web/docs/tailwind.config.ts'), }, }, rules: { 'import/extensions': 'off', + // better-tailwindcss assumes you're using v4...we're being explicit here due to our dual tailwind setups + 'better-tailwindcss/no-deprecated-classes': 'off', + 'better-tailwindcss/no-unknown-classes': [ + 'error', + { + ignore: [ + 'light', + 'hive-focus', + 'hive-focus-within', + 'nextra-focus', + 'nextra-scrollbar', + 'no-scrollbar', // from Nextra + 'hive-slider', + 'hive-prose', + 'subheader', + 'subheading-anchor', + 'duration-\\[.*\\]', // Allow arbitrary duration values like duration-[.8s] + 'ease-\\[var\\(--.*\\)\\]', // Allow CSS variables in arbitrary ease values + 'x:.*', // Allow Nextra 4 custom variant prefix + ], + }, + ], + // Allow CSS variables in arbitrary values for Tailwind v3 + 'better-tailwindcss/enforce-consistent-variable-syntax': 'off', }, }, { diff --git a/.github/workflows/release-stable.yaml b/.github/workflows/release-stable.yaml index 9eb8f638f..24cfc613e 100644 --- a/.github/workflows/release-stable.yaml +++ b/.github/workflows/release-stable.yaml @@ -57,14 +57,21 @@ jobs: with: toolchain: stable + # see https://github.com/changesets/action/issues/523 + - name: fix gh-api issues with changesets + run: | + echo "Cargo.lock" >> .gitignore + git ls-files | while read -r file; do [ -x "$file" ] && chmod -x "$file" || true; done + - name: publish stable id: changesets - uses: changesets/action@06245a4e0a36c064a573d4150030f5ec548e4fcc # v1.4.10 + uses: changesets/action@e0145edc7d9d8679003495b11f87bd8ef63c0cba # v1.5.3 with: publish: pnpm release version: pnpm release:version commit: 'chore(release): update monorepo packages versions' title: 'Upcoming Release Changes' + commitMode: github-api env: GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }} diff --git a/.npmrc b/.npmrc index 73925186b..05ef7f4dd 100644 --- a/.npmrc +++ b/.npmrc @@ -1,3 +1,6 @@ enable-pre-post-scripts=true shamefully-hoist=true +public-hoist-pattern[]=@tailwindcss/vite +public-hoist-pattern[]=!tailwindcss +public-hoist-pattern[]=!@tailwindcss/* engine-strict=true diff --git a/package.json b/package.json index 73d25b539..0005b4b58 100644 --- a/package.json +++ b/package.json @@ -89,9 +89,9 @@ "cypress": "13.17.0", "dotenv": "16.4.7", "eslint": "8.57.1", + "eslint-plugin-better-tailwindcss": "^4.0.0", "eslint-plugin-cypress": "4.1.0", "eslint-plugin-hive": "file:rules", - "eslint-plugin-tailwindcss": "npm:@hasparus/eslint-plugin-tailwindcss@3.17.5", "fs-extra": "11.2.0", "graphql": "16.9.0", "gray-matter": "4.0.3", @@ -134,6 +134,9 @@ "ip": "npm:neoip@2.1.0", "miniflare@3>undici": "^7.18.2", "tailwindcss": "3.4.17", + "@hive/app>tailwindcss": "4.1.18", + "@tailwindcss/node>tailwindcss": "4.1.18", + "@tailwindcss/vite>tailwindcss": "4.1.18", "estree-util-value-to-estree": "^3.3.3", "nodemailer@^6.0.0": "^7.0.11", "@types/nodemailer>@aws-sdk/client-sesv2": "-", diff --git a/packages/web/app/package.json b/packages/web/app/package.json index 50eefd12a..c17eba140 100644 --- a/packages/web/app/package.json +++ b/packages/web/app/package.json @@ -69,6 +69,7 @@ "@storybook/react-vite": "8.6.15", "@stripe/react-stripe-js": "3.1.1", "@stripe/stripe-js": "5.5.0", + "@tailwindcss/vite": "^4.1.18", "@tanstack/react-form": "^1.27.0", "@tanstack/react-query": "5.63.0", "@tanstack/react-router": "1.34.9", @@ -93,7 +94,6 @@ "@urql/exchange-graphcache": "7.1.0", "@vitejs/plugin-react": "4.3.4", "@xyflow/react": "12.4.4", - "autoprefixer": "10.4.21", "class-variance-authority": "0.7.1", "clsx": "2.1.1", "cmdk": "0.2.1", @@ -149,9 +149,7 @@ "supertokens-auth-react": "0.38.0", "supertokens-web-js": "0.9.0", "tailwind-merge": "2.6.0", - "tailwindcss": "3.4.17", - "tailwindcss-animate": "1.0.7", - "tailwindcss-radix": "3.0.5", + "tailwindcss": "4.1.18", "tslib": "2.8.1", "tsx": "4.19.2", "urql": "4.1.0", diff --git a/packages/web/app/postcss.config.mjs b/packages/web/app/postcss.config.mjs deleted file mode 100644 index 9eef821c4..000000000 --- a/packages/web/app/postcss.config.mjs +++ /dev/null @@ -1,6 +0,0 @@ -export default { - plugins: { - autoprefixer: {}, - tailwindcss: {}, - }, -}; diff --git a/packages/web/app/src/components/common/index.tsx b/packages/web/app/src/components/common/index.tsx index 9e31e30bc..0ce19569e 100644 --- a/packages/web/app/src/components/common/index.tsx +++ b/packages/web/app/src/components/common/index.tsx @@ -5,7 +5,7 @@ export function Label({ className, children, ...props }: ComponentProps<'span'>) return ( @@ -50,7 +50,7 @@ export function GetStartedProgress(props: { {remaining} remaining task{remaining > 1 ? 's' : ''}
-
+
-
+
-
+
{currentOrganization ? ( @@ -383,7 +383,7 @@ export function CreateProjectModalContent(props: { }) { return ( - +
diff --git a/packages/web/app/src/components/layouts/project.tsx b/packages/web/app/src/components/layouts/project.tsx index f1bd13ac2..8802a3f78 100644 --- a/packages/web/app/src/components/layouts/project.tsx +++ b/packages/web/app/src/components/layouts/project.tsx @@ -87,7 +87,7 @@ export function ProjectLayout({ return ( <>
-
+
) : ( <> -
+
{currentOrganization && currentProject ? ( @@ -298,7 +298,7 @@ export function CreateTargetModalContent(props: { }) { return ( - + diff --git a/packages/web/app/src/components/layouts/target.tsx b/packages/web/app/src/components/layouts/target.tsx index 409188c86..6923d9f69 100644 --- a/packages/web/app/src/components/layouts/target.tsx +++ b/packages/web/app/src/components/layouts/target.tsx @@ -157,7 +157,7 @@ export const TargetLayout = ({ targetSlug={props.targetSlug} >
-
+
) : ( <> -
+
{currentOrganization && currentProject && currentTarget ? ( diff --git a/packages/web/app/src/components/organization/billing/BillingPlanPicker.tsx b/packages/web/app/src/components/organization/billing/BillingPlanPicker.tsx index 88e017010..e345fba48 100644 --- a/packages/web/app/src/components/organization/billing/BillingPlanPicker.tsx +++ b/packages/web/app/src/components/organization/billing/BillingPlanPicker.tsx @@ -138,13 +138,13 @@ export function BillingPlanPicker({ }): ReactElement { const plans = useFragment(BillingPlanPicker_PlanFragment, props.plans); return ( - + {plans.map(plan => ( diff --git a/packages/web/app/src/components/target/explorer/common.tsx b/packages/web/app/src/components/target/explorer/common.tsx index a42ab3e62..ae6c3421f 100644 --- a/packages/web/app/src/components/target/explorer/common.tsx +++ b/packages/web/app/src/components/target/explorer/common.tsx @@ -62,7 +62,7 @@ export function SchemaExplorerUsageStats(props: {
diff --git a/packages/web/app/src/components/target/laboratory/create-collection-modal.tsx b/packages/web/app/src/components/target/laboratory/create-collection-modal.tsx index 61eac5bb8..5d9b84bcd 100644 --- a/packages/web/app/src/components/target/laboratory/create-collection-modal.tsx +++ b/packages/web/app/src/components/target/laboratory/create-collection-modal.tsx @@ -235,10 +235,7 @@ export function CreateCollectionModalContent(props: { }) { return ( - + {!props.fetching && ( diff --git a/packages/web/app/src/components/target/laboratory/create-operation-modal.tsx b/packages/web/app/src/components/target/laboratory/create-operation-modal.tsx index a89303ce0..bed9e6fd6 100644 --- a/packages/web/app/src/components/target/laboratory/create-operation-modal.tsx +++ b/packages/web/app/src/components/target/laboratory/create-operation-modal.tsx @@ -190,10 +190,7 @@ export function CreateOperationModalContent(props: { props.form.reset(); }} > - + {!props.fetching && ( @@ -231,7 +228,7 @@ export function CreateOperationModalContent(props: { {props.collections.find(c => c.id === field.value)?.name ?? 'Select a Collection'} - + {props.collections.map(c => ( {c.name} diff --git a/packages/web/app/src/components/target/laboratory/edit-operation-modal.tsx b/packages/web/app/src/components/target/laboratory/edit-operation-modal.tsx index 35eb13814..27b081a59 100644 --- a/packages/web/app/src/components/target/laboratory/edit-operation-modal.tsx +++ b/packages/web/app/src/components/target/laboratory/edit-operation-modal.tsx @@ -167,10 +167,7 @@ export const EditOperationModalContent = (props: { props.form.reset(); }} > - + {!props.fetching && ( diff --git a/packages/web/app/src/components/target/proposals/Review.tsx b/packages/web/app/src/components/target/proposals/Review.tsx index 6a6f069db..3afd299fc 100644 --- a/packages/web/app/src/components/target/proposals/Review.tsx +++ b/packages/web/app/src/components/target/proposals/Review.tsx @@ -34,7 +34,7 @@ export function ReviewComments(props: { return ( <> -
+
{review.comments?.edges?.map(({ node: comment }, idx) => { return ( diff --git a/packages/web/app/src/components/target/proposals/editor.tsx b/packages/web/app/src/components/target/proposals/editor.tsx index ce0d25b90..43482693e 100644 --- a/packages/web/app/src/components/target/proposals/editor.tsx +++ b/packages/web/app/src/components/target/proposals/editor.tsx @@ -391,7 +391,7 @@ export function ProposalEditor(props: { ? `new-${idx}` : `tab-${service.id}` } - className="relative mt-0 rounded border py-0" + className="relative mt-0 rounded-sm border py-0" > void; }) { return ( - + Token successfully created! @@ -197,7 +194,7 @@ export function GenerateTokenContent(props: { noPermissionsSelected: boolean; }) { return ( - + {/** LOL https://github.com/radix-ui/primitives/issues/2722 */} - + {children} diff --git a/packages/web/app/src/components/ui/select.tsx b/packages/web/app/src/components/ui/select.tsx index 0155789a6..80193c2b8 100644 --- a/packages/web/app/src/components/ui/select.tsx +++ b/packages/web/app/src/components/ui/select.tsx @@ -67,7 +67,7 @@ const SelectContent = React.forwardRef< className={cn( 'p-1', position === 'popper' && - 'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]', + 'max-h-(--radix-select-content-available-height) min-w-(--radix-select-trigger-width) w-full', )} > {children} @@ -96,7 +96,7 @@ const SelectItem = React.forwardRef< ) : ( - + diff --git a/packages/web/app/src/laboratory/components/laboratory/collections.tsx b/packages/web/app/src/laboratory/components/laboratory/collections.tsx index 5d83ad7bd..0f77c2203 100644 --- a/packages/web/app/src/laboratory/components/laboratory/collections.tsx +++ b/packages/web/app/src/laboratory/components/laboratory/collections.tsx @@ -80,7 +80,7 @@ export const CollectionItem = (props: { collection: LaboratoryCollection }) => {