@epoch32/visage 0.0.0-stage → 0.0.0

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 (138) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +110 -2
  3. package/dist/bundle.dev.js +4875 -0
  4. package/dist/index.js +9633 -0
  5. package/dist/src/api/index.js +4002 -0
  6. package/dist/src/charts/index.js +2717 -0
  7. package/dist/src/devtools/index.js +4677 -0
  8. package/dist/src/dom/index.js +1550 -0
  9. package/dist/src/form/index.js +1415 -0
  10. package/dist/src/index.js +11826 -0
  11. package/dist/src/jsx-runtime/index.js +1630 -0
  12. package/dist/src/query/index.js +2422 -0
  13. package/dist/src/router/index.js +1856 -0
  14. package/dist/src/rpc/index.js +3484 -0
  15. package/dist/src/server/index.js +1173 -0
  16. package/dist/src/signals/index.js +1077 -0
  17. package/dist/src/style/index.js +2340 -0
  18. package/dist/src/template/index.js +1149 -0
  19. package/dist/src/ui/index.js +4155 -0
  20. package/dist/src/virtual/index.js +1955 -0
  21. package/dist/src/vite/index.js +984 -0
  22. package/dist/vite/index.js +707 -0
  23. package/package.json +140 -4
  24. package/src/api/client.ts +371 -0
  25. package/src/api/file-router.ts +183 -0
  26. package/src/api/handler.ts +326 -0
  27. package/src/api/index.ts +71 -0
  28. package/src/api/middleware.ts +54 -0
  29. package/src/api/pragma.ts +155 -0
  30. package/src/api/procedure.ts +172 -0
  31. package/src/api/types.ts +249 -0
  32. package/src/charts/Area.tsx +111 -0
  33. package/src/charts/Axis.tsx +126 -0
  34. package/src/charts/Bar.tsx +86 -0
  35. package/src/charts/CartesianGrid.tsx +72 -0
  36. package/src/charts/Chart.tsx +269 -0
  37. package/src/charts/Cursor.tsx +42 -0
  38. package/src/charts/Legend.tsx +56 -0
  39. package/src/charts/Line.tsx +106 -0
  40. package/src/charts/Pie.tsx +88 -0
  41. package/src/charts/Tooltip.tsx +127 -0
  42. package/src/charts/context.ts +30 -0
  43. package/src/charts/index.ts +14 -0
  44. package/src/charts/path.ts +155 -0
  45. package/src/charts/scale.ts +133 -0
  46. package/src/charts/types.ts +50 -0
  47. package/src/devtools/DomTab.tsx +134 -0
  48. package/src/devtools/GraphInspector.tsx +196 -0
  49. package/src/devtools/GraphTab.tsx +315 -0
  50. package/src/devtools/QueryTab.tsx +200 -0
  51. package/src/devtools/RpcTab.tsx +190 -0
  52. package/src/devtools/SignalsTab.tsx +129 -0
  53. package/src/devtools/component.tsx +243 -0
  54. package/src/devtools/highlighter.ts +134 -0
  55. package/src/devtools/hub.ts +175 -0
  56. package/src/devtools/index.ts +20 -0
  57. package/src/devtools/styles.ts +313 -0
  58. package/src/devtools/types.ts +45 -0
  59. package/src/dom/async.ts +232 -0
  60. package/src/dom/control-flow.ts +353 -0
  61. package/src/dom/index.ts +32 -0
  62. package/src/dom/lazy.ts +82 -0
  63. package/src/dom/render.ts +286 -0
  64. package/src/dom/resource.ts +120 -0
  65. package/src/form/form.ts +218 -0
  66. package/src/form/index.ts +17 -0
  67. package/src/form/schema.ts +299 -0
  68. package/src/index.ts +413 -0
  69. package/src/jsx-dev-runtime/index.ts +1 -0
  70. package/src/jsx-runtime/index.ts +112 -0
  71. package/src/jsx-runtime/jsx.d.ts +278 -0
  72. package/src/query/create-mutation.ts +64 -0
  73. package/src/query/create-query.ts +426 -0
  74. package/src/query/focus-manager.ts +68 -0
  75. package/src/query/index.ts +63 -0
  76. package/src/query/mutation-cache.ts +138 -0
  77. package/src/query/online-manager.ts +67 -0
  78. package/src/query/query-cache.ts +369 -0
  79. package/src/query/query-client.ts +248 -0
  80. package/src/query/types.ts +221 -0
  81. package/src/query/utils.ts +132 -0
  82. package/src/router/index.ts +19 -0
  83. package/src/router/router.tsx +352 -0
  84. package/src/rpc/client.ts +317 -0
  85. package/src/rpc/error.ts +70 -0
  86. package/src/rpc/index.ts +52 -0
  87. package/src/rpc/procedure.ts +88 -0
  88. package/src/rpc/router.ts +105 -0
  89. package/src/rpc/server.ts +511 -0
  90. package/src/rpc/types.ts +328 -0
  91. package/src/server/hydrate.ts +21 -0
  92. package/src/server/index.ts +10 -0
  93. package/src/server/render-to-stream.ts +31 -0
  94. package/src/server/render-to-string.ts +125 -0
  95. package/src/signals/computed.ts +217 -0
  96. package/src/signals/context.ts +89 -0
  97. package/src/signals/effect.ts +161 -0
  98. package/src/signals/index.ts +57 -0
  99. package/src/signals/scope.ts +132 -0
  100. package/src/signals/signal.ts +203 -0
  101. package/src/signals/store.ts +163 -0
  102. package/src/signals/system.ts +124 -0
  103. package/src/signals/types.ts +64 -0
  104. package/src/style/component.tsx +122 -0
  105. package/src/style/create-style.ts +229 -0
  106. package/src/style/cx.ts +75 -0
  107. package/src/style/hash.ts +19 -0
  108. package/src/style/index.ts +8 -0
  109. package/src/style/layout.tsx +406 -0
  110. package/src/style/manager.ts +87 -0
  111. package/src/style/parser.ts +257 -0
  112. package/src/style/scale.ts +237 -0
  113. package/src/template/index.ts +4 -0
  114. package/src/template/template.ts +126 -0
  115. package/src/ui/accordion.tsx +286 -0
  116. package/src/ui/command-dialog.tsx +49 -0
  117. package/src/ui/command.tsx +400 -0
  118. package/src/ui/data-table.tsx +322 -0
  119. package/src/ui/dialog.tsx +362 -0
  120. package/src/ui/dropdown-menu.tsx +381 -0
  121. package/src/ui/icon.tsx +69 -0
  122. package/src/ui/index.ts +138 -0
  123. package/src/ui/layout.tsx +13 -0
  124. package/src/ui/popover.tsx +249 -0
  125. package/src/ui/switch.tsx +114 -0
  126. package/src/ui/tabs.tsx +297 -0
  127. package/src/ui/toast.tsx +280 -0
  128. package/src/ui/tooltip.tsx +262 -0
  129. package/src/ui/utils.ts +110 -0
  130. package/src/virtual/index.ts +12 -0
  131. package/src/virtual/virtual-list.tsx +185 -0
  132. package/src/virtual/virtualizer.ts +274 -0
  133. package/src/vite/hmr.ts +38 -0
  134. package/src/vite/index.ts +3 -0
  135. package/src/vite/lucide.ts +124 -0
  136. package/src/vite/plugin.ts +102 -0
  137. package/src/vite/rpc-middleware.ts +82 -0
  138. package/src/vite/types.ts +65 -0
