@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.
- package/LICENSE +373 -0
- package/README.md +110 -2
- package/dist/bundle.dev.js +4875 -0
- package/dist/index.js +9633 -0
- package/dist/src/api/index.js +4002 -0
- package/dist/src/charts/index.js +2717 -0
- package/dist/src/devtools/index.js +4677 -0
- package/dist/src/dom/index.js +1550 -0
- package/dist/src/form/index.js +1415 -0
- package/dist/src/index.js +11826 -0
- package/dist/src/jsx-runtime/index.js +1630 -0
- package/dist/src/query/index.js +2422 -0
- package/dist/src/router/index.js +1856 -0
- package/dist/src/rpc/index.js +3484 -0
- package/dist/src/server/index.js +1173 -0
- package/dist/src/signals/index.js +1077 -0
- package/dist/src/style/index.js +2340 -0
- package/dist/src/template/index.js +1149 -0
- package/dist/src/ui/index.js +4155 -0
- package/dist/src/virtual/index.js +1955 -0
- package/dist/src/vite/index.js +984 -0
- package/dist/vite/index.js +707 -0
- package/package.json +140 -4
- package/src/api/client.ts +371 -0
- package/src/api/file-router.ts +183 -0
- package/src/api/handler.ts +326 -0
- package/src/api/index.ts +71 -0
- package/src/api/middleware.ts +54 -0
- package/src/api/pragma.ts +155 -0
- package/src/api/procedure.ts +172 -0
- package/src/api/types.ts +249 -0
- package/src/charts/Area.tsx +111 -0
- package/src/charts/Axis.tsx +126 -0
- package/src/charts/Bar.tsx +86 -0
- package/src/charts/CartesianGrid.tsx +72 -0
- package/src/charts/Chart.tsx +269 -0
- package/src/charts/Cursor.tsx +42 -0
- package/src/charts/Legend.tsx +56 -0
- package/src/charts/Line.tsx +106 -0
- package/src/charts/Pie.tsx +88 -0
- package/src/charts/Tooltip.tsx +127 -0
- package/src/charts/context.ts +30 -0
- package/src/charts/index.ts +14 -0
- package/src/charts/path.ts +155 -0
- package/src/charts/scale.ts +133 -0
- package/src/charts/types.ts +50 -0
- package/src/devtools/DomTab.tsx +134 -0
- package/src/devtools/GraphInspector.tsx +196 -0
- package/src/devtools/GraphTab.tsx +315 -0
- package/src/devtools/QueryTab.tsx +200 -0
- package/src/devtools/RpcTab.tsx +190 -0
- package/src/devtools/SignalsTab.tsx +129 -0
- package/src/devtools/component.tsx +243 -0
- package/src/devtools/highlighter.ts +134 -0
- package/src/devtools/hub.ts +175 -0
- package/src/devtools/index.ts +20 -0
- package/src/devtools/styles.ts +313 -0
- package/src/devtools/types.ts +45 -0
- package/src/dom/async.ts +232 -0
- package/src/dom/control-flow.ts +353 -0
- package/src/dom/index.ts +32 -0
- package/src/dom/lazy.ts +82 -0
- package/src/dom/render.ts +286 -0
- package/src/dom/resource.ts +120 -0
- package/src/form/form.ts +218 -0
- package/src/form/index.ts +17 -0
- package/src/form/schema.ts +299 -0
- package/src/index.ts +413 -0
- package/src/jsx-dev-runtime/index.ts +1 -0
- package/src/jsx-runtime/index.ts +112 -0
- package/src/jsx-runtime/jsx.d.ts +278 -0
- package/src/query/create-mutation.ts +64 -0
- package/src/query/create-query.ts +426 -0
- package/src/query/focus-manager.ts +68 -0
- package/src/query/index.ts +63 -0
- package/src/query/mutation-cache.ts +138 -0
- package/src/query/online-manager.ts +67 -0
- package/src/query/query-cache.ts +369 -0
- package/src/query/query-client.ts +248 -0
- package/src/query/types.ts +221 -0
- package/src/query/utils.ts +132 -0
- package/src/router/index.ts +19 -0
- package/src/router/router.tsx +352 -0
- package/src/rpc/client.ts +317 -0
- package/src/rpc/error.ts +70 -0
- package/src/rpc/index.ts +52 -0
- package/src/rpc/procedure.ts +88 -0
- package/src/rpc/router.ts +105 -0
- package/src/rpc/server.ts +511 -0
- package/src/rpc/types.ts +328 -0
- package/src/server/hydrate.ts +21 -0
- package/src/server/index.ts +10 -0
- package/src/server/render-to-stream.ts +31 -0
- package/src/server/render-to-string.ts +125 -0
- package/src/signals/computed.ts +217 -0
- package/src/signals/context.ts +89 -0
- package/src/signals/effect.ts +161 -0
- package/src/signals/index.ts +57 -0
- package/src/signals/scope.ts +132 -0
- package/src/signals/signal.ts +203 -0
- package/src/signals/store.ts +163 -0
- package/src/signals/system.ts +124 -0
- package/src/signals/types.ts +64 -0
- package/src/style/component.tsx +122 -0
- package/src/style/create-style.ts +229 -0
- package/src/style/cx.ts +75 -0
- package/src/style/hash.ts +19 -0
- package/src/style/index.ts +8 -0
- package/src/style/layout.tsx +406 -0
- package/src/style/manager.ts +87 -0
- package/src/style/parser.ts +257 -0
- package/src/style/scale.ts +237 -0
- package/src/template/index.ts +4 -0
- package/src/template/template.ts +126 -0
- package/src/ui/accordion.tsx +286 -0
- package/src/ui/command-dialog.tsx +49 -0
- package/src/ui/command.tsx +400 -0
- package/src/ui/data-table.tsx +322 -0
- package/src/ui/dialog.tsx +362 -0
- package/src/ui/dropdown-menu.tsx +381 -0
- package/src/ui/icon.tsx +69 -0
- package/src/ui/index.ts +138 -0
- package/src/ui/layout.tsx +13 -0
- package/src/ui/popover.tsx +249 -0
- package/src/ui/switch.tsx +114 -0
- package/src/ui/tabs.tsx +297 -0
- package/src/ui/toast.tsx +280 -0
- package/src/ui/tooltip.tsx +262 -0
- package/src/ui/utils.ts +110 -0
- package/src/virtual/index.ts +12 -0
- package/src/virtual/virtual-list.tsx +185 -0
- package/src/virtual/virtualizer.ts +274 -0
- package/src/vite/hmr.ts +38 -0
- package/src/vite/index.ts +3 -0
- package/src/vite/lucide.ts +124 -0
- package/src/vite/plugin.ts +102 -0
- package/src/vite/rpc-middleware.ts +82 -0
- package/src/vite/types.ts +65 -0
|
@@ -0,0 +1,1149 @@
|
|
|
1
|
+
// src/signals/types.ts
|
|
2
|
+
var SubscriberState;
|
|
3
|
+
((SubscriberState) => {
|
|
4
|
+
SubscriberState[SubscriberState["CLEAN"] = 0] = "CLEAN";
|
|
5
|
+
SubscriberState[SubscriberState["CHECK_DIRTY"] = 1] = "CHECK_DIRTY";
|
|
6
|
+
SubscriberState[SubscriberState["DIRTY"] = 2] = "DIRTY";
|
|
7
|
+
SubscriberState[SubscriberState["DISPOSED"] = 3] = "DISPOSED";
|
|
8
|
+
})(SubscriberState ||= {});
|
|
9
|
+
var SIGNAL_BRAND = Symbol("visage.signal");
|
|
10
|
+
var COMPUTED_BRAND = Symbol("visage.computed");
|
|
11
|
+
function isSignal(value) {
|
|
12
|
+
return typeof value === "function" && ((SIGNAL_BRAND in value) || (COMPUTED_BRAND in value));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// src/signals/system.ts
|
|
16
|
+
var currentSubscriber = null;
|
|
17
|
+
var currentScope = null;
|
|
18
|
+
var batchDepth = 0;
|
|
19
|
+
var pendingEffects = new Set;
|
|
20
|
+
var warnedCyclicSubscribers = new WeakSet;
|
|
21
|
+
var isFlushing = false;
|
|
22
|
+
function setCurrentSubscriber(sub) {
|
|
23
|
+
currentSubscriber = sub;
|
|
24
|
+
}
|
|
25
|
+
function setCurrentScope(scope) {
|
|
26
|
+
currentScope = scope;
|
|
27
|
+
}
|
|
28
|
+
function getCurrentScope() {
|
|
29
|
+
return currentScope;
|
|
30
|
+
}
|
|
31
|
+
function addPendingEffect(eff) {
|
|
32
|
+
pendingEffects.add(eff);
|
|
33
|
+
}
|
|
34
|
+
function removePendingEffect(eff) {
|
|
35
|
+
pendingEffects.delete(eff);
|
|
36
|
+
}
|
|
37
|
+
var MAX_FLUSH_COUNT = 100;
|
|
38
|
+
function flushEffects() {
|
|
39
|
+
if (isFlushing || batchDepth > 0)
|
|
40
|
+
return;
|
|
41
|
+
isFlushing = true;
|
|
42
|
+
let iterations = 0;
|
|
43
|
+
try {
|
|
44
|
+
while (pendingEffects.size > 0) {
|
|
45
|
+
if (++iterations > MAX_FLUSH_COUNT) {
|
|
46
|
+
pendingEffects.clear();
|
|
47
|
+
throw new Error(`[Visage Reactivity] Maximum update depth exceeded (${MAX_FLUSH_COUNT} cycles). ` + `An effect continuously triggered state mutations (infinite loop detected). ` + `Ensure effects that modify signals do not unconditionally depend on them, or use untrack() to read state.`);
|
|
48
|
+
}
|
|
49
|
+
const effectsToRun = Array.from(pendingEffects);
|
|
50
|
+
pendingEffects.clear();
|
|
51
|
+
for (const eff of effectsToRun) {
|
|
52
|
+
if (eff.state === 2 /* DIRTY */ || eff.state === 1 /* CHECK_DIRTY */) {
|
|
53
|
+
eff.run();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
} finally {
|
|
58
|
+
isFlushing = false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function batch(fn) {
|
|
62
|
+
batchDepth++;
|
|
63
|
+
try {
|
|
64
|
+
return fn();
|
|
65
|
+
} finally {
|
|
66
|
+
batchDepth--;
|
|
67
|
+
if (batchDepth === 0) {
|
|
68
|
+
flushEffects();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function untrack(fn) {
|
|
73
|
+
const prev = currentSubscriber;
|
|
74
|
+
currentSubscriber = null;
|
|
75
|
+
try {
|
|
76
|
+
return fn();
|
|
77
|
+
} finally {
|
|
78
|
+
currentSubscriber = prev;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/signals/computed.ts
|
|
83
|
+
class Computed {
|
|
84
|
+
[COMPUTED_BRAND] = true;
|
|
85
|
+
_fn;
|
|
86
|
+
_value;
|
|
87
|
+
_subscribers = new Set;
|
|
88
|
+
sources = new Set;
|
|
89
|
+
sourceVersions = new Map;
|
|
90
|
+
state = 2 /* DIRTY */;
|
|
91
|
+
scope;
|
|
92
|
+
version = 0;
|
|
93
|
+
constructor(fn) {
|
|
94
|
+
this._fn = fn;
|
|
95
|
+
this.scope = currentScope;
|
|
96
|
+
if (currentScope) {
|
|
97
|
+
currentScope.addSubscriber(this);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
get() {
|
|
101
|
+
if (this.state === 3 /* DISPOSED */) {
|
|
102
|
+
return this._fn();
|
|
103
|
+
}
|
|
104
|
+
if (currentSubscriber !== null && currentSubscriber.state !== 3 /* DISPOSED */) {
|
|
105
|
+
this._subscribers.add(currentSubscriber);
|
|
106
|
+
currentSubscriber.sources.add(this);
|
|
107
|
+
currentSubscriber.sourceVersions.set(this, this.version);
|
|
108
|
+
}
|
|
109
|
+
if (this.state === 2 /* DIRTY */ || this.state === 1 /* CHECK_DIRTY */) {
|
|
110
|
+
this.updateIfNecessary();
|
|
111
|
+
}
|
|
112
|
+
return this._value;
|
|
113
|
+
}
|
|
114
|
+
get value() {
|
|
115
|
+
return this.get();
|
|
116
|
+
}
|
|
117
|
+
removeSubscriber(sub) {
|
|
118
|
+
this._subscribers.delete(sub);
|
|
119
|
+
}
|
|
120
|
+
markDirty(targetState = 1 /* CHECK_DIRTY */) {
|
|
121
|
+
if (this.state >= targetState || this.state === 3 /* DISPOSED */) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
this.state = targetState;
|
|
125
|
+
for (const sub of this._subscribers) {
|
|
126
|
+
sub.markDirty(1 /* CHECK_DIRTY */);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
updateIfNecessary() {
|
|
130
|
+
if (this.state === 2 /* DIRTY */) {
|
|
131
|
+
const prev = this._value;
|
|
132
|
+
this.recompute();
|
|
133
|
+
return !Object.is(prev, this._value);
|
|
134
|
+
}
|
|
135
|
+
if (this.state === 1 /* CHECK_DIRTY */) {
|
|
136
|
+
let anyChanged = false;
|
|
137
|
+
for (const source of this.sources) {
|
|
138
|
+
if (source instanceof Computed) {
|
|
139
|
+
source.updateIfNecessary();
|
|
140
|
+
}
|
|
141
|
+
const lastVersion = this.sourceVersions.get(source);
|
|
142
|
+
if (lastVersion !== undefined && lastVersion !== source.version) {
|
|
143
|
+
anyChanged = true;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (anyChanged) {
|
|
147
|
+
const prev = this._value;
|
|
148
|
+
this.recompute();
|
|
149
|
+
return !Object.is(prev, this._value);
|
|
150
|
+
}
|
|
151
|
+
this.state = 0 /* CLEAN */;
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
recompute() {
|
|
157
|
+
this.cleanupSources();
|
|
158
|
+
const prevSubscriber = currentSubscriber;
|
|
159
|
+
setCurrentSubscriber(this);
|
|
160
|
+
const prevScope = currentScope;
|
|
161
|
+
setCurrentScope(this.scope);
|
|
162
|
+
try {
|
|
163
|
+
const next = this._fn();
|
|
164
|
+
if (!Object.is(this._value, next)) {
|
|
165
|
+
this._value = next;
|
|
166
|
+
this.version++;
|
|
167
|
+
}
|
|
168
|
+
this.state = 0 /* CLEAN */;
|
|
169
|
+
} finally {
|
|
170
|
+
setCurrentSubscriber(prevSubscriber);
|
|
171
|
+
setCurrentScope(prevScope);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
cleanupSources() {
|
|
175
|
+
for (const source of this.sources) {
|
|
176
|
+
source.removeSubscriber(this);
|
|
177
|
+
}
|
|
178
|
+
this.sources.clear();
|
|
179
|
+
this.sourceVersions.clear();
|
|
180
|
+
}
|
|
181
|
+
dispose() {
|
|
182
|
+
if (this.state === 3 /* DISPOSED */)
|
|
183
|
+
return;
|
|
184
|
+
this.state = 3 /* DISPOSED */;
|
|
185
|
+
this.cleanupSources();
|
|
186
|
+
this._subscribers.clear();
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function computed(fn, options) {
|
|
190
|
+
const isInternal = options?.internal ?? false;
|
|
191
|
+
const customName = options?.name;
|
|
192
|
+
const c = new Computed(fn);
|
|
193
|
+
const accessor = () => c.get();
|
|
194
|
+
Object.defineProperties(accessor, {
|
|
195
|
+
[COMPUTED_BRAND]: { value: true },
|
|
196
|
+
get: { value: () => c.get() },
|
|
197
|
+
value: { get: () => c.get() }
|
|
198
|
+
});
|
|
199
|
+
if (!isInternal && typeof window !== "undefined" && window.__VISAGE_DEVTOOLS__) {
|
|
200
|
+
const devtools = window.__VISAGE_DEVTOOLS__;
|
|
201
|
+
const sigId = devtools.registerSignal({
|
|
202
|
+
name: customName,
|
|
203
|
+
type: "computed",
|
|
204
|
+
getValue: () => c.get(),
|
|
205
|
+
version: () => c.version,
|
|
206
|
+
subscribersCount: () => c._subscribers?.size ?? 0,
|
|
207
|
+
dependencies: () => Array.from(c.sources ?? []).map((src) => src._devId).filter(Boolean),
|
|
208
|
+
dependents: () => Array.from(c._subscribers ?? []).map((sub) => sub._devId).filter(Boolean)
|
|
209
|
+
});
|
|
210
|
+
c._devId = sigId;
|
|
211
|
+
if (currentScope) {
|
|
212
|
+
currentScope.addCleanup(() => {
|
|
213
|
+
devtools.unregisterSignal(sigId);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return accessor;
|
|
218
|
+
}
|
|
219
|
+
var createMemo = computed;
|
|
220
|
+
// src/signals/scope.ts
|
|
221
|
+
class Scope {
|
|
222
|
+
subscribers = new Set;
|
|
223
|
+
cleanups = [];
|
|
224
|
+
parent = null;
|
|
225
|
+
isDisposed = false;
|
|
226
|
+
context;
|
|
227
|
+
constructor(parent = currentScope) {
|
|
228
|
+
this.parent = parent;
|
|
229
|
+
if (parent && !parent.isDisposed) {
|
|
230
|
+
parent.cleanups.push(() => this.dispose());
|
|
231
|
+
if (parent.context) {
|
|
232
|
+
this.context = new Map(parent.context);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
addSubscriber(sub) {
|
|
237
|
+
if (this.isDisposed)
|
|
238
|
+
return;
|
|
239
|
+
this.subscribers.add(sub);
|
|
240
|
+
}
|
|
241
|
+
addCleanup(fn) {
|
|
242
|
+
if (this.isDisposed) {
|
|
243
|
+
fn();
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
this.cleanups.push(fn);
|
|
247
|
+
}
|
|
248
|
+
dispose() {
|
|
249
|
+
if (this.isDisposed)
|
|
250
|
+
return;
|
|
251
|
+
this.isDisposed = true;
|
|
252
|
+
for (const sub of this.subscribers) {
|
|
253
|
+
sub.dispose();
|
|
254
|
+
}
|
|
255
|
+
this.subscribers.clear();
|
|
256
|
+
for (let i = this.cleanups.length - 1;i >= 0; i--) {
|
|
257
|
+
try {
|
|
258
|
+
this.cleanups[i]();
|
|
259
|
+
} catch (err) {
|
|
260
|
+
console.error("Error during cleanup:", err);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
this.cleanups = [];
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function onCleanup(fn) {
|
|
267
|
+
if (currentSubscriber && "addCleanup" in currentSubscriber) {
|
|
268
|
+
currentSubscriber.addCleanup(fn);
|
|
269
|
+
} else if (currentScope) {
|
|
270
|
+
currentScope.addCleanup(fn);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function createRoot(fn) {
|
|
274
|
+
const prevScope = currentScope;
|
|
275
|
+
const scope = new Scope(null);
|
|
276
|
+
setCurrentScope(scope);
|
|
277
|
+
try {
|
|
278
|
+
return fn(() => scope.dispose());
|
|
279
|
+
} finally {
|
|
280
|
+
setCurrentScope(prevScope);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
function runInScope(scope, fn) {
|
|
284
|
+
const prevScope = currentScope;
|
|
285
|
+
setCurrentScope(scope);
|
|
286
|
+
try {
|
|
287
|
+
return fn();
|
|
288
|
+
} finally {
|
|
289
|
+
setCurrentScope(prevScope);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function getActiveScope() {
|
|
293
|
+
return getCurrentScope();
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// src/signals/context.ts
|
|
297
|
+
function createContext(defaultValue) {
|
|
298
|
+
const id = Symbol("visage.context");
|
|
299
|
+
const context = {
|
|
300
|
+
id,
|
|
301
|
+
defaultValue,
|
|
302
|
+
Provider: (props) => {
|
|
303
|
+
const parentScope = getActiveScope();
|
|
304
|
+
const scope = new Scope(parentScope);
|
|
305
|
+
if (!scope.context) {
|
|
306
|
+
scope.context = new Map(parentScope?.context);
|
|
307
|
+
}
|
|
308
|
+
scope.context.set(id, props.value);
|
|
309
|
+
return runInScope(scope, () => {
|
|
310
|
+
const content = typeof props.children === "function" ? untrack(() => props.children()) : props.children;
|
|
311
|
+
if (typeof document !== "undefined") {
|
|
312
|
+
const frag = document.createDocumentFragment();
|
|
313
|
+
insertChild(frag, content);
|
|
314
|
+
return frag;
|
|
315
|
+
}
|
|
316
|
+
return content;
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
return context;
|
|
321
|
+
}
|
|
322
|
+
function useContext(context) {
|
|
323
|
+
let scope = getActiveScope();
|
|
324
|
+
while (scope) {
|
|
325
|
+
if (scope.context?.has(context.id)) {
|
|
326
|
+
return scope.context.get(context.id);
|
|
327
|
+
}
|
|
328
|
+
scope = scope.parent;
|
|
329
|
+
}
|
|
330
|
+
return context.defaultValue;
|
|
331
|
+
}
|
|
332
|
+
// src/signals/effect.ts
|
|
333
|
+
class Effect {
|
|
334
|
+
_fn;
|
|
335
|
+
sources = new Set;
|
|
336
|
+
sourceVersions = new Map;
|
|
337
|
+
cleanups = [];
|
|
338
|
+
state = 2 /* DIRTY */;
|
|
339
|
+
scope;
|
|
340
|
+
constructor(fn) {
|
|
341
|
+
this._fn = fn;
|
|
342
|
+
this.scope = currentScope;
|
|
343
|
+
if (currentScope) {
|
|
344
|
+
currentScope.addSubscriber(this);
|
|
345
|
+
}
|
|
346
|
+
this.run();
|
|
347
|
+
}
|
|
348
|
+
addCleanup(fn) {
|
|
349
|
+
this.cleanups.push(fn);
|
|
350
|
+
}
|
|
351
|
+
runCleanups() {
|
|
352
|
+
for (let i = this.cleanups.length - 1;i >= 0; i--) {
|
|
353
|
+
try {
|
|
354
|
+
this.cleanups[i]();
|
|
355
|
+
} catch (e) {
|
|
356
|
+
console.error("Error in effect cleanup:", e);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
this.cleanups = [];
|
|
360
|
+
}
|
|
361
|
+
markDirty(targetState = 2 /* DIRTY */) {
|
|
362
|
+
if (this.state >= targetState || this.state === 3 /* DISPOSED */) {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
this.state = targetState;
|
|
366
|
+
addPendingEffect(this);
|
|
367
|
+
if (batchDepth === 0) {
|
|
368
|
+
flushEffects();
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
run() {
|
|
372
|
+
if (this.state === 3 /* DISPOSED */)
|
|
373
|
+
return;
|
|
374
|
+
if (this.state === 1 /* CHECK_DIRTY */) {
|
|
375
|
+
let isDirty = false;
|
|
376
|
+
for (const source of this.sources) {
|
|
377
|
+
if (source instanceof Computed) {
|
|
378
|
+
source.updateIfNecessary();
|
|
379
|
+
}
|
|
380
|
+
const lastVersion = this.sourceVersions.get(source);
|
|
381
|
+
if (lastVersion !== undefined && lastVersion !== source.version) {
|
|
382
|
+
isDirty = true;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
if (!isDirty) {
|
|
386
|
+
this.state = 0 /* CLEAN */;
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
this.runCleanups();
|
|
391
|
+
this.cleanupSources();
|
|
392
|
+
const prevSubscriber = currentSubscriber;
|
|
393
|
+
setCurrentSubscriber(this);
|
|
394
|
+
const prevScope = currentScope;
|
|
395
|
+
setCurrentScope(this.scope);
|
|
396
|
+
try {
|
|
397
|
+
this.state = 0 /* CLEAN */;
|
|
398
|
+
const res = this._fn();
|
|
399
|
+
if (typeof res === "function") {
|
|
400
|
+
this.cleanups.push(res);
|
|
401
|
+
}
|
|
402
|
+
} finally {
|
|
403
|
+
setCurrentSubscriber(prevSubscriber);
|
|
404
|
+
setCurrentScope(prevScope);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
cleanupSources() {
|
|
408
|
+
for (const source of this.sources) {
|
|
409
|
+
source.removeSubscriber(this);
|
|
410
|
+
}
|
|
411
|
+
this.sources.clear();
|
|
412
|
+
this.sourceVersions.clear();
|
|
413
|
+
}
|
|
414
|
+
dispose() {
|
|
415
|
+
if (this.state === 3 /* DISPOSED */)
|
|
416
|
+
return;
|
|
417
|
+
this.state = 3 /* DISPOSED */;
|
|
418
|
+
this.runCleanups();
|
|
419
|
+
this.cleanupSources();
|
|
420
|
+
removePendingEffect(this);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
function effect(fn) {
|
|
424
|
+
const eff = new Effect(fn);
|
|
425
|
+
return () => eff.dispose();
|
|
426
|
+
}
|
|
427
|
+
var createEffect = effect;
|
|
428
|
+
// src/signals/signal.ts
|
|
429
|
+
class Signal {
|
|
430
|
+
[SIGNAL_BRAND] = true;
|
|
431
|
+
_value;
|
|
432
|
+
_subscribers = new Set;
|
|
433
|
+
_equals;
|
|
434
|
+
version = 0;
|
|
435
|
+
constructor(initialValue, equals) {
|
|
436
|
+
this._value = initialValue;
|
|
437
|
+
this._equals = equals ?? Object.is;
|
|
438
|
+
}
|
|
439
|
+
get() {
|
|
440
|
+
if (currentSubscriber !== null && currentSubscriber.state !== 3 /* DISPOSED */) {
|
|
441
|
+
this._subscribers.add(currentSubscriber);
|
|
442
|
+
currentSubscriber.sources.add(this);
|
|
443
|
+
currentSubscriber.sourceVersions.set(this, this.version);
|
|
444
|
+
}
|
|
445
|
+
return this._value;
|
|
446
|
+
}
|
|
447
|
+
set(newValue) {
|
|
448
|
+
if (this._equals(this._value, newValue)) {
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
if (currentSubscriber !== null && this._subscribers.has(currentSubscriber)) {
|
|
452
|
+
if (!warnedCyclicSubscribers.has(currentSubscriber)) {
|
|
453
|
+
warnedCyclicSubscribers.add(currentSubscriber);
|
|
454
|
+
if (typeof console !== "undefined" && typeof console.warn === "function") {
|
|
455
|
+
console.warn(`[Visage Reactivity] Cyclic update detected: An active subscriber modified a signal that it depends on. ` + `To read a signal inside an effect/computed without creating a circular dependency, wrap the read in untrack():
|
|
456
|
+
` + ` untrack(() => signal())`);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
this._value = newValue;
|
|
461
|
+
this.version++;
|
|
462
|
+
batch(() => {
|
|
463
|
+
this.notify();
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
update(fn) {
|
|
467
|
+
this.set(fn(this._value));
|
|
468
|
+
}
|
|
469
|
+
get value() {
|
|
470
|
+
return this.get();
|
|
471
|
+
}
|
|
472
|
+
set value(val) {
|
|
473
|
+
this.set(val);
|
|
474
|
+
}
|
|
475
|
+
removeSubscriber(sub) {
|
|
476
|
+
this._subscribers.delete(sub);
|
|
477
|
+
}
|
|
478
|
+
notify() {
|
|
479
|
+
if (this._subscribers.size === 0)
|
|
480
|
+
return;
|
|
481
|
+
const subs = Array.from(this._subscribers);
|
|
482
|
+
for (const sub of subs) {
|
|
483
|
+
sub.markDirty(2 /* DIRTY */);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
function signal(initialValue, optionsOrEquals) {
|
|
488
|
+
const equals = typeof optionsOrEquals === "function" ? optionsOrEquals : optionsOrEquals?.equals;
|
|
489
|
+
const isInternal = typeof optionsOrEquals === "object" ? optionsOrEquals?.internal : false;
|
|
490
|
+
const customName = typeof optionsOrEquals === "object" ? optionsOrEquals?.name : undefined;
|
|
491
|
+
const s = new Signal(initialValue, equals);
|
|
492
|
+
const accessor = (...args) => {
|
|
493
|
+
if (args.length === 0) {
|
|
494
|
+
return s.get();
|
|
495
|
+
}
|
|
496
|
+
s.set(args[0]);
|
|
497
|
+
return args[0];
|
|
498
|
+
};
|
|
499
|
+
Object.defineProperties(accessor, {
|
|
500
|
+
[SIGNAL_BRAND]: { value: true },
|
|
501
|
+
get: { value: () => s.get() },
|
|
502
|
+
set: { value: (v) => s.set(v) },
|
|
503
|
+
update: { value: (fn) => s.update(fn) },
|
|
504
|
+
value: {
|
|
505
|
+
get: () => s.get(),
|
|
506
|
+
set: (v) => s.set(v)
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
if (!isInternal && typeof window !== "undefined" && window.__VISAGE_DEVTOOLS__) {
|
|
510
|
+
const devtools = window.__VISAGE_DEVTOOLS__;
|
|
511
|
+
const sigId = devtools.registerSignal({
|
|
512
|
+
name: customName,
|
|
513
|
+
type: "signal",
|
|
514
|
+
getValue: () => s.get(),
|
|
515
|
+
version: () => s.version,
|
|
516
|
+
subscribersCount: () => s._subscribers?.size ?? 0,
|
|
517
|
+
dependents: () => Array.from(s._subscribers ?? []).map((sub) => sub._devId).filter(Boolean)
|
|
518
|
+
});
|
|
519
|
+
s._devId = sigId;
|
|
520
|
+
if (currentScope) {
|
|
521
|
+
currentScope.addCleanup(() => {
|
|
522
|
+
devtools.unregisterSignal(sigId);
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
return accessor;
|
|
527
|
+
}
|
|
528
|
+
function createSignal(initialValue, optionsOrEquals) {
|
|
529
|
+
const s = signal(initialValue, optionsOrEquals);
|
|
530
|
+
const setter = (value) => {
|
|
531
|
+
if (typeof value === "function") {
|
|
532
|
+
s.update(value);
|
|
533
|
+
} else {
|
|
534
|
+
s.set(value);
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
return [s, setter];
|
|
538
|
+
}
|
|
539
|
+
// src/signals/store.ts
|
|
540
|
+
var STORE_RAW = Symbol("visage.store.raw");
|
|
541
|
+
var STORE_SIGNALS = Symbol("visage.store.signals");
|
|
542
|
+
var STORE_PROXY = Symbol("visage.store.proxy");
|
|
543
|
+
function isObject(val) {
|
|
544
|
+
return typeof val === "object" && val !== null && (typeof Node === "undefined" || !(val instanceof Node)) && !isSignal(val);
|
|
545
|
+
}
|
|
546
|
+
function getOrCreatePropertySignal(target, prop) {
|
|
547
|
+
let signalsMap = target[STORE_SIGNALS];
|
|
548
|
+
if (!signalsMap) {
|
|
549
|
+
signalsMap = new Map;
|
|
550
|
+
Object.defineProperty(target, STORE_SIGNALS, {
|
|
551
|
+
value: signalsMap,
|
|
552
|
+
enumerable: false,
|
|
553
|
+
writable: true
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
let sig = signalsMap.get(prop);
|
|
557
|
+
if (!sig) {
|
|
558
|
+
sig = new Signal(target[prop]);
|
|
559
|
+
signalsMap.set(prop, sig);
|
|
560
|
+
}
|
|
561
|
+
return sig;
|
|
562
|
+
}
|
|
563
|
+
function createStoreProxy(target) {
|
|
564
|
+
if (!isObject(target))
|
|
565
|
+
return target;
|
|
566
|
+
if (target[STORE_PROXY])
|
|
567
|
+
return target[STORE_PROXY];
|
|
568
|
+
const proxy = new Proxy(target, {
|
|
569
|
+
get(target, prop, receiver) {
|
|
570
|
+
if (prop === STORE_RAW)
|
|
571
|
+
return target;
|
|
572
|
+
if (prop === STORE_PROXY)
|
|
573
|
+
return proxy;
|
|
574
|
+
if (typeof prop === "string" || typeof prop === "symbol") {
|
|
575
|
+
const sig = getOrCreatePropertySignal(target, prop);
|
|
576
|
+
sig.get();
|
|
577
|
+
}
|
|
578
|
+
const value = Reflect.get(target, prop, receiver);
|
|
579
|
+
if (isObject(value)) {
|
|
580
|
+
return createStoreProxy(value);
|
|
581
|
+
}
|
|
582
|
+
return value;
|
|
583
|
+
},
|
|
584
|
+
set(target, prop, value, receiver) {
|
|
585
|
+
const prevValue = Reflect.get(target, prop, receiver);
|
|
586
|
+
if (Object.is(prevValue, value)) {
|
|
587
|
+
return true;
|
|
588
|
+
}
|
|
589
|
+
const success = Reflect.set(target, prop, value, receiver);
|
|
590
|
+
if (success) {
|
|
591
|
+
const sig = getOrCreatePropertySignal(target, prop);
|
|
592
|
+
sig.set(value);
|
|
593
|
+
if (Array.isArray(target) && prop !== "length") {
|
|
594
|
+
const lenSig = getOrCreatePropertySignal(target, "length");
|
|
595
|
+
lenSig.set(target.length);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
return success;
|
|
599
|
+
},
|
|
600
|
+
deleteProperty(target, prop) {
|
|
601
|
+
const hadProp = Reflect.has(target, prop);
|
|
602
|
+
const success = Reflect.deleteProperty(target, prop);
|
|
603
|
+
if (hadProp && success) {
|
|
604
|
+
const sig = getOrCreatePropertySignal(target, prop);
|
|
605
|
+
sig.set(undefined);
|
|
606
|
+
}
|
|
607
|
+
return success;
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
Object.defineProperty(target, STORE_PROXY, {
|
|
611
|
+
value: proxy,
|
|
612
|
+
enumerable: false,
|
|
613
|
+
writable: true
|
|
614
|
+
});
|
|
615
|
+
return proxy;
|
|
616
|
+
}
|
|
617
|
+
function createStore(initialState) {
|
|
618
|
+
if (!isObject(initialState)) {
|
|
619
|
+
throw new Error("createStore requires an object or array as initial state");
|
|
620
|
+
}
|
|
621
|
+
return createStoreProxy(initialState);
|
|
622
|
+
}
|
|
623
|
+
function mutateStore(store, mutator) {
|
|
624
|
+
batch(() => {
|
|
625
|
+
mutator(store);
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
function unwrapStore(store) {
|
|
629
|
+
if (isObject(store) && store[STORE_RAW]) {
|
|
630
|
+
return store[STORE_RAW];
|
|
631
|
+
}
|
|
632
|
+
return store;
|
|
633
|
+
}
|
|
634
|
+
// src/style/cx.ts
|
|
635
|
+
function hasReactiveClass(val) {
|
|
636
|
+
if (typeof val === "function")
|
|
637
|
+
return true;
|
|
638
|
+
if (Array.isArray(val)) {
|
|
639
|
+
for (let i = 0;i < val.length; i++) {
|
|
640
|
+
if (hasReactiveClass(val[i]))
|
|
641
|
+
return true;
|
|
642
|
+
}
|
|
643
|
+
return false;
|
|
644
|
+
}
|
|
645
|
+
if (typeof val === "object" && val !== null) {
|
|
646
|
+
for (const k in val) {
|
|
647
|
+
if (typeof val[k] === "function")
|
|
648
|
+
return true;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
return false;
|
|
652
|
+
}
|
|
653
|
+
function normalizeClass(val) {
|
|
654
|
+
if (!val)
|
|
655
|
+
return "";
|
|
656
|
+
if (typeof val === "function")
|
|
657
|
+
return normalizeClass(val());
|
|
658
|
+
if (typeof val === "string")
|
|
659
|
+
return val.trim();
|
|
660
|
+
if (typeof val === "number")
|
|
661
|
+
return String(val);
|
|
662
|
+
if (Array.isArray(val)) {
|
|
663
|
+
let res = "";
|
|
664
|
+
for (let i = 0;i < val.length; i++) {
|
|
665
|
+
const item = typeof val[i] === "function" ? val[i]() : val[i];
|
|
666
|
+
const itemStr = normalizeClass(item);
|
|
667
|
+
if (itemStr) {
|
|
668
|
+
res = res ? `${res} ${itemStr}` : itemStr;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
return res;
|
|
672
|
+
}
|
|
673
|
+
if (typeof val === "object") {
|
|
674
|
+
let res = "";
|
|
675
|
+
for (const key in val) {
|
|
676
|
+
const condition = typeof val[key] === "function" ? val[key]() : val[key];
|
|
677
|
+
if (condition) {
|
|
678
|
+
res = res ? `${res} ${key}` : key;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
return res;
|
|
682
|
+
}
|
|
683
|
+
return "";
|
|
684
|
+
}
|
|
685
|
+
function cx(...args) {
|
|
686
|
+
return normalizeClass(args);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// src/style/scale.ts
|
|
690
|
+
var UNITLESS_PROPERTIES = new Set([
|
|
691
|
+
"animationIterationCount",
|
|
692
|
+
"aspectRatio",
|
|
693
|
+
"borderImageSlice",
|
|
694
|
+
"columnCount",
|
|
695
|
+
"columns",
|
|
696
|
+
"flex",
|
|
697
|
+
"flexGrow",
|
|
698
|
+
"flexShrink",
|
|
699
|
+
"flexOrder",
|
|
700
|
+
"fontWeight",
|
|
701
|
+
"lineHeight",
|
|
702
|
+
"opacity",
|
|
703
|
+
"order",
|
|
704
|
+
"orphans",
|
|
705
|
+
"scale",
|
|
706
|
+
"tabSize",
|
|
707
|
+
"widows",
|
|
708
|
+
"zIndex",
|
|
709
|
+
"zoom",
|
|
710
|
+
"fillOpacity",
|
|
711
|
+
"strokeOpacity"
|
|
712
|
+
]);
|
|
713
|
+
var DIMENSION_KEYWORDS = {
|
|
714
|
+
screen: "100dvh",
|
|
715
|
+
"screen-h": "100dvh",
|
|
716
|
+
"screen-w": "100dvw",
|
|
717
|
+
full: "100%",
|
|
718
|
+
half: "50%",
|
|
719
|
+
third: "33.333333%",
|
|
720
|
+
"two-thirds": "66.666667%",
|
|
721
|
+
quarter: "25%",
|
|
722
|
+
"three-quarters": "75%",
|
|
723
|
+
auto: "auto",
|
|
724
|
+
min: "min-content",
|
|
725
|
+
max: "max-content",
|
|
726
|
+
fit: "fit-content"
|
|
727
|
+
};
|
|
728
|
+
function space(val) {
|
|
729
|
+
if (val === undefined || val === null || val === "")
|
|
730
|
+
return "";
|
|
731
|
+
if (typeof val === "number") {
|
|
732
|
+
if (val === 0)
|
|
733
|
+
return "0px";
|
|
734
|
+
return `${val * 4}px`;
|
|
735
|
+
}
|
|
736
|
+
const str = String(val).trim();
|
|
737
|
+
if (str in DIMENSION_KEYWORDS) {
|
|
738
|
+
return DIMENSION_KEYWORDS[str];
|
|
739
|
+
}
|
|
740
|
+
return str;
|
|
741
|
+
}
|
|
742
|
+
function resolveDimension(val) {
|
|
743
|
+
if (val === undefined || val === null || val === "")
|
|
744
|
+
return "";
|
|
745
|
+
if (typeof val === "number") {
|
|
746
|
+
if (val === 0)
|
|
747
|
+
return "0px";
|
|
748
|
+
if (val > 48)
|
|
749
|
+
return `${val}px`;
|
|
750
|
+
return `${val * 4}px`;
|
|
751
|
+
}
|
|
752
|
+
const str = String(val).trim();
|
|
753
|
+
if (str in DIMENSION_KEYWORDS) {
|
|
754
|
+
return DIMENSION_KEYWORDS[str];
|
|
755
|
+
}
|
|
756
|
+
return str;
|
|
757
|
+
}
|
|
758
|
+
function px(val) {
|
|
759
|
+
return `${val}px`;
|
|
760
|
+
}
|
|
761
|
+
function rem(val) {
|
|
762
|
+
return `${val}rem`;
|
|
763
|
+
}
|
|
764
|
+
function em(val) {
|
|
765
|
+
return `${val}em`;
|
|
766
|
+
}
|
|
767
|
+
function fluid(minPx, maxPx, options) {
|
|
768
|
+
const minVw = options?.minVw ?? 375;
|
|
769
|
+
const maxVw = options?.maxVw ?? 1280;
|
|
770
|
+
const slope = (maxPx - minPx) / (maxVw - minVw);
|
|
771
|
+
const yIntercept = -minVw * slope + minPx;
|
|
772
|
+
const slopeVw = slope * 100;
|
|
773
|
+
const preferred = `${yIntercept.toFixed(2)}px + ${slopeVw.toFixed(2)}vw`;
|
|
774
|
+
const min = Math.min(minPx, maxPx);
|
|
775
|
+
const max = Math.max(minPx, maxPx);
|
|
776
|
+
return `clamp(${min}px, ${preferred}, ${max}px)`;
|
|
777
|
+
}
|
|
778
|
+
var SHADOW_PRESETS = {
|
|
779
|
+
none: "none",
|
|
780
|
+
sm: "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
|
|
781
|
+
md: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)",
|
|
782
|
+
lg: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)",
|
|
783
|
+
xl: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)",
|
|
784
|
+
soft: "0 8px 30px rgba(0, 0, 0, 0.06)",
|
|
785
|
+
glow: "0 0 24px rgba(168, 85, 247, 0.35)",
|
|
786
|
+
inner: "inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)"
|
|
787
|
+
};
|
|
788
|
+
function shadow(variant) {
|
|
789
|
+
if (variant in SHADOW_PRESETS) {
|
|
790
|
+
return SHADOW_PRESETS[variant];
|
|
791
|
+
}
|
|
792
|
+
return variant;
|
|
793
|
+
}
|
|
794
|
+
var RADIUS_PRESETS = {
|
|
795
|
+
none: "0px",
|
|
796
|
+
sm: "4px",
|
|
797
|
+
md: "8px",
|
|
798
|
+
lg: "12px",
|
|
799
|
+
xl: "16px",
|
|
800
|
+
"2xl": "20px",
|
|
801
|
+
"3xl": "24px",
|
|
802
|
+
full: "9999px"
|
|
803
|
+
};
|
|
804
|
+
function radius(variant) {
|
|
805
|
+
if (typeof variant === "number") {
|
|
806
|
+
return `${variant}px`;
|
|
807
|
+
}
|
|
808
|
+
if (variant in RADIUS_PRESETS) {
|
|
809
|
+
return RADIUS_PRESETS[variant];
|
|
810
|
+
}
|
|
811
|
+
return String(variant);
|
|
812
|
+
}
|
|
813
|
+
function glass(options = {}) {
|
|
814
|
+
const blurVal = typeof options.blur === "number" ? `${options.blur}px` : options.blur ?? "20px";
|
|
815
|
+
const tintVal = options.tint ?? "rgba(255, 255, 255, 0.65)";
|
|
816
|
+
const borderVal = options.border ?? "1px solid rgba(255, 255, 255, 0.75)";
|
|
817
|
+
return {
|
|
818
|
+
backdropFilter: `blur(${blurVal})`,
|
|
819
|
+
WebkitBackdropFilter: `blur(${blurVal})`,
|
|
820
|
+
backgroundColor: tintVal,
|
|
821
|
+
border: borderVal
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
function formatStyleProp(prop, val) {
|
|
825
|
+
if (val === null || val === undefined || val === "")
|
|
826
|
+
return "";
|
|
827
|
+
if (typeof val === "number") {
|
|
828
|
+
if (val === 0 || UNITLESS_PROPERTIES.has(prop)) {
|
|
829
|
+
return String(val);
|
|
830
|
+
}
|
|
831
|
+
return `${val}px`;
|
|
832
|
+
}
|
|
833
|
+
const str = String(val).trim();
|
|
834
|
+
if (str in DIMENSION_KEYWORDS) {
|
|
835
|
+
const lowerProp = prop.toLowerCase();
|
|
836
|
+
if (str === "screen") {
|
|
837
|
+
if (lowerProp.includes("width"))
|
|
838
|
+
return "100dvw";
|
|
839
|
+
return "100dvh";
|
|
840
|
+
}
|
|
841
|
+
return DIMENSION_KEYWORDS[str];
|
|
842
|
+
}
|
|
843
|
+
return str;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// src/dom/render.ts
|
|
847
|
+
function isReactive(value) {
|
|
848
|
+
return isSignal(value) || typeof value === "function";
|
|
849
|
+
}
|
|
850
|
+
function resolveValue(val) {
|
|
851
|
+
if (typeof val === "function") {
|
|
852
|
+
return val();
|
|
853
|
+
}
|
|
854
|
+
return val;
|
|
855
|
+
}
|
|
856
|
+
function render(fn, container) {
|
|
857
|
+
return createRoot((dispose) => {
|
|
858
|
+
container.textContent = "";
|
|
859
|
+
const node = insertChild(container, fn());
|
|
860
|
+
onCleanup(() => {
|
|
861
|
+
if (node && node instanceof Node && node.parentNode === container) {
|
|
862
|
+
container.removeChild(node);
|
|
863
|
+
}
|
|
864
|
+
});
|
|
865
|
+
return dispose;
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
function setAttribute(el, key, value) {
|
|
869
|
+
if (key.startsWith("on") && typeof value === "function") {
|
|
870
|
+
const eventName = key.startsWith("onCapture") ? key.slice(9).toLowerCase() : key.slice(2).toLowerCase();
|
|
871
|
+
const useCapture = key.startsWith("onCapture");
|
|
872
|
+
el.addEventListener(eventName, value, useCapture);
|
|
873
|
+
onCleanup(() => {
|
|
874
|
+
el.removeEventListener(eventName, value, useCapture);
|
|
875
|
+
});
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
if (key === "ref" && typeof value === "function") {
|
|
879
|
+
value(el);
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
if (key === "class" || key === "className") {
|
|
883
|
+
if (hasReactiveClass(value)) {
|
|
884
|
+
effect(() => {
|
|
885
|
+
const cls = normalizeClass(value);
|
|
886
|
+
if (cls)
|
|
887
|
+
el.setAttribute("class", cls);
|
|
888
|
+
else
|
|
889
|
+
el.removeAttribute("class");
|
|
890
|
+
});
|
|
891
|
+
} else {
|
|
892
|
+
const cls = normalizeClass(value);
|
|
893
|
+
if (cls)
|
|
894
|
+
el.setAttribute("class", cls);
|
|
895
|
+
else
|
|
896
|
+
el.removeAttribute("class");
|
|
897
|
+
}
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
if (isReactive(value)) {
|
|
901
|
+
effect(() => {
|
|
902
|
+
const resolved = resolveValue(value);
|
|
903
|
+
applyProp(el, key, resolved);
|
|
904
|
+
});
|
|
905
|
+
} else {
|
|
906
|
+
applyProp(el, key, value);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
function setStyleProperty(el, prop, val) {
|
|
910
|
+
const formatted = formatStyleProp(prop, val);
|
|
911
|
+
if (prop.startsWith("--") || prop.includes("-")) {
|
|
912
|
+
if (formatted === "") {
|
|
913
|
+
el.style.removeProperty(prop);
|
|
914
|
+
} else {
|
|
915
|
+
el.style.setProperty(prop, formatted);
|
|
916
|
+
}
|
|
917
|
+
} else {
|
|
918
|
+
el.style[prop] = formatted;
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
function applyProp(el, key, value) {
|
|
922
|
+
if (value === null || value === undefined || value === false && !key.startsWith("aria-") && !key.startsWith("data-")) {
|
|
923
|
+
if (key === "className" || key === "class") {
|
|
924
|
+
el.removeAttribute("class");
|
|
925
|
+
} else if (key === "style" && typeof value === "string") {
|
|
926
|
+
el.removeAttribute("style");
|
|
927
|
+
} else if (key in el && !(el instanceof SVGElement)) {
|
|
928
|
+
try {
|
|
929
|
+
el[key] = typeof el[key] === "boolean" ? false : "";
|
|
930
|
+
} catch {
|
|
931
|
+
el.removeAttribute(key);
|
|
932
|
+
}
|
|
933
|
+
} else {
|
|
934
|
+
el.removeAttribute(key);
|
|
935
|
+
}
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
if (key === "className" || key === "class") {
|
|
939
|
+
const cls = normalizeClass(value);
|
|
940
|
+
if (cls) {
|
|
941
|
+
el.setAttribute("class", cls);
|
|
942
|
+
} else {
|
|
943
|
+
el.removeAttribute("class");
|
|
944
|
+
}
|
|
945
|
+
} else if (key === "style") {
|
|
946
|
+
if (typeof value === "string") {
|
|
947
|
+
el.setAttribute("style", value);
|
|
948
|
+
} else if (typeof value === "object" && value !== null) {
|
|
949
|
+
for (const styleKey in value) {
|
|
950
|
+
const styleVal = value[styleKey];
|
|
951
|
+
if (isReactive(styleVal)) {
|
|
952
|
+
effect(() => {
|
|
953
|
+
setStyleProperty(el, styleKey, resolveValue(styleVal));
|
|
954
|
+
});
|
|
955
|
+
} else {
|
|
956
|
+
setStyleProperty(el, styleKey, styleVal);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
} else if (key === "dangerouslySetInnerHTML" && value && typeof value.__html === "string") {
|
|
961
|
+
el.innerHTML = value.__html;
|
|
962
|
+
} else if (key in el && !(el instanceof SVGElement) && key !== "list" && key !== "form") {
|
|
963
|
+
try {
|
|
964
|
+
el[key] = value;
|
|
965
|
+
} catch {
|
|
966
|
+
el.setAttribute(key, String(value));
|
|
967
|
+
}
|
|
968
|
+
} else {
|
|
969
|
+
if (key.startsWith("aria-") || key.startsWith("data-")) {
|
|
970
|
+
el.setAttribute(key, String(value));
|
|
971
|
+
} else if (value === true) {
|
|
972
|
+
el.setAttribute(key, "");
|
|
973
|
+
} else {
|
|
974
|
+
el.setAttribute(key, String(value));
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
function insertChild(parent, child, before = null) {
|
|
979
|
+
if (child === null || child === undefined || child === false || child === true) {
|
|
980
|
+
return null;
|
|
981
|
+
}
|
|
982
|
+
if (child instanceof Node) {
|
|
983
|
+
parent.insertBefore(child, before);
|
|
984
|
+
return child;
|
|
985
|
+
}
|
|
986
|
+
if (Array.isArray(child)) {
|
|
987
|
+
const fragment = document.createDocumentFragment();
|
|
988
|
+
for (const item of child) {
|
|
989
|
+
insertChild(fragment, item);
|
|
990
|
+
}
|
|
991
|
+
parent.insertBefore(fragment, before);
|
|
992
|
+
return fragment;
|
|
993
|
+
}
|
|
994
|
+
if (isReactive(child)) {
|
|
995
|
+
const marker = document.createTextNode("");
|
|
996
|
+
parent.insertBefore(marker, before);
|
|
997
|
+
let childScope = null;
|
|
998
|
+
let currentNodes = [];
|
|
999
|
+
effect(() => {
|
|
1000
|
+
const resolved = resolveValue(child);
|
|
1001
|
+
if ((typeof resolved === "string" || typeof resolved === "number") && currentNodes.length === 1 && currentNodes[0].nodeType === Node.TEXT_NODE) {
|
|
1002
|
+
currentNodes[0].data = String(resolved);
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
if (childScope) {
|
|
1006
|
+
childScope.dispose();
|
|
1007
|
+
}
|
|
1008
|
+
childScope = new Scope(getActiveScope());
|
|
1009
|
+
runInScope(childScope, () => {
|
|
1010
|
+
for (const node of currentNodes) {
|
|
1011
|
+
if (node.parentNode) {
|
|
1012
|
+
node.parentNode.removeChild(node);
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
currentNodes = [];
|
|
1016
|
+
if (resolved === null || resolved === undefined || resolved === false) {
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
const frag = document.createDocumentFragment();
|
|
1020
|
+
if (typeof resolved === "string" || typeof resolved === "number" || typeof resolved === "boolean") {
|
|
1021
|
+
frag.appendChild(document.createTextNode(String(resolved)));
|
|
1022
|
+
} else {
|
|
1023
|
+
insertChild(frag, resolved);
|
|
1024
|
+
}
|
|
1025
|
+
currentNodes = Array.from(frag.childNodes);
|
|
1026
|
+
if (marker.parentNode) {
|
|
1027
|
+
marker.parentNode.insertBefore(frag, marker);
|
|
1028
|
+
}
|
|
1029
|
+
});
|
|
1030
|
+
});
|
|
1031
|
+
onCleanup(() => {
|
|
1032
|
+
if (childScope) {
|
|
1033
|
+
childScope.dispose();
|
|
1034
|
+
}
|
|
1035
|
+
for (const node of currentNodes) {
|
|
1036
|
+
if (node.parentNode) {
|
|
1037
|
+
node.parentNode.removeChild(node);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
if (marker.parentNode) {
|
|
1041
|
+
marker.parentNode.removeChild(marker);
|
|
1042
|
+
}
|
|
1043
|
+
});
|
|
1044
|
+
return marker;
|
|
1045
|
+
}
|
|
1046
|
+
const textNode = document.createTextNode(String(child));
|
|
1047
|
+
parent.insertBefore(textNode, before);
|
|
1048
|
+
return textNode;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
// src/template/template.ts
|
|
1052
|
+
var templateCache = new Map;
|
|
1053
|
+
function template(htmlString) {
|
|
1054
|
+
let templateEl = templateCache.get(htmlString);
|
|
1055
|
+
if (!templateEl && typeof document !== "undefined") {
|
|
1056
|
+
templateEl = document.createElement("template");
|
|
1057
|
+
templateEl.innerHTML = htmlString.trim();
|
|
1058
|
+
templateCache.set(htmlString, templateEl);
|
|
1059
|
+
}
|
|
1060
|
+
return () => {
|
|
1061
|
+
if (!templateEl) {
|
|
1062
|
+
const wrapper = document.createElement("div");
|
|
1063
|
+
wrapper.innerHTML = htmlString.trim();
|
|
1064
|
+
return wrapper.firstElementChild;
|
|
1065
|
+
}
|
|
1066
|
+
return templateEl.content.firstElementChild.cloneNode(true);
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
function html(strings, ...values) {
|
|
1070
|
+
const MARKER_PREFIX = "visage-bind-";
|
|
1071
|
+
let htmlString = "";
|
|
1072
|
+
const bindings = [];
|
|
1073
|
+
for (let i = 0;i < strings.length; i++) {
|
|
1074
|
+
htmlString += strings[i];
|
|
1075
|
+
if (i < values.length) {
|
|
1076
|
+
const val = values[i];
|
|
1077
|
+
const markerId = `${MARKER_PREFIX}${i}`;
|
|
1078
|
+
const lastOpeningTag = htmlString.lastIndexOf("<");
|
|
1079
|
+
const lastClosingTag = htmlString.lastIndexOf(">");
|
|
1080
|
+
if (lastOpeningTag > lastClosingTag) {
|
|
1081
|
+
const match = htmlString.match(/([a-zA-Z0-9_-]+)=["']?$/);
|
|
1082
|
+
if (match?.[1]) {
|
|
1083
|
+
const attrName = match[1];
|
|
1084
|
+
bindings.push({ id: markerId, value: val, isAttr: true, attrName });
|
|
1085
|
+
htmlString += `${markerId}`;
|
|
1086
|
+
} else {
|
|
1087
|
+
bindings.push({ id: markerId, value: val, isAttr: true });
|
|
1088
|
+
htmlString += `data-visage-prop-${i}="${markerId}"`;
|
|
1089
|
+
}
|
|
1090
|
+
} else {
|
|
1091
|
+
bindings.push({ id: markerId, value: val, isAttr: false });
|
|
1092
|
+
htmlString += `<!--${markerId}-->`;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
const clone = template(htmlString);
|
|
1097
|
+
const root = clone();
|
|
1098
|
+
for (const bind of bindings) {
|
|
1099
|
+
if (bind.isAttr && bind.attrName) {
|
|
1100
|
+
const targetEl = findElementWithAttributeValue(root, bind.attrName, bind.id);
|
|
1101
|
+
if (targetEl) {
|
|
1102
|
+
targetEl.removeAttribute(bind.attrName);
|
|
1103
|
+
setAttribute(targetEl, bind.attrName, bind.value);
|
|
1104
|
+
}
|
|
1105
|
+
} else if (!bind.isAttr) {
|
|
1106
|
+
const commentNode = findCommentNode(root, bind.id);
|
|
1107
|
+
if (commentNode?.parentNode) {
|
|
1108
|
+
insertChild(commentNode.parentNode, bind.value, commentNode);
|
|
1109
|
+
commentNode.parentNode.removeChild(commentNode);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
return root;
|
|
1114
|
+
}
|
|
1115
|
+
function findElementWithAttributeValue(root, attrName, value) {
|
|
1116
|
+
if (root.getAttribute(attrName) === value) {
|
|
1117
|
+
return root;
|
|
1118
|
+
}
|
|
1119
|
+
return root.querySelector(`[${attrName}="${value}"]`);
|
|
1120
|
+
}
|
|
1121
|
+
function findCommentNode(root, text) {
|
|
1122
|
+
const iterator = typeof document !== "undefined" && document.createNodeIterator ? document.createNodeIterator(root, 128) : null;
|
|
1123
|
+
if (iterator) {
|
|
1124
|
+
let node = iterator.nextNode();
|
|
1125
|
+
while (node) {
|
|
1126
|
+
if (node.nodeValue === text) {
|
|
1127
|
+
return node;
|
|
1128
|
+
}
|
|
1129
|
+
node = iterator.nextNode();
|
|
1130
|
+
}
|
|
1131
|
+
return null;
|
|
1132
|
+
}
|
|
1133
|
+
const traverse = (node) => {
|
|
1134
|
+
for (const child of node.childNodes || []) {
|
|
1135
|
+
if (child.nodeType === 8 && child.data === text) {
|
|
1136
|
+
return child;
|
|
1137
|
+
}
|
|
1138
|
+
const res = traverse(child);
|
|
1139
|
+
if (res)
|
|
1140
|
+
return res;
|
|
1141
|
+
}
|
|
1142
|
+
return null;
|
|
1143
|
+
};
|
|
1144
|
+
return traverse(root);
|
|
1145
|
+
}
|
|
1146
|
+
export {
|
|
1147
|
+
html,
|
|
1148
|
+
template
|
|
1149
|
+
};
|