From 8c3f12a04ddf004cafaaa848c5e22da3409e97b5 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 10 Sep 2026 04:38:45 +0000 Subject: [PATCH 1/7] chore(deps): bump lucide-react 1.31.0 -> 1.43.0 and repair the one retired spelling Supersedes the stale Dependabot branch for this bump (objectui#7058), whose base was weeks behind `main`. Measured against the installed artifact, not the changelog: across the whole 1.31.0 -> 1.43.0 jump lucide removes ZERO public names from `lucide-react` (6072 -> 6230 d.ts names, none dropped; 6068 -> 6224 runtime exports, none dropped) and ZERO names from `lucide-react/dynamic.mjs`. Exactly one key leaves the runtime `icons` record: `Trash2`, which upstream retired in favour of `trash` (lucide-icons/lucide#3141). It survives as a DEPRECATED EXPORT of the same object, so nothing breaks at a named import or in the type checker -- only STRING lookups through `resolveIcon`, which read record membership. Repaired, all four sites the gate names: - examples/schema-catalog .../action-button-variants.json - examples/schema-catalog .../confirmation-dialog.json - examples/schema-catalog .../profile-detail-card.json - packages/plugin-detail/src/DetailView.tsx `trash` is the visually lossless replacement: lucide 1.43.0's `trash` icon node is byte-identical to 1.31.0's `trash-2` icon node (control: `pencil` identical across both versions). Also re-anchored the two ranges that quote the workspace: - packages/cli/src/utils/app-generator.ts (app-generator.test.ts anchor) - skills/objectui/guides/plugin-development.md (doc-version-claims anchor) and the four doc/comment examples that taught the retired spelling. The lockfile is regenerated from current `main`, so the @objectstack 17.4.0 -> 17.3.0 downgrade, the zod 4.4.3/4.5.4 split and the resulting duplicated vendor chunk that reddened objectui#7058 are all absent here. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01611D6ZaRaMmwTNQmSbk8MH --- apps/console/package.json | 2 +- apps/site/package.json | 2 +- content/docs/api/schema-reference.md | 2 +- content/docs/guide/schema-playground.md | 2 +- .../actions/action-button-variants.json | 2 +- .../schemas/actions/confirmation-dialog.json | 2 +- .../profile-detail-card.json | 2 +- packages/app-shell/package.json | 2 +- packages/cli/src/utils/app-generator.ts | 2 +- packages/components/package.json | 2 +- .../src/renderers/action/action-bar.tsx | 2 +- packages/fields/package.json | 2 +- packages/layout/package.json | 2 +- packages/plugin-ai/package.json | 2 +- packages/plugin-calendar/package.json | 2 +- packages/plugin-charts/package.json | 2 +- packages/plugin-chatbot/package.json | 2 +- packages/plugin-dashboard/package.json | 2 +- packages/plugin-designer/package.json | 2 +- packages/plugin-detail/package.json | 2 +- packages/plugin-detail/src/DetailView.tsx | 2 +- packages/plugin-form/package.json | 2 +- packages/plugin-gantt/package.json | 2 +- packages/plugin-grid/package.json | 2 +- packages/plugin-kanban/package.json | 2 +- packages/plugin-list/package.json | 2 +- packages/plugin-report/package.json | 2 +- packages/plugin-tree/package.json | 2 +- packages/plugin-view/package.json | 2 +- packages/runner/package.json | 2 +- packages/types/src/objectql.ts | 2 +- pnpm-lock.yaml | 123 ++++++++---------- skills/objectui/guides/plugin-development.md | 2 +- 33 files changed, 89 insertions(+), 98 deletions(-) diff --git a/apps/console/package.json b/apps/console/package.json index eeb86d7b08..ce45a7b21f 100644 --- a/apps/console/package.json +++ b/apps/console/package.json @@ -105,7 +105,7 @@ "@vitest/ui": "^4.1.10", "autoprefixer": "^10.5.4", "happy-dom": "^20.11.2", - "lucide-react": "^1.31.0", + "lucide-react": "^1.43.0", "postcss": "^8.5.26", "react": "19.2.8", "react-dom": "19.2.8", diff --git a/apps/site/package.json b/apps/site/package.json index 161ab80b7f..e2c4c61bf8 100644 --- a/apps/site/package.json +++ b/apps/site/package.json @@ -36,7 +36,7 @@ "fumadocs-core": "16.15.4", "fumadocs-mdx": "15.2.3", "fumadocs-ui": "16.15.4", - "lucide-react": "^1.31.0", + "lucide-react": "^1.43.0", "next": "16.3.1", "react": "19.2.8", "react-dom": "19.2.8", diff --git a/content/docs/api/schema-reference.md b/content/docs/api/schema-reference.md index 0f21bb0b87..34ee89b46c 100644 --- a/content/docs/api/schema-reference.md +++ b/content/docs/api/schema-reference.md @@ -683,7 +683,7 @@ A single-record detail view with grouped fields, actions, and tabs. ], "actions": [ { "type": "action", "label": "Edit", "icon": "Pencil", "level": "primary" }, - { "type": "action", "label": "Delete", "icon": "Trash2", "level": "danger", "actionType": "confirm" } + { "type": "action", "label": "Delete", "icon": "trash", "level": "danger", "actionType": "confirm" } ], "tabs": [ { diff --git a/content/docs/guide/schema-playground.md b/content/docs/guide/schema-playground.md index bcef234383..05bf9349cb 100644 --- a/content/docs/guide/schema-playground.md +++ b/content/docs/guide/schema-playground.md @@ -190,7 +190,7 @@ A data grid with sortable columns and row actions: ], "actions": [ { "label": "Edit", "icon": "pencil", "action": "edit" }, - { "label": "Delete", "icon": "trash-2", "action": "delete", "variant": "destructive" } + { "label": "Delete", "icon": "trash", "action": "delete", "variant": "destructive" } ], "pagination": { "pageSize": 10, diff --git a/examples/schema-catalog/src/schemas/actions/action-button-variants.json b/examples/schema-catalog/src/schemas/actions/action-button-variants.json index 708a50ed25..14968babe4 100644 --- a/examples/schema-catalog/src/schemas/actions/action-button-variants.json +++ b/examples/schema-catalog/src/schemas/actions/action-button-variants.json @@ -23,7 +23,7 @@ "type": "button", "label": "Delete", "variant": "destructive", - "icon": "trash-2" + "icon": "trash" }, { "type": "button", diff --git a/examples/schema-catalog/src/schemas/actions/confirmation-dialog.json b/examples/schema-catalog/src/schemas/actions/confirmation-dialog.json index f77db55016..3e840e2320 100644 --- a/examples/schema-catalog/src/schemas/actions/confirmation-dialog.json +++ b/examples/schema-catalog/src/schemas/actions/confirmation-dialog.json @@ -35,7 +35,7 @@ "type": "button", "label": "Yes, Delete", "variant": "destructive", - "icon": "trash-2" + "icon": "trash" } ] } diff --git a/examples/schema-catalog/src/schemas/components-layout-card/profile-detail-card.json b/examples/schema-catalog/src/schemas/components-layout-card/profile-detail-card.json index f084c90940..2fca357ef1 100644 --- a/examples/schema-catalog/src/schemas/components-layout-card/profile-detail-card.json +++ b/examples/schema-catalog/src/schemas/components-layout-card/profile-detail-card.json @@ -124,7 +124,7 @@ "label": "Delete", "variant": "destructive", "size": "sm", - "icon": "trash-2" + "icon": "trash" } ] } diff --git a/packages/app-shell/package.json b/packages/app-shell/package.json index 040a7c5c90..75a219e2bc 100644 --- a/packages/app-shell/package.json +++ b/packages/app-shell/package.json @@ -86,7 +86,7 @@ "@objectstack/spec": "^17.0.0", "@sentry/react": "^10.70.0", "jsonc-parser": "^3.3.1", - "lucide-react": "^1.31.0", + "lucide-react": "^1.43.0", "qrcode": "^1.5.4", "sonner": "^2.0.8", "zod": "^4.4.3" diff --git a/packages/cli/src/utils/app-generator.ts b/packages/cli/src/utils/app-generator.ts index 5e6c26238d..50706afdfa 100644 --- a/packages/cli/src/utils/app-generator.ts +++ b/packages/cli/src/utils/app-generator.ts @@ -201,7 +201,7 @@ function buildRoutedAppDependencies(): Record { react: REACT_RANGE, 'react-dom': REACT_RANGE, 'react-router-dom': '^7.18.2', - 'lucide-react': '^1.31.0', + 'lucide-react': '^1.43.0', ...Object.fromEntries(PLATFORM_RUNTIME_PACKAGES.map((name) => [name, range])) }; } diff --git a/packages/components/package.json b/packages/components/package.json index 97f1edb4f7..66f5b433c7 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -72,7 +72,7 @@ "date-fns": "^4.4.0", "embla-carousel-react": "^8.6.0", "input-otp": "^1.4.2", - "lucide-react": "^1.31.0", + "lucide-react": "^1.43.0", "next-themes": "^0.4.6", "react-day-picker": "^10.0.1", "react-hook-form": "^7.85.0", diff --git a/packages/components/src/renderers/action/action-bar.tsx b/packages/components/src/renderers/action/action-bar.tsx index e986327a76..5cf73ec29d 100644 --- a/packages/components/src/renderers/action/action-bar.tsx +++ b/packages/components/src/renderers/action/action-bar.tsx @@ -30,7 +30,7 @@ * location: 'record_header', * actions: [ * { name: 'mark_complete', label: 'Mark Complete', type: 'script', icon: 'check', component: 'action:button' }, - * { name: 'delete', label: 'Delete', type: 'api', icon: 'trash-2', variant: 'destructive', component: 'action:button' }, + * { name: 'delete', label: 'Delete', type: 'api', icon: 'trash', variant: 'destructive', component: 'action:button' }, * ], * }} /> * ``` diff --git a/packages/fields/package.json b/packages/fields/package.json index 8177869d7c..bce0c789fd 100644 --- a/packages/fields/package.json +++ b/packages/fields/package.json @@ -37,7 +37,7 @@ "@object-ui/react": "workspace:*", "@object-ui/types": "workspace:*", "@objectstack/spec": "^17.0.0", - "lucide-react": "^1.31.0", + "lucide-react": "^1.43.0", "react-markdown": "^10.1.0", "rehype-sanitize": "^6.0.0", "remark-gfm": "^4.0.1" diff --git a/packages/layout/package.json b/packages/layout/package.json index e4a160cb43..36bd16acdc 100644 --- a/packages/layout/package.json +++ b/packages/layout/package.json @@ -31,7 +31,7 @@ "@object-ui/react": "workspace:*", "@object-ui/types": "workspace:*", "@objectstack/spec": "^17.0.0", - "lucide-react": "^1.31.0", + "lucide-react": "^1.43.0", "react": "19.2.8" }, "peerDependencies": { diff --git a/packages/plugin-ai/package.json b/packages/plugin-ai/package.json index 6dbc065a9b..5e6cc52836 100644 --- a/packages/plugin-ai/package.json +++ b/packages/plugin-ai/package.json @@ -33,7 +33,7 @@ "@object-ui/components": "workspace:*", "@object-ui/core": "workspace:*", "@object-ui/types": "workspace:*", - "lucide-react": "^1.31.0" + "lucide-react": "^1.43.0" }, "devDependencies": { "@types/node": "^26.2.0", diff --git a/packages/plugin-calendar/package.json b/packages/plugin-calendar/package.json index 118b0d3358..de57bad09e 100644 --- a/packages/plugin-calendar/package.json +++ b/packages/plugin-calendar/package.json @@ -39,7 +39,7 @@ "@object-ui/plugin-detail": "workspace:*", "@object-ui/react": "workspace:*", "@object-ui/types": "workspace:*", - "lucide-react": "^1.31.0" + "lucide-react": "^1.43.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", diff --git a/packages/plugin-charts/package.json b/packages/plugin-charts/package.json index 8a6eabeddd..378af866e3 100644 --- a/packages/plugin-charts/package.json +++ b/packages/plugin-charts/package.json @@ -36,7 +36,7 @@ "@object-ui/i18n": "workspace:*", "@object-ui/react": "workspace:*", "@object-ui/types": "workspace:*", - "lucide-react": "^1.31.0", + "lucide-react": "^1.43.0", "recharts": "^3.10.1" }, "peerDependencies": { diff --git a/packages/plugin-chatbot/package.json b/packages/plugin-chatbot/package.json index 3af0bb33a4..811e2aba30 100644 --- a/packages/plugin-chatbot/package.json +++ b/packages/plugin-chatbot/package.json @@ -42,7 +42,7 @@ "@radix-ui/react-use-controllable-state": "^1.2.6", "ai": "^7.0.65", "class-variance-authority": "^0.7.1", - "lucide-react": "^1.31.0", + "lucide-react": "^1.43.0", "motion": "^13.2.0", "nanoid": "^6.0.1", "shiki": "^4.4.2", diff --git a/packages/plugin-dashboard/package.json b/packages/plugin-dashboard/package.json index 688c9d7dbc..2c18eb57fa 100644 --- a/packages/plugin-dashboard/package.json +++ b/packages/plugin-dashboard/package.json @@ -31,7 +31,7 @@ "@object-ui/permissions": "workspace:*", "@object-ui/react": "workspace:*", "@object-ui/types": "workspace:*", - "lucide-react": "^1.31.0", + "lucide-react": "^1.43.0", "react": "19.2.8" }, "peerDependencies": { diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index c92439fe2a..90bb62c4ba 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -42,7 +42,7 @@ "@object-ui/react": "workspace:*", "@object-ui/types": "workspace:*", "clsx": "^2.1.1", - "lucide-react": "^1.31.0", + "lucide-react": "^1.43.0", "sonner": "^2.0.8", "tailwind-merge": "^3.6.0" }, diff --git a/packages/plugin-detail/package.json b/packages/plugin-detail/package.json index b80090bc89..d59f3460f5 100644 --- a/packages/plugin-detail/package.json +++ b/packages/plugin-detail/package.json @@ -33,7 +33,7 @@ "dependencies": { "@object-ui/i18n": "workspace:*", "@objectstack/spec": "^17.1.0", - "lucide-react": "^1.31.0" + "lucide-react": "^1.43.0" }, "peerDependencies": { "@object-ui/components": "workspace:^", diff --git a/packages/plugin-detail/src/DetailView.tsx b/packages/plugin-detail/src/DetailView.tsx index 6e2fdb7215..76ef9d121c 100644 --- a/packages/plugin-detail/src/DetailView.tsx +++ b/packages/plugin-detail/src/DetailView.tsx @@ -926,7 +926,7 @@ export const DetailView: React.FC = ({ items.push({ name: 'sys_delete', label: t('detail.delete'), - icon: 'trash-2', + icon: 'trash', type: 'script', variant: 'destructive', tags: ['separator-before'], diff --git a/packages/plugin-form/package.json b/packages/plugin-form/package.json index c3b40d9de3..7e271c3b68 100644 --- a/packages/plugin-form/package.json +++ b/packages/plugin-form/package.json @@ -29,7 +29,7 @@ "@object-ui/react": "workspace:*", "@object-ui/types": "workspace:*", "@objectstack/spec": "^17.0.0", - "lucide-react": "^1.31.0" + "lucide-react": "^1.43.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", diff --git a/packages/plugin-gantt/package.json b/packages/plugin-gantt/package.json index bfe2a7592e..6d3fe98911 100644 --- a/packages/plugin-gantt/package.json +++ b/packages/plugin-gantt/package.json @@ -40,7 +40,7 @@ "@object-ui/react": "workspace:*", "@object-ui/types": "workspace:*", "@objectstack/spec": "^17.0.0", - "lucide-react": "^1.31.0", + "lucide-react": "^1.43.0", "sonner": "^2.0.8" }, "peerDependencies": { diff --git a/packages/plugin-grid/package.json b/packages/plugin-grid/package.json index 4cb92b5682..e56042c669 100644 --- a/packages/plugin-grid/package.json +++ b/packages/plugin-grid/package.json @@ -33,7 +33,7 @@ "@objectstack/spec": "^17.0.0", "@tanstack/react-virtual": "^3.14.9", "exceljs": "^4.4.0", - "lucide-react": "^1.31.0" + "lucide-react": "^1.43.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", diff --git a/packages/plugin-kanban/package.json b/packages/plugin-kanban/package.json index f22f7bff86..117eeb3f86 100644 --- a/packages/plugin-kanban/package.json +++ b/packages/plugin-kanban/package.json @@ -44,7 +44,7 @@ "@object-ui/react": "workspace:*", "@object-ui/types": "workspace:*", "@tanstack/react-virtual": "^3.14.9", - "lucide-react": "^1.31.0" + "lucide-react": "^1.43.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", diff --git a/packages/plugin-list/package.json b/packages/plugin-list/package.json index d4b415978e..48abb73fc9 100644 --- a/packages/plugin-list/package.json +++ b/packages/plugin-list/package.json @@ -31,7 +31,7 @@ "lint": "eslint ." }, "dependencies": { - "lucide-react": "^1.31.0" + "lucide-react": "^1.43.0" }, "peerDependencies": { "@object-ui/components": "workspace:^", diff --git a/packages/plugin-report/package.json b/packages/plugin-report/package.json index e3857bed11..d84629393c 100644 --- a/packages/plugin-report/package.json +++ b/packages/plugin-report/package.json @@ -32,7 +32,7 @@ "@object-ui/i18n": "workspace:*", "@object-ui/react": "workspace:*", "@object-ui/types": "workspace:*", - "lucide-react": "^1.31.0" + "lucide-react": "^1.43.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", diff --git a/packages/plugin-tree/package.json b/packages/plugin-tree/package.json index 2419150c27..79bd7b6cc2 100644 --- a/packages/plugin-tree/package.json +++ b/packages/plugin-tree/package.json @@ -38,7 +38,7 @@ "@object-ui/react": "workspace:*", "@object-ui/types": "workspace:*", "@objectstack/spec": "^17.0.0", - "lucide-react": "^1.31.0" + "lucide-react": "^1.43.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", diff --git a/packages/plugin-view/package.json b/packages/plugin-view/package.json index e34a92e5e8..ae430ecce2 100644 --- a/packages/plugin-view/package.json +++ b/packages/plugin-view/package.json @@ -34,7 +34,7 @@ "@object-ui/types": "workspace:*", "@objectstack/spec": "^17.0.0", "class-variance-authority": "^0.7.1", - "lucide-react": "^1.31.0" + "lucide-react": "^1.43.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", diff --git a/packages/runner/package.json b/packages/runner/package.json index aceca9209c..a2fe2f6439 100644 --- a/packages/runner/package.json +++ b/packages/runner/package.json @@ -28,7 +28,7 @@ "@object-ui/plugin-kanban": "workspace:*", "@object-ui/react": "workspace:*", "@object-ui/types": "workspace:*", - "lucide-react": "^1.31.0", + "lucide-react": "^1.43.0", "react": "19.2.8", "react-dom": "19.2.8", "tailwindcss-animate": "^1.0.7" diff --git a/packages/types/src/objectql.ts b/packages/types/src/objectql.ts index 9b32d3525d..7c92be7255 100644 --- a/packages/types/src/objectql.ts +++ b/packages/types/src/objectql.ts @@ -481,7 +481,7 @@ export interface BulkActionDef { name: string; /** Human-readable label shown on the button + dialog header. */ label?: string; - /** Lucide icon name (e.g. 'user-check', 'trash-2'); falls back to a generic icon. */ + /** Lucide icon name (e.g. 'user-check', 'trash'); falls back to a generic icon. */ icon?: string; /** Visual treatment of the action button. */ variant?: 'primary' | 'secondary' | 'danger' | 'ghost' | 'outline'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8555436611..9d840456a8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -317,8 +317,8 @@ importers: specifier: ^20.11.2 version: 20.11.2 lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) postcss: specifier: ^8.5.26 version: 8.5.28 @@ -417,16 +417,16 @@ importers: version: 17.4.0(ai@7.0.65(zod@4.4.3)) fumadocs-core: specifier: 16.15.4 - version: 16.15.4(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.18)(lucide-react@1.31.0(react@19.2.8))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react-router@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(zod@4.4.3) + version: 16.15.4(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.18)(lucide-react@1.43.0(react@19.2.8))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react-router@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(zod@4.4.3) fumadocs-mdx: specifier: 15.2.3 - version: 15.2.3(@types/mdast@4.0.4)(@types/mdx@2.0.14)(@types/react@19.2.18)(fumadocs-core@16.15.4(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.18)(lucide-react@1.31.0(react@19.2.8))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react-router@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(zod@4.4.3))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(rolldown@1.2.7)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)(yaml@2.9.0)) + version: 15.2.3(@types/mdast@4.0.4)(@types/mdx@2.0.14)(@types/react@19.2.18)(fumadocs-core@16.15.4(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.18)(lucide-react@1.43.0(react@19.2.8))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react-router@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(zod@4.4.3))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(rolldown@1.2.7)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)(yaml@2.9.0)) fumadocs-ui: specifier: 16.15.4 - version: 16.15.4(@types/mdx@2.0.14)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(fumadocs-core@16.15.4(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.18)(lucide-react@1.31.0(react@19.2.8))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react-router@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(zod@4.4.3))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(tailwindcss@4.3.3) + version: 16.15.4(@types/mdx@2.0.14)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(fumadocs-core@16.15.4(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.18)(lucide-react@1.43.0(react@19.2.8))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react-router@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(zod@4.4.3))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(tailwindcss@4.3.3) lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) next: specifier: 16.3.1 version: 16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -786,8 +786,8 @@ importers: specifier: ^3.3.1 version: 3.3.1 lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) qrcode: specifier: ^1.5.4 version: 1.5.4 @@ -1099,8 +1099,8 @@ importers: specifier: ^1.4.2 version: 1.4.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) next-themes: specifier: ^0.4.6 version: 0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -1283,8 +1283,8 @@ importers: specifier: ^17.0.0 version: 17.4.0(ai@7.0.65(zod@4.4.3)) lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) react: specifier: 19.2.8 version: 19.2.8 @@ -1387,8 +1387,8 @@ importers: specifier: ^17.0.0 version: 17.4.0(ai@7.0.65(zod@4.4.3)) lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) react: specifier: 19.2.8 version: 19.2.8 @@ -1471,8 +1471,8 @@ importers: specifier: workspace:* version: link:../types lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) react: specifier: 19.2.8 version: 19.2.8 @@ -1529,8 +1529,8 @@ importers: specifier: workspace:* version: link:../types lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) react: specifier: 19.2.8 version: 19.2.8 @@ -1581,8 +1581,8 @@ importers: specifier: workspace:* version: link:../types lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) react: specifier: 19.2.8 version: 19.2.8 @@ -1654,8 +1654,8 @@ importers: specifier: ^0.7.1 version: 0.7.1 lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) motion: specifier: ^13.2.0 version: 13.2.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -1730,8 +1730,8 @@ importers: specifier: workspace:* version: link:../types lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) react: specifier: 19.2.8 version: 19.2.8 @@ -1800,8 +1800,8 @@ importers: specifier: ^2.1.1 version: 2.1.1 lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) react: specifier: 19.2.8 version: 19.2.8 @@ -1849,8 +1849,8 @@ importers: specifier: ^17.1.0 version: 17.4.0(ai@7.0.65(zod@4.4.3)) lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) react: specifier: 19.2.8 version: 19.2.8 @@ -1974,8 +1974,8 @@ importers: specifier: ^17.0.0 version: 17.4.0(ai@7.0.65(zod@4.4.3)) lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) react: specifier: 19.2.8 version: 19.2.8 @@ -2035,8 +2035,8 @@ importers: specifier: ^17.0.0 version: 17.4.0(ai@7.0.65(zod@4.4.3)) lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) react: specifier: 19.2.8 version: 19.2.8 @@ -2102,8 +2102,8 @@ importers: specifier: ^4.4.0 version: 4.4.0 lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) react: specifier: 19.2.8 version: 19.2.8 @@ -2184,8 +2184,8 @@ importers: specifier: ^3.14.9 version: 3.14.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8) lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) react: specifier: 19.2.8 version: 19.2.8 @@ -2233,8 +2233,8 @@ importers: packages/plugin-list: dependencies: lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) react: specifier: 19.2.8 version: 19.2.8 @@ -2431,8 +2431,8 @@ importers: specifier: workspace:* version: link:../types lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) react: specifier: 19.2.8 version: 19.2.8 @@ -2556,8 +2556,8 @@ importers: specifier: ^17.0.0 version: 17.4.0(ai@7.0.65(zod@4.4.3)) lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) react: specifier: 19.2.8 version: 19.2.8 @@ -2626,8 +2626,8 @@ importers: specifier: ^0.7.1 version: 0.7.1 lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) react: specifier: 19.2.8 version: 19.2.8 @@ -2737,8 +2737,8 @@ importers: specifier: workspace:* version: link:../types lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + specifier: ^1.43.0 + version: 1.43.0(react@19.2.8) react: specifier: 19.2.8 version: 19.2.8 @@ -8739,13 +8739,8 @@ packages: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} - lucide-react@1.31.0: - resolution: {integrity: sha512-G8u2eEtoHUnUa9f8lbvqDhCiORMnYLdUEo06EEG9MQvHQrInKcX3Pa2TH39MM5qyzRcWETxB0+aOwAPI1g1kEg==} - peerDependencies: - react: 19.2.8 - - lucide-react@1.35.0: - resolution: {integrity: sha512-yXCCWxGFYT6bLIPYC4SY6fPQPRs/d797rRIue+J9XP2Td6vQvD53gaQRBCnIVT1kTQRHtAtxlfOQNWAuIF8ELg==} + lucide-react@1.43.0: + resolution: {integrity: sha512-ubtnda1fVK5ky0PNEpOmB0wiwhpZUyJiol4K14KCm+QKvuCkfUu54Et/rIjyupJpwiJ5Hg+BLQE86/GEsS+IgQ==} peerDependencies: react: 19.2.8 @@ -16251,7 +16246,7 @@ snapshots: mkdirp: 0.5.6 rimraf: 2.7.1 - fumadocs-core@16.15.4(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.18)(lucide-react@1.31.0(react@19.2.8))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react-router@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(zod@4.4.3): + fumadocs-core@16.15.4(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.18)(lucide-react@1.43.0(react@19.2.8))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react-router@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(zod@4.4.3): dependencies: '@fumari/image-size': 0.1.0 estree-util-value-to-estree: 3.5.0 @@ -16279,7 +16274,7 @@ snapshots: '@types/hast': 3.0.5 '@types/mdast': 4.0.4 '@types/react': 19.2.18 - lucide-react: 1.31.0(react@19.2.8) + lucide-react: 1.43.0(react@19.2.8) next: 16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) @@ -16288,14 +16283,14 @@ snapshots: transitivePeerDependencies: - supports-color - fumadocs-mdx@15.2.3(@types/mdast@4.0.4)(@types/mdx@2.0.14)(@types/react@19.2.18)(fumadocs-core@16.15.4(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.18)(lucide-react@1.31.0(react@19.2.8))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react-router@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(zod@4.4.3))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(rolldown@1.2.7)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)(yaml@2.9.0)): + fumadocs-mdx@15.2.3(@types/mdast@4.0.4)(@types/mdx@2.0.14)(@types/react@19.2.18)(fumadocs-core@16.15.4(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.18)(lucide-react@1.43.0(react@19.2.8))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react-router@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(zod@4.4.3))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(rolldown@1.2.7)(vite@8.2.2(@types/node@26.2.0)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)(yaml@2.9.0)): dependencies: '@mdx-js/mdx': 3.1.1 '@standard-schema/spec': 1.1.0 chokidar: 5.0.0 esbuild: 0.28.2 estree-util-value-to-estree: 3.5.0 - fumadocs-core: 16.15.4(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.18)(lucide-react@1.31.0(react@19.2.8))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react-router@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(zod@4.4.3) + fumadocs-core: 16.15.4(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.18)(lucide-react@1.43.0(react@19.2.8))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react-router@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(zod@4.4.3) github-slugger: 2.0.0 magic-string: 1.2.0 mdast-util-mdx: 3.0.0 @@ -16321,7 +16316,7 @@ snapshots: transitivePeerDependencies: - supports-color - fumadocs-ui@16.15.4(@types/mdx@2.0.14)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(fumadocs-core@16.15.4(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.18)(lucide-react@1.31.0(react@19.2.8))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react-router@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(zod@4.4.3))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(tailwindcss@4.3.3): + fumadocs-ui@16.15.4(@types/mdx@2.0.14)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(fumadocs-core@16.15.4(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.18)(lucide-react@1.43.0(react@19.2.8))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react-router@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(zod@4.4.3))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(tailwindcss@4.3.3): dependencies: '@fuma-translate/react': 1.0.2(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@fumadocs/tailwind': 0.1.1(tailwindcss@4.3.3) @@ -16337,8 +16332,8 @@ snapshots: '@radix-ui/react-tabs': 1.1.21(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) class-variance-authority: 0.7.1 cnfast: 0.1.0 - fumadocs-core: 16.15.4(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.18)(lucide-react@1.31.0(react@19.2.8))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react-router@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(zod@4.4.3) - lucide-react: 1.35.0(react@19.2.8) + fumadocs-core: 16.15.4(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.18)(lucide-react@1.43.0(react@19.2.8))(next@16.3.1(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@playwright/test@1.62.1)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react-router@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8)(zod@4.4.3) + lucide-react: 1.43.0(react@19.2.8) motion: 13.1.1(react-dom@19.2.8(react@19.2.8))(react@19.2.8) next-themes: 0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 @@ -17229,11 +17224,7 @@ snapshots: dependencies: yallist: 4.0.0 - lucide-react@1.31.0(react@19.2.8): - dependencies: - react: 19.2.8 - - lucide-react@1.35.0(react@19.2.8): + lucide-react@1.43.0(react@19.2.8): dependencies: react: 19.2.8 diff --git a/skills/objectui/guides/plugin-development.md b/skills/objectui/guides/plugin-development.md index 73cd506710..9f00484237 100644 --- a/skills/objectui/guides/plugin-development.md +++ b/skills/objectui/guides/plugin-development.md @@ -379,7 +379,7 @@ double-displays it. "@object-ui/core": "workspace:*", "@object-ui/react": "workspace:*", "@object-ui/types": "workspace:*", - "lucide-react": "^1.31.0" + "lucide-react": "^1.43.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", From d8b099222db867aedb00caf20484a17cf1fbf67b Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 10 Sep 2026 05:22:00 +0000 Subject: [PATCH 2/7] fix(components,examples): re-anchor the two DOM pins lucide 1.43.0's alias classes retired lucide-react 1.43.0 reshaped `createLucideIcon` to take an icon-data object carrying `aliases`, and it now emits one CSS class per retired alias. Measured on the installed artifact: 248 of 1818 icon modules carry an alias; 1.31.0 icon modules have no `aliases` field at all. Censused the whole tree for the two shapes this can break, using the alias index as the oracle: 28 distinct `lucide-*` class names are referenced anywhere in the repository (all file types, snapshots included) and exactly two of them are aliases in 1.43.0 -- `lucide-home` (owned by `house`) and `lucide-loader-2` (owned by `loader-circle`). Both are repaired here; the other 26 still name a canonical icon and stay discriminating. Control: injecting the known alias `trash-2` into the census is found, and `check` is correctly absent. - examples/schema-catalog svg-host-dom-leak-5632: asserts the EXACT attribute set, so the added class has to be named. Kept exact on purpose -- that list is what catches an authored prop reaching the DOM. - components button-shared-icon-resolver: its negative half read `querySelector('svg.lucide-home')` is null to prove `home` resolved through the rename to House. `house` now emits `lucide-home` itself, so that class no longer says which glyph was drawn. Replaced with a form that still fires for the same defect: one svg, and the alias class on that same element. Also adds the changeset the four touched released packages owe. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01611D6ZaRaMmwTNQmSbk8MH --- .../lucide-react-1-43-0-retired-trash2.md | 38 +++++++++++++++++++ .../test/svg-host-dom-leak-5632.test.tsx | 14 ++++++- .../button-shared-icon-resolver.test.tsx | 17 ++++++++- scripts/__tests__/doc-version-claims.test.ts | 2 +- 4 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 .changeset/lucide-react-1-43-0-retired-trash2.md diff --git a/.changeset/lucide-react-1-43-0-retired-trash2.md b/.changeset/lucide-react-1-43-0-retired-trash2.md new file mode 100644 index 0000000000..6707804c7b --- /dev/null +++ b/.changeset/lucide-react-1-43-0-retired-trash2.md @@ -0,0 +1,38 @@ +--- +'@object-ui/plugin-detail': patch +'@object-ui/components': patch +'@object-ui/types': patch +'@object-ui/cli': patch +--- + +Move `lucide-react` from `^1.31.0` to `^1.43.0` and repair the one spelling the jump +retires, so the delete affordances that resolve their icon from a STRING keep drawing a +glyph. + +Measured against the installed artifact rather than the upstream changelog. Across the +whole 1.31.0 to 1.43.0 jump lucide removes **zero** public names — 6072 to 6230 names in +`lucide-react`'s type surface with none dropped, 6068 to 6224 runtime exports with none +dropped, and nothing at all removed from `lucide-react/dynamic.mjs`. Every one of the 333 +value names and the one type name this repository imports resolves in both versions +(controls: `Trash` resolves in both, a bogus name resolves in neither). So no import +breaks and no type breaks. + +Exactly one key leaves the runtime `icons` record: `Trash2`. lucide retired it in favour +of `trash`, and it survives as a DEPRECATED EXPORT of the same object — which is why +nothing goes red on the compiler or on a component render, and only STRING lookups +through `renderers/action/resolve-icon.ts` are affected, because those read record +MEMBERSHIP. Repaired at all four sites that reach that resolver, three schema-catalog +documents and `DetailView`'s system delete action. + +What a user sees change: + +- `DetailView`'s delete action (`icon: 'trash-2'` to `'trash'`) draws its icon again + instead of a label with nothing beside it. The glyph is unchanged: lucide 1.43.0's + `trash` icon node is byte-identical to 1.31.0's `trash-2` icon node. +- Icons that lucide has since renamed now carry an extra class per retired alias — a + spinner renders `class="lucide lucide-loader-circle lucide-loader-2 ..."`. This is + additive (248 of 1818 icon modules carry an alias), so a `.lucide-loader-circle` + selector still matches; a selector asserting the exact, complete class string does not. +- The workspace stops installing two copies of the icon library. `main` resolves + `lucide-react` twice — 1.31.0 for this workspace and 1.35.0 for `fumadocs-ui` — and + both collapse onto 1.43.0 here. diff --git a/examples/schema-catalog/test/svg-host-dom-leak-5632.test.tsx b/examples/schema-catalog/test/svg-host-dom-leak-5632.test.tsx index eb4b4db607..0c4cf69d88 100644 --- a/examples/schema-catalog/test/svg-host-dom-leak-5632.test.tsx +++ b/examples/schema-catalog/test/svg-host-dom-leak-5632.test.tsx @@ -314,13 +314,23 @@ describe('schema-catalog — no SVG-hosted renderer leaks an authored prop to th // `SpinnerSchema.size` is an ENUM consumed through `sizeClasses`. Spreading // it handed the string to lucide's numeric `size` prop, which is how // `width="lg" height="lg"` reached every sized spinner in the catalog. - // `class` carries lucide's own two classes AND both of this renderer's — + // `class` carries lucide's own classes AND both of this renderer's — // `animate-spin` and the size class. Before this slice it carried ONLY // lucide's: the spread's `className` overrode the computed one, so a // `ui:spinner` rendered through `SchemaRenderer` did not spin. + // + // `lucide-loader-2` is lucide's own RETIRED-ALIAS class, not a leak. It + // appeared when `createLucideIcon` was reshaped to take an icon-data object + // carrying `aliases` (lucide-react 1.43.0; absent in 1.31.0, where icon + // modules have no `aliases` field at all) and it now emits one class per + // alias. Measured on the installed artifact: 248 of 1818 icon modules carry + // aliases, so any icon with one gains a class here. The assertion stays + // EXACT on purpose — this list is what catches an authored prop reaching + // the DOM, which is the whole point of objectui#5632; loosening it to a + // substring match would retire the check rather than update it. expect(attributesOf({ type: 'spinner', size: 'lg' })).toEqual([ 'aria-hidden="true"', - 'class="lucide lucide-loader-circle animate-spin h-8 w-8"', + 'class="lucide lucide-loader-circle lucide-loader-2 animate-spin h-8 w-8"', 'data-obj-type="spinner"', 'fill="none"', 'height="24"', diff --git a/packages/components/src/renderers/form/__tests__/button-shared-icon-resolver.test.tsx b/packages/components/src/renderers/form/__tests__/button-shared-icon-resolver.test.tsx index 20090a0eb4..694a340c12 100644 --- a/packages/components/src/renderers/form/__tests__/button-shared-icon-resolver.test.tsx +++ b/packages/components/src/renderers/form/__tests__/button-shared-icon-resolver.test.tsx @@ -142,8 +142,21 @@ describe('ui:button icon resolution (objectui#5993)', () => { // The single entry both maps carried. It is the one input whose answer // would have changed had the dedupe dropped the alias on the floor. const button = renderButton({ icon: 'home' }); - expect(button.querySelector('svg.lucide-house')).not.toBeNull(); - expect(button.querySelector('svg.lucide-home')).toBeNull(); + const house = button.querySelector('svg.lucide-house'); + expect(house).not.toBeNull(); + // The negative half used to read `querySelector('svg.lucide-home')` is + // null. That form RETIRED on lucide-react 1.43.0, which reshaped + // `createLucideIcon` to take an icon-data object carrying `aliases` and + // to emit one class PER ALIAS: `house` now renders + // `class="lucide lucide-house lucide-home ..."` itself, so the class no + // longer says which glyph was drawn (measured: 248 of 1818 icon modules + // carry aliases; 1.31.0 icon modules have no `aliases` field at all). + // The discriminating form is below and still fires for the same defect: + // `Home` is not a key of the runtime record, so had the rename been + // dropped this button would render NO glyph at all, and any SECOND glyph + // would be a different element from `house`. + expect(button.querySelectorAll('svg')).toHaveLength(1); + expect(button.querySelector('svg.lucide-home')).toBe(house); }); it('renders NO glyph for a retired spelling — the RECORD surface, not a fallback', () => { diff --git a/scripts/__tests__/doc-version-claims.test.ts b/scripts/__tests__/doc-version-claims.test.ts index 3b9b9ce4d6..90b49b9136 100644 --- a/scripts/__tests__/doc-version-claims.test.ts +++ b/scripts/__tests__/doc-version-claims.test.ts @@ -1175,7 +1175,7 @@ const KNOWN_CLAIMS: KnownClaim[] = [ // Reads as a `react` claim and is not one, for the same reason the plugins.md // `@vitejs/plugin-react` entry does: `React` is a TOOLCHAIN word and the `-` before it // is a word boundary, so the recorded literal is the TAIL of `lucide-react`. - claim: 'react": "^1.31.0', + claim: 'react": "^1.43.0', kind: 'anchored', skeletonDep: 'lucide-react', why: 'A runtime dependency of an IN-WORKSPACE plugin skeleton - the block is named @object-ui/plugin-my-widget, takes all four @object-ui dependencies at workspace:* and builds with vite build, so it resolves in this workspace and nowhere else. Anchor measured at the objectui#4981 cut: 16 of the 19 packages/plugin- manifests declare lucide-react and all 16 say ^1.31.0 (23 workspace-wide, unanimous). It read ^0.400.0, which is worse than an ordinary fossil: a 0.x caret cannot cross a minor, so that range resolves inside 0.400.x forever - the trap objectui#3755 removed from create-plugin\'s own dependency map. Recorded fork, not acted on here: #3755 DELETED its lucide entry rather than re-anchoring it, on the rule that this repo declares an icon library only where it imports one, and no code on this page imports one. Deleting the line is the alternative disposition; it would retire this entry with it.', From d8a940b6ee56202f59f91bf990e6fa5624b8380e Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 10 Sep 2026 06:04:52 +0000 Subject: [PATCH 3/7] chore(perf): raise the `ui-components` eager-closure ceiling for lucide 1.43.0 Measured on this branch's console build: `ui-components` is 410,904 bytes gzipped against a 399,000 ceiling -- over by 11,904. Ruled out as a tree-shaking regression BEFORE the number moved, because "the bundler stopped shaking" and "the dependency got bigger" want opposite fixes and only one of them is a ceiling: - ALL 1,818 keys of lucide 1.43.0's runtime `icons` record appear verbatim in the built chunk. Of 1.31.0's 1,767 keys, 1,766 appear in the same chunk -- the one absent is `Trash2`, the key lucide retired, which is what shows the probe discriminates rather than matching everything. A fabricated key is not found. - Icons therefore do not tree-shake here and did not before. That is deliberate: `resolve-icon.ts` imports the whole record because string lookups read record MEMBERSHIP (the objectui#5935 seam). Moving it to `lucide-react/dynamic.mjs` to shed bytes would resolve the very names the record drops -- `trash-2`, `edit`, `smile` -- which the icon gate's own header calls worse than having no gate. - The library is bigger two ways. Same-artwork control: `pencil.mjs`, whose icon node is byte-identical across versions, goes 455 -> 522 bytes because 1.43.0 reshaped every icon module into an `__iconData` object carrying `name`, `size` and `aliases`. And there are more icons: the icon directory, licence headers stripped and gzipped, goes 166,705 -> 176,968 bytes (+10,263, +6.2%) -- the same order as the chunk delta. Ceiling and baseline move together, in this one commit. New headroom is 9,096 bytes = 0.10x REGRESSION_THIS_GATE_MUST_CATCH_BYTES, the proportion objectui#7399 re-pinned this key to -- chosen over "just enough to pass", because a line left with almost no headroom is the defect objectui#8816 records. REGRESSION_THIS_GATE_MUST_CATCH_BYTES did not move. Nothing else moved: the aggregate was re-read on the same build and passes on its own (3,589,068 of 3,597,000, headroom 7,932), so it is left alone. The raised gate still fails: padding `ui-components` by 15,000 bytes in a COPY of the report gives `OVER by 5.8 KB` and exit 1, while the same invocation on an unpadded copy exits 0. The real report was never mutated. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01611D6ZaRaMmwTNQmSbk8MH --- scripts/check-eager-closure-budget.mjs | 55 +++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/scripts/check-eager-closure-budget.mjs b/scripts/check-eager-closure-budget.mjs index 1e108dfdbe..197723b68d 100644 --- a/scripts/check-eager-closure-budget.mjs +++ b/scripts/check-eager-closure-budget.mjs @@ -635,6 +635,48 @@ export const REGRESSION_THIS_GATE_MUST_CATCH_BYTES = 89 * 1024; * itself. Nothing else moved either — not the other three ceilings, not the * aggregate, not {@link BASELINE}. One ceiling and its baseline, in one commit. * + * ## Why `ui-components` moved UP — lucide-react 1.31.0 to 1.43.0 + * + * Measured on this branch's console build: 410,904 bytes, 11,904 over the + * 399,000 that stood. The cause is the icon library growing, and it was ruled + * out as a tree-shaking regression BEFORE this number moved, because "the + * bundler stopped shaking" and "the dependency got bigger" want opposite fixes + * and only one of them is a ceiling. + * + * What was measured, and the control that fired with it: + * + * - ALL 1,818 keys of lucide 1.43.0's runtime `icons` record appear verbatim + * in the built `ui-components` chunk. Not most — all. Of 1.31.0's 1,767 + * keys, 1,766 appear in that same chunk; the one absent is `Trash2`, the + * key lucide retired, which is what tells you the probe discriminates + * rather than matching everything. A fabricated key is not found. + * - So icons do not tree-shake here and did not tree-shake before either. + * That is DELIBERATE, not a defect: `renderers/action/resolve-icon.ts` + * imports the whole `icons` record because string lookups are resolved + * against record MEMBERSHIP, which is the seam objectui#5935 consolidated + * onto and `check-lucide-icon-record-names.mjs` enforces. Moving that seam + * to `lucide-react/dynamic.mjs` to shed the bytes would resolve names the + * record deliberately drops (`trash-2`, `edit`, `smile`), which is the + * exact failure that gate's header calls worse than having no gate. + * - The library itself is bigger, two independent ways. Same-artwork control: + * `pencil.mjs`, whose icon node is byte-identical across the two versions, + * goes 455 to 522 bytes, because 1.43.0 reshaped every icon module into an + * `__iconData` object carrying `name`, `size` and `aliases`. And there are + * more icons: the whole icon directory, licence headers stripped and + * gzipped, goes 166,705 to 176,968 bytes (+10,263, +6.2%) from 1.31.0 to + * 1.43.0 — the same order as the chunk delta this raise absorbs. + * + * ⇒ the bytes are not avoidable from the import side, so the ceiling moves. + * + * Headroom 9,096 bytes = 0.10x {@link REGRESSION_THIS_GATE_MUST_CATCH_BYTES} — + * the proportion objectui#7399 re-pinned THIS key to, chosen deliberately over + * "just enough to pass". A line left with almost no headroom is the defect + * objectui#8816 records, and this key was the tightest of the four before this + * raise. ⛔ {@link REGRESSION_THIS_GATE_MUST_CATCH_BYTES} did not move, and + * nothing else moved: not the other three ceilings, not the aggregate, not + * {@link BASELINE}. The aggregate was re-read on the same build and PASSES on + * its own — 3,589,068 of 3,597,000, headroom 7,932 bytes — so it is left alone. + * * ## Raising one * * Same discipline as {@link MAX_EAGER_CLOSURE_GZIP_BYTES}, and the same two @@ -663,7 +705,13 @@ export const PER_CHUNK_GZIP_CEILINGS = Object.freeze({ // REGRESSION_THIS_GATE_MUST_CATCH_BYTES on `3f775eeb8` — the loosest of the // four. See "Why `framework` moved UP" above for what that costs. framework: 100_000, - 'ui-components': 399_000, + // Raised for lucide-react 1.31.0 -> 1.43.0: the icons record ships whole by + // design and the library grew both in icon count and in per-icon metadata. + // Ruled out as a tree-shaking regression first — see "Why `ui-components` + // moved UP" above for the measurement and its controls. Headroom 9,096 bytes + // = 0.10x REGRESSION_THIS_GATE_MUST_CATCH_BYTES, the proportion objectui#7399 + // re-pinned this key to. + 'ui-components': 420_000, }); /** @@ -778,7 +826,10 @@ export const PER_CHUNK_BASELINE = Object.freeze({ // BASELINE's. Moved with the ceiling in the same commit, per the maintainer // ruling of 2026-09-08 and the rule stated under "Raising one". framework: 72_245, - 'ui-components': 391_095, + // Moved with its ceiling in the same commit, per the rule stated under + // "Raising one": this branch's own console build of the lucide-react 1.43.0 + // bump. ⛔ Not `2c8474c04`'s build, which measured the 1.31.0 icon set. + 'ui-components': 410_904, }); /** From fe84559725e3d059d1b18e6080b82504a6bc9c90 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 09:46:47 +0000 Subject: [PATCH 4/7] fix(components): keep the lazy-icon placeholder typed as a box under lucide 1.43.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `icons`-record-free seam objectui#9251 landed renders lucide's `Icon` with an `iconNode` it may not have yet, falling back to an empty node so the glyph still occupies its box while the module loads. lucide 1.43.0 split `Icon`'s props into a union — one arm takes `iconNode` and forbids `icon`, the other takes `icon` and forbids `iconNode`. Indexing a union yields the union of its members, so type IconNode = React.ComponentProps['iconNode']; quietly picked up the second arm's `iconNode?: undefined`. That widened the placeholder to include `undefined` — the one value NEITHER arm accepts — and the declaration build of `@object-ui/components` stopped at TS2769. Narrowing the alias with `NonNullable` restores what it always meant. It is a no-op against 1.31.0's single-arm props, so it says nothing new about the old version; it only stops the union widening the alias. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_018HrVaotisyhgmot9o2MLRq --- .../src/renderers/action/resolve-icon.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/components/src/renderers/action/resolve-icon.ts b/packages/components/src/renderers/action/resolve-icon.ts index 7dc71026ce..3124810a89 100644 --- a/packages/components/src/renderers/action/resolve-icon.ts +++ b/packages/components/src/renderers/action/resolve-icon.ts @@ -208,8 +208,18 @@ function lucideClassNames(recordKey: string, kebab: string, className?: string): .trim(); } -/** lucide's own path-data shape, taken from the component that consumes it. */ -type IconNode = React.ComponentProps['iconNode']; +/** + * lucide's own path-data shape, taken from the component that consumes it. + * + * ⛔ `NonNullable` is load-bearing, not decoration. lucide 1.43.0 split `Icon`'s + * props into a UNION — one arm takes `iconNode` and forbids `icon`, the other + * takes `icon` and forbids `iconNode` — and indexing a union yields the union + * of the members, so this alias silently picked up the second arm's + * `iconNode?: undefined`. That widened {@link EMPTY_ICON_NODE} to include + * `undefined`, which is the one value NEITHER arm accepts, so the placeholder + * written to guarantee a box stopped type-checking as a box. + */ +type IconNode = NonNullable['iconNode']>; /** * What the glyph holds before its module arrives: the same `` lucide From 6f20cfb06412f7251e3ca24a86639a9709f80a48 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 10:16:49 +0000 Subject: [PATCH 5/7] fix(components): read the icon path data lucide 1.43.0 actually exports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit objectui#9251's seam loads a glyph through `dynamicIconImports` and reads `__iconNode` off the resolved module. lucide 1.43.0 wraps that array in `__iconData`, next to `name`, `size` and `aliases`, and no longer exports `__iconNode` at all. The read therefore returned `undefined` for every icon, the `if (!node) return` guard took it, and the placeholder `` stayed empty forever — so under 1.43.0 every lazily resolved glyph in the product drew an empty box. ⚠️ The failure is invisible by construction. The placeholder is mounted with the right classes, the right box and the right attributes on the first frame, precisely so nothing reflows while the module is in flight; a glyph that never arrives is pixel-identical to one that has not arrived yet. Nothing throws, nothing logs, and the seam's own `.catch` is not entered because the import succeeded. Both spellings are read. The version this repo installs only needs the new one, but the two cost the same and the old one is what a consumer pinning an earlier lucide would ship. Caught by `resolve-icon-lazy-9251.test.tsx`'s `fills the path data in once the icon module arrives`, which went from `expected 0 to be greater than 0` to green on this change alone. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_018HrVaotisyhgmot9o2MLRq --- .../components/src/renderers/action/resolve-icon.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/components/src/renderers/action/resolve-icon.ts b/packages/components/src/renderers/action/resolve-icon.ts index 3124810a89..cc7d80e9ed 100644 --- a/packages/components/src/renderers/action/resolve-icon.ts +++ b/packages/components/src/renderers/action/resolve-icon.ts @@ -268,8 +268,15 @@ function lazyIconComponent(recordKey: string, kebab: string): LucideIcon { // better answer than a thrown render. if (!load) return undefined; void load() - .then((module: { __iconNode?: IconNode }) => { - const node = module.__iconNode; + .then((module: { __iconNode?: IconNode; __iconData?: { node?: IconNode } }) => { + // lucide moved the path data between these two exports: an icon + // module used to expose `__iconNode` directly and now wraps it in + // `__iconData` alongside `name`, `size` and `aliases`. Both are read + // because the failure mode of reading only one is invisible — the + // placeholder `` below is already mounted with the right classes + // and the right box, so a glyph that never arrives looks exactly like + // one that has not arrived YET. Nothing throws and nothing logs. + const node = module.__iconData?.node ?? module.__iconNode; if (!node) return; loadedIconNodes.set(kebab, node); if (live) setIconNode(node); From 178da2eeaba1ea16adb215a5a992bc323c34b18c Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 25 Sep 2026 11:56:25 +0000 Subject: [PATCH 6/7] test(components): relax the two class-fidelity pins lucide 1.43.0 turned red (ruling C) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Executes the maintainer's ruling C on objectui#8941 (comment 5750512894, verbatim 「8941 C」): relax the two pins, land the lucide-react bump. Exactly two pins, each carrying at its site what it used to refuse and why it no longer does. lucide-react 1.43.0 emits one class per DECLARED ALIAS and no longer the class it derived from the PascalCase key. The alias list lives only inside each icon module, which objectui#9251 made lazy, while the seam puts its classes on the first frame. Re-measured on the installed 1.43.0: of 1818 record keys the seam's class set and lucide's disagree on 324 (80 seam-only, 223 lucide-only, 21 both) and agree on 1494; the canonical `lucide-` class is on the seam for all 1818, and "the seam's set is a subset of lucide's" holds for only 1717, so the subset form of C would still be red and the canonical-only form is the one taken. resolve-icon-lazy-9251.test.tsx `reproduces lucide's per-icon class names over the WHOLE record vocabulary` becomes `carries lucide's CANONICAL per-icon class over the WHOLE record vocabulary`: `lucide` plus lucide's canonical class are required of the seam, against the record's own component for every key; alias classes and the key-derived class are no longer compared. button-shared-icon-resolver.test.tsx `resolves home through the RENAME alias to House` no longer requires the `lucide-home` alias class on the house svg, and does not return to the older "svg.lucide-home is null" form either, because lucide 1.43.0 puts that class on the house glyph itself. Exactly one svg, and it is `svg.lucide-house`. resolve-icon.ts (comment only) The `lucideClassNames` docblock claimed its classes were derived the way lucide derives them and that a pin catches either derivation drifting, under a test file name that does not exist. Both stopped being true with this bump and this relaxation; it now says what is emitted, what lucide 1.43.0 emits instead, and which pin holds how much. No code change. This weakens a gate that was telling the truth. The ruling was taken knowing that. Claude-Session: https://claude.ai/code/session_013RDBh5DqXd2xnLwvHLgLFr Co-authored-by: Claude --- .../__tests__/resolve-icon-lazy-9251.test.tsx | 39 +++++++++++++------ .../src/renderers/action/resolve-icon.ts | 34 +++++++++------- .../button-shared-icon-resolver.test.tsx | 29 +++++++------- 3 files changed, 65 insertions(+), 37 deletions(-) diff --git a/packages/components/src/renderers/action/__tests__/resolve-icon-lazy-9251.test.tsx b/packages/components/src/renderers/action/__tests__/resolve-icon-lazy-9251.test.tsx index 4dbc6436e8..ebbc559164 100644 --- a/packages/components/src/renderers/action/__tests__/resolve-icon-lazy-9251.test.tsx +++ b/packages/components/src/renderers/action/__tests__/resolve-icon-lazy-9251.test.tsx @@ -90,14 +90,27 @@ describe('objectui#9251 — the seam draws lazily without moving what renders', expect(renderIcon(resolveIcon('house')!, { size: 32 })!.getAttribute('width')).toBe('32'); }); - it('reproduces lucide\'s per-icon class names over the WHOLE record vocabulary', () => { - // ⚠️ The class names are the part a conversion rule gets wrong silently: 95 - // of the record's keys pack digits that lucide splits in the module name and - // not in the class derived from the key, so `Trash2` renders BOTH - // `lucide-trash2` and `lucide-trash-2`. `createLucideIcon` is what builds - // them and the seam no longer calls it, so every name is compared against - // the record's own component here — not a sample, and not a copy of the - // rule. + it('carries lucide\'s CANONICAL per-icon class over the WHOLE record vocabulary', () => { + // ⚠️ RELAXED under the maintainer's ruling C on objectui#8941 (comment + // 5750512894, verbatim 「8941 C」). This row USED TO REFUSE any seam glyph + // whose complete class set differed from lucide's own component's. It NO + // LONGER DOES, because lucide-react 1.43.0 emits one class per DECLARED + // ALIAS (`house` renders `lucide-house lucide-home`) and no longer emits the + // class it used to derive from the key, and the alias list exists only + // inside each icon module — the modules objectui#9251 made lazy — while the + // seam has to put its classes on the FIRST frame. The ruling chose the bump + // over carrying every alias in the eager static name list (option A), and + // it was taken knowing that it weakens this row. So a seam glyph missing + // lucide's alias classes, or carrying the key-derived class lucide no longer + // emits, now passes here. + // + // What it still refuses: a seam glyph without `lucide` or without lucide's + // CANONICAL class, `lucide-`, which lucide emits first after the + // bare `lucide`. That is the class a conversion rule gets wrong silently, + // because many keys pack digits that lucide splits in the module name + // (`ArrowDown01` is `lucide-arrow-down-0-1`, never `lucide-arrow-down01`). + // Every name is still compared against the record's own component — not a + // sample, and not a copy of the rule. const keys = Object.keys(icons); expect(keys.length).toBeGreaterThan(1000); const mismatches: string[] = []; @@ -106,9 +119,13 @@ describe('objectui#9251 — the seam draws lazily without moving what renders', if (/\d/.test(key)) digitKeysChecked += 1; const reference = renderIcon((icons as Record)[key], {}); const seam = renderIcon(resolveIcon(key)!, {}); - const want = classesOf(reference).join(' '); - const got = classesOf(seam).join(' '); - if (want !== got) mismatches.push(`${key}: expected "${want}", got "${got}"`); + // Read in lucide's own order: `lucide`, then the canonical class, then + // one class per alias. Only the first two are required of the seam. + const [base, canonical] = (reference?.getAttribute('class') ?? '').split(/\s+/).filter(Boolean); + const got = classesOf(seam); + if (base !== 'lucide' || !canonical?.startsWith('lucide-') || !got.includes(base) || !got.includes(canonical)) { + mismatches.push(`${key}: expected "${base} ${canonical}" among "${got.join(' ')}"`); + } } expect(mismatches.slice(0, 10)).toEqual([]); // Non-vacuity, both ways: the loop ran, and it ran over the class of name diff --git a/packages/components/src/renderers/action/resolve-icon.ts b/packages/components/src/renderers/action/resolve-icon.ts index cc7d80e9ed..99c47bc103 100644 --- a/packages/components/src/renderers/action/resolve-icon.ts +++ b/packages/components/src/renderers/action/resolve-icon.ts @@ -180,25 +180,33 @@ function recordIconName(key: string): string | undefined { } /** - * The two `lucide-*` class names lucide's own `createLucideIcon` puts on every - * glyph, rebuilt here because they are added by `createLucideIcon`, which builds the - * per-icon components this seam no longer loads. `Icon` — the component every - * lucide glyph ultimately renders, and the one used below — contributes only - * the bare `lucide` class. + * The per-icon `lucide-*` class names, rebuilt here because lucide derives them + * from the icon's own module, which this seam does not have on the first frame. + * `Icon` — the component every lucide glyph ultimately renders, and the one + * used below — contributes only the bare `lucide` class when it is handed a + * bare `iconNode`. * * ⚠️ Without this, `svg.lucide-house` would stop matching anywhere in the * product and in 194 lines of this repo's own assertions, and it would stop * matching SILENTLY: the glyph still draws, so nothing looks broken until a * stylesheet or a query that selects by icon identity quietly matches nothing. * - * Both spellings are derived the way lucide derives them — - * `lucide-${toKebabCase(toPascalCase(kebab))}` and `lucide-${kebab}` — which is - * one class for most icons and two for the 95 whose PascalCase key packs digits - * (`Trash2` gives `lucide-trash2 lucide-trash-2`). The PascalCase key is - * already in hand here, so only the kebab-casing of it is re-implemented; - * `resolve-icon-classnames.test.ts` pins the result against the record's own - * components over the WHOLE vocabulary, so a lucide change to either derivation - * fails rather than drifts. + * Two spellings are emitted: `lucide-${kebab}`, lucide's CANONICAL class for + * the icon, and `lucide-${toKebabCase(toPascalCase(kebab))}`, the class lucide + * derived from the PascalCase key up to 1.35.0 — one class for most icons and + * two for the keys that pack digits or a leading initial (`ArrowDown01` also + * gives `lucide-arrow-down01`). The PascalCase key is already in hand here, so + * only the kebab-casing of it is re-implemented. + * + * ⚠️ That is NOT the set lucide-react 1.43.0 puts on its own component, which + * no longer carries the key-derived class and carries one class per DECLARED + * ALIAS instead (`house` also renders `lucide-home`). The alias list + * exists only inside each lazily loaded icon module, and the maintainer's + * ruling C on objectui#8941 (comment 5750512894, 「8941 C」) accepted that the + * seam reproduces the canonical class and not the aliases, rather than carry + * every alias in the eager static name list. `resolve-icon-lazy-9251.test.tsx` + * pins exactly that much — `lucide` plus the canonical class — against the + * record's own components over the WHOLE vocabulary. */ function lucideClassNames(recordKey: string, kebab: string, className?: string): string { const fromKey = `lucide-${recordKey.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()}`; diff --git a/packages/components/src/renderers/form/__tests__/button-shared-icon-resolver.test.tsx b/packages/components/src/renderers/form/__tests__/button-shared-icon-resolver.test.tsx index 694a340c12..34c0577b11 100644 --- a/packages/components/src/renderers/form/__tests__/button-shared-icon-resolver.test.tsx +++ b/packages/components/src/renderers/form/__tests__/button-shared-icon-resolver.test.tsx @@ -142,21 +142,24 @@ describe('ui:button icon resolution (objectui#5993)', () => { // The single entry both maps carried. It is the one input whose answer // would have changed had the dedupe dropped the alias on the floor. const button = renderButton({ icon: 'home' }); - const house = button.querySelector('svg.lucide-house'); - expect(house).not.toBeNull(); - // The negative half used to read `querySelector('svg.lucide-home')` is - // null. That form RETIRED on lucide-react 1.43.0, which reshaped - // `createLucideIcon` to take an icon-data object carrying `aliases` and - // to emit one class PER ALIAS: `house` now renders - // `class="lucide lucide-house lucide-home ..."` itself, so the class no - // longer says which glyph was drawn (measured: 248 of 1818 icon modules - // carry aliases; 1.31.0 icon modules have no `aliases` field at all). - // The discriminating form is below and still fires for the same defect: + expect(button.querySelector('svg.lucide-house')).not.toBeNull(); + // ⚠️ RELAXED under the maintainer's ruling C on objectui#8941 (comment + // 5750512894, verbatim 「8941 C」). This row USED TO REFUSE a house glyph + // that did not also carry lucide's `lucide-home` ALIAS class on the same + // element: `querySelector('svg.lucide-home')` had to BE the house svg. It + // NO LONGER DOES, because this button draws through the objectui#9251 + // seam, which emits lucide's canonical class and not lucide-react + // 1.43.0's per-alias classes, and the ruling accepted that rather than + // put every icon's aliases into the eager static name list. + // + // ⛔ Nor does it go back to the older form, `svg.lucide-home` is null: + // lucide 1.43.0 itself puts `lucide-home` on the house glyph, so that + // class no longer says which glyph was drawn, and pinning its absence + // would pin the seam's divergence from lucide. `lucide-home` is neither + // required nor forbidden here. What still discriminates is the count: // `Home` is not a key of the runtime record, so had the rename been - // dropped this button would render NO glyph at all, and any SECOND glyph - // would be a different element from `house`. + // dropped this button would render NO glyph at all. expect(button.querySelectorAll('svg')).toHaveLength(1); - expect(button.querySelector('svg.lucide-home')).toBe(house); }); it('renders NO glyph for a retired spelling — the RECORD surface, not a fallback', () => { From 989330df0f750350cdd1dd4751da414f170e54b2 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 25 Sep 2026 12:09:51 +0000 Subject: [PATCH 7/7] docs(changeset): restate the lucide-react 1.43.0 entry against today's tree The entry was written before objectui#9251 landed and before main's lockfile moved to 1.35.0. Three of its claims stopped being true: the double lucide install it credited to this bump was already collapsed by the #9316 dedupe; its class note called the per-alias classes purely additive, when 1.43.0 also drops the key-derived class on component imports; and it said nothing about string-resolved icons, which under ruling C keep the seam's classes and do not get lucide's alias classes. It now declares every released package whose `lucide-react` range moves (20 in `dependencies`, the console in `devDependencies`) plus `cli` and `types`, whose source changed, all `patch`. It names the invisible-glyph repair (`__iconData`) as a user-visible fix, and dates the `Trash2` class example in the pending objectui#9251 entry, without editing that entry. Claude-Session: https://claude.ai/code/session_013RDBh5DqXd2xnLwvHLgLFr Co-authored-by: Claude --- .../lucide-react-1-43-0-retired-trash2.md | 81 ++++++++++++------- 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/.changeset/lucide-react-1-43-0-retired-trash2.md b/.changeset/lucide-react-1-43-0-retired-trash2.md index 6707804c7b..85d6abb688 100644 --- a/.changeset/lucide-react-1-43-0-retired-trash2.md +++ b/.changeset/lucide-react-1-43-0-retired-trash2.md @@ -1,38 +1,61 @@ --- -'@object-ui/plugin-detail': patch +'@object-ui/app-shell': patch +'@object-ui/cli': patch '@object-ui/components': patch +'@object-ui/console': patch +'@object-ui/fields': patch +'@object-ui/layout': patch +'@object-ui/plugin-ai': patch +'@object-ui/plugin-calendar': patch +'@object-ui/plugin-charts': patch +'@object-ui/plugin-chatbot': patch +'@object-ui/plugin-dashboard': patch +'@object-ui/plugin-designer': patch +'@object-ui/plugin-detail': patch +'@object-ui/plugin-form': patch +'@object-ui/plugin-gantt': patch +'@object-ui/plugin-grid': patch +'@object-ui/plugin-kanban': patch +'@object-ui/plugin-list': patch +'@object-ui/plugin-report': patch +'@object-ui/plugin-tree': patch +'@object-ui/plugin-view': patch +'@object-ui/runner': patch '@object-ui/types': patch -'@object-ui/cli': patch --- -Move `lucide-react` from `^1.31.0` to `^1.43.0` and repair the one spelling the jump -retires, so the delete affordances that resolve their icon from a STRING keep drawing a -glyph. - -Measured against the installed artifact rather than the upstream changelog. Across the -whole 1.31.0 to 1.43.0 jump lucide removes **zero** public names — 6072 to 6230 names in -`lucide-react`'s type surface with none dropped, 6068 to 6224 runtime exports with none -dropped, and nothing at all removed from `lucide-react/dynamic.mjs`. Every one of the 333 -value names and the one type name this repository imports resolves in both versions -(controls: `Trash` resolves in both, a bogus name resolves in neither). So no import -breaks and no type breaks. +Move `lucide-react` from `^1.31.0` to `^1.43.0` in every package that declares it, and +repair what the jump breaks, so icons resolved from a STRING keep drawing a glyph. -Exactly one key leaves the runtime `icons` record: `Trash2`. lucide retired it in favour -of `trash`, and it survives as a DEPRECATED EXPORT of the same object — which is why -nothing goes red on the compiler or on a component render, and only STRING lookups -through `renderers/action/resolve-icon.ts` are affected, because those read record -MEMBERSHIP. Repaired at all four sites that reach that resolver, three schema-catalog -documents and `DetailView`'s system delete action. +Measured once against the installed 1.43.0 artifact when this change was made; nothing in +the repository re-derives these readings. Across the jump lucide removes no runtime export, +no public type name and no `lucide-react/dynamic.mjs` name, and every name this repository +imports from `lucide-react` resolves. Exactly one key leaves the runtime `icons` record: +`Trash2`, retired in favour of `trash`. What a user sees change: -- `DetailView`'s delete action (`icon: 'trash-2'` to `'trash'`) draws its icon again - instead of a label with nothing beside it. The glyph is unchanged: lucide 1.43.0's - `trash` icon node is byte-identical to 1.31.0's `trash-2` icon node. -- Icons that lucide has since renamed now carry an extra class per retired alias — a - spinner renders `class="lucide lucide-loader-circle lucide-loader-2 ..."`. This is - additive (248 of 1818 icon modules carry an alias), so a `.lucide-loader-circle` - selector still matches; a selector asserting the exact, complete class string does not. -- The workspace stops installing two copies of the icon library. `main` resolves - `lucide-react` twice — 1.31.0 for this workspace and 1.35.0 for `fumadocs-ui` — and - both collapse onto 1.43.0 here. +- Icons the lazy icon seam draws (`resolveIcon`, objectui#9251) get their path data again. + lucide 1.43.0 icon modules export their path data inside `__iconData` and no longer + export `__iconNode`; the seam now reads both. Reading only `__iconNode` against 1.43.0 + leaves every such glyph an empty box, with nothing thrown or logged. +- `DetailView`'s delete action and three schema-catalog examples spell their icon + `trash`, not `trash-2`, so they keep resolving. The glyph is unchanged: 1.43.0's `trash` + path data is byte-identical to the `trash-2` path data of 1.31.0 and 1.35.0. Anything + that already authored `trash` now draws that same artwork, because lucide moved it under + the `trash` name; a few other glyphs were also redrawn upstream. +- Icons imported as COMPONENTS carry lucide 1.43.0's own classes: one class per declared + alias (a spinner renders `class="lucide lucide-loader-circle lucide-loader-2 ..."`), and + no longer the class lucide used to derive from the PascalCase key where that differs + (`ArrowDown01` no longer carries `lucide-arrow-down01`). The canonical + `lucide-` class is still there, so a `.lucide-loader-circle` selector still + matches. +- Icons resolved from a STRING through the seam keep the classes they had: `lucide`, the + canonical `lucide-` class and the key-derived class. They do not carry + lucide's per-alias classes. That is a maintainer ruling (objectui#8941, option C): the + alias list lives only inside each lazily loaded icon module, and it was not moved into + the eager name list. A selector that targets an alias class matches a component-imported + icon and not a string-resolved one. This also dates the example in the objectui#9251 + entry: `trash-2` no longer resolves as a string, so no seam-drawn glyph carries + `lucide-trash2 lucide-trash-2`; a digit-bearing name that still resolves, such as + `arrow-down-0-1`, carries `lucide-arrow-down01 lucide-arrow-down-0-1`.