Skip to content

fix(components): div 废弃提示每次模块加载只报一次;catalog 换类型那一半升级待定夺 (#3965) - #3998

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-3965-catalog-div-retirement
Aug 9, 2026
Merged

fix(components): div 废弃提示每次模块加载只报一次;catalog 换类型那一半升级待定夺 (#3965)#3998
yinlianghui merged 1 commit into
mainfrom
claude/issue-3965-catalog-div-retirement

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes #3965

⚠️ 合并前请把上面的 Fixes 改成 Refs 本 PR 只落地 #3965第二半(div.tsx 的 warn 去重)。第一半(catalog 示例换掉废弃的 div)在现有组件词表下无法完整完成 —— 已带 file:line 证据升级给维护者定夺,见下面「第一半为什么没做」。按 Fixes 合并会把还有一半未做的 issue 自动关掉。

基 sha 0cbdca888


落地的:div 废弃提示改为每次模块加载只报一次

packages/components/src/renderers/basic/div.tsx

DivRenderer 原先在每一次渲染console.warn。单个 div 的页面看不出问题,div 多的页面就被刷成噪声墙:docs 的 schema-catalog 索引页渲染 400+ 个示例缩略图,catalog 里共 189 个 div 节点,于是刷出百来条完全相同的提示,把页面真正的报错埋在下面 —— #3903 / PR #3964 的两条嵌套按钮报错就是从这堆噪声里捞出来的,浏览器实证因此两次丢掉信号。

废弃本身一字未动:dev 构建照旧提示,文案与迁移建议逐字节不变,production 构建照旧静默;去掉的只是重复。守卫是模块级 Set(按 type 记,span.tsx 将来照抄同一形状即可),production 的提前返回发生在标记之前 —— 所以一次 production 渲染不会吞掉后续 dev 构建的提示。这一条顺序是被测试钉住的,不是注释里的口头承诺。

钉子

packages/components/src/__tests__/div-deprecation-warn-once.test.tsx,3 条:

  1. stays silent in production builds —— production 构建零提示,且必须跑在最前(守卫是模块级的,会 latch)。它同时钉住上面那条顺序:production 渲染不得标记 Set。
  2. warns exactly once however many div nodes render —— 3 次 render、其中一次嵌 3 层共 6 个 div 节点,只允许 1 条提示;并断言文案里的两条迁移建议原样保留(证明钉的是「去重」而不是「删警告」)。
  3. does not warn again on a later render —— 同一模块实例里后续渲染不再报。

反向验证(先预判,后执行)

预判:把无守卫的旧写法改回去,用例 1 应当保持绿(旧写法同样按 NODE_ENV 门控,production 本来就静默),用例 2、3 应当翻红

实测与预判一致:

❯ |dom| packages/components/src/__tests__/div-deprecation-warn-once.test.tsx (3 tests | 2 failed)
     × warns exactly once however many div nodes render 19ms
     × does not warn again on a later render 3ms
AssertionError: expected [ …(9) ] to have a length of 1 but got 9
AssertionError: expected [ Array(1) ] to have a length of +0 but got 1
 Test Files  1 failed (1)
      Tests  2 failed | 1 passed (3)

旧写法下实测 9 条(不是节点数 6 —— 提示条数取决于 React 的渲染次数,不是 schema 里的节点数)。这正是钉子在修好一侧断言「恰好 1 条」而不是断言某个具体刷屏条数的原因。变异未提交。


第一半为什么没做:现有词表里有一半 div 没有非废弃对等物

在基 sha 上重新量过(与分诊评论的 47 一致,issue 卡片的 48 是过时计数):47 个文件、189 个 div 节点。节点上出现过的键只有 type / className / children / body —— 没有 id、没有 events,它们全是纯样式包装。

按 className 里是否真的写着布局意图分类:

分类 节点数 有对等物?
className 含 flex(不含 flex-col) 84 是 → flex
className 含 space-y-* 9 是 → stack
className 含 max-w-* 8 是 → container
className 含 grid / grid-cols-* 5 是 → grid
纯装饰盒子(p-4 h-full bg-slate-50w-full h-12 rounded-md bg-primary mb-2p-12 border rounded bg-gradient-to-r …) 61
完全没有 className 的分组包装 22

可换的 106 个,换不掉的 83 个、散在 26 个文件里 —— 也就是说即使把能换的全换掉,47 个文件里仍有 26 个含 div。那不是「豁免清单」,那是这一半做不成。

为什么废弃提示自己给的建议都不是对等物

提示推荐 card / flex / container / stack / grid。逐个读渲染器:每一个都往 className 前面注入类,div 是唯一的透传:

  • layout/container.tsx:21-53 —— 注入 w-full max-w-xl mx-auto p-2 sm:p-3 md:p-4
  • layout/flex.tsx:22-55 —— 注入 flex flex-row justify-start items-start gap-1.5 sm:gap-2
  • layout/stack.tsx:25-58 —— 注入 flex flex-col justify-start items-stretch gap-*
  • layout/grid.tsx:91-103 —— 注入 grid grid-cols-* gap-*
  • layout/card.tsx:36-56 —— Card 自带 border / shadow / rounded,children 还被塞进 CardContent(自带 padding)

对 8 个空的颜色色板(theme/semantic-color-palette.jsonw-full h-12 rounded-md bg-primary mb-2 这种、无 children)来说,以上每一个都会改变渲染:凭空多出边框、flex 上下文或 max-width。

唯一逐字节等价的是 layout/semantic.tsx:13-47 —— article / aside / main / nav / section / header / footer 就是 className + children || body 的裸透传(bare section/header/footer 由它拿走:containers.tsx 那三个注册的是 page:*skipFallback: true,不冲突)。但它们是 sectioning / landmark 元素:main 标签在一个文档里必须唯一,而 docs 页面是把示例嵌进去渲染的;把 22 个「没有 className 的分组包装」和 8 个空色板写成 section,等于把「用 sectioning 元素当通用盒子」这条写进 45 个文档范本。issue 的立论正是「范本的示范价值」—— 用一个错范本换掉另一个错范本,不解决问题。

而且 div 结构上退不掉

kind: 'html' 那一层作者面(ADR-0080)会把标签名原样变成 type:

  • sdui-parser/src/parse.ts:85 —— const node: SchemaElement = { type: tag, ...props }
  • sdui-parser/src/index.ts:33 —— allowedTags = new Set(Object.keys(manifest.components))
  • components/src/renderers/layout/page.tsx:438-470 —— 白名单由 ComponentRegistry.getKnownTypes() 生成,裸 div 在内
  • basic/html-elements.tsx:15,36 —— 自己的 TAGS 列表故意排除 div,注释写明「div 已在别处注册」

所以一个 kind: 'html' 页面里写一个 div 标签,编译出的就是 { "type": "div" },照样打到废弃渲染器上。div 是 html tier 词表的必需成员,不可退休 —— 于是「零 div」在本仓永远不可能是一条全仓不变量,而这条废弃提示会永久地对引擎自己解析器的输出开火。

另外查了 @objectstack/spec:element:* 词表里既没有 div 也没有 box,div 是 objectui 本地词表(ui 命名空间)的东西 —— 所以这不是 spec 层的取舍,是本仓自己的公共契约取舍。

请维护者定夺的三个选项

A. 补一个中性容器类型(如 box)。 注册表 + @object-ui/types schema + docs + parser 白名单一并落。之后 189 个节点 divbox 是一次零渲染差异、机械可验的替换,catalog 才可能真的零 div

  • 长期健康度:高。废弃一个类型却没给替代品,本来就是这条废弃没做完 —— 补上替代品是把契约补完整,不是绕过它。
  • 让 AI 写的 metadata 不容易写错:高。作者面得到一个**名字就说明「我只是个盒子」**的类型,不必在 container(悄悄加 max-width)和 section(悄悄加 landmark 语义)之间猜。
  • 代价:新增公共类型;div 的废弃需要重新指向 box

B. 收窄这条废弃,承认残余 div 合法。 JSON 作者面继续劝退;html tier 的解析产物不再报废弃;catalog 里 106 个明确写着布局意图的节点转成 flex/stack/grid/container(那 106 个是纯赚:JSON 手写 Tailwind 复刻一等公民组件的 props,本来就该用 props);余下 83 个保留 div

  • 长期健康度:中。诚实地承认 div 退不掉,但留下「一个废弃类型永久合法」这一含糊状态。
  • 让 AI 写的 metadata 不容易写错:中。提示不再对 html tier 误伤是净收益,但作者仍要自己判断「这个 div 属于劝退的那批还是合法的那批」。
  • 代价:最小改动,不动公共词表。

C. 强推 semantic 标签。 83 个残余全换 section / article

  • 长期健康度:低。词表不用动,但把「sectioning 元素 = 通用盒子」写进 45 个文档范本,a11y 与文档大纲语义都变差,而且 div 在 html tier 依然会被解析出来 —— 提示照旧刷。
  • 让 AI 写的 metadata 不容易写错:。这是最典型的「照着范本抄」放大错误的路径:AI 会学到用 landmark 元素包一切。
  • 代价:表面上最省,实际把成本转移给未来的每一个作者。

推荐:短期 B,长期 A。 两轴一致指向「先把误伤 html tier 的部分收窄 + 把 106 个明确布局意图转成 props(这批与词表决定无关,任何选项下都成立),同时把 box 作为把这条废弃真正做完的方向」。明确不推荐 C —— 它在第二轴上是负的,而第二轴正是这个 issue 的立论。

选定之后我可以把对应的 sweep 单独接着做;现在不猜,因为三个选项指向的 diff 形状完全不同(A 是 189 个节点一行改一个字;B 是 106 个节点重写成 props;C 是 83 个节点换 sectioning 标签),猜错要全部推倒。


验证

  • pnpm --workspace-concurrency=2 --filter "@object-ui/components^..." build —— 绿(新 worktree 先建依赖)。
  • pnpm exec vitest run packages/components/src/__tests__/div-deprecation-warn-once.test.tsx packages/components/src/__tests__/basic-renderers.test.tsx examples/schema-catalog --maxWorkers=2 —— Test Files 6 passed (6) / Tests 1115 passed (1115)
  • pnpm exec turbo run type-check --filter=@object-ui/components --concurrency=2 —— Tasks: 8 successful, 8 total
  • node scripts/check-control-bytes.mjs —— OK (scanned 3902 tracked text file(s));改动文件另做了越过门禁盲区的自查,零命中。
  • node scripts/check-changeset-presence.mjs / check-changeset-no-major.mjs —— 均绿。

边界

只动了 packages/components/src/renderers/basic/div.tsx + 一个新测试 + 一个 changeset。没有examples/schema-catalog/**(含同批 #3968 的 test/tsconfig/scripts 面)、没有碰 26 个 MDX 文档页、没有content/docs/releases/basic/span.tsx 带同族的逐次渲染警告(catalog 里 span 命中 0),按派发边界未动 —— 它该照抄本 PR 的守卫形状,留作后续。


Generated by Claude Code

`DivRenderer` 原先在每一次渲染里 `console.warn`。单个 `div` 的页面看不出问题,
`div` 多的页面就被刷成噪声墙:docs 的 schema-catalog 索引页渲染 400+ 个示例缩略图,
实测刷出约 190 条完全相同的提示,把页面真正的报错埋在下面 —— #3903 / PR #3964 的两条
嵌套按钮报错就是从这堆噪声里捞出来的,浏览器实证也因此两次丢掉信号。

废弃本身一字未动:dev 构建照旧提示,文案与迁移建议不变,production 构建照旧静默,
去掉的只是重复。守卫是模块级 `Set`(按 type 记),production 的提前返回发生在标记之前,
所以一次 production 渲染不会吞掉后续 dev 构建的提示。

反向验证(先预判后执行):把无守卫的旧写法改回去,「production 静默」用例按预期保持
绿(旧写法同样按 NODE_ENV 门控),「只报一次」与「后续渲染不再报」两条按预期翻红
(9 条提示 vs 期望 1 条;后续渲染多出 1 条)。

注:本 PR 只完成 #3965 的第二半(warn 去重)。第一半(catalog 48 个示例换掉废弃的
`div`)在现有组件词表下无法完整完成,已在 issue 上以证据升级给维护者定夺,见 PR 正文。

Co-Authored-By: Claude <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectui Ignored Ignored Aug 9, 2026 10:31pm

Request Review

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 28.1 KB 350 KB
Entry file index-D5_RDZU1.js
Status PASS

📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 8.66KB 3.13KB
app-shell (runtime-config.js) 7.42KB 2.32KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 7.57KB 2.97KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 22.10KB 4.37KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.13KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.64KB 2.21KB
auth (SocialSignInButtons.js) 9.60KB 3.89KB
auth (UserMenu.js) 3.40KB 1.22KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 35.76KB 9.11KB
auth (createAuthenticatedFetch.js) 4.37KB 1.69KB
auth (index.js) 2.35KB 1.07KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 4.91KB 0.87KB
auth (useIsWorkspaceAdmin.js) 1.61KB 0.85KB
collaboration (CommentThread.js) 26.07KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.65KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 483.72KB 106.71KB
core (index.js) 3.00KB 1.14KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 139.61KB 35.99KB
fields (index.js) 227.99KB 56.47KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.32KB 1.77KB
i18n (index.js) 2.65KB 1.06KB
i18n (pickLocalized.js) 1.70KB 0.83KB
i18n (provider.js) 9.48KB 3.27KB
i18n (useObjectLabel.js) 27.59KB 6.63KB
i18n (useSafeTranslation.js) 4.52KB 1.96KB
layout (index.js) 38.82KB 10.79KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.74KB
mobile (index.js) 1.50KB 0.62KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.71KB 0.42KB
mobile (useResponsiveConfig.js) 1.36KB 0.63KB
mobile (useSpecGesture.js) 4.32KB 1.64KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 8.75KB 3.06KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 3.67KB 1.12KB
permissions (evaluator.js) 4.41KB 1.44KB
permissions (index.js) 0.91KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.52KB
permissions (usePermissions.js) 1.55KB 0.71KB
plugin-ai (index.js) 15.71KB 3.79KB
plugin-calendar (index.js) 45.23KB 12.45KB
plugin-charts (index.js) 61.49KB 17.48KB
plugin-chatbot (index.js) 180.33KB 42.79KB
plugin-dashboard (index.js) 118.67KB 30.69KB
plugin-designer (index.js) 210.51KB 42.51KB
plugin-detail (index.js) 237.80KB 59.48KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 112.86KB 27.24KB
plugin-gantt (index.js) 162.79KB 39.67KB
plugin-grid (index.js) 187.97KB 49.79KB
plugin-kanban (index.js) 48.53KB 13.38KB
plugin-list (index.js) 109.73KB 26.55KB
plugin-map (index.js) 17.05KB 5.33KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 40.58KB 10.58KB
plugin-timeline (index.js) 25.99KB 7.42KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 84.03KB 20.55KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.71KB 3.53KB
providers (index.js) 0.44KB 0.22KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.67KB 2.37KB
react (LazyPluginLoader.js) 3.77KB 1.33KB
react (SchemaRenderer.js) 23.71KB 7.95KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.23KB 0.66KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 4.09KB 1.74KB
sdui-parser (index.js) 4.47KB 2.03KB
sdui-parser (parse.js) 10.04KB 2.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 4.69KB 1.48KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.87KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-retry.js) 4.32KB 2.02KB
types (index.js) 2.71KB 1.34KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 2.59KB 1.31KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (spec-report.js) 5.05KB 1.93KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 3.40KB 1.71KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Copy link
Copy Markdown
Collaborator Author

补两条给「将来真做 catalog sweep 的人」的关键约束,免得踩进去:

1. components-basic-div/ 下有两个示例是故意保留的废弃范本,任何选项下都不能换。

  • components-basic-div/custom-card.json(2 个 div 节点)
  • components-basic-div/nested-divs.json(3 个 div 节点)

它们被 content/docs/components/basic/div.mdx:62-70 以「Legacy Examples (For Reference Only)」这个小节引用,存在的意义就是展示 div 长什么样、以便和上面 use-card-instead / flex-layout / grid-layout 三个迁移范本对照。把它们换掉等于把这一页讲的事情本身删了。也就是说 47 个文件里至少 2 个永久豁免,「零 div」再怎么算都得带豁免清单。

2. 同目录的迁移范本 grid-layout.json 自己写错了键,已单独开 #4001:它写 cols: 2,而 GridSchema / 渲染器 / 注册表 inputs 声明的都是 columns,实测 cols 被静默丢弃(cols:4 渲染出 grid grid-cols-2,而 columns:4 才是 grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4)。catalog 里共 13 个文件中招,要 3/4 列的 6 个在 docs 站上就是错的(production 也错)。与本 PR 的 div 面不相交,故分开。

另:div 的废弃警告会对 kind: 'html' tier 自己解析出的节点开火(作者无法消除)已单独记为 #4000 —— 它是上面「div 结构上退不掉」那一节的独立化,决定选项 A/B 时需要一并考虑。


Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

PM 验收(session_01GTRjn8xBqp75dk7kFupVRt):通过,转 ready 并挂 auto-merge —— 验收的是已落地的 warn 去重半边;catalog 换类型半边的 needs_decision 升级完全正确(83/189 节点无非废弃对等物 + div 因 html-tier 解析器结构上不可退役 = 补救可行性前提失效,越过部分清扫进入公共词表决定 —— 这正是该停的地方)。

核验记录(head e1cb3e712,基 0cbdca888,实物核验 + CI 亲读):

  1. warn-once 实现:module Set 按 type 记(span.tsx 将来照抄)、production 提前返回排在标记前(顺序被钉住而非注释承诺)、文案逐字节不变;沿 containers.tsx 既有 warn-once 惯例。
  2. 反向验证是混合方向且预判命中(旧写法下用例 1 保持绿 —— production 本就静默;2/3 翻红;实测 9 条揭示计数随渲染次数非节点数 —— 钉「恰好 1」而非刷屏数的理由被实测支撑)。
  3. 拒绝模板化伪钉:派发词的钉①③在半边未做时无意义,不写 —— 正确。
  4. 门与规程:1115 测试绿;type-check scoped + CI 全量绿(偏离已披露且论证成立);控制字节门;changeset patch;fable 0;边界零违规。
  5. CI 亲读终态:20/20 全 completed、0 失败(Test shard×4 至 22:37:26Z)。

Fixes 语义处置(dev 自请改 Refs):PM 不整体重写正文(避免转义风险),改为:合并自动关闭 #3965 后,PM 立即重开并挂 needs-user-decision 承载 A/B 词表决策 —— 状态机结果等价。106 个明确布局意图节点的 prop 转换(任何终态下都成立)已拆独立实施单先行。


Generated by Claude Code

@yinlianghui
yinlianghui marked this pull request as ready for review August 9, 2026 22:42
@yinlianghui
yinlianghui added this pull request to the merge queue Aug 9, 2026
Merged via the queue into main with commit 0fa5e4d Aug 9, 2026
21 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-3965-catalog-div-retirement branch August 9, 2026 22:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

examples/schema-catalog: 48 个示例仍用已废弃的 div 组件类型,docs 站每张缩略图都刷一条 deprecation warning

1 participant