Skip to content

Adopt Destyler core 0.3.1 - #163

Merged
elonehoo merged 2 commits into
mainfrom
cursor/core-0-3-0-d9e6
Oct 28, 2026
Merged

elonehoo merged 2 commits into
mainfrom
cursor/core-0-3-0-d9e6

Conversation

@elonehoo

@elonehoo elonehoo commented Oct 27, 2026 •

Copy link
Copy Markdown
Member

Summary

This adopts Destyler core 0.3.1 in the UI workspace. Every @destyler/* catalog entry is ^0.3.1, and the installed-consumer gate pins exact core 0.3.1. Public UI package versions stay 0.0.1-beta.17. Nothing in this pull request publishes, retags, or releases.

Core 0.3.1 restores the machine, anatomy, and props declarations that 0.3.0 published as any (destyler/destyler v0.3.1). The 18 type-only patches added for 0.3.0 are removed. Storybook, eslint-plugin-react-x, and eslint-plugin-solid patches stay. Node remains >=22.22.3, the floor core 0.3.0 set (destyler/destyler#360) and 0.3.1 keeps.

Tabs ValueChangeDetails.value is string | null (core destyler/destyler#353, migration notes from destyler/destyler#356). Vue is the source of truth. React, Solid, and Svelte follow that contract.

Published UI 0.0.1-beta.17 wrote open.controlled keys that current core ignores (#151). Current source forwards open state by key presence. The compatibility gate now covers Dialog, Popover, and Menu open state, plus deselectable Tabs clearing to null, on packed Vue, React, Solid, and Svelte consumers.

#154 asks for the Svelte Tree branch-trigger migration to be included in the upcoming beta.18 release notes. That note is already prepared in docs/release-scope.md ("Pending note: Svelte Tree branch triggers") and packages/svelte/README.md ("Tree branch triggers"). This pull request does not publish beta.18 and does not close #154.

Fixes #151

Changes

Workspace

  • pnpm-workspace.yaml: every @destyler/* catalog entry, including @destyler/docs, is ^0.3.1. The lockfile resolves those ranges to 0.3.1.
  • Removed patches/@destyler__*@0.3.0.patch for calendar, carousel, checkbox, color-picker, combobox, dialog, dynamic, edit, file-upload, floating-panel, hover-card, menu, popover, radio, select, switch, tooltip, and tour, plus their patchedDependencies entries and the matching section in patches/PROVENANCE.md.
  • scripts/test-core-compat.mjs pins core 0.3.1.

Vue

  • packages/vue/src/components/tabs/types.ts: valueChange uses @destyler/tabs ValueChangeDetails (value: string | null).
  • packages/vue/src/components/tabs/test/nullable-contract.types.ts checks that the public change payload matches core ValueChangeDetails, including null.

React

  • packages/react/src/components/tabs/examples/Basic.tsx: defaultValue accepts string | null.
  • packages/react/src/components/tabs/test/nullable-contract.types.ts locks onValueChange to core ValueChangeDetails.

Solid

  • packages/solid/src/components/tabs/test/nullable-contract.types.ts locks onValueChange to core ValueChangeDetails.

Svelte

  • packages/svelte/src/lib/components/tabs/test/nullable-contract.types.ts locks onValueChange to core ValueChangeDetails.
  • packages/svelte/src/lib/utils/create-machine-props.ts drops legacy *.controlled keys. packages/svelte/src/lib/utils/test/create-machine-props.test.ts covers open.controlled and value.controlled.

Installed-consumer gate

scripts/fixtures/core-compat/ now renders Popover and Menu beside Dialog, with the same four open modes: omitted open, defaultOpen false, defaultOpen true, and controlled open={false}. Menu closes through its trigger. Deselectable Tabs with no initial value select alpha, clear to null, then select beta.

Docs

  • Tabs nullable migration names the 0.3.1 pin.
  • docs/node-support.md and docs/core-compatibility-release.md name the 0.3.1 gate. The 2026-10-21 beta.17 plus core 0.2.13 record stays historical.

Verification

Local Node v22.23.4. No @destyler/* declaration patch was required.

  • pnpm lint: exit 0. 667 problems, 0 errors, 667 warnings.
  • pnpm --filter @destyler-ui/vue check (vue-tsc --noEmit): exit 0.
  • pnpm --filter @destyler-ui/react check (tsc --noEmit): exit 0.
  • pnpm --filter @destyler-ui/solid typecheck (tsc --noEmit): exit 0.
  • pnpm --filter @destyler-ui/svelte typecheck (svelte-check): 0 errors and 0 warnings.
  • pnpm test: 438 files passed, 7174 tests passed, 48 skipped.
  • pnpm build: exit 0.
  • pnpm test:core-compat: runner tests 14 passed, 0 failed. Packed React, Vue, Solid, and Svelte consumers each passed against exact core 0.3.1 (@destyler/dialog recorded as 0.3.1, and every installed @destyler/* package at 0.3.1). Each consumer passed Dialog, Popover, and Menu omitted, default-false, default-true, and controlled-false, plus Tabs nullable (alpha, null, beta). Packed UI artifacts stayed 0.0.1-beta.17.

Release notes

When beta.18 is prepared, include the Svelte Tree branch-trigger migration from docs/release-scope.md and packages/svelte/README.md (#154). Do not treat this pull request as that release.

Open in Web Open in Cursor 

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Note

Medium Risk
Wide dependency bump plus Tabs callback typing changes can break consumers with narrow handlers; expanded compat tests reduce but do not eliminate regression risk across all components.

Reviewed by Cursor Bugbot for commit 3090a28. Bugbot is set up for automated code reviews on this repo. Configure here.

Pin every @destyler/* catalog entry to ^0.3.0 and run the Dialog
compatibility gate against exact core 0.3.0. Keep Tabs selection
callbacks on the core ValueChangeDetails contract (string | null)
across Vue, React, Solid, and Svelte. Restore 0.3.0 declarations
that published machine, anatomy, and props types as any, without
changing those packages' runtime bundles.

Node remains >=22.22.3. Nothing is published.

Co-authored-by: Elone Hoo <hi@elonehoo.me>
@vercel

vercel Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
destyler-ui Ready Ready Preview Oct 28, 2026 12:01am UTC
destyler-ui-dev Ready Ready Preview Oct 28, 2026 12:01am UTC

@elonehoo

elonehoo commented Oct 27, 2026 •

Copy link
Copy Markdown
Member Author

🤖 Review(中文)

更新于:3090a28(上次评审基于 0f8d57b)

概要:本次更新把所有 @destyler/* catalog 条目从 ^0.3.0 升到 ^0.3.1,并删除了 18 个只修声明文件的 @destyler__*@0.3.0.patch(core 0.3.1 已在上游恢复 machine / anatomy / props 的类型)。安装态兼容门禁 pnpm test:core-compat 改为固定 core 0.3.1,并在 Vue / React / Solid / Svelte 四个打包消费者中,从只测 Dialog 扩展为 Dialog、Popover、Menu 的四种 open 模式,外加可取消选择的 Tabs 清空为 null。文档同步改为 0.3.1。改动与描述一致;lockfile 中除 @destyler/* 外只有 @devframes/* / devframe 的 peer 解析后缀变化,没有夹带无关升级。

上次建议的处理情况

  • ✅ 第 1 点(声明补丁只在本仓库生效,可能掩盖消费者侧回归):已解决。补丁已全部移除,本地 vue-tsc / tsc / svelte-check 现在面对的就是消费者实际安装的 core 0.3.1 声明。
  • ✅ 第 2 点(^0.3.0 与精确版本补丁键不一致):随补丁移除而不再存在。
  • ✅ 第 3 点(补丁覆盖范围):同上,不再适用。
  • ⏳ 第 4 点(Svelte create-machine-props.ts):仍未处理。该文件只改了注释,实际行为在 main 上已存在;描述仍写作 "drops legacy *.controlled keys",容易被理解为行为变更。另外测试里 'value.controlled': false 仍没有同时出现 value 键的用例。
  • ⏳ 第 5 点(侧边栏标签大小写):docs/astro.config.ts 中仍是 Tabs nullable selection,与同级的 Controllable State、Getting Started 不一致。

新的建议

  1. Tabs 门禁只覆盖非受控场景:scripts/fixtures/core-compat/run.mjs 中的 Tabs 用例只测了非受控的 alpha → null → beta。迁移文档 tabs-nullable-migration.mdx 明确描述了受控语义(父组件写回 null 才接受清空、保持原值即否决、重复 clear 会再次通知、父组件写入不回显通知)。建议至少补一个受控用例:传入 value: 'alpha' 且不更新,点击已选 trigger 后断言 changes 为 [null] 且仍选中 alpha。这正是 Verify and resolve beta.17 UI package compatibility with core 0.2.13 #151 这类“当前 core 忽略旧 key”的问题最容易出现的地方。
  2. isOpen 判断变宽松:isOpen 现在是 aria-expanded === 'true' || data-state === 'open'。以前 Dialog 只认 aria-expanded,现在即使 Dialog trigger 的 aria-expanded 坏掉,只要 data-state 正确也会通过。建议按组件区分:Dialog / Popover / Menu 都应断言 aria-expanded,只在确实不提供该属性的组件上才回退到 data-state;或者两者同时断言。
  3. Tabs 选中状态依赖 data-value:selected() 读取 trigger 的 data-value。如果某个框架的 trigger 没有输出这个属性,初始的 selected() === null 断言会“空通过”,直到下一步才失败,错误信息会误导排查。建议先断言两个 tab 都带有 data-value,或改用 aria-controls / 文本来识别。
  4. Menu 只通过 trigger 关闭:目前没有覆盖选中 Menu.Item 后关闭(closeOnSelect)以及该路径下的 onOpenChange 序列。这是 Menu 最常见的关闭方式,建议补一个变体。
  5. 消费者侧类型检查(可选):补丁去掉后风险已大幅降低,但门禁仍只做运行时断言。若想防止 core 再次发布 any 声明,可以在打包消费者中加一个很小的 tsc --noEmit 步骤(例如断言 Tabs onValueChange 参数是 string | null 而不是 any)。
  6. 验证尚未完成:描述写明 Lint、框架测试、构建和 pnpm test:core-compat 仍在运行;目前 CI(Lint、Test、packed-consumer、浏览器可访问性 smoke)都处于 pending。建议在合并前确认全部通过,并按描述把结果补到 PR 中。

结论:这次更新解决了上次最主要的风险(只在仓库内生效的声明补丁),整体方向正确、风险较低。合并前建议等 CI 全部通过,并考虑补上受控 Tabs 用例和更严格的 open 状态断言;第 4、5 点属于小问题。

@elonehoo

elonehoo commented Oct 27, 2026 •

Copy link
Copy Markdown
Member Author

🤖 Review (English)

Updated: 3090a28 (previous review was based on 0f8d57b)

Summary: This update moves every @destyler/* catalog entry from ^0.3.0 to ^0.3.1 and deletes the 18 declaration-only @destyler__*@0.3.0.patch files, since core 0.3.1 restores the machine / anatomy / props types upstream. The installed-consumer gate (pnpm test:core-compat) now pins core 0.3.1 and, in the packed Vue, React, Solid, and Svelte consumers, goes beyond Dialog to cover the four open modes for Dialog, Popover, and Menu, plus deselectable Tabs clearing to null. The docs are updated to 0.3.1. The changes match the description. Apart from @destyler/*, the lockfile only shows peer-resolution suffix changes for @devframes/* / devframe, so no unrelated upgrades slipped in.

Status of earlier suggestions

  • ✅ Point 1 (declaration patches only apply inside this repo and may hide a consumer regression): resolved. All patches are gone, so local vue-tsc / tsc / svelte-check now see the same core 0.3.1 declarations that consumers install.
  • ✅ Point 2 (^0.3.0 ranges vs. exact-version patch keys): no longer applies now that the patches are removed.
  • ✅ Point 3 (patch coverage): no longer applies, same reason.
  • ⏳ Point 4 (Svelte create-machine-props.ts): still open. Only the comment changes in that file, and the behavior already exists on main, but the description still says "drops legacy *.controlled keys", which reads like a behavior change. The test's 'value.controlled': false case still has no matching value key.
  • ⏳ Point 5 (sidebar label casing): docs/astro.config.ts still uses Tabs nullable selection, which doesn't match its siblings Controllable State and Getting Started.

New suggestions

  1. The Tabs gate only covers the uncontrolled case: In scripts/fixtures/core-compat/run.mjs, the Tabs case only checks uncontrolled alpha → null → beta. The migration doc (tabs-nullable-migration.mdx) explicitly describes controlled semantics: the parent accepts a clear by writing null back, vetoes by keeping its value, repeated clears notify again, and parent writes don't echo. Please add at least one controlled case: pass value: 'alpha' without updating it, click the selected trigger, and assert that changes is [null] while alpha stays selected. That is exactly where "current core ignores the old key" problems like Verify and resolve beta.17 UI package compatibility with core 0.2.13 #151 tend to show up.
  2. isOpen got looser: isOpen is now aria-expanded === 'true' || data-state === 'open'. Dialog used to require aria-expanded; now a broken aria-expanded on the Dialog trigger would still pass as long as data-state is right. Consider asserting aria-expanded for Dialog, Popover, and Menu, and falling back to data-state only for a component that really doesn't expose it, or assert both.
  3. Tabs selection relies on data-value: selected() reads each trigger's data-value. If one framework's trigger doesn't render that attribute, the initial selected() === null assertion passes vacuously and the failure only shows up one step later with a misleading message. Assert that both tabs carry data-value first, or identify them by aria-controls or text.
  4. Menu only closes through its trigger: Closing by selecting a Menu.Item (closeOnSelect) and the resulting onOpenChange sequence aren't covered. That's the most common way a Menu closes, so a variant for it would be worthwhile.
  5. Consumer-side type check (optional): Removing the patches lowers the risk a lot, but the gate still only makes runtime assertions. To catch core publishing any declarations again, a tiny tsc --noEmit step in the packed consumers would do it (for example, asserting the Tabs onValueChange payload is string | null and not any).
  6. Verification isn't finished: The description says lint, framework tests, build, and pnpm test:core-compat are still running, and CI (Lint, Test, packed-consumer, browser accessibility smoke) is currently pending. Please confirm everything passes before merging and record the results in the PR as the description promises.

Verdict: This update resolves the main risk from the last review (declaration patches that only applied inside the repo). The direction is right and the risk is low. Before merging, I'd wait for green CI and consider adding the controlled Tabs case and the stricter open-state assertion; points 4 and 5 are minor.

@elonehoo

elonehoo commented Oct 27, 2026 •

Copy link
Copy Markdown
Member Author

🤖 レビュー(日本語)

更新: 3090a28(前回のレビューは 0f8d57b 時点)

概要:今回の更新では、すべての @destyler/* catalog エントリを ^0.3.0 から ^0.3.1 に上げ、宣言ファイルだけを修正していた 18 個の @destyler__*@0.3.0.patch を削除しています(core 0.3.1 で machine / anatomy / props の型が上流で復元されたため)。インストール済みコンシューマーの互換ゲート pnpm test:core-compat は core 0.3.1 に固定され、Vue / React / Solid / Svelte のパック済みコンシューマーで、Dialog だけでなく Dialog・Popover・Menu の 4 種類の open モードと、選択解除可能な Tabs が null に戻るケースを検証するようになりました。ドキュメントも 0.3.1 に更新されています。変更内容は説明と一致しています。lockfile は @destyler/* 以外では @devframes/* / devframe の peer 解決サフィックスが変わっただけで、無関係なアップグレードは含まれていません。

前回の指摘への対応状況

  • ✅ 1 点目(宣言パッチがこのリポジトリ内でしか効かず、コンシューマー側の退行を隠す恐れ):解決済みです。パッチはすべて削除され、ローカルの vue-tsc / tsc / svelte-check はコンシューマーが実際にインストールする core 0.3.1 の宣言をそのまま見ています。
  • ✅ 2 点目(^0.3.0 の範囲指定と厳密バージョンのパッチキーの不一致):パッチ削除により該当しなくなりました。
  • ✅ 3 点目(パッチの対象範囲):同じ理由で該当しなくなりました。
  • ⏳ 4 点目(Svelte の create-machine-props.ts):未対応です。このファイルはコメントだけの変更で、挙動はすでに main にありますが、説明文は依然として「drops legacy *.controlled keys」となっており、挙動変更のように読めます。また、テストの 'value.controlled': false には対応する value キーを同時に持つケースがまだありません。
  • ⏳ 5 点目(サイドバーラベルの大文字小文字):docs/astro.config.ts は Tabs nullable selection のままで、隣の Controllable State や Getting Started と揃っていません。

新しい提案

  1. Tabs のゲートが非制御ケースのみ:scripts/fixtures/core-compat/run.mjs の Tabs ケースは、非制御の alpha → null → beta しか検証していません。移行ドキュメント tabs-nullable-migration.mdx では制御モードの挙動(親が null を書き戻せばクリアを受け入れ、値を維持すれば拒否、クリア要求の繰り返しは再通知、親からの書き込みは通知をエコーしない)を明記しています。少なくとも制御ケースを 1 つ追加することをお勧めします。たとえば value: 'alpha' を渡して更新せず、選択中のトリガーをクリックしたあと、changes が [null] で、alpha が選択されたままであることを確認します。Verify and resolve beta.17 UI package compatibility with core 0.2.13 #151 のような「現在の core が古いキーを無視する」問題が出やすいのはまさにこの部分です。
  2. isOpen の判定が緩くなった:isOpen は aria-expanded === 'true' || data-state === 'open' になりました。以前の Dialog は aria-expanded だけを見ていましたが、今は Dialog トリガーの aria-expanded が壊れていても data-state が正しければ通ってしまいます。Dialog・Popover・Menu では aria-expanded を確認し、その属性を本当に出さないコンポーネントに限って data-state にフォールバックするか、両方を確認することを検討してください。
  3. Tabs の選択判定が data-value に依存:selected() は各トリガーの data-value を読んでいます。あるフレームワークのトリガーがこの属性を出力しない場合、最初の selected() === null は空振りで通過し、次のステップで初めて分かりにくいメッセージで失敗します。先に両方のタブが data-value を持つことを確認するか、aria-controls やテキストで識別することをお勧めします。
  4. Menu はトリガーでしか閉じていない:Menu.Item を選択して閉じる経路(closeOnSelect)と、その際の onOpenChange の順序がカバーされていません。Menu を閉じる最も一般的な方法なので、バリエーションを追加する価値があります。
  5. コンシューマー側の型チェック(任意):パッチ削除でリスクは大きく下がりましたが、ゲートは依然として実行時のアサーションだけです。core が再び any の宣言を公開するのを防ぐなら、パック済みコンシューマーに小さな tsc --noEmit ステップを加えるとよいです(例:Tabs の onValueChange の引数が any ではなく string | null であることを確認する)。
  6. 検証が未完了:説明文には、Lint・フレームワークのテスト・ビルド・pnpm test:core-compat がまだ実行中と書かれており、現時点の CI(Lint、Test、packed-consumer、ブラウザのアクセシビリティ smoke)もすべて pending です。マージ前にすべて通ることを確認し、説明どおり結果を PR に記録してください。

結論:今回の更新で、前回最大のリスクだった「リポジトリ内でしか効かない宣言パッチ」は解消されました。方向性は正しく、リスクは低いです。マージ前に CI がすべて通るのを待ち、制御モードの Tabs ケースと、より厳密な open 状態の確認を追加することを検討してください。4・5 点目は軽微な指摘です。

Pin every @destyler/* catalog entry to ^0.3.1 and drop the type-only
patches that restored 0.3.0 declarations emitted as any. Extend the
installed-consumer gate to Popover and Menu open state and Tabs
nullable selection.

Nothing is published.

Co-authored-by: Elone Hoo <hi@elonehoo.me>
@cursor cursor Bot changed the title Adopt Destyler core 0.3.0 Adopt Destyler core 0.3.1 Oct 27, 2026
@elonehoo
elonehoo merged commit 69f3d66 into main Oct 28, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Include the existing Svelte Tree migration guidance in the next release notes Verify and resolve beta.17 UI package compatibility with core 0.2.13

2 participants