@alloy-js/core 0.21.0-dev.1 → 0.21.0-dev.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/src/components/ReferenceOrContent.d.ts +1 -1
  2. package/dist/src/components/ReferenceOrContent.d.ts.map +1 -1
  3. package/dist/src/pretty-string/pretty-string.d.ts +47 -0
  4. package/dist/src/pretty-string/pretty-string.d.ts.map +1 -0
  5. package/dist/src/pretty-string/pretty-string.js +100 -0
  6. package/dist/src/pretty-string/pretty-string.js.map +1 -0
  7. package/dist/src/pretty-string/pretty-string.test.d.ts +2 -0
  8. package/dist/src/pretty-string/pretty-string.test.d.ts.map +1 -0
  9. package/dist/src/pretty-string/pretty-string.test.js +38 -0
  10. package/dist/src/pretty-string/pretty-string.test.js.map +1 -0
  11. package/dist/src/refkey.d.ts +2 -0
  12. package/dist/src/refkey.d.ts.map +1 -1
  13. package/dist/src/refkey.js +7 -0
  14. package/dist/src/refkey.js.map +1 -1
  15. package/dist/src/render.d.ts.map +1 -1
  16. package/dist/src/render.js +6 -1
  17. package/dist/src/render.js.map +1 -1
  18. package/dist/src/runtime/component.d.ts +21 -1
  19. package/dist/src/runtime/component.d.ts.map +1 -1
  20. package/dist/src/runtime/component.js +18 -0
  21. package/dist/src/runtime/component.js.map +1 -1
  22. package/dist/src/tracer.d.ts.map +1 -1
  23. package/dist/src/tracer.js +2 -2
  24. package/dist/src/tracer.js.map +1 -1
  25. package/dist/test/rendering/basic.test.js +22 -0
  26. package/dist/test/rendering/basic.test.js.map +1 -1
  27. package/dist/tsconfig.tsbuildinfo +1 -1
  28. package/package.json +1 -1
  29. package/src/pretty-string/pretty-string.test.ts +47 -0
  30. package/src/pretty-string/pretty-string.ts +130 -0
  31. package/src/refkey.ts +13 -0
  32. package/src/render.ts +7 -0
  33. package/src/runtime/component.ts +31 -0
  34. package/src/tracer.ts +2 -5
  35. package/temp/api.json +244 -4
  36. package/test/rendering/basic.test.tsx +35 -1