@@ -0,0 +1,313 @@
1
+ export const devtoolsStyles = `
2
+ .visage-devtools-root {
3
+ position: fixed;
4
+ z-index: 999999;
5
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
6
+ font-size: 13px;
7
+ color: #f1f5f9;
8
+ box-sizing: border-box;
9
+ }
10
+ .visage-devtools-root * {
11
+ box-sizing: border-box;
12
+ }
13
+ .visage-devtools-trigger {
14
+ position: fixed;
15
+ bottom: 20px;
16
+ left: 20px;
17
+ background: #0f172a;
18
+ color: #38bdf8;
19
+ border: 1px solid #334155;
20
+ border-radius: 9999px;
21
+ padding: 8px 14px;
22
+ display: flex;
23
+ align-items: center;
24
+ gap: 8px;
25
+ cursor: pointer;
26
+ font-weight: 600;
27
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.5), 0 0 10px rgba(56, 189, 248, 0.2);
28
+ transition: all 0.2s ease;
29
+ z-index: 999999;
30
+ }
31
+ .visage-devtools-trigger:hover {
32
+ background: #1e293b;
33
+ border-color: #38bdf8;
34
+ transform: translateY(-2px);
35
+ }
36
+ .visage-devtools-drawer {
37
+ position: fixed;
38
+ bottom: 0;
39
+ left: 0;
40
+ right: 0;
41
+ height: 420px;
42
+ background: #090d16;
43
+ border-top: 1px solid #1e293b;
44
+ display: flex;
45
+ flex-direction: column;
46
+ box-shadow: 0 -20px 25px -5px rgba(0, 0, 0, 0.7);
47
+ z-index: 999999;
48
+ }
49
+ .visage-devtools-header {
50
+ display: flex;
51
+ align-items: center;
52
+ justify-content: space-between;
53
+ padding: 8px 16px;
54
+ background: #0f172a;
55
+ border-bottom: 1px solid #1e293b;
56
+ }
57
+ .visage-devtools-tabs {
58
+ display: flex;
59
+ gap: 4px;
60
+ }
61
+ .visage-devtools-tab {
62
+ background: transparent;
63
+ border: none;
64
+ color: #94a3b8;
65
+ padding: 6px 12px;
66
+ border-radius: 6px;
67
+ cursor: pointer;
68
+ font-size: 12px;
69
+ font-weight: 500;
70
+ display: flex;
71
+ align-items: center;
72
+ gap: 6px;
73
+ }
74
+ .visage-devtools-tab:hover {
75
+ color: #f1f5f9;
76
+ background: #1e293b;
77
+ }
78
+ .visage-devtools-tab.active {
79
+ color: #38bdf8;
80
+ background: #1e293b;
81
+ font-weight: 600;
82
+ }
83
+ .visage-devtools-badge {
84
+ background: #334155;
85
+ color: #f1f5f9;
86
+ padding: 1px 6px;
87
+ border-radius: 9999px;
88
+ font-size: 10px;
89
+ font-weight: 600;
90
+ }
91
+ .visage-devtools-body {
92
+ flex: 1;
93
+ display: flex;
94
+ overflow: hidden;
95
+ }
96
+ .visage-devtools-sidebar {
97
+ width: 320px;
98
+ border-right: 1px solid #1e293b;
99
+ display: flex;
100
+ flex-direction: column;
101
+ background: #0c111d;
102
+ }
103
+ .visage-devtools-search {
104
+ padding: 8px;
105
+ border-bottom: 1px solid #1e293b;
106
+ }
107
+ .visage-devtools-input {
108
+ width: 100%;
109
+ background: #090d16;
110
+ border: 1px solid #334155;
111
+ border-radius: 6px;
112
+ color: #f1f5f9;
113
+ padding: 6px 10px;
114
+ font-size: 12px;
115
+ outline: none;
116
+ }
117
+ .visage-devtools-input:focus {
118
+ border-color: #38bdf8;
119
+ }
120
+ .visage-devtools-list {
121
+ flex: 1;
122
+ overflow-y: auto;
123
+ padding: 4px;
124
+ }
125
+ .visage-devtools-item {
126
+ padding: 8px 10px;
127
+ border-radius: 6px;
128
+ cursor: pointer;
129
+ display: flex;
130
+ align-items: center;
131
+ justify-content: space-between;
132
+ margin-bottom: 2px;
133
+ font-size: 12px;
134
+ }
135
+ .visage-devtools-item:hover {
136
+ background: #1e293b;
137
+ }
138
+ .visage-devtools-item.selected {
139
+ background: #1e293b;
140
+ border-left: 3px solid #38bdf8;
141
+ }
142
+ .visage-devtools-main {
143
+ flex: 1;
144
+ padding: 16px;
145
+ overflow-y: auto;
146
+ background: #090d16;
147
+ }
148
+ .visage-devtools-json {
149
+ background: #050811;
150
+ border: 1px solid #1e293b;
151
+ border-radius: 6px;
152
+ padding: 12px;
153
+ font-family: "JetBrains Mono", Menlo, Monaco, Consolas, monospace;
154
+ font-size: 12px;
155
+ color: #38bdf8;
156
+ overflow-x: auto;
157
+ white-space: pre-wrap;
158
+ }
159
+ .visage-devtools-actions {
160
+ display: flex;
161
+ align-items: center;
162
+ gap: 8px;
163
+ }
164
+ .visage-devtools-btn {
165
+ background: #1e293b;
166
+ border: 1px solid #334155;
167
+ color: #f1f5f9;
168
+ padding: 4px 10px;
169
+ border-radius: 4px;
170
+ font-size: 11px;
171
+ cursor: pointer;
172
+ font-weight: 500;
173
+ }
174
+ .visage-devtools-btn:hover {
175
+ background: #334155;
176
+ }
177
+ .visage-devtools-btn.active {
178
+ background: #0284c7;
179
+ border-color: #38bdf8;
180
+ }
181
+ /* DAG Graph Visualization */
182
+ .visage-graph-container {
183
+ flex: 1;
184
+ display: flex;
185
+ flex-direction: column;
186
+ overflow: hidden;
187
+ background: #050811;
188
+ position: relative;
189
+ }
190
+ .visage-graph-toolbar {
191
+ padding: 8px 16px;
192
+ background: #090d16;
193
+ border-bottom: 1px solid #1e293b;
194
+ display: flex;
195
+ align-items: center;
196
+ justify-content: space-between;
197
+ gap: 12px;
198
+ }
199
+ .visage-graph-canvas {
200
+ flex: 1;
201
+ overflow: auto;
202
+ padding: 24px;
203
+ position: relative;
204
+ display: flex;
205
+ gap: 40px;
206
+ }
207
+ .visage-graph-column {
208
+ display: flex;
209
+ flex-direction: column;
210
+ gap: 16px;
211
+ min-width: 220px;
212
+ }
213
+ .visage-graph-col-header {
214
+ font-size: 11px;
215
+ font-weight: 700;
216
+ text-transform: uppercase;
217
+ letter-spacing: 0.05em;
218
+ color: #64748b;
219
+ margin-bottom: 4px;
220
+ display: flex;
221
+ align-items: center;
222
+ gap: 6px;
223
+ }
224
+ .visage-graph-node {
225
+ background: #0f172a;
226
+ border: 1px solid #1e293b;
227
+ border-radius: 8px;
228
+ padding: 10px 12px;
229
+ cursor: pointer;
230
+ transition: all 0.2s ease;
231
+ position: relative;
232
+ }
233
+ .visage-graph-node:hover {
234
+ border-color: #38bdf8;
235
+ transform: translateY(-2px);
236
+ box-shadow: 0 4px 12px rgba(56, 189, 248, 0.15);
237
+ }
238
+ .visage-graph-node.selected {
239
+ border-color: #38bdf8;
240
+ box-shadow: 0 0 0 2px rgba(56, 189, 248, 0.4);
241
+ background: #131d35;
242
+ }
243
+ .visage-graph-node.is-dependency {
244
+ border-color: #38bdf8;
245
+ box-shadow: 0 0 0 1px #38bdf8, 0 2px 8px rgba(56, 189, 248, 0.25);
246
+ background: #082f49;
247
+ }
248
+ .visage-graph-node.is-dependent {
249
+ border-color: #c084fc;
250
+ box-shadow: 0 0 0 1px #c084fc, 0 2px 8px rgba(192, 132, 252, 0.25);
251
+ background: #3b0764;
252
+ }
253
+ .visage-graph-node.is-dimmed {
254
+ opacity: 0.3;
255
+ filter: grayscale(0.5);
256
+ }
257
+ .visage-graph-node-title {
258
+ font-weight: 600;
259
+ font-size: 12px;
260
+ color: #f8fafc;
261
+ margin-bottom: 4px;
262
+ display: flex;
263
+ align-items: center;
264
+ justify-content: space-between;
265
+ }
266
+ .visage-graph-node-val {
267
+ font-family: monospace;
268
+ font-size: 11px;
269
+ color: #94a3b8;
270
+ overflow: hidden;
271
+ text-overflow: ellipsis;
272
+ white-space: nowrap;
273
+ max-width: 190px;
274
+ }
275
+ .visage-graph-pulse {
276
+ display: inline-block;
277
+ width: 8px;
278
+ height: 8px;
279
+ border-radius: 50%;
280
+ background: #10b981;
281
+ box-shadow: 0 0 8px #10b981;
282
+ }
283
+ .visage-graph-pulse.computed {
284
+ background: #a855f7;
285
+ box-shadow: 0 0 8px #a855f7;
286
+ }
287
+ .visage-graph-pill {
288
+ display: inline-flex;
289
+ align-items: center;
290
+ gap: 4px;
291
+ background: #1e293b;
292
+ color: #cbd5e1;
293
+ padding: 3px 8px;
294
+ border-radius: 4px;
295
+ font-size: 11px;
296
+ cursor: pointer;
297
+ border: 1px solid #334155;
298
+ transition: all 0.15s ease;
299
+ }
300
+ .visage-graph-pill:hover {
301
+ background: #334155;
302
+ color: #fff;
303
+ border-color: #38bdf8;
304
+ }
305
+ .visage-graph-pill.source {
306
+ border-color: #0369a1;
307
+ color: #7dd3fc;
308
+ }
309
+ .visage-graph-pill.target {
310
+ border-color: #7e22ce;
311
+ color: #d8b4fe;
312
+ }
313
+ `;
@@ -0,0 +1,45 @@
1
+ export type DevToolsTab = "signals" | "graph" | "query" | "rpc" | "dom" | "concepts";
2
+
3
+ export interface SignalRecord {
4
+ id: string;
5
+ name: string;
6
+ type: "signal" | "computed";
7
+ getValue: () => any;
8
+ version: () => number;
9
+ dependencies?: () => string[];
10
+ dependents?: () => string[];
11
+ subscribersCount?: () => number;
12
+ lastUpdatedAt: number;
13
+ }
14
+
15
+ export interface QueryRecord {
16
+ hash: string;
17
+ key: any;
18
+ status: () => string;
19
+ fetchStatus: () => string;
20
+ data: () => any;
21
+ error: () => any;
22
+ dataUpdatedAt: () => number;
23
+ refetch?: () => Promise<any>;
24
+ invalidate?: () => void;
25
+ }
26
+
27
+ export interface RpcRecord {
28
+ id: string;
29
+ path: string;
30
+ type: "query" | "mutation" | "subscription";
31
+ input: any;
32
+ response?: any;
33
+ error?: any;
34
+ status: "pending" | "success" | "error" | "streaming";
35
+ startTime: number;
36
+ duration?: number;
37
+ events?: Array<{ timestamp: number; data: any }>;
38
+ }
39
+
40
+ export interface DevToolsOptions {
41
+ position?: "bottom-right" | "bottom-left" | "top-right" | "top-left";
42
+ initialOpen?: boolean;
43
+ initialTab?: DevToolsTab;
44
+ highlightDOM?: boolean;
45
+ }
@@ -0,0 +1,232 @@
1
+ import { effect, getActiveScope, onCleanup, runInScope, Scope, signal } from "../signals";
2
+ import { type Child, insertChild } from "./render";
3
+ import {
4
+ createResource,
5
+ type Resource,
6
+ type ResourceActions,
7
+ SuspenseContext,
8
+ type SuspenseContextValue
9
+ } from "./resource";
10
+
11
+ export {
12
+ type Component,
13
+ type LazyComponent,
14
+ lazy
15
+ } from "./lazy";
16
+ export {
17
+ createResource,
18
+ type Resource,
19
+ type ResourceActions,
20
+ SuspenseContext,
21
+ type SuspenseContextValue
22
+ };
23
+
24
+ export interface SuspenseProps {
25
+ fallback: Child;
26
+ children: Child | (() => Child);
27
+ }
28
+
29
+ /**
30
+ * Suspense boundary for fine-grained async coordination.
31
+ * Displays the `fallback` UI while child async resources or queries are loading.
32
+ *
33
+ * @example
34
+ * ```tsx
35
+ * <Suspense fallback={<div>Loading profile...</div>}>
36
+ * <UserProfile />
37
+ * </Suspense>
38
+ * ```
39
+ */
40
+ export function Suspense(props: SuspenseProps): any {
41
+ if (typeof document === "undefined") {
42
+ return typeof props.children === "function"
43
+ ? (props.children as () => Child)()
44
+ : props.children;
45
+ }
46
+
47
+ const marker = document.createTextNode("");
48
+ const initialFrag = document.createDocumentFragment();
49
+ const pendingCount = signal(0);
50
+ let currentScope: Scope | null = null;
51
+ let currentNodes: Node[] = [];
52
+ let isMounted = false;
53
+
54
+ const suspenseValue: SuspenseContextValue = {
55
+ registerPromise(p: Promise<any>) {
56
+ pendingCount.update((c) => c + 1);
57
+ p.finally(() => {
58
+ pendingCount.update((c) => Math.max(0, c - 1));
59
+ });
60
+ }
61
+ };
62
+
63
+ const renderContent = (content: Child) => {
64
+ const parent = marker.parentNode ?? (!isMounted ? initialFrag : null);
65
+ if (!parent) return;
66
+
67
+ for (const n of currentNodes) {
68
+ if (n.parentNode) n.parentNode.removeChild(n);
69
+ }
70
+ currentNodes = [];
71
+
72
+ const frag = document.createDocumentFragment();
73
+ insertChild(frag, content);
74
+ currentNodes = Array.from(frag.childNodes);
75
+
76
+ if (marker.parentNode) {
77
+ marker.parentNode.insertBefore(frag, marker);
78
+ } else if (!isMounted) {
79
+ initialFrag.appendChild(frag);
80
+ }
81
+ };
82
+
83
+ effect(() => {
84
+ if (currentScope) {
85
+ currentScope.dispose();
86
+ currentScope = null;
87
+ }
88
+
89
+ currentScope = new Scope(getActiveScope());
90
+
91
+ runInScope(currentScope, () => {
92
+ let threwPromise: Promise<any> | null = null;
93
+ let rendered: any = null;
94
+
95
+ try {
96
+ const SuspenseProvider = SuspenseContext.Provider;
97
+ rendered = SuspenseProvider({
98
+ value: suspenseValue,
99
+ children: props.children
100
+ });
101
+ } catch (err: any) {
102
+ if (err && typeof err.then === "function") {
103
+ threwPromise = err;
104
+ suspenseValue.registerPromise(err);
105
+ } else {
106
+ throw err;
107
+ }
108
+ }
109
+
110
+ if (pendingCount() > 0 || threwPromise) {
111
+ renderContent(props.fallback);
112
+ } else {
113
+ renderContent(rendered);
114
+ }
115
+ });
116
+ });
117
+
118
+ isMounted = true;
119
+ initialFrag.appendChild(marker);
120
+
121
+ onCleanup(() => {
122
+ if (currentScope) currentScope.dispose();
123
+ });
124
+
125
+ return initialFrag;
126
+ }
127
+
128
+ export interface ErrorBoundaryProps {
129
+ fallback: Child | ((error: any, reset: () => void) => Child);
130
+ children: Child | (() => Child);
131
+ }
132
+
133
+ /**
134
+ * Catches JavaScript rendering and effect errors in descendant subtrees
135
+ * and displays a fallback UI instead of crashing the application.
136
+ *
137
+ * @example
138
+ * ```tsx
139
+ * <ErrorBoundary fallback={(err, reset) => (
140
+ * <div>
141
+ * <p>Something went wrong: {err.message}</p>
142
+ * <button onClick={reset}>Retry</button>
143
+ * </div>
144
+ * )}>
145
+ * <RiskyComponent />
146
+ * </ErrorBoundary>
147
+ * ```
148
+ */
149
+ export function ErrorBoundary(props: ErrorBoundaryProps): any {
150
+ if (typeof document === "undefined") {
151
+ try {
152
+ return typeof props.children === "function"
153
+ ? (props.children as () => Child)()
154
+ : props.children;
155
+ } catch (err: any) {
156
+ return typeof props.fallback === "function"
157
+ ? (props.fallback as any)(err, () => {})
158
+ : props.fallback;
159
+ }
160
+ }
161
+
162
+ const marker = document.createTextNode("");
163
+ const initialFrag = document.createDocumentFragment();
164
+ const currentError = signal<any>(null);
165
+ let currentScope: Scope | null = null;
166
+ let currentNodes: Node[] = [];
167
+ let isMounted = false;
168
+
169
+ const reset = () => {
170
+ currentError.set(null);
171
+ };
172
+
173
+ const renderNodes = (child: Child) => {
174
+ const parent = marker.parentNode ?? (!isMounted ? initialFrag : null);
175
+ if (!parent) return;
176
+
177
+ for (const n of currentNodes) {
178
+ if (n.parentNode) n.parentNode.removeChild(n);
179
+ }
180
+ currentNodes = [];
181
+
182
+ const frag = document.createDocumentFragment();
183
+ insertChild(frag, child);
184
+ currentNodes = Array.from(frag.childNodes);
185
+
186
+ if (marker.parentNode) {
187
+ marker.parentNode.insertBefore(frag, marker);
188
+ } else if (!isMounted) {
189
+ initialFrag.appendChild(frag);
190
+ }
191
+ };
192
+
193
+ effect(() => {
194
+ const err = currentError();
195
+
196
+ if (currentScope) {
197
+ currentScope.dispose();
198
+ currentScope = null;
199
+ }
200
+
201
+ currentScope = new Scope(getActiveScope());
202
+
203
+ runInScope(currentScope, () => {
204
+ if (err !== null) {
205
+ const fallbackNode =
206
+ typeof props.fallback === "function"
207
+ ? (props.fallback as (err: any, reset: () => void) => Child)(err, reset)
208
+ : props.fallback;
209
+ renderNodes(fallbackNode);
210
+ } else {
211
+ try {
212
+ const content =
213
+ typeof props.children === "function"
214
+ ? (props.children as () => Child)()
215
+ : props.children;
216
+ renderNodes(content);
217
+ } catch (catchedErr) {
218
+ currentError.set(catchedErr);
219
+ }
220
+ }
221
+ });
222
+ });
223
+
224
+ isMounted = true;
225
+ initialFrag.appendChild(marker);
226
+
227
+ onCleanup(() => {
228
+ if (currentScope) currentScope.dispose();
229
+ });
230
+
231
+ return initialFrag;
232
+ }