From 3fade11319560741c8b46ce448ddeb77a82b2fcd Mon Sep 17 00:00:00 2001 From: aammami-ledger Date: Fri, 9 Jan 2026 11:50:16 +0100 Subject: [PATCH 01/16] chore(dependencies): upgrade Tailwind CSS to v4.1.17. --- apps/app-sandbox-react/postcss.config.js | 5 +- apps/app-sandbox-react/src/global.css | 5 +- apps/app-sandbox-react/vite.config.ts | 6 +- libs/design-core/README.md | 4 +- libs/design-core/package.json | 2 +- libs/design-core/src/presets/allBrands.ts | 4 +- libs/design-core/src/presets/enterprise.ts | 4 +- libs/design-core/src/presets/ledger-live.ts | 4 +- libs/design-core/src/presets/websites.ts | 4 +- .../src/utils/createAnimationsPlugin.ts | 4 +- .../src/utils/createCustomPlugin.ts | 10 +- .../src/utils/createPrimitivesPlugin.ts | 7 +- .../.storybook/components/ComponentCard.tsx | 4 +- .../.storybook/components/CustomTabs.tsx | 2 +- .../components/DoVsDont/DoBlock.tsx | 8 +- .../components/DoVsDont/DoVsDontRow.tsx | 2 +- .../components/DoVsDont/DontBlock.tsx | 8 +- libs/ui-react/.storybook/docs/QuickStart.mdx | 2 +- .../.storybook/docs/SetupTailwind.mdx | 10 +- libs/ui-react/.storybook/main.ts | 5 +- .../Components/AddressInput/AddressInput.tsx | 4 +- .../Components/AmountInput/AmountInput.tsx | 4 +- .../lib/Components/BaseInput/BaseInput.tsx | 12 +- .../src/lib/Components/Button/BaseButton.tsx | 2 +- .../lib/Components/CardButton/CardButton.tsx | 2 +- .../src/lib/Components/Checkbox/Checkbox.tsx | 2 +- .../Design-tokens/styles/backdrop.stories.tsx | 2 +- .../ui-react/src/lib/Components/Menu/Menu.tsx | 4 +- .../Components/SearchInput/SearchInput.tsx | 2 +- .../src/lib/Components/Select/Select.tsx | 18 +- .../src/lib/Components/Switch/Switch.tsx | 4 +- .../src/lib/Components/Tooltip/Tooltip.tsx | 2 +- libs/ui-react/src/styles.css | 5 +- package-lock.json | 1146 +++++++++++------ package.json | 8 +- 35 files changed, 835 insertions(+), 482 deletions(-) diff --git a/apps/app-sandbox-react/postcss.config.js b/apps/app-sandbox-react/postcss.config.js index 6e11d077e..b7ca7c7de 100644 --- a/apps/app-sandbox-react/postcss.config.js +++ b/apps/app-sandbox-react/postcss.config.js @@ -5,9 +5,6 @@ export default { plugins: { - tailwindcss: { - config: './tailwind.config.ts', - }, - autoprefixer: {}, + '@tailwindcss/postcss': {}, }, }; diff --git a/apps/app-sandbox-react/src/global.css b/apps/app-sandbox-react/src/global.css index b5c61c956..37eb4665d 100644 --- a/apps/app-sandbox-react/src/global.css +++ b/apps/app-sandbox-react/src/global.css @@ -1,3 +1,2 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +@import 'tailwindcss'; +@config '../tailwind.config.ts'; diff --git a/apps/app-sandbox-react/vite.config.ts b/apps/app-sandbox-react/vite.config.ts index 042a2d009..b7b64ba9f 100644 --- a/apps/app-sandbox-react/vite.config.ts +++ b/apps/app-sandbox-react/vite.config.ts @@ -1,4 +1,5 @@ /// +import tailwindcss from '@tailwindcss/vite'; import react from '@vitejs/plugin-react'; import { defineConfig } from 'vite'; @@ -13,10 +14,7 @@ export default defineConfig(() => ({ port: 4300, host: 'localhost', }, - css: { - postcss: './postcss.config.js', - }, - plugins: [react()], + plugins: [tailwindcss(), react()], // Uncomment this if you are using workers. // worker: { // plugins: [ nxViteTsPaths() ], diff --git a/libs/design-core/README.md b/libs/design-core/README.md index 83d85dd63..6d9d47feb 100644 --- a/libs/design-core/README.md +++ b/libs/design-core/README.md @@ -8,10 +8,10 @@ npm install @ledgerhq/lumen-design-core # Install required peer dependency -npm install tailwindcss +npm install tailwindcss@^4.1.17 @tailwindcss/postcss ``` -**Note:** Tailwind CSS v3.x is required as a peer dependency. Not compatible yet with Tailwind CSS v4. +**Note:** Tailwind CSS v4.x is the supported peer dependency. ## ⚡ Quick Setup diff --git a/libs/design-core/package.json b/libs/design-core/package.json index 5239fd440..62dcc880e 100644 --- a/libs/design-core/package.json +++ b/libs/design-core/package.json @@ -27,7 +27,7 @@ "!dist/figma/*" ], "dependencies": { - "tailwindcss": "^3.4.0", + "tailwindcss": "^4.1.17", "tslib": "^2.3.0" } } diff --git a/libs/design-core/src/presets/allBrands.ts b/libs/design-core/src/presets/allBrands.ts index 5e997f688..a8af7dcd0 100644 --- a/libs/design-core/src/presets/allBrands.ts +++ b/libs/design-core/src/presets/allBrands.ts @@ -9,7 +9,7 @@ import { createShadowPlugin, } from '../utils/index.js'; -export const allBrandsPreset = { +export const allBrandsPreset: Config = { content: [], theme: { boxShadow: {}, @@ -26,4 +26,4 @@ export const allBrandsPreset = { createAnimationsPlugin(), ], darkMode: 'class', -} satisfies Config; +}; diff --git a/libs/design-core/src/presets/enterprise.ts b/libs/design-core/src/presets/enterprise.ts index ee7258f47..0bf15af40 100644 --- a/libs/design-core/src/presets/enterprise.ts +++ b/libs/design-core/src/presets/enterprise.ts @@ -10,7 +10,7 @@ import { createShadowPlugin, } from '../utils/index.js'; -export const enterprisePreset = { +export const enterprisePreset: Config = { content: [], theme: { boxShadow: {}, @@ -27,4 +27,4 @@ export const enterprisePreset = { createAnimationsPlugin(), ], darkMode: 'class', -} satisfies Config; +}; diff --git a/libs/design-core/src/presets/ledger-live.ts b/libs/design-core/src/presets/ledger-live.ts index e31275abd..985936b2e 100644 --- a/libs/design-core/src/presets/ledger-live.ts +++ b/libs/design-core/src/presets/ledger-live.ts @@ -9,7 +9,7 @@ import { createShadowPlugin, } from '../utils/index.js'; -export const ledgerLivePreset = { +export const ledgerLivePreset: Config = { content: [], theme: { boxShadow: {}, @@ -26,4 +26,4 @@ export const ledgerLivePreset = { createAnimationsPlugin(), ], darkMode: 'class', -} satisfies Config; +}; diff --git a/libs/design-core/src/presets/websites.ts b/libs/design-core/src/presets/websites.ts index 44bbf0d2a..80cad3ac2 100644 --- a/libs/design-core/src/presets/websites.ts +++ b/libs/design-core/src/presets/websites.ts @@ -10,7 +10,7 @@ import { createShadowPlugin, } from '../utils/index.js'; -export const websitesPreset = { +export const websitesPreset: Config = { content: [], theme: { boxShadow: {}, @@ -27,4 +27,4 @@ export const websitesPreset = { createAnimationsPlugin(), ], darkMode: 'class', -} satisfies Config; +}; diff --git a/libs/design-core/src/utils/createAnimationsPlugin.ts b/libs/design-core/src/utils/createAnimationsPlugin.ts index 54652a99f..eb4a6981e 100644 --- a/libs/design-core/src/utils/createAnimationsPlugin.ts +++ b/libs/design-core/src/utils/createAnimationsPlugin.ts @@ -1,6 +1,8 @@ import plugin from 'tailwindcss/plugin.js'; -export function createAnimationsPlugin() { +type TailwindPlugin = ReturnType; + +export function createAnimationsPlugin(): TailwindPlugin { return plugin( () => {}, // eslint-disable-line @typescript-eslint/no-empty-function { diff --git a/libs/design-core/src/utils/createCustomPlugin.ts b/libs/design-core/src/utils/createCustomPlugin.ts index d53c4b2da..a5f4d22e3 100644 --- a/libs/design-core/src/utils/createCustomPlugin.ts +++ b/libs/design-core/src/utils/createCustomPlugin.ts @@ -1,6 +1,8 @@ import plugin from 'tailwindcss/plugin.js'; import { getThemeUtilsByPrefix } from './getThemeUtilsByPrefix.js'; +type TailwindPlugin = ReturnType; + const DEFAULT_COLOR_VALUES = { transparent: 'transparent', inherit: 'inherit', @@ -16,7 +18,7 @@ function extendWithDefaultColors>(colors: T) { export function createThemePlugin( brandTheme: Record>, -) { +): TailwindPlugin { const cryptoColor = getThemeUtilsByPrefix(brandTheme, '--color-crypto-', { customPrefix: 'crypto-', }); @@ -65,7 +67,7 @@ export function createThemePlugin( ); } -export function createTypographyPlugin() { +export function createTypographyPlugin(): TailwindPlugin { return plugin(function ({ addUtilities }) { const fontSmoothing = { '-webkit-font-smoothing': 'antialiased', @@ -315,7 +317,7 @@ function extractCryptoNames( export function createGradientPlugin( brandTheme?: Record>, -) { +): TailwindPlugin { return plugin(function ({ addUtilities }) { const gradientStyles = { '.bg-gradient-top': { @@ -354,7 +356,7 @@ export function createGradientPlugin( }); } -export function createShadowPlugin() { +export function createShadowPlugin(): TailwindPlugin { return plugin(function ({ theme, addUtilities, matchUtilities }) { const defaultColor = 'rgba(0, 0, 0, 0.10)'; const strongDefaultColor = 'rgba(0, 0, 0, 0.25)'; diff --git a/libs/design-core/src/utils/createPrimitivesPlugin.ts b/libs/design-core/src/utils/createPrimitivesPlugin.ts index 28e958d45..a2fdaf91f 100644 --- a/libs/design-core/src/utils/createPrimitivesPlugin.ts +++ b/libs/design-core/src/utils/createPrimitivesPlugin.ts @@ -1,11 +1,12 @@ import plugin from 'tailwindcss/plugin.js'; -import { CSSRuleObject } from 'tailwindcss/types/config.js'; + +type TailwindPlugin = ReturnType; import { primitivesTheme } from '../themes/css'; import { createIconUtilities } from './createIconUtilities.js'; import { createSpotUtilities } from './createSpotUtilities.js'; import { getThemeUtilsByPrefix } from './getThemeUtilsByPrefix.js'; -export function createPrimitivesPlugin() { +export function createPrimitivesPlugin(): TailwindPlugin { const spacing = getThemeUtilsByPrefix(primitivesTheme, '--spacing-'); const size = getThemeUtilsByPrefix(primitivesTheme, '--size-'); const borderRadius = getThemeUtilsByPrefix( @@ -37,7 +38,7 @@ export function createPrimitivesPlugin() { return plugin( function ({ addBase, theme, addUtilities }) { // TODO: Remove type cast after exporting all values as strings from Figma - addBase(primitivesTheme as CSSRuleObject); + addBase(primitivesTheme as never); addUtilities(createIconUtilities(theme)); addUtilities(createSpotUtilities(theme)); }, diff --git a/libs/ui-react/.storybook/components/ComponentCard.tsx b/libs/ui-react/.storybook/components/ComponentCard.tsx index 690c0c09f..abc3f7f35 100644 --- a/libs/ui-react/.storybook/components/ComponentCard.tsx +++ b/libs/ui-react/.storybook/components/ComponentCard.tsx @@ -39,11 +39,11 @@ export const ComponentCard: React.FC = ({ {/* Content area */}
-