@@ -0,0 +1,47 @@
1
+ import { expect, it } from "vitest";
2
+ import { pret, PrettyString } from "./pretty-string.js";
3
+
4
+ function expectRender(
5
+ pretty: PrettyString,
6
+ expected: {
7
+ toString: string;
8
+ toAnsi: string;
9
+ },
10
+ ) {
11
+ expect(pretty.toString()).toBe(expected.toString);
12
+ expect(pretty.toAnsi()).toBe(expected.toAnsi);
13
+ }
14
+
15
+ it("interpolate basic string", () => {
16
+ const result = pret`foo ${"bar"} baz`;
17
+ expectRender(result, {
18
+ toString: "foo bar baz",
19
+ toAnsi: "foo bar baz",
20
+ });
21
+ });
22
+
23
+ // cspell:ignore mbar
24
+ it("interpolate pretty segment", () => {
25
+ const result = pret`foo ${pret.red("bar")} baz`;
26
+ expectRender(result, {
27
+ toString: "foo bar baz",
28
+ toAnsi: "foo \x1b[31mbar\x1b[39m baz",
29
+ });
30
+ });
31
+
32
+ it("interpolate another pretty string with more formatting", () => {
33
+ const a = pret`foo ${pret.red("bar")} baz`;
34
+ const result = pret`Hi, ${pret.bgGreen(a)}`;
35
+ expectRender(result, {
36
+ toString: "Hi, foo bar baz",
37
+ toAnsi: "Hi, \x1b[42mfoo \x1b[31mbar\x1b[39m baz\x1b[49m",
38
+ });
39
+ });
40
+
41
+ it("use full rgb", () => {
42
+ const result = pret`foo ${pret.rgb(123, 45, 67, "bar")} baz`;
43
+ expectRender(result, {
44
+ toString: "foo bar baz",
45
+ toAnsi: "foo \x1b[38;2;123;45;67mbar\x1b[39m baz",
46
+ });
47
+ });
@@ -0,0 +1,130 @@
1
+ import { inspect } from "../inspect.js";
2
+
3
+ export function pret(
4
+ strings: TemplateStringsArray,
5
+ ...keys: PrettyStringSegment[]
6
+ ): PrettyString {
7
+ const result: PrettyStringSegment[] = [strings[0]];
8
+ keys.forEach((key, i) => {
9
+ result.push(key);
10
+ result.push(strings[i + 1]);
11
+ });
12
+
13
+ return new PrettyString(result);
14
+ }
15
+
16
+ pret.black = (x: PrettyStringSegment) => new PrettyStringColored(x, "black");
17
+ pret.red = (x: PrettyStringSegment) => new PrettyStringColored(x, "red");
18
+ pret.green = (x: PrettyStringSegment) => new PrettyStringColored(x, "green");
19
+ pret.yellow = (x: PrettyStringSegment) => new PrettyStringColored(x, "yellow");
20
+ pret.blue = (x: PrettyStringSegment) => new PrettyStringColored(x, "blue");
21
+ pret.magenta = (x: PrettyStringSegment) =>
22
+ new PrettyStringColored(x, "magenta");
23
+ pret.cyan = (x: PrettyStringSegment) => new PrettyStringColored(x, "cyan");
24
+ pret.white = (x: PrettyStringSegment) => new PrettyStringColored(x, "white");
25
+ pret.gray = (x: PrettyStringSegment) => new PrettyStringColored(x, "gray");
26
+
27
+ pret.bgBlack = (x: PrettyStringSegment) =>
28
+ new PrettyStringColored(x, "bgBlack");
29
+ pret.bgRed = (x: PrettyStringSegment) => new PrettyStringColored(x, "bgRed");
30
+ pret.bgGreen = (x: PrettyStringSegment) =>
31
+ new PrettyStringColored(x, "bgGreen");
32
+ pret.bgYellow = (x: PrettyStringSegment) =>
33
+ new PrettyStringColored(x, "bgYellow");
34
+ pret.bgBlue = (x: PrettyStringSegment) => new PrettyStringColored(x, "bgBlue");
35
+ pret.bgMagenta = (x: PrettyStringSegment) =>
36
+ new PrettyStringColored(x, "bgMagenta");
37
+ pret.bgCyan = (x: PrettyStringSegment) => new PrettyStringColored(x, "bgCyan");
38
+ pret.bgWhite = (x: PrettyStringSegment) =>
39
+ new PrettyStringColored(x, "bgWhite");
40
+
41
+ pret.rgb = (r: number, g: number, b: number, x: PrettyStringSegment) =>
42
+ new PrettyStringColored(x, { kind: "rgb", r, g, b });
43
+
44
+ const ansiColors = {
45
+ reset: ["\x1b[0m", "\x1b[0m"],
46
+ bold: ["\x1b[1m", "\x1b[22m"],
47
+ dim: ["\x1b[2m", "\x1b[22m"],
48
+ italic: ["\x1b[3m", "\x1b[23m"],
49
+ underline: ["\x1b[4m", "\x1b[24m"],
50
+ inverse: ["\x1b[7m", "\x1b[27m"],
51
+ hidden: ["\x1b[8m", "\x1b[28m"],
52
+ strikethrough: ["\x1b[9m", "\x1b[29m"],
53
+ black: ["\x1b[30m", "\x1b[39m"],
54
+ red: ["\x1b[31m", "\x1b[39m"],
55
+ green: ["\x1b[32m", "\x1b[39m"],
56
+ yellow: ["\x1b[33m", "\x1b[39m"],
57
+ blue: ["\x1b[34m", "\x1b[39m"],
58
+ magenta: ["\x1b[35m", "\x1b[39m"],
59
+ cyan: ["\x1b[36m", "\x1b[39m"],
60
+ white: ["\x1b[37m", "\x1b[39m"],
61
+ gray: ["\x1b[90m", "\x1b[39m"],
62
+ bgBlack: ["\x1b[40m", "\x1b[49m"],
63
+ bgRed: ["\x1b[41m", "\x1b[49m"],
64
+ bgGreen: ["\x1b[42m", "\x1b[49m"],
65
+ bgYellow: ["\x1b[43m", "\x1b[49m"],
66
+ bgBlue: ["\x1b[44m", "\x1b[49m"],
67
+ bgMagenta: ["\x1b[45m", "\x1b[49m"],
68
+ bgCyan: ["\x1b[46m", "\x1b[49m"],
69
+ bgWhite: ["\x1b[47m", "\x1b[49m"],
70
+ } as Record<string, [string, string]>;
71
+
72
+ export type PrettyStringSegment = string | PrettyStringColored | PrettyString;
73
+
74
+ export interface RgbColor {
75
+ kind: "rgb";
76
+ r: number;
77
+ g: number;
78
+ b: number;
79
+ }
80
+
81
+ export type ColorCodes = keyof typeof ansiColors;
82
+ export type Color = ColorCodes | RgbColor;
83
+ export class PrettyStringColored {
84
+ #value: PrettyStringSegment;
85
+ #color: Color;
86
+
87
+ constructor(value: PrettyStringSegment, color: Color) {
88
+ this.#value = value;
89
+ this.#color = color;
90
+ }
91
+
92
+ toString(): string {
93
+ return this.#value.toString();
94
+ }
95
+
96
+ toAnsi(): string {
97
+ if (typeof this.#color === "string") {
98
+ const [start, end] = ansiColors[this.#color];
99
+ return `${start}${typeof this.#value === "string" ? this.#value : this.#value.toAnsi()}${end}`;
100
+ }
101
+ const { r, g, b } = this.#color;
102
+ const start = `\x1b[38;2;${r};${g};${b}m`;
103
+ const end = `\x1b[39m`;
104
+ return `${start}${typeof this.#value === "string" ? this.#value : this.#value.toAnsi()}${end}`;
105
+ }
106
+ }
107
+
108
+ export class PrettyString {
109
+ #segments: PrettyStringSegment[];
110
+
111
+ constructor(segments: PrettyStringSegment[]) {
112
+ this.#segments = segments;
113
+ }
114
+
115
+ toString(): string {
116
+ return this.#segments
117
+ .map((s) => (typeof s === "string" ? s : s.toString()))
118
+ .join("");
119
+ }
120
+
121
+ toAnsi(): string {
122
+ return this.#segments
123
+ .map((s) => (typeof s === "string" ? s : s.toAnsi()))
124
+ .join("");
125
+ }
126
+
127
+ [inspect.custom]() {
128
+ return this.toAnsi();
129
+ }
130
+ }
package/src/refkey.ts CHANGED
@@ -192,3 +192,16 @@ export function memberRefkey(
192
192
  [RefkeySym]: true,
193
193
  };
194
194
  }
