From 5996d4794083616273fdfd649277af7c94f162a2 Mon Sep 17 00:00:00 2001 From: Shevchik Igor Date: Fri, 3 Jul 2026 04:28:54 +0000 Subject: [PATCH] fix(Button): allow inline event handlers with non-void return types Port of upstream nuxt/ui 269080a (#6668). Narrow handler-prop types from `(e) => void | Promise` to `(e) => void` on onClick/onSubmit across Button, Form, LinkBase, PageCard, PageFeature, User and the inertia LinkBase override. TypeScript's void-return bivalence means a function returning anything is assignable to a `=> void` parameter, so inline template handlers whose expression returns a non-void value are accepted instead of erroring against the `void | Promise` union. Also applied to b24ui's clickable Badge `onCloseClick` (b24ui-only prop, same pattern). Type-only; no snapshot changes. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01JS8ypVfQSFzYVZzkTHhURb --- ...69080a85dc877a2140bdc951c32ccd5626f4684.md | 37 +++++++++++++++++++ .sync/nuxt-ui.json | 12 ++++-- src/runtime/components/Badge.vue | 2 +- src/runtime/components/Button.vue | 2 +- src/runtime/components/Form.vue | 2 +- src/runtime/components/LinkBase.vue | 2 +- src/runtime/components/PageCard.vue | 2 +- src/runtime/components/PageFeature.vue | 2 +- src/runtime/components/User.vue | 2 +- .../vue/overrides/inertia/LinkBase.vue | 2 +- 10 files changed, 54 insertions(+), 11 deletions(-) create mode 100644 .sync/log/269080a85dc877a2140bdc951c32ccd5626f4684.md diff --git a/.sync/log/269080a85dc877a2140bdc951c32ccd5626f4684.md b/.sync/log/269080a85dc877a2140bdc951c32ccd5626f4684.md new file mode 100644 index 00000000..0faf53d0 --- /dev/null +++ b/.sync/log/269080a85dc877a2140bdc951c32ccd5626f4684.md @@ -0,0 +1,37 @@ +# Port: fix(Button): allow inline event handlers with non-void return types (#6668) + +**Upstream:** `269080a85dc877a2140bdc951c32ccd5626f4684` (nuxt/ui) +**Decision:** port + +## Upstream change +Narrows the handler-prop types from `(e) => void | Promise` to +`(e) => void` on `onClick`/`onSubmit` across Button, Form, LinkBase, PageCard, +PageFeature, User, BlogPost, ChangelogVersion, and the inertia LinkBase +override. Counter-intuitively this **widens** what callers may pass: TypeScript's +void-return bivalence means a function returning *anything* is assignable to a +`=> void` parameter type, so inline template handlers whose expression returns a +non-void value (e.g. `@click="count++"`) are accepted instead of erroring +against the `void | Promise` union. + +## b24ui port — 1:1 + one b24ui extension +Applied `=> void | Promise` → `=> void` (both the single-arg and the +`Array<…>`/`() => …` union variants) in the b24ui-matching files: +`Button.vue` (onClick), `Form.vue` (onSubmit), `LinkBase.vue` (onClick), +`PageCard.vue` (onClick), `PageFeature.vue` (onClick), `User.vue` (onClick), +`vue/overrides/inertia/LinkBase.vue` (onClick). Upstream's `BlogPost.vue` / +`ChangelogVersion.vue` are **absent** in b24ui (N/A). + +**b24ui extension:** b24ui's `Badge.vue` is clickable and carries an +`onCloseClick?: ((e) => void | Promise) | Array<…>` prop that upstream's +Badge does not have. Same bug, same fix — applied there too so b24ui's Badge +close handler accepts inline non-void handlers consistently. (Deviation noted in +the PR.) + +8 files, +8/−8 (one line each). No renames (`ui`→`b24ui` etc. not involved). + +## Tests +Type-only change, no runtime/markup change → no snapshot churn. Full suite +unchanged (225 files, 5147 passed / 6 skipped). + +## Verify (CI=true) +`dev:prepare` · `lint` · `typecheck` · `test` · `build` — all green. diff --git a/.sync/nuxt-ui.json b/.sync/nuxt-ui.json index 1b1f7f7c..ccafccb0 100644 --- a/.sync/nuxt-ui.json +++ b/.sync/nuxt-ui.json @@ -2,7 +2,7 @@ "upstream": "nuxt/ui", "branch": "v4", "sync_enabled": false, - "cursor": "dfbbfeb5a9ab3cbaf9582ba3393cceb1584baa5e", + "cursor": "269080a85dc877a2140bdc951c32ccd5626f4684", "_cursor_note": "cursor = last upstream commit ported into b24ui (oldest-first, manual cadence). sync_enabled stays false until Phase 2 (porter workflow #67 + CLAUDE_CODE_OAUTH_TOKEN) is wired and trusted. `processed` is maintained per port from now on (backfilled #68-#72 on 2026-06-09).", "stats": { "queue_depth": 0, @@ -845,10 +845,16 @@ "summary": "chore(github): update reproduire workflow version — NO-OP: re-pins Hebilicious/reproduire @v1 -> @4b686ae...#v0.0.9 in .github/workflows/reproduire.yml (partial revert of df099a5's un-pin). b24ui has no reproduire.yml (only ci/deploy/npm-publish workflows); same N/A basis as df099a5 (#232). Bookkeeping only" }, "dfbbfeb5a9ab3cbaf9582ba3393cceb1584baa5e": { - "pr": null, - "b24ui_sha": "pending-merge", + "pr": 238, + "b24ui_sha": "a2c59cf0", "decision": "skip", "summary": "chore(deps): migrate AI SDK to v7 (#6636) — SKIPPED/DEFERRED (maintainer call): major dep migration ai ^6->^7, @ai-sdk/anthropic ^3->^4, @ai-sdk/gateway ^3->^4, @ai-sdk/mcp ^1->^2, @ai-sdk/vue ^3->^4 + docs/playground client (new Chat()->useChat()) + server routes (system->instructions, stepCountIs->isStepCount, toUIMessageStreamResponse->toUIMessageStream+createUIMessageStreamResponse, toTextStreamResponse->createTextStreamResponse, onFinish->onEnd, model ids). Upstream touched NO src/runtime, but b24ui runtime imports ai (ChatMessages/ChatMessage/ChatPromptSubmit + utils/ai.ts) AND has a b24ui-only bx-assistant module (AssistantPanel/search.ts/useAssistant.ts) using @ai-sdk/vue+streamText with no upstream reference -> not a mechanical replay; needs a deliberate v7 adoption pass verifying runtime types + hand-migrating bx-assistant + lockfile regen + end-to-end test. Also verbatim .patch fetch egress-blocked this session. b24ui stays on ai@6. Consistent with prior deferrals #220/#194. Bookkeeping only, cursor advances; tracked for future AI-SDK-v7 task" + }, + "269080a85dc877a2140bdc951c32ccd5626f4684": { + "pr": null, + "b24ui_sha": "pending-merge", + "decision": "port", + "summary": "fix(Button): allow inline event handlers with non-void return types (#6668) — narrow handler types `=> void | Promise` -> `=> void` on onClick/onSubmit (TS void-bivalence widens accepted return types so inline template handlers returning non-void no longer error). b24ui files: Button(onClick), Form(onSubmit), LinkBase(onClick), PageCard, PageFeature, User, vue/overrides/inertia/LinkBase — all single+Array/()=> union variants. BlogPost/ChangelogVersion absent (N/A). +b24ui extension: Badge.onCloseClick (b24ui-only clickable-close prop, same pattern/fix). 8 files +8/-8. Type-only, no snapshot churn" } } } diff --git a/src/runtime/components/Badge.vue b/src/runtime/components/Badge.vue index 5092971e..6c81d86b 100644 --- a/src/runtime/components/Badge.vue +++ b/src/runtime/components/Badge.vue @@ -41,7 +41,7 @@ export interface BadgeProps extends Omit void | Promise) | Array<((event: MouseEvent) => void | Promise)> + onCloseClick?: ((event: MouseEvent) => void) | Array<((event: MouseEvent) => void)> class?: any b24ui?: Badge['slots'] } diff --git a/src/runtime/components/Button.vue b/src/runtime/components/Button.vue index f310eb36..f5b9f6ef 100644 --- a/src/runtime/components/Button.vue +++ b/src/runtime/components/Button.vue @@ -61,7 +61,7 @@ export interface ButtonProps extends Omit void | Promise) | Array<((event: MouseEvent) => void | Promise)> + onClick?: ((event: MouseEvent) => void) | Array<((event: MouseEvent) => void)> class?: any /** * The class to apply when the link is active diff --git a/src/runtime/components/Form.vue b/src/runtime/components/Form.vue index acd92f1d..0e1dacca 100644 --- a/src/runtime/components/Form.vue +++ b/src/runtime/components/Form.vue @@ -62,7 +62,7 @@ export type FormProps>) => void | Promise) | (() => void | Promise) + onSubmit?: ((event: FormSubmitEvent>) => void) | (() => void) } & /** @vue-ignore */ Omit export interface FormEmits { diff --git a/src/runtime/components/LinkBase.vue b/src/runtime/components/LinkBase.vue index aa55da92..e6a850bc 100644 --- a/src/runtime/components/LinkBase.vue +++ b/src/runtime/components/LinkBase.vue @@ -5,7 +5,7 @@ export interface LinkBaseProps { as?: string type?: string disabled?: boolean - onClick?: ((e: MouseEvent) => void | Promise) | Array<((e: MouseEvent) => void | Promise)> + onClick?: ((e: MouseEvent) => void) | Array<((e: MouseEvent) => void)> href?: string | null navigate?: (e: MouseEvent) => void target?: LinkProps['target'] diff --git a/src/runtime/components/PageCard.vue b/src/runtime/components/PageCard.vue index bb506dcd..744ae725 100644 --- a/src/runtime/components/PageCard.vue +++ b/src/runtime/components/PageCard.vue @@ -56,7 +56,7 @@ export interface PageCardProps { variant?: PageCard['variants']['variant'] to?: LinkProps['to'] target?: LinkProps['target'] - onClick?: (event: MouseEvent) => void | Promise + onClick?: (event: MouseEvent) => void class?: any b24ui?: PageCard['slots'] } diff --git a/src/runtime/components/PageFeature.vue b/src/runtime/components/PageFeature.vue index 9603b9c1..47ff85c2 100644 --- a/src/runtime/components/PageFeature.vue +++ b/src/runtime/components/PageFeature.vue @@ -28,7 +28,7 @@ export interface PageFeatureProps { orientation?: PageFeature['variants']['orientation'] to?: LinkProps['to'] target?: LinkProps['target'] - onClick?: (event: MouseEvent) => void | Promise + onClick?: (event: MouseEvent) => void class?: any b24ui?: PageFeature['slots'] } diff --git a/src/runtime/components/User.vue b/src/runtime/components/User.vue index 04b56204..04acc987 100644 --- a/src/runtime/components/User.vue +++ b/src/runtime/components/User.vue @@ -30,7 +30,7 @@ export interface UserProps { orientation?: User['variants']['orientation'] to?: LinkProps['to'] target?: LinkProps['target'] - onClick?: (event: MouseEvent) => void | Promise + onClick?: (event: MouseEvent) => void class?: any b24ui?: User['slots'] } diff --git a/src/runtime/vue/overrides/inertia/LinkBase.vue b/src/runtime/vue/overrides/inertia/LinkBase.vue index 7ed73b59..e75681da 100644 --- a/src/runtime/vue/overrides/inertia/LinkBase.vue +++ b/src/runtime/vue/overrides/inertia/LinkBase.vue @@ -5,7 +5,7 @@ export interface LinkBaseProps { as?: string type?: string disabled?: boolean - onClick?: ((e: MouseEvent) => void | Promise) | Array<((e: MouseEvent) => void | Promise)> + onClick?: ((e: MouseEvent) => void) | Array<((e: MouseEvent) => void)> href?: string target?: LinkProps['target'] rel?: LinkProps['rel']