feat(ui): add ui.createScope() lifecycle helper (SD-2918)#3091
Conversation
createScope() collects subscription unsubscribes, custom-command registrations, and DOM event listeners under one teardown call. ui.destroy() cascades into every live scope before tearing down its own resources, so non-React consumers no longer need to remember multiple teardown calls. The minimum surface is small on purpose: add(teardown), register(), on(target, type, listener), child(), and destroy(). Convenience sugar like scope.subscribe(handle, fn) is held back until SD-2919 unifies subscribe and observe shapes across domain handles. Post-destroy contract: add() invokes the teardown synchronously; on() is a no-op; register() throws; child() returns a destroyed scope. All three are documented inline so framework adapter authors do not have to discover them by experimentation. Lifecycle is verified by 13 vitest cases covering: idempotent destroy, parent-before-child unwinding (LIFO), ui.destroy() cascade, custom-command auto-unregister, addEventListener / removeEventListener option parity, and that one failing teardown does not block the rest.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 250bffaba7
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
- Re-export SuperDocUIScope from the public superdoc/ui sub-entry so
consumers can write `import type { SuperDocUIScope } from 'superdoc/ui'`
without falling through to the inner workspace package.
- Guard ui.createScope() against post-destroy: returns an
already-destroyed scope, mirroring the destroyed-parent behavior of
scope.child(). Prevents a leak when consumers race shutdown / HMR
teardown.
- Rewrite the misleading comment block in scope.ts that claimed
untrack runs before consumer cleanups (it actually runs last,
matching the parenthetical clarification in the same comment).
- Replace remaining em-dashes in types.ts and create-super-doc-ui.ts
comments per project writing-style rule.
|
🎉 This PR is included in @superdoc-dev/mcp v0.3.0-next.36 The release is available on GitHub release |
|
🎉 This PR is included in vscode-ext v2.3.0-next.80 |
|
🎉 This PR is included in @superdoc-dev/react v1.2.0-next.78 The release is available on GitHub release |
|
🎉 This PR is included in superdoc-cli v0.8.0-next.54 The release is available on GitHub release |
|
🎉 This PR is included in superdoc v1.30.0-next.37 The release is available on GitHub release |
|
🎉 This PR is included in superdoc-sdk v1.8.0-next.39 |
|
🎉 This PR is included in superdoc-cli v0.9.0 The release is available on GitHub release |
|
🎉 This PR is included in superdoc v1.32.0 The release is available on GitHub release |
|
🎉 This PR is included in @superdoc-dev/mcp v0.4.0 The release is available on GitHub release |
|
🎉 This PR is included in @superdoc-dev/react v1.3.0 The release is available on GitHub release |
|
🎉 This PR is included in vscode-ext v2.4.0 |
|
🎉 This PR is included in superdoc-sdk v1.9.0 |
Non-React consumers were rolling their own disposers to track subscription unsubscribes, custom-command registrations, and DOM listeners under one teardown call.
ui.createScope()collects all three into a single primitive, andui.destroy()cascades into every live scope so consumers do not need to remember a separate teardown path.The minimum surface is small on purpose:
add(teardown),register(...),on(target, type, listener),child(), anddestroy(). Sugar likescope.subscribe(handle, fn)is held back until SD-2919 unifies subscribe and observe shapes across domain handles.Post-destroy contract is documented inline so adapter authors do not have to discover it by experimentation.
addruns the teardown synchronously,onis a no-op,registerthrows,childreturns a destroyed scope.Verified: `pnpm --filter superdoc build` clean; `pnpm --filter @superdoc/super-editor test scope` passes 13/13.