195
+
196
+ export function inspectRefkey(refkey: Refkey): string {
197
+ const text =
198
+ isMemberRefkey(refkey) ?
199
+ `memberRefkey[${inspectRefkey(refkey.base)} -> ${inspectRefkey(refkey.member)}]`
200
+ : `refkey[${refkey.key}]`;
201
+
202
+ return text;
203
+ }
204
+
205
+ export function unresolvedRefkey(refkey: Refkey): string {
206
+ return `<Unresolved Symbol: ${inspectRefkey(refkey)}>`;
207
+ }
package/src/render.ts CHANGED
@@ -20,7 +20,9 @@ import {
20
20
  Children,
21
21
  Component,
22
22
  isComponentCreator,
23
+ isRenderableObject,
23
24
  Props,
25
+ RENDERABLE,
24
26
  } from "./runtime/component.js";
25
27
  import { IntrinsicElement, isIntrinsicElement } from "./runtime/intrinsic.js";
26
28
  import { flushJobs, flushJobsAsync } from "./scheduler.js";
@@ -548,6 +550,9 @@ function normalizeChild(child: Child): NormalizedChildren {
548
550
 
549
551
  return sfContext.reference({ refkey: child });
550
552
  };
553
+ } else if (isRenderableObject(child)) {
554
+ // For custom renderable objects, we will just normalize them to a bound function.
555
+ return child[RENDERABLE].bind(child);
551
556
  } else if (isCustomContext(child)) {
552
557
  return child;
553
558
  } else if (isIntrinsicElement(child)) {
@@ -573,6 +578,8 @@ function debugPrintChild(child: Children): string {
573
578
  return "$ref";
574
579
  } else if (isIntrinsicElement(child)) {
575
580
  return `<${child.name}>`;
581
+ } else if (isRenderableObject(child)) {
582
+ return `CustomChildElement(${JSON.stringify(child)})`;
576
583
  } else {
577
584
  return JSON.stringify(child);
578
585
  }
@@ -3,7 +3,38 @@ import { CustomContext } from "../reactivity.js";
3
3
  import { Refkey } from "../refkey.js";
4
4
  import { IntrinsicElement } from "./intrinsic.js";
5
5
 
6
+ export const RENDERABLE = Symbol.for("Alloy.CustomElement");
7
+
8
+ /**
9
+ * A renderable object is any object that has an `[ay.RENDERABLE]` method that
10
+ * returns children. This is used to allow custom object types to be used as
11
+ * children in Alloy components.
12
+ */
13
+ export interface RenderableObject {
14
+ /**
15
+ * Renders this object to children.
16
+ */
17
+ [RENDERABLE](): Children;
18
+ }
19
+
20
+ /**
21
+ * Returns true if the item is a renderable object, meaning it has an `[ay.RENDERABLE]`
22
+ * method.
23
+ *
24
+ * @param item - The item to check.
25
+ * @returns True if the item is a renderable object.
26
+ */
27
+ export function isRenderableObject(item: unknown): item is RenderableObject {
28
+ return (
29
+ typeof item === "object" &&
30
+ item !== null &&
31
+ RENDERABLE in item &&
32
+ typeof (item as any)[RENDERABLE] === "function"
33
+ );
34
+ }
35
+
6
36
  export type Child =
37
+ | RenderableObject
7
38
  | string
8
39
  | boolean
9
40
  | number
package/src/tracer.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { effect, ReactiveEffectRunner } from "@vue/reactivity";
2
2
  import { untrack } from "./reactivity.js";
3
- import { isMemberRefkey, type Refkey } from "./refkey.js";
3
+ import { inspectRefkey, type Refkey } from "./refkey.js";
4
4
  import { scheduler } from "./scheduler.js";
5
5
  import { type OutputScope } from "./symbols/output-scope.js";
6
6
  import type {
@@ -429,10 +429,7 @@ export function formatRefkeys(refkeys: Refkey[] | Refkey | undefined) {
429
429
  }
430
430
 
431
431
  function formatRefkey(refkey: Refkey): string {
432
- const text =
433
- isMemberRefkey(refkey) ?
434
- `memberRefkey[${formatRefkey(refkey.base)} -> ${formatRefkey(refkey.member)}]`
435
- : `refkey[${refkey.key}]`;
432
+ const text = inspectRefkey(refkey);
436
433
 
437
434
  return colorText(text, {
438
435
  fg: {
package/temp/api.json CHANGED
@@ -2233,9 +2233,14 @@
2233
2233
  "kind": "Content",
2234
2234
  "text": "export type Child = "
2235
2235
  },
2236
+ {
2237
+ "kind": "Reference",
2238
+ "text": "RenderableObject",
2239
+ "canonicalReference": "@alloy-js/core!RenderableObject:interface"
2240
+ },
2236
2241
  {
2237
2242
  "kind": "Content",
2238
- "text": "string | boolean | number | undefined | null | void | (() => "
2243
+ "text": " | string | boolean | number | undefined | null | void | (() => "
2239
2244
  },
2240
2245
  {
2241
2246
  "kind": "Reference",
@@ -2288,7 +2293,7 @@
2288
2293
  "name": "Child",
2289
2294
  "typeTokenRange": {
2290
2295
  "startIndex": 1,
2291
- "endIndex": 11
2296
+ "endIndex": 12
2292
2297
  }
2293
2298
  },
2294
2299
  {
@@ -7668,6 +7673,52 @@
7668
7673
  ],
7669
7674
  "extendsTokenRanges": []
7670
7675
  },
7676
+ {
7677
+ "kind": "Function",
7678
+ "canonicalReference": "@alloy-js/core!inspectRefkey:function(1)",
7679
+ "docComment": "",
7680
+ "excerptTokens": [
7681
+ {
7682
+ "kind": "Content",
7683
+ "text": "export declare function inspectRefkey(refkey: "
7684
+ },
7685
+ {
7686
+ "kind": "Reference",
7687
+ "text": "Refkey",
7688
+ "canonicalReference": "@alloy-js/core!Refkey:type"
7689
+ },
7690
+ {
7691
+ "kind": "Content",
7692
+ "text": "): "
7693
+ },
7694
+ {
7695
+ "kind": "Content",
7696
+ "text": "string"
7697
+ },
7698
+ {
7699
+ "kind": "Content",
7700
+ "text": ";"
7701
+ }
7702
+ ],
7703
+ "fileUrlPath": "src/refkey.ts",
7704
+ "returnTypeTokenRange": {
7705
+ "startIndex": 3,
7706
+ "endIndex": 4
7707
+ },
7708
+ "releaseTag": "Public",
7709
+ "overloadIndex": 1,
7710
+ "parameters": [
7711
+ {
7712
+ "parameterName": "refkey",
7713
+ "parameterTypeTokenRange": {
7714
+ "startIndex": 1,
7715
+ "endIndex": 2
7716
+ },
7717
+ "isOptional": false
7718
+ }
7719
+ ],
7720
+ "name": "inspectRefkey"
7721
+ },
7671
7722
  {
7672
7723
  "kind": "Function",
7673
7724
  "canonicalReference": "@alloy-js/core!instantiateTakenMembersTo:function(1)",
@@ -9273,6 +9324,61 @@
9273
9324
  ],
9274
9325
  "name": "isRefkey"
9275
9326
  },
9327
+ {
9328
+ "kind": "Function",
9329
+ "canonicalReference": "@alloy-js/core!isRenderableObject:function(1)",
9330
+ "docComment": "/**\n * Returns true if the item is a renderable object, meaning it has an `[ay.RENDERABLE]`\n * method.\n *\n * @param item - The item to check.\n *\n * @returns True if the item is a renderable object.\n */\n",
9331
+ "excerptTokens": [
9332
+ {
9333
+ "kind": "Content",
9334
+ "text": "export declare function isRenderableObject(item: "
9335
+ },
9336
+ {
9337
+ "kind": "Content",
9338
+ "text": "unknown"
9339
+ },
9340
+ {
9341
+ "kind": "Content",
9342
+ "text": "): "
9343
+ },
9344
+ {
9345
+ "kind": "Reference",
9346
+ "text": "item",
9347
+ "canonicalReference": "@alloy-js/core!~item"
9348
+ },
9349
+ {
9350
+ "kind": "Content",
9351
+ "text": " is "
9352
+ },
9353
+ {
9354
+ "kind": "Reference",
9355
+ "text": "RenderableObject",
9356
+ "canonicalReference": "@alloy-js/core!RenderableObject:interface"
9357
+ },
9358
+ {
9359
+ "kind": "Content",
9360
+ "text": ";"
9361
+ }
9362
+ ],
9363
+ "fileUrlPath": "src/runtime/component.ts",
9364
+ "returnTypeTokenRange": {
9365
+ "startIndex": 3,
9366
+ "endIndex": 6
9367
+ },
9368
+ "releaseTag": "Public",
9369
+ "overloadIndex": 1,
9370
+ "parameters": [
9371
+ {
9372
+ "parameterName": "item",
9373
+ "parameterTypeTokenRange": {
9374
+ "startIndex": 1,
9375
+ "endIndex": 2
9376
+ },
9377
+ "isOptional": false
9378
+ }
9379
+ ],
9380
+ "name": "isRenderableObject"
9381
+ },
9276
9382
  {
9277
9383
  "kind": "Function",
9278
9384
  "canonicalReference": "@alloy-js/core!isSymbolRefkey:function(1)",
@@ -17634,7 +17740,16 @@
17634
17740
  },
17635
17741
  {
17636
17742
  "kind": "Content",
17637
- "text": "<string | number | boolean | void | (() => "
17743
+ "text": "<string | number | boolean | void | import(\"../runtime/component.js\")."
17744
+ },
17745
+ {
17746
+ "kind": "Reference",
17747
+ "text": "RenderableObject",
17748
+ "canonicalReference": "@alloy-js/core!RenderableObject:interface"
17749
+ },
17750
+ {
17751
+ "kind": "Content",
17752
+ "text": " | (() => "
17638
17753
  },
17639
17754
  {
17640
17755
  "kind": "Reference",
@@ -17878,7 +17993,7 @@
17878
17993
  "fileUrlPath": "src/components/ReferenceOrContent.tsx",
17879
17994
  "returnTypeTokenRange": {
17880
17995
  "startIndex": 3,
17881
- "endIndex": 58
17996
+ "endIndex": 60
17882
17997
  },
17883
17998
  "releaseTag": "Public",
17884
17999
  "overloadIndex": 1,
@@ -18158,6 +18273,85 @@
18158
18273
  ],
18159
18274
  "name": "render"
18160
18275
  },
18276
+ {
18277
+ "kind": "Variable",
18278
+ "canonicalReference": "@alloy-js/core!RENDERABLE:var",
18279
+ "docComment": "",
18280
+ "excerptTokens": [
18281
+ {
18282
+ "kind": "Content",
18283
+ "text": "RENDERABLE: "
18284
+ },
18285
+ {
18286
+ "kind": "Content",
18287
+ "text": "unique symbol"
18288
+ }
18289
+ ],
18290
+ "fileUrlPath": "src/runtime/component.ts",
18291
+ "isReadonly": true,
18292
+ "releaseTag": "Public",
18293
+ "name": "RENDERABLE",
18294
+ "variableTypeTokenRange": {
18295
+ "startIndex": 1,
18296
+ "endIndex": 2
18297
+ }
18298
+ },
18299
+ {
18300
+ "kind": "Interface",
18301
+ "canonicalReference": "@alloy-js/core!RenderableObject:interface",
18302
+ "docComment": "/**\n * A renderable object is any object that has an `[ay.RENDERABLE]` method that\n * returns children. This is used to allow custom object types to be used as\n * children in Alloy components.\n */\n",
18303
+ "excerptTokens": [
18304
+ {
18305
+ "kind": "Content",
18306
+ "text": "export interface RenderableObject "
18307
+ }
18308
+ ],
18309
+ "fileUrlPath": "src/runtime/component.ts",
18310
+ "releaseTag": "Public",
18311
+ "name": "RenderableObject",
18312
+ "preserveMemberOrder": false,
18313
+ "members": [
18314
+ {
18315
+ "kind": "MethodSignature",
18316
+ "canonicalReference": "@alloy-js/core!RenderableObject#[RENDERABLE]:member(1)",
18317
+ "docComment": "/**\n * Renders this object to children.\n */\n",
18318
+ "excerptTokens": [
18319
+ {
18320
+ "kind": "Content",
18321
+ "text": "["
18322
+ },
18323
+ {
18324
+ "kind": "Reference",
18325
+ "text": "RENDERABLE",
18326
+ "canonicalReference": "@alloy-js/core!RENDERABLE:var"
18327
+ },
18328
+ {
18329
+ "kind": "Content",
18330
+ "text": "](): "
18331
+ },
18332
+ {
18333
+ "kind": "Reference",
18334
+ "text": "Children",
18335
+ "canonicalReference": "@alloy-js/core!Children:type"
18336
+ },
18337
+ {
18338
+ "kind": "Content",
18339
+ "text": ";"
18340
+ }
18341
+ ],
18342
+ "isOptional": false,
18343
+ "returnTypeTokenRange": {
18344
+ "startIndex": 3,
18345
+ "endIndex": 4
18346
+ },
18347
+ "releaseTag": "Public",
18348
+ "overloadIndex": 1,
18349
+ "parameters": [],
18350
+ "name": "[RENDERABLE]"
18351
+ }
18352
+ ],
18353
+ "extendsTokenRanges": []
18354
+ },
18161
18355
  {
18162
18356
  "kind": "Function",
18163
18357
  "canonicalReference": "@alloy-js/core!renderAsync:function(1)",
@@ -23233,6 +23427,52 @@
23233
23427
  ],
23234
23428
  "name": "traverseOutput"
23235
23429
  },
23430
+ {
23431
+ "kind": "Function",
23432
+ "canonicalReference": "@alloy-js/core!unresolvedRefkey:function(1)",
23433
+ "docComment": "",
23434
+ "excerptTokens": [
23435
+ {
23436
+ "kind": "Content",
23437
+ "text": "export declare function unresolvedRefkey(refkey: "
23438
+ },
23439
+ {
23440
+ "kind": "Reference",
23441
+ "text": "Refkey",
23442
+ "canonicalReference": "@alloy-js/core!Refkey:type"
23443
+ },
23444
+ {
23445
+ "kind": "Content",
23446
+ "text": "): "
23447
+ },
23448
+ {
23449
+ "kind": "Content",
23450
+ "text": "string"
23451
+ },
23452
+ {
23453
+ "kind": "Content",
23454
+ "text": ";"
23455
+ }
23456
+ ],
23457
+ "fileUrlPath": "src/refkey.ts",
23458
+ "returnTypeTokenRange": {
23459
+ "startIndex": 3,
23460
+ "endIndex": 4
23461
+ },
23462
+ "releaseTag": "Public",
23463
+ "overloadIndex": 1,
23464
+ "parameters": [
23465
+ {
23466
+ "parameterName": "refkey",
23467
+ "parameterTypeTokenRange": {
23468
+ "startIndex": 1,
23469
+ "endIndex": 2
23470
+ },
23471
+ "isOptional": false
23472
+ }
23473
+ ],
23474
+ "name": "unresolvedRefkey"
23475
+ },
23236
23476
  {
23237
23477
  "kind": "Function",
23238
23478
  "canonicalReference": "@alloy-js/core!untrack:function(1)",
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { Children } from "../../src/runtime/component.js";
2
+ import { Children, RENDERABLE } from "../../src/runtime/component.js";
3
3
  import "../../testing/extend-expect.js";
4
4
  describe("string nodes", () => {
5
5
  it("renders string nodes with substitutions", () => {
@@ -49,6 +49,40 @@ describe("component nodes", () => {
49
49
  </>,
50
50
  ).toRenderTo("Str Str");
51
51
  });
52
+
53
+ it("renders custom elements", () => {
54
+ const customElement = {
55
+ [RENDERABLE]() {
56
+ return (
57
+ <>
58
+ <Str /> <Str />
59
+ </>
60
+ );
61
+ },
62
+ };
63
+
64
+ expect(customElement).toRenderTo("Str Str");
65
+ });
66
+
67
+ it("renders nested custom elements", () => {
68
+ const e1 = {
69
+ [RENDERABLE]() {
70
+ return <Str />;
71
+ },
72
+ };
73
+
74
+ const e2 = {
75
+ [RENDERABLE]() {
76
+ return (
77
+ <>
78
+ {e1} {e1}
79
+ </>
80
+ );
81
+ },
82
+ };
83
+
84
+ expect(e2).toRenderTo("Str Str");
85
+ });
52
86
  });
53
87
 
54
88
  describe("memo nodes", () => {