diff --git a/.changeset/ninety-radios-smash.md b/.changeset/ninety-radios-smash.md
new file mode 100644
index 0000000..194426f
--- /dev/null
+++ b/.changeset/ninety-radios-smash.md
@@ -0,0 +1,5 @@
+---
+"@marko/tsrx": patch
+---
+
+Member expression tag names map to dynamic tags
diff --git a/packages/tsrx/README.md b/packages/tsrx/README.md
index b724f23..0757fb5 100644
--- a/packages/tsrx/README.md
+++ b/packages/tsrx/README.md
@@ -27,7 +27,7 @@ const { files } = compile(source, "App.tsrx");
| --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `component App(props: T) { ... }` | `export type Input = T;` + `` |
| `component App({ a, b }: T) { ... }` | `export type Input = T;` + `` |
-| `component App() { ... }` | (no Input type, no binding) |
+| `component App() { ... }` | (no Input type, no binding) |
| `
{expr}
` | `${expr}
` |
| `{text "safe string"}` | `safe string` (plain text when value contains none of `< > $ {`) |
| `{text expr}` | `${expr}` |
@@ -38,12 +38,13 @@ const { files } = compile(source, "App.tsrx");
| `` | `
` |
| `const name = expr` | `
` |
| `let name` / `let name = expr` | `
` / `
` |
-| `const title =
{"Hi"};` | `
${"Hi"}` · use `{title}` → Marko `<${title}/>` |
+| `const title =
{"Hi"};` | `
${"Hi"}` · use `{title}` → Marko `<${title}/>` |
+| `
` | `<${input.content}/>` (member expression tag names map to dynamic tags) |
| `if / else if / else` | `
`, ``, `` |
| `for (const x of xs; index i)` | `` |
| `for (const x of xs; key x.id)` | ` x.id>` |
| `switch (d) { case a: ...; default: ...; }` | chained `` / `` |
-| `try { ... } pending { ... } catch (err) { ... }` | `` … `<@placeholder>` … `<@catch|err|>` … `` (catch param name replaces `err`) |
+| `try { ... } pending { ... } catch (err) { ... }` | `` … `<@placeholder>` … `<@catch\|err\|>` … `` (catch param name replaces `err`) |
| `` | `` (passed through as CSS-modules-friendly; scoped hash is applied by the existing `@tsrx/core` pipeline) |
## Not yet supported (MVP)
diff --git a/packages/tsrx/src/transform.ts b/packages/tsrx/src/transform.ts
index 8d9dea0..f5a4e88 100644
--- a/packages/tsrx/src/transform.ts
+++ b/packages/tsrx/src/transform.ts
@@ -433,8 +433,9 @@ export class Transformer {
}
const isDynamic =
- el.id.type === "Identifier" &&
- this.#defineNames.has((el.id as AST.Identifier).name);
+ el.id.type === "MemberExpression" ||
+ (el.id.type === "Identifier" &&
+ this.#defineNames.has((el.id as AST.Identifier).name));
const refAttr = el.attributes.find((a) => a.type === "RefAttribute") as
| (AST.BaseNode & { type: "RefAttribute"; argument: AST.Expression })
diff --git a/packages/tsrx/tests/__snapshots__/volar-mappings.txt b/packages/tsrx/tests/__snapshots__/volar-mappings.txt
index 458206b..0f661d6 100644
--- a/packages/tsrx/tests/__snapshots__/volar-mappings.txt
+++ b/packages/tsrx/tests/__snapshots__/volar-mappings.txt
@@ -213,6 +213,10 @@
=== style-tag ===
+=== tag-member-expression ===
+ src: 2 "div" -> "div"
+ src: 2 "input.content" -> "input.content"
+
=== top-level-text ===
src: 1 "{ count: number }" -> "{ count: number }"
src: 1 "{ count }" -> "{ count }"
diff --git a/packages/tsrx/tests/fixtures/tag-member-expression/__snapshots__/index.marko b/packages/tsrx/tests/fixtures/tag-member-expression/__snapshots__/index.marko
new file mode 100644
index 0000000..225cb90
--- /dev/null
+++ b/packages/tsrx/tests/fixtures/tag-member-expression/__snapshots__/index.marko
@@ -0,0 +1 @@
+<${input.content}/>
\ No newline at end of file
diff --git a/packages/tsrx/tests/fixtures/tag-member-expression/index.tsrx b/packages/tsrx/tests/fixtures/tag-member-expression/index.tsrx
new file mode 100644
index 0000000..4c4d595
--- /dev/null
+++ b/packages/tsrx/tests/fixtures/tag-member-expression/index.tsrx
@@ -0,0 +1,3 @@
+export default component(input) {
+
+}