+

{emoji &&
{emoji}
} {title}

-

+

{emoji &&
{emoji}
} {title}

diff --git a/libs/ui-react/.storybook/components/CustomTabs.tsx b/libs/ui-react/.storybook/components/CustomTabs.tsx index cbe930af4..d61318c1a 100644 --- a/libs/ui-react/.storybook/components/CustomTabs.tsx +++ b/libs/ui-react/.storybook/components/CustomTabs.tsx @@ -32,7 +32,7 @@ export const CustomTabs: React.FC = ({ children }) => { diff --git a/libs/ui-react/src/lib/Components/Link/Link.stories.tsx b/libs/ui-react/src/lib/Components/Link/Link.stories.tsx index 1d5a4808a..5c59f75f4 100644 --- a/libs/ui-react/src/lib/Components/Link/Link.stories.tsx +++ b/libs/ui-react/src/lib/Components/Link/Link.stories.tsx @@ -314,7 +314,7 @@ import { Link as RouterLink } from 'react-router-dom'; export const InheritVariants: Story = { render: () => (
-
+
By continuing, you agree to our{' '} Terms & Conditions @@ -326,14 +326,14 @@ export const InheritVariants: Story = { .
-
+
Need help?{' '} Contact Support
-
+
Learn more about security in our{' '} Security Guide @@ -341,7 +341,7 @@ export const InheritVariants: Story = { .
-
+
Already have an account?{' '} Sign in diff --git a/libs/ui-react/src/lib/Components/ListItem/ListItem.stories.tsx b/libs/ui-react/src/lib/Components/ListItem/ListItem.stories.tsx index 3395b2a0a..4418853f4 100644 --- a/libs/ui-react/src/lib/Components/ListItem/ListItem.stories.tsx +++ b/libs/ui-react/src/lib/Components/ListItem/ListItem.stories.tsx @@ -345,7 +345,7 @@ export const DisabledState: Story = { export const ResponsiveLayout: Story = { render: () => (
-
Container: 320px wide
+
Container: 320px wide
diff --git a/libs/ui-react/src/lib/Components/ListItem/ListItem.tsx b/libs/ui-react/src/lib/Components/ListItem/ListItem.tsx index 995f1b96c..0d98ee9c4 100644 --- a/libs/ui-react/src/lib/Components/ListItem/ListItem.tsx +++ b/libs/ui-react/src/lib/Components/ListItem/ListItem.tsx @@ -159,7 +159,7 @@ export const ListItemDescription = React.forwardRef<
{/* Search status indicator */} {isSearching && ( -
Searching...
+
Searching...
)} {/* Results */} {inputValue.length > 0 && !isSearching && (
{filteredResults.length > 0 ? (
-

+

Found {filteredResults.length} result {filteredResults.length !== 1 ? 's' : ''} for "{searchQuery}"

@@ -232,8 +232,8 @@ export const DebouncedSearchInput: Story = {
) : (
-

Nothing found

-

+

Nothing found

+

No fruits match "{searchQuery}"

diff --git a/libs/ui-react/src/lib/Components/Select/Select.stories.tsx b/libs/ui-react/src/lib/Components/Select/Select.stories.tsx index 2d58e3bd8..162c4d997 100644 --- a/libs/ui-react/src/lib/Components/Select/Select.stories.tsx +++ b/libs/ui-react/src/lib/Components/Select/Select.stories.tsx @@ -234,14 +234,14 @@ export const WithDescription: Story = { className='flex flex-col items-start justify-start gap-2' > Option 1 -
this is a description
+
this is a description
Option 2 -
this is a description
+
this is a description
diff --git a/libs/ui-react/src/lib/Components/Select/Select.tsx b/libs/ui-react/src/lib/Components/Select/Select.tsx index ffda44231..88156d5ef 100644 --- a/libs/ui-react/src/lib/Components/Select/Select.tsx +++ b/libs/ui-react/src/lib/Components/Select/Select.tsx @@ -26,9 +26,9 @@ function SelectGroup({ ...props }: SelectGroupProps) { const triggerStyles = cn( 'group relative flex h-48 w-full items-center justify-between gap-8', 'rounded-sm bg-muted px-16', - 'text-base body-2', + 'body-2 text-base', 'hover:bg-muted-hover', - 'transition-colors duration-200 focus:outline-hidden focus:ring-2 focus:ring-focus', + 'transition-colors duration-200 focus:ring-2 focus:ring-focus focus:outline-hidden', 'disabled:cursor-not-allowed disabled:text-disabled', ); @@ -36,7 +36,8 @@ const labelStyles = cn( 'pointer-events-none absolute left-16 origin-left text-muted transition-all duration-300', 'top-10 -translate-y-4 body-4', 'group-data-placeholder:top-14 group-data-placeholder:translate-y-0 group-data-placeholder:body-2', - 'group-data-[:disabled]:text-disabled disabled:text-disabled group-data-disabled:text-disabled group-data-[placeholder][disabled]:text-disabled', + // eslint-disable-next-line better-tailwindcss/no-unknown-classes + 'group-data-[placeholder][disabled]:text-disabled group-data-:disabled:text-disabled group-data-disabled:text-disabled disabled:text-disabled', 'max-w-[calc(100%-var(--size-56))] truncate', ); @@ -55,7 +56,7 @@ const SelectTrigger = React.forwardRef< )} )); SelectLabel.displayName = SelectPrimitive.Label.displayName; const itemStyles = cn( - 'relative flex w-full cursor-default select-none items-center bg-base-transparent', + 'relative flex w-full cursor-default items-center bg-base-transparent select-none', 'rounded-sm p-8', - 'text-base body-2', + 'body-2 text-base', 'outline-hidden', 'focus:bg-base-transparent-hover', 'active:bg-base-transparent-pressed', @@ -193,7 +194,7 @@ const SelectItemText = React.forwardRef< )); diff --git a/libs/ui-react/src/lib/Components/Spinner/Spinner.stories.tsx b/libs/ui-react/src/lib/Components/Spinner/Spinner.stories.tsx index de9743192..22657999e 100644 --- a/libs/ui-react/src/lib/Components/Spinner/Spinner.stories.tsx +++ b/libs/ui-react/src/lib/Components/Spinner/Spinner.stories.tsx @@ -39,31 +39,31 @@ export const Sizes: Story = {
- 12 + 12
- 16 + 16
- 20 + 20
- 24 + 24
- 40 + 40
- 48 + 48
- 56 + 56
), diff --git a/libs/ui-react/src/lib/Components/Subheader/Subheader.stories.tsx b/libs/ui-react/src/lib/Components/Subheader/Subheader.stories.tsx index 2c46ec8ba..53ccb5311 100644 --- a/libs/ui-react/src/lib/Components/Subheader/Subheader.stories.tsx +++ b/libs/ui-react/src/lib/Components/Subheader/Subheader.stories.tsx @@ -246,7 +246,7 @@ export const ContentVariations: Story = { export const ResponsiveLayout: Story = { render: () => ( -
+
Container with a fixed width
diff --git a/libs/ui-react/src/lib/Components/TextInput/TextInput.stories.tsx b/libs/ui-react/src/lib/Components/TextInput/TextInput.stories.tsx index b3a0d62fb..250500818 100644 --- a/libs/ui-react/src/lib/Components/TextInput/TextInput.stories.tsx +++ b/libs/ui-react/src/lib/Components/TextInput/TextInput.stories.tsx @@ -175,7 +175,7 @@ export const HiddenClearButton: Story = { onChange={(e) => setValue(e.target.value)} hideClearButton /> -
+
Use hideClearButton to prevent the clear button from appearing.
@@ -217,7 +217,7 @@ export const WithError: Story = { !isValidEmail ? 'Please enter a valid email address' : undefined } /> -
+
Try typing a valid email address or clicking the clear button to remove the error state
@@ -324,7 +324,7 @@ export const WithCustomElement: Story = { />
-
+
The suffix prop allows you to add custom interactive elements like tooltips, or action buttons
@@ -413,10 +413,10 @@ export const Interactive: Story = { if (isSubmitted) { return (
-
+
✓ Form submitted successfully!
-
Resetting form...
+
Resetting form...
); } @@ -487,7 +487,7 @@ export const Interactive: Story = {
-
+
This example demonstrates form validation, error handling, clear buttons, and right elements working together.
diff --git a/libs/ui-react/src/lib/Components/Tile/Tile.stories.tsx b/libs/ui-react/src/lib/Components/Tile/Tile.stories.tsx index b8ea2ce8c..79b7b0b14 100644 --- a/libs/ui-react/src/lib/Components/Tile/Tile.stories.tsx +++ b/libs/ui-react/src/lib/Components/Tile/Tile.stories.tsx @@ -127,7 +127,7 @@ export const VariantsShowcase: Story = { With Trailing Content Additional information -
+7.87%
+
+7.87%
), diff --git a/libs/ui-react/src/lib/Components/Tile/Tile.tsx b/libs/ui-react/src/lib/Components/Tile/Tile.tsx index 658a12dd0..cd053b5da 100644 --- a/libs/ui-react/src/lib/Components/Tile/Tile.tsx +++ b/libs/ui-react/src/lib/Components/Tile/Tile.tsx @@ -24,7 +24,7 @@ const tileVariants = { root: cva( [ 'group relative flex flex-col items-center gap-8 text-base transition-colors', - 'focus-visible:outline-focus rounded-md focus-visible:outline-2', + 'rounded-md focus-visible:outline-2 focus-visible:outline-focus', ], { variants: { @@ -75,7 +75,7 @@ const tileVariants = { }, ), button: cva( - 'focus-visible:outline-focus flex w-full flex-col items-center gap-8 rounded-md px-8 py-12 focus-visible:outline-2', + 'flex w-full flex-col items-center gap-8 rounded-md px-8 py-12 focus-visible:outline-2 focus-visible:outline-focus', ), }; @@ -254,7 +254,7 @@ export const TileTitle = ({ return (
(
-

Compare different delay durations

+

Compare different delay durations

diff --git a/libs/ui-react/src/lib/Components/Tooltip/Tooltip.tsx b/libs/ui-react/src/lib/Components/Tooltip/Tooltip.tsx index cfc49606e..3f2a4ce6d 100644 --- a/libs/ui-react/src/lib/Components/Tooltip/Tooltip.tsx +++ b/libs/ui-react/src/lib/Components/Tooltip/Tooltip.tsx @@ -9,7 +9,7 @@ import { } from './types'; const tooltipContentVariants = cva( - 'z-tooltip w-fit select-none text-balance rounded-xs bg-interactive px-8 py-4 text-on-interactive body-3', + 'z-tooltip w-fit rounded-xs bg-interactive px-8 py-4 body-3 text-balance text-on-interactive select-none', { variants: { side: { From acb55cc6d92b686f5e4021c94f66c0d55be55fef Mon Sep 17 00:00:00 2001 From: aammami-ledger Date: Mon, 12 Jan 2026 10:50:27 +0100 Subject: [PATCH 05/16] refactor(animations): remove 8px offset slide animations from createAnimationsPlugin --- .../src/utils/createAnimationsPlugin.ts | 87 +------------------ .../src/lib/Components/Select/Select.tsx | 13 ++- 2 files changed, 7 insertions(+), 93 deletions(-) diff --git a/libs/design-core/src/utils/createAnimationsPlugin.ts b/libs/design-core/src/utils/createAnimationsPlugin.ts index eb4a6981e..8b120e2fb 100644 --- a/libs/design-core/src/utils/createAnimationsPlugin.ts +++ b/libs/design-core/src/utils/createAnimationsPlugin.ts @@ -62,44 +62,7 @@ export function createAnimationsPlugin(): TailwindPlugin { }, to: { transform: 'translateX(0px)', opacity: '1' }, }, - // Slide in animations (8px offset) - 'slide-in-from-top-8': { - from: { - transform: 'translateY(calc(var(--spacing-10) * -1))', - opacity: '0', - }, - to: { transform: 'translateY(var(--spacing-8))', opacity: '1' }, - }, - 'slide-in-from-bottom-8': { - from: { - transform: 'translateY(var(--spacing-10))', - opacity: '0', - }, - to: { - transform: 'translateY(calc(var(--spacing-8) * -1))', - opacity: '1', - }, - }, - 'slide-in-from-left-8': { - from: { - transform: 'translateX(calc(var(--spacing-10) * -1))', - opacity: '0', - }, - to: { - transform: 'translateX(calc(var(--spacing-8) * -1))', - opacity: '1', - }, - }, - 'slide-in-from-right-8': { - from: { - transform: 'translateX(var(--spacing-10))', - opacity: '0', - }, - to: { - transform: 'translateX(calc(var(--spacing-8) * -1))', - opacity: '1', - }, - }, + 'slide-out-to-top': { from: { transform: 'translateY(0px)', opacity: '1' }, to: { @@ -122,43 +85,6 @@ export function createAnimationsPlugin(): TailwindPlugin { from: { transform: 'translateX(0px)', opacity: '1' }, to: { transform: 'translateX(var(--spacing-10))', opacity: '0' }, }, - // Slide out animations (8px offset) - 'slide-out-to-top-8': { - from: { transform: 'translateY(var(--spacing-8))', opacity: '1' }, - to: { - transform: 'translateY(calc(var(--spacing-10) * -1))', - opacity: '0', - }, - }, - 'slide-out-to-bottom-8': { - from: { - transform: 'translateY(calc(var(--spacing-8) * -1))', - opacity: '1', - }, - to: { transform: 'translateY(var(--spacing-10))', opacity: '0' }, - }, - 'slide-out-to-left-8': { - from: { - transform: 'translateX(calc(var(--spacing-8) * -1))', - opacity: '1', - }, - to: { - transform: 'translateX(calc(var(--spacing-10) * -1))', - opacity: '0', - }, - }, - 'slide-out-to-right-8': { - from: { transform: 'translateX(var(--spacing-8))', opacity: '1' }, - to: { transform: 'translateX(var(--spacing-10))', opacity: '0' }, - }, - 'translate-from-right': { - from: { - transform: 'translateX(var(--spacing-10))', - }, - to: { - transform: 'translateX(0)', - }, - }, }, animation: { 'content-show': 'content-show 300ms ease-in', @@ -166,7 +92,6 @@ export function createAnimationsPlugin(): TailwindPlugin { 'fade-in': 'fade-in 300ms ease-in', 'fade-out': 'fade-out 300ms ease-out', - // Slide animations with default 0px offset 'slide-in-from-top': 'slide-in-from-top 300ms ease-in', 'slide-in-from-bottom': 'slide-in-from-bottom 300ms ease-in', 'slide-in-from-left': 'slide-in-from-left 300ms ease-in', @@ -176,16 +101,6 @@ export function createAnimationsPlugin(): TailwindPlugin { 'slide-out-to-left': 'slide-out-to-left 300ms ease-out', 'slide-out-to-right': 'slide-out-to-right 300ms ease-out', - // Slide animations with 8px offset - 'slide-in-from-top-8': 'slide-in-from-top-8 300ms ease-in', - 'slide-in-from-bottom-8': 'slide-in-from-bottom-8 300ms ease-in', - 'slide-in-from-left-8': 'slide-in-from-left-8 300ms ease-in', - 'slide-in-from-right-8': 'slide-in-from-right-8 300ms ease-in', - 'slide-out-to-top-8': 'slide-out-to-top-8 300ms ease-out', - 'slide-out-to-bottom-8': 'slide-out-to-bottom-8 300ms ease-out', - 'slide-out-to-left-8': 'slide-out-to-left-8 300ms ease-out', - 'slide-out-to-right-8': 'slide-out-to-right-8 300ms ease-out', - 'translate-from-right': 'translate-from-right 250ms cubic-bezier(0.4, 0, 0.2, 1)', }, diff --git a/libs/ui-react/src/lib/Components/Select/Select.tsx b/libs/ui-react/src/lib/Components/Select/Select.tsx index 88156d5ef..2fb913714 100644 --- a/libs/ui-react/src/lib/Components/Select/Select.tsx +++ b/libs/ui-react/src/lib/Components/Select/Select.tsx @@ -36,8 +36,7 @@ const labelStyles = cn( 'pointer-events-none absolute left-16 origin-left text-muted transition-all duration-300', 'top-10 -translate-y-4 body-4', 'group-data-placeholder:top-14 group-data-placeholder:translate-y-0 group-data-placeholder:body-2', - // eslint-disable-next-line better-tailwindcss/no-unknown-classes - 'group-data-[placeholder][disabled]:text-disabled group-data-:disabled:text-disabled group-data-disabled:text-disabled disabled:text-disabled', + 'group-data-disabled:text-disabled disabled:text-disabled', 'max-w-[calc(100%-var(--size-56))] truncate', ); @@ -67,7 +66,7 @@ const SelectTrigger = React.forwardRef< @@ -79,10 +78,10 @@ const contentStyles = cva( 'relative z-select max-h-(--radix-select-content-available-height) overflow-x-hidden overflow-y-auto', 'rounded-sm bg-muted', 'shadow-md', - 'data-[side=bottom]:animate-slide-in-from-top-8', - 'data-[side=top]:animate-slide-in-from-bottom-8', - 'data-[side=left]:animate-slide-in-from-right-8', - 'data-[side=right]:animate-slide-in-from-left-8', + 'data-[side=bottom]:animate-slide-in-from-top', + 'data-[side=top]:animate-slide-in-from-bottom', + 'data-[side=left]:animate-slide-in-from-right', + 'data-[side=right]:animate-slide-in-from-left', ], { variants: { From fed0d591e18175a49f4c04aade5794770628b3be Mon Sep 17 00:00:00 2001 From: aammami-ledger Date: Mon, 12 Jan 2026 11:49:07 +0100 Subject: [PATCH 06/16] feat(theme): deactivate tailwind colors --- libs/design-core/src/presets/allBrands.ts | 2 ++ libs/design-core/src/presets/enterprise.ts | 2 ++ libs/design-core/src/presets/ledger-live.ts | 2 ++ libs/design-core/src/presets/websites.ts | 2 ++ libs/design-core/src/utils/createCustomPlugin.ts | 2 +- 5 files changed, 9 insertions(+), 1 deletion(-) diff --git a/libs/design-core/src/presets/allBrands.ts b/libs/design-core/src/presets/allBrands.ts index a8af7dcd0..f102333f6 100644 --- a/libs/design-core/src/presets/allBrands.ts +++ b/libs/design-core/src/presets/allBrands.ts @@ -13,9 +13,11 @@ export const allBrandsPreset: Config = { content: [], theme: { boxShadow: {}, + boxShadowColor: {}, fontSize: {}, fontWeight: {}, lineHeight: {}, + colors: {}, }, plugins: [ createPrimitivesPlugin(), diff --git a/libs/design-core/src/presets/enterprise.ts b/libs/design-core/src/presets/enterprise.ts index 0bf15af40..77d84c5d0 100644 --- a/libs/design-core/src/presets/enterprise.ts +++ b/libs/design-core/src/presets/enterprise.ts @@ -14,9 +14,11 @@ export const enterprisePreset: Config = { content: [], theme: { boxShadow: {}, + boxShadowColor: {}, fontSize: {}, fontWeight: {}, lineHeight: {}, + colors: {}, }, plugins: [ createPrimitivesPlugin(), diff --git a/libs/design-core/src/presets/ledger-live.ts b/libs/design-core/src/presets/ledger-live.ts index 985936b2e..c357fda76 100644 --- a/libs/design-core/src/presets/ledger-live.ts +++ b/libs/design-core/src/presets/ledger-live.ts @@ -13,9 +13,11 @@ export const ledgerLivePreset: Config = { content: [], theme: { boxShadow: {}, + boxShadowColor: {}, fontSize: {}, fontWeight: {}, lineHeight: {}, + colors: {}, }, plugins: [ createPrimitivesPlugin(), diff --git a/libs/design-core/src/presets/websites.ts b/libs/design-core/src/presets/websites.ts index 80cad3ac2..550eb9e00 100644 --- a/libs/design-core/src/presets/websites.ts +++ b/libs/design-core/src/presets/websites.ts @@ -14,9 +14,11 @@ export const websitesPreset: Config = { content: [], theme: { boxShadow: {}, + boxShadowColor: {}, fontSize: {}, fontWeight: {}, lineHeight: {}, + colors: {}, }, plugins: [ createPrimitivesPlugin(), diff --git a/libs/design-core/src/utils/createCustomPlugin.ts b/libs/design-core/src/utils/createCustomPlugin.ts index a5f4d22e3..287f40076 100644 --- a/libs/design-core/src/utils/createCustomPlugin.ts +++ b/libs/design-core/src/utils/createCustomPlugin.ts @@ -387,7 +387,7 @@ export function createShadowPlugin(): TailwindPlugin { addUtilities(shadows); matchUtilities( { shadow: (value) => ({ '--tw-shadow-color': value }) }, - { values: theme('colors') }, + { values: theme('boxShadowColor') }, ); }); } From be0a19adc64c808c479d83578e1b8155b579fc0c Mon Sep 17 00:00:00 2001 From: aammami-ledger Date: Mon, 12 Jan 2026 12:02:23 +0100 Subject: [PATCH 07/16] refactor(ui-react): run linter after conflict resolution --- .../Components/Design-tokens/styles/gradients.stories.tsx | 6 +++--- .../src/lib/Components/Dialog/DialogHeader/DialogHeader.tsx | 2 +- libs/ui-react/src/lib/Components/Subheader/Subheader.tsx | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/ui-react/src/lib/Components/Design-tokens/styles/gradients.stories.tsx b/libs/ui-react/src/lib/Components/Design-tokens/styles/gradients.stories.tsx index 822fb163a..e76db36b9 100644 --- a/libs/ui-react/src/lib/Components/Design-tokens/styles/gradients.stories.tsx +++ b/libs/ui-react/src/lib/Components/Design-tokens/styles/gradients.stories.tsx @@ -12,7 +12,7 @@ const GradientShowcase = () => (
-

Directional Gradients

+

Directional Gradients

{[ { name: 'Top', class: 'bg-gradient-top' }, @@ -30,7 +30,7 @@ const GradientShowcase = () => (
-

Status Gradients

+

Status Gradients

{[ { name: 'Error', class: 'bg-gradient-error' }, @@ -49,7 +49,7 @@ const GradientShowcase = () => (
-

Asset Gradients

+

Asset Gradients

{[ { name: 'Aion', class: 'bg-gradient-aion' }, diff --git a/libs/ui-react/src/lib/Components/Dialog/DialogHeader/DialogHeader.tsx b/libs/ui-react/src/lib/Components/Dialog/DialogHeader/DialogHeader.tsx index 4568327b7..2b6e4e143 100644 --- a/libs/ui-react/src/lib/Components/Dialog/DialogHeader/DialogHeader.tsx +++ b/libs/ui-react/src/lib/Components/Dialog/DialogHeader/DialogHeader.tsx @@ -119,7 +119,7 @@ const DialogHeaderComponent = React.forwardRef< })} > {title && ( -
+
{title}
)} diff --git a/libs/ui-react/src/lib/Components/Subheader/Subheader.tsx b/libs/ui-react/src/lib/Components/Subheader/Subheader.tsx index 5e9e257f8..499c7ca0c 100644 --- a/libs/ui-react/src/lib/Components/Subheader/Subheader.tsx +++ b/libs/ui-react/src/lib/Components/Subheader/Subheader.tsx @@ -85,7 +85,7 @@ export const Subheader = ({ {...props} >
-

{title}

+

{title}

{infoSlot}
{actionSlot} From 0297318f1c214823bab3515cc24eea7c10388059 Mon Sep 17 00:00:00 2001 From: aammami-ledger Date: Mon, 12 Jan 2026 13:26:26 +0100 Subject: [PATCH 08/16] fix(backdrop): revert description for backdrop blur in story --- .../lib/Components/Design-tokens/styles/backdrop.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ui-react/src/lib/Components/Design-tokens/styles/backdrop.stories.tsx b/libs/ui-react/src/lib/Components/Design-tokens/styles/backdrop.stories.tsx index f8842baf0..9f06df0f6 100644 --- a/libs/ui-react/src/lib/Components/Design-tokens/styles/backdrop.stories.tsx +++ b/libs/ui-react/src/lib/Components/Design-tokens/styles/backdrop.stories.tsx @@ -48,7 +48,7 @@ export const Backdrop: Story = {
From 1d861e42518d2a1f20ea3f958846b8777f28db29 Mon Sep 17 00:00:00 2001 From: aammami-ledger Date: Mon, 12 Jan 2026 15:56:49 +0100 Subject: [PATCH 09/16] refactor(checkbox): update checkbox styles to use `cn` --- libs/ui-react/src/lib/Components/Checkbox/Checkbox.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/ui-react/src/lib/Components/Checkbox/Checkbox.tsx b/libs/ui-react/src/lib/Components/Checkbox/Checkbox.tsx index fb5af61a9..a903c7b58 100644 --- a/libs/ui-react/src/lib/Components/Checkbox/Checkbox.tsx +++ b/libs/ui-react/src/lib/Components/Checkbox/Checkbox.tsx @@ -4,9 +4,9 @@ import React from 'react'; import { Check } from '../../Symbols/Icons/Check'; import { CheckboxProps } from './types'; -const checkboxStyles = [ - 'h-20 w-20 shrink-0 rounded-xs transition-colors', - 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-focus focus-visible:ring-offset-2', +const checkboxStyles = cn( + 'size-20 shrink-0 rounded-xs transition-colors', + 'focus-visible:ring-2 focus-visible:ring-focus focus-visible:ring-offset-2 focus-visible:outline-hidden', 'data-[state=unchecked]:border data-[state=unchecked]:border-muted data-[state=unchecked]:bg-base', 'data-[state=unchecked]:hover:bg-base-hover', @@ -17,7 +17,7 @@ const checkboxStyles = [ 'data-[state=checked]:hover:bg-active-hover', 'data-[state=checked]:active:bg-active-pressed', 'data-[state=checked]:disabled:bg-disabled data-[state=checked]:disabled:text-disabled', -].join(' '); +); /** * A customizable checkbox component built on top of Radix UI Checkbox primitive. From a1890e193105965666570173c96bdaaeb355a743 Mon Sep 17 00:00:00 2001 From: aammami-ledger Date: Mon, 12 Jan 2026 16:41:53 +0100 Subject: [PATCH 10/16] fix(select): restore `text-muted` --- libs/ui-react/src/lib/Components/Select/Select.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ui-react/src/lib/Components/Select/Select.tsx b/libs/ui-react/src/lib/Components/Select/Select.tsx index 2fb913714..3350f70ee 100644 --- a/libs/ui-react/src/lib/Components/Select/Select.tsx +++ b/libs/ui-react/src/lib/Components/Select/Select.tsx @@ -66,7 +66,7 @@ const SelectTrigger = React.forwardRef< From 54193ea4976a2522cbd064d8551f023d5ed3490e Mon Sep 17 00:00:00 2001 From: aammami-ledger Date: Mon, 12 Jan 2026 17:07:09 +0100 Subject: [PATCH 11/16] refactor(ui-react): update components to use cursor-pointer. --- libs/ui-react/src/lib/Components/Checkbox/Checkbox.tsx | 2 +- .../src/lib/Components/InteractiveIcon/InteractiveIcon.tsx | 2 +- libs/ui-react/src/lib/Components/Select/Select.tsx | 4 ++-- libs/ui-react/src/lib/Components/Switch/Switch.tsx | 2 +- libs/ui-react/src/lib/Components/Tile/Tile.tsx | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/ui-react/src/lib/Components/Checkbox/Checkbox.tsx b/libs/ui-react/src/lib/Components/Checkbox/Checkbox.tsx index a903c7b58..8108ca435 100644 --- a/libs/ui-react/src/lib/Components/Checkbox/Checkbox.tsx +++ b/libs/ui-react/src/lib/Components/Checkbox/Checkbox.tsx @@ -5,7 +5,7 @@ import { Check } from '../../Symbols/Icons/Check'; import { CheckboxProps } from './types'; const checkboxStyles = cn( - 'size-20 shrink-0 rounded-xs transition-colors', + 'size-20 shrink-0 cursor-pointer rounded-xs transition-colors', 'focus-visible:ring-2 focus-visible:ring-focus focus-visible:ring-offset-2 focus-visible:outline-hidden', 'data-[state=unchecked]:border data-[state=unchecked]:border-muted data-[state=unchecked]:bg-base', diff --git a/libs/ui-react/src/lib/Components/InteractiveIcon/InteractiveIcon.tsx b/libs/ui-react/src/lib/Components/InteractiveIcon/InteractiveIcon.tsx index 69c136265..724ad9314 100644 --- a/libs/ui-react/src/lib/Components/InteractiveIcon/InteractiveIcon.tsx +++ b/libs/ui-react/src/lib/Components/InteractiveIcon/InteractiveIcon.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { InteractiveIconProps } from './types'; const buttonVariants = cva( - 'inline-flex size-fit items-center justify-center rounded-full text-muted transition-colors hover:text-muted-hover focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus active:text-muted-pressed disabled:text-disabled', + 'inline-flex size-fit cursor-pointer items-center justify-center rounded-full text-muted transition-colors hover:text-muted-hover focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus active:text-muted-pressed disabled:text-disabled', { variants: { iconType: { diff --git a/libs/ui-react/src/lib/Components/Select/Select.tsx b/libs/ui-react/src/lib/Components/Select/Select.tsx index 3350f70ee..036033691 100644 --- a/libs/ui-react/src/lib/Components/Select/Select.tsx +++ b/libs/ui-react/src/lib/Components/Select/Select.tsx @@ -24,7 +24,7 @@ function SelectGroup({ ...props }: SelectGroupProps) { } const triggerStyles = cn( - 'group relative flex h-48 w-full items-center justify-between gap-8', + 'group relative flex h-48 w-full cursor-pointer items-center justify-between gap-8', 'rounded-sm bg-muted px-16', 'body-2 text-base', 'hover:bg-muted-hover', @@ -146,7 +146,7 @@ const SelectLabel = React.forwardRef< SelectLabel.displayName = SelectPrimitive.Label.displayName; const itemStyles = cn( - 'relative flex w-full cursor-default items-center bg-base-transparent select-none', + 'relative flex w-full cursor-pointer items-center bg-base-transparent select-none', 'rounded-sm p-8', 'body-2 text-base', 'outline-hidden', diff --git a/libs/ui-react/src/lib/Components/Switch/Switch.tsx b/libs/ui-react/src/lib/Components/Switch/Switch.tsx index de77eed61..bd30c224f 100644 --- a/libs/ui-react/src/lib/Components/Switch/Switch.tsx +++ b/libs/ui-react/src/lib/Components/Switch/Switch.tsx @@ -6,7 +6,7 @@ import { SwitchProps } from './types'; const switchVariants = cva( cn( - 'group flex items-center rounded-full p-2 transition-colors duration-200 ease-in-out focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus', + 'group flex cursor-pointer items-center rounded-full p-2 transition-colors duration-200 ease-in-out focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus', '[&[data-state=unchecked]:not([data-disabled])]:bg-muted-strong [&[data-state=unchecked]:not([data-disabled])]:hover:bg-muted-strong-hover [&[data-state=unchecked]:not([data-disabled])]:active:bg-muted-strong-pressed', '[&[data-state=checked]:not([data-disabled])]:bg-active [&[data-state=checked]:not([data-disabled])]:hover:bg-active-hover [&[data-state=checked]:not([data-disabled])]:active:bg-active-pressed', 'data-disabled:bg-disabled-strong', diff --git a/libs/ui-react/src/lib/Components/Tile/Tile.tsx b/libs/ui-react/src/lib/Components/Tile/Tile.tsx index cd053b5da..abaaa41e9 100644 --- a/libs/ui-react/src/lib/Components/Tile/Tile.tsx +++ b/libs/ui-react/src/lib/Components/Tile/Tile.tsx @@ -75,7 +75,7 @@ const tileVariants = { }, ), button: cva( - 'flex w-full flex-col items-center gap-8 rounded-md px-8 py-12 focus-visible:outline-2 focus-visible:outline-focus', + 'flex w-full cursor-pointer flex-col items-center gap-8 rounded-md px-8 py-12 focus-visible:outline-2 focus-visible:outline-focus', ), }; From 929825c951d7d395bed2c27b3455d4708974d792 Mon Sep 17 00:00:00 2001 From: aammami-ledger Date: Mon, 12 Jan 2026 17:45:42 +0100 Subject: [PATCH 12/16] refactor(animations): fix dialog animation --- libs/design-core/src/utils/createAnimationsPlugin.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libs/design-core/src/utils/createAnimationsPlugin.ts b/libs/design-core/src/utils/createAnimationsPlugin.ts index 8b120e2fb..705bf6349 100644 --- a/libs/design-core/src/utils/createAnimationsPlugin.ts +++ b/libs/design-core/src/utils/createAnimationsPlugin.ts @@ -12,18 +12,21 @@ export function createAnimationsPlugin(): TailwindPlugin { 'content-show': { from: { opacity: '0', - transform: 'translate(-50%, -48%) scale(0.96)', + scale: '0.96', + }, + to: { + opacity: '1', + scale: '1', }, - to: { opacity: '1', transform: 'translate(-50%, -50%) scale(1)' }, }, 'content-hide': { from: { opacity: '1', - transform: 'translate(-50%, -50%) scale(1)', + scale: '1', }, to: { opacity: '0', - transform: 'translate(-50%, -48%) scale(0.96)', + scale: '0.96', }, }, 'fade-in': { From 0aa17066f410e8c8b3aaa2bb6e873b0961ae9603 Mon Sep 17 00:00:00 2001 From: aammami-ledger Date: Mon, 12 Jan 2026 17:57:20 +0100 Subject: [PATCH 13/16] refactor(DoVsDont): fix do and dont sections --- libs/ui-react/.storybook/components/DoVsDont/DoBlock.tsx | 2 +- libs/ui-react/.storybook/components/DoVsDont/DontBlock.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/ui-react/.storybook/components/DoVsDont/DoBlock.tsx b/libs/ui-react/.storybook/components/DoVsDont/DoBlock.tsx index 288c8c822..037176c68 100644 --- a/libs/ui-react/.storybook/components/DoVsDont/DoBlock.tsx +++ b/libs/ui-react/.storybook/components/DoVsDont/DoBlock.tsx @@ -35,7 +35,7 @@ export const DoBlockItem: React.FC = ({ )} {/* Code Block */} -
+
{children}
diff --git a/libs/ui-react/.storybook/components/DoVsDont/DontBlock.tsx b/libs/ui-react/.storybook/components/DoVsDont/DontBlock.tsx index 5aa28d13f..9dfa3777a 100644 --- a/libs/ui-react/.storybook/components/DoVsDont/DontBlock.tsx +++ b/libs/ui-react/.storybook/components/DoVsDont/DontBlock.tsx @@ -35,7 +35,7 @@ export const DontBlockItem: React.FC = ({ )} {/* Code Block */} -
+
{children}
From 7ed6564d201b4f0886a379152a1f4f651135c94c Mon Sep 17 00:00:00 2001 From: aammami-ledger Date: Tue, 13 Jan 2026 17:51:17 +0100 Subject: [PATCH 14/16] feat(animations): add 'translate-from-right' keyframe --- libs/design-core/src/utils/createAnimationsPlugin.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libs/design-core/src/utils/createAnimationsPlugin.ts b/libs/design-core/src/utils/createAnimationsPlugin.ts index 705bf6349..fdb0faa64 100644 --- a/libs/design-core/src/utils/createAnimationsPlugin.ts +++ b/libs/design-core/src/utils/createAnimationsPlugin.ts @@ -88,6 +88,14 @@ export function createAnimationsPlugin(): TailwindPlugin { from: { transform: 'translateX(0px)', opacity: '1' }, to: { transform: 'translateX(var(--spacing-10))', opacity: '0' }, }, + 'translate-from-right': { + from: { + transform: 'translateX(4px)', + }, + to: { + transform: 'translateX(0px)', + }, + }, }, animation: { 'content-show': 'content-show 300ms ease-in', From 2c2aa19dc249fc62de9f161592ef7815bc8ca122 Mon Sep 17 00:00:00 2001 From: aammami-ledger Date: Tue, 13 Jan 2026 17:54:53 +0100 Subject: [PATCH 15/16] chore(version-plan): add new version plan for UI component upgrades --- .nx/version-plans/version-plan-1768323163192.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .nx/version-plans/version-plan-1768323163192.md diff --git a/.nx/version-plans/version-plan-1768323163192.md b/.nx/version-plans/version-plan-1768323163192.md new file mode 100644 index 000000000..6203123fa --- /dev/null +++ b/.nx/version-plans/version-plan-1768323163192.md @@ -0,0 +1,6 @@ +--- +'@ledgerhq/lumen-design-core': patch +'@ledgerhq/lumen-ui-react': patch +--- + +BREAKING_CHANGE(ui-react): Upgrade tailwind to v4 From a029d93c0e5b179196446478cefa75eaf035b540 Mon Sep 17 00:00:00 2001 From: aammami-ledger Date: Wed, 14 Jan 2026 11:01:17 +0100 Subject: [PATCH 16/16] BREAKING_CHANGE(ui-react): provide migration guide --- .../version-plan-1768323163192.md | 60 ++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/.nx/version-plans/version-plan-1768323163192.md b/.nx/version-plans/version-plan-1768323163192.md index 6203123fa..cfad48803 100644 --- a/.nx/version-plans/version-plan-1768323163192.md +++ b/.nx/version-plans/version-plan-1768323163192.md @@ -3,4 +3,62 @@ '@ledgerhq/lumen-ui-react': patch --- -BREAKING_CHANGE(ui-react): Upgrade tailwind to v4 +BREAKING_CHANGE(ui-react): Upgrade Tailwind to v4 + +## Migration Guide + +### 1. Upgrade Tailwind CSS + +Run the official upgrade tool to automatically migrate your project: + +```bash +npx @tailwindcss/upgrade +``` + +This will update your dependencies, migrate your CSS configuration, and update any deprecated utility classes. + +For detailed migration steps, see the official [Tailwind CSS v4 Upgrade Guide](https://tailwindcss.com/docs/upgrade-guide). + +### 2. Install PostCSS Plugin + +In Tailwind v4, the PostCSS plugin no longer lives in the `tailwindcss` package. Install the dedicated package: + +```bash +npm install -D @tailwindcss/postcss +``` + +#### Using Vite + +If you're using Vite, we recommend migrating from the PostCSS plugin to the dedicated Vite plugin for improved performance and the best developer experience: + +```bash +npm install -D @tailwindcss/vite +``` + +```ts +// vite.config.ts +import { defineConfig } from 'vite'; +import tailwindcss from '@tailwindcss/vite'; + +export default defineConfig({ + plugins: [tailwindcss()], +}); +``` + +### 3. Update ESLint Plugin + +Replace `eslint-plugin-tailwindcss` with [eslint-plugin-better-tailwindcss](https://github.com/schoero/eslint-plugin-better-tailwindcss). + +> **Why?** The original `eslint-plugin-tailwindcss` does not support Tailwind v4 and has been inactive for a while ([see issue](https://github.com/francoismassart/eslint-plugin-tailwindcss/issues/325)). + +```bash +npm install -D eslint-plugin-better-tailwindcss +``` + +Configure the `entryPoint` in your ESLint config to point to your main Tailwind stylesheet (e.g., `./src/styles.css`). See our [eslint.config.mjs](https://github.com/LedgerHQ/lumen-design-system/blob/main/libs/ui-react/eslint.config.mjs) for a complete configuration example. + +> **Note:** In NX monorepos, you might need the beta version due to an issue with `entryPoint` not being resolved correctly ([see issue](https://github.com/schoero/eslint-plugin-better-tailwindcss/issues/154)): +> +> ```bash +> npm install -D eslint-plugin-better-tailwindcss@beta +> ```