fix(runtime): accept JSX children on components under automatic runtime

Text/Box/Static/Transform read children via slots but never surfaced
`children` on their JSX `$props`. Under the automatic JSX runtime
(jsx: react-jsx + jsxImportSource: vue), children are passed as a
`children` prop, so `<Text>x</Text>` failed to type-check. Add a
type-only WithChildren cast that declares optional `children` on $props;
Vue routes that prop to the default slot at runtime, so there is no
runtime change.
This commit is contained in:
Yunfei He
2026-05-28 17:07:37 +08:00
parent a5a96fed31
commit 304fdf2e21
5 changed files with 27 additions and 4 deletions
+4 -1
View File
@@ -1,5 +1,6 @@
import { defineComponent, h, inject, type PropType } from "vue";
import { AppContextKey } from "../context.ts";
import type { WithChildren } from "./with-children.ts";
type Spacing = number;
type FlexDirection = "row" | "row-reverse" | "column" | "column-reverse";
@@ -63,7 +64,7 @@ export interface AriaState {
selected?: boolean;
}
export const Box = defineComponent({
const BoxImpl = defineComponent({
name: "Box",
props: {
flexDirection: String as PropType<FlexDirection>,
@@ -157,3 +158,5 @@ export const Box = defineComponent({
};
},
});
export const Box = BoxImpl as WithChildren<typeof BoxImpl>;
+4 -1
View File
@@ -1,6 +1,7 @@
import { defineComponent, h, type PropType } from "vue";
import type { WithChildren } from "./with-children.ts";
export const Static = defineComponent({
const StaticImpl = defineComponent({
name: "Static",
props: {
items: { type: Array as PropType<unknown[]>, required: true },
@@ -22,3 +23,5 @@ export const Static = defineComponent({
};
},
});
export const Static = StaticImpl as WithChildren<typeof StaticImpl>;
+4 -1
View File
@@ -1,5 +1,6 @@
import { defineComponent, getCurrentInstance, h, inject, type PropType } from "vue";
import { AppContextKey } from "../context.ts";
import type { WithChildren } from "./with-children.ts";
type Color = string | [number, number, number];
type WrapMode =
@@ -10,7 +11,7 @@ type WrapMode =
| "truncate-middle"
| "truncate-start";
export const Text = defineComponent({
const TextImpl = defineComponent({
name: "Text",
props: {
color: [String, Array] as PropType<Color>,
@@ -54,6 +55,8 @@ export const Text = defineComponent({
},
});
export const Text = TextImpl as WithChildren<typeof TextImpl>;
function isInsideText(): boolean {
let parent = getCurrentInstance()?.parent;
while (parent) {
+4 -1
View File
@@ -1,9 +1,10 @@
import { defineComponent, h, inject, type PropType } from "vue";
import { AppContextKey } from "../context.ts";
import type { WithChildren } from "./with-children.ts";
type TransformFn = (line: string, lineIndex: number) => string;
export const Transform = defineComponent({
const TransformImpl = defineComponent({
name: "Transform",
props: {
transform: { type: Function as PropType<TransformFn>, required: true },
@@ -25,3 +26,5 @@ export const Transform = defineComponent({
};
},
});
export const Transform = TransformImpl as WithChildren<typeof TransformImpl>;
@@ -0,0 +1,11 @@
/**
* Adds an optional `children` to a component's JSX `$props` so that TSX written
* under the automatic runtime (`jsx: "react-jsx"` + `jsxImportSource: "vue"`)
* accepts child content. Vue's JSX namespace defines no `ElementChildrenAttribute`,
* so the automatic runtime passes children as a `children` prop — which must be
* present on `$props` to type-check. Vue routes that prop to the default slot at
* runtime, so this is a type-only shim with no runtime effect.
*/
export type WithChildren<C, T = unknown> = C & {
new (): { $props: { children?: T } };
};