@manyducks.co/dolla 0.67.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 (53) hide show
  1. package/README.md +643 -0
  2. package/build.js +34 -0
  3. package/index.d.ts +12 -0
  4. package/jsx-dev-runtime.d.ts +1 -0
  5. package/jsx-runtime.d.ts +1 -0
  6. package/lib/app.d.ts +138 -0
  7. package/lib/classes/CrashCollector.d.ts +30 -0
  8. package/lib/classes/DebugHub.d.ts +60 -0
  9. package/lib/index.d.ts +23 -0
  10. package/lib/index.js +4062 -0
  11. package/lib/index.js.map +7 -0
  12. package/lib/jsx/jsx-dev-runtime.d.ts +3 -0
  13. package/lib/jsx/jsx-dev-runtime.js +20 -0
  14. package/lib/jsx/jsx-dev-runtime.js.map +7 -0
  15. package/lib/jsx/jsx-runtime.d.ts +10 -0
  16. package/lib/jsx/jsx-runtime.js +22 -0
  17. package/lib/jsx/jsx-runtime.js.map +7 -0
  18. package/lib/markup.d.ts +81 -0
  19. package/lib/nodes/cond.d.ts +28 -0
  20. package/lib/nodes/html.d.ts +30 -0
  21. package/lib/nodes/observer.d.ts +33 -0
  22. package/lib/nodes/outlet.d.ts +26 -0
  23. package/lib/nodes/portal.d.ts +22 -0
  24. package/lib/nodes/repeat.d.ts +36 -0
  25. package/lib/nodes/text.d.ts +20 -0
  26. package/lib/spring.d.ts +40 -0
  27. package/lib/state.d.ts +84 -0
  28. package/lib/store.d.ts +67 -0
  29. package/lib/stores/dialog.d.ts +30 -0
  30. package/lib/stores/document.d.ts +10 -0
  31. package/lib/stores/http.d.ts +60 -0
  32. package/lib/stores/language.d.ts +39 -0
  33. package/lib/stores/render.d.ts +18 -0
  34. package/lib/stores/router.d.ts +118 -0
  35. package/lib/testing/classes/MockHTTP.d.ts +10 -0
  36. package/lib/testing/index.d.ts +4 -0
  37. package/lib/testing/makeMockDOMNode.d.ts +10 -0
  38. package/lib/testing/makeMockFetch.d.ts +36 -0
  39. package/lib/testing/makeMockFetch.test.d.ts +1 -0
  40. package/lib/testing/stores/dialog.d.ts +6 -0
  41. package/lib/testing/stores/http.d.ts +13 -0
  42. package/lib/testing/stores/page.d.ts +7 -0
  43. package/lib/testing/stores/router.d.ts +12 -0
  44. package/lib/testing/wrapStore.d.ts +8 -0
  45. package/lib/testing/wrapStore.test.d.ts +1 -0
  46. package/lib/testing/wrapView.d.ts +0 -0
  47. package/lib/types.d.ts +3388 -0
  48. package/lib/utils.d.ts +14 -0
  49. package/lib/view.d.ts +80 -0
  50. package/lib/views/fragment.d.ts +2 -0
  51. package/lib/views/store-scope.d.ts +10 -0
  52. package/package.json +56 -0
  53. package/tests/state.test.js +290 -0
package/lib/index.js ADDED
@@ -0,0 +1,4062 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __commonJS = (cb, mod) => function __require() {
8
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
19
+ // If the importer is in node compatibility mode or this is not an ESM
20
+ // file that has been converted to a CommonJS file using a Babel-
21
+ // compatible transform (i.e. "__esModule" has not been set), then set
22
+ // "default" to the CommonJS "module.exports" for node compatibility.
23
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
24
+ mod
25
+ ));
26
+
27
+ // node_modules/simple-color-hash/lib/index.js
28
+ var require_lib = __commonJS({
29
+ "node_modules/simple-color-hash/lib/index.js"(exports, module) {
30
+ "use strict";
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ var _slicedToArray = function() {
33
+ function a(a2, b) {
34
+ var c = [], d = true, e = false, f = void 0;
35
+ try {
36
+ for (var g, h = a2[Symbol.iterator](); !(d = (g = h.next()).done) && (c.push(g.value), !(b && c.length === b)); d = true)
37
+ ;
38
+ } catch (a3) {
39
+ e = true, f = a3;
40
+ } finally {
41
+ try {
42
+ !d && h["return"] && h["return"]();
43
+ } finally {
44
+ if (e)
45
+ throw f;
46
+ }
47
+ }
48
+ return c;
49
+ }
50
+ return function(b, c) {
51
+ if (Array.isArray(b))
52
+ return b;
53
+ if (Symbol.iterator in Object(b))
54
+ return a(b, c);
55
+ throw new TypeError("Invalid attempt to destructure non-iterable instance");
56
+ };
57
+ }();
58
+ var rgbToHex = function(a) {
59
+ return a.reduce(function(a2, b) {
60
+ return 16 > b ? a2 + "0" + b.toString(16) : a2 + b.toString(16);
61
+ }, "#");
62
+ };
63
+ var hslToRgb = function(a, b, c) {
64
+ var d = 0.5 > c ? c * (1 + b) : c + b - c * b, e = 2 * c - d, f = function(a2, b2, c2) {
65
+ var d2 = Math.round, e2 = 0 > c2 ? c2 + 1 : 1 < c2 ? c2 - 1 : c2;
66
+ return e2 = e2 < 1 / 6 ? a2 + 6 * (b2 - a2) * e2 : e2 < 1 / 2 ? b2 : e2 < 2 / 3 ? a2 + 6 * (b2 - a2) * (2 / 3 - e2) : a2, d2(255 * e2);
67
+ }, g = f(e, d, a + 1 / 3), h = f(e, d, a), i = f(e, d, a - 1 / 3);
68
+ return [g, h, i];
69
+ };
70
+ var hslGeneration = function(a, b, c, d) {
71
+ var e = a % 1007 / 1007, f = function(a2, b2, c2) {
72
+ return a2 * (c2 - b2) + b2;
73
+ }, g = f(e, b.min, b.max), h = f(e, c.min, c.max), i = f(e, d.max, d.min);
74
+ return [g, h, i];
75
+ };
76
+ var standardHashFunction = function(a) {
77
+ return a.split("").reduce(function(a2, b, c) {
78
+ return a2 * b.charCodeAt(0) * c + 1;
79
+ }, 1);
80
+ };
81
+ var generateColorHash = function(a) {
82
+ var b = a.str, c = a.hue, d = c === void 0 ? { min: 0, max: 360 } : c, e = a.sat, f = e === void 0 ? { min: 0.35, max: 0.65 } : e, g = a.light, h = g === void 0 ? { min: 0.3, max: 0.7 } : g, i = a.hashFunction, j = i === void 0 ? standardHashFunction : i, k = a.scheme, l = k === void 0 ? "hex" : k, m2 = hslGeneration(j(b), d, f, h), n = _slicedToArray(m2, 3), o = n[0], p = n[1], q = n[2], r = hslToRgb(o / 360, p, q), s = rgbToHex(r);
83
+ if ("hsl" === l)
84
+ return [o, p, q];
85
+ return "rgb" === l ? r : s;
86
+ };
87
+ exports.default = generateColorHash, module.exports = exports.default;
88
+ }
89
+ });
90
+
91
+ // node_modules/@borf/bedrock/lib/typeChecking.js
92
+ function typeOf(value) {
93
+ if (value === void 0) {
94
+ return "undefined";
95
+ }
96
+ if (value === null) {
97
+ return "null";
98
+ }
99
+ const type = typeof value;
100
+ switch (type) {
101
+ case "number":
102
+ if (isNaN(value)) {
103
+ return "NaN";
104
+ }
105
+ return "number";
106
+ case "function":
107
+ if (isClass(value)) {
108
+ return "class";
109
+ }
110
+ return type;
111
+ case "object":
112
+ if (isArray(value)) {
113
+ return "array";
114
+ }
115
+ if (isPromise(value)) {
116
+ return "promise";
117
+ }
118
+ return type;
119
+ default:
120
+ return type;
121
+ }
122
+ }
123
+ function isArray(value) {
124
+ return Array.isArray(value);
125
+ }
126
+ function isArrayOf(...args) {
127
+ const check = args[0];
128
+ const test = (value) => {
129
+ return isArray(value) && value.every((item) => check(item));
130
+ };
131
+ if (args.length < 2) {
132
+ return test;
133
+ } else {
134
+ return test(args[1]);
135
+ }
136
+ }
137
+ function assertArrayOf(...args) {
138
+ const check = args[0];
139
+ const message = isString(args[2]) ? args[2] : "Expected an array of valid items. Got type: %t, value: %v";
140
+ const test = (value) => {
141
+ if (isArray(value) && value.every((item) => check(item))) {
142
+ return true;
143
+ }
144
+ throw new TypeError(formatError(value, message));
145
+ };
146
+ if (args.length < 2) {
147
+ return test;
148
+ } else {
149
+ return test(args[1]);
150
+ }
151
+ }
152
+ function isString(value) {
153
+ return typeof value === "string";
154
+ }
155
+ function assertString(value, errorMessage) {
156
+ if (isString(value)) {
157
+ return true;
158
+ }
159
+ throw new TypeError(formatError(value, errorMessage ?? "Expected a string. Got type: %t, value: %v"));
160
+ }
161
+ function isFunction(value) {
162
+ return typeof value === "function" && !isClass(value);
163
+ }
164
+ function assertFunction(value, errorMessage) {
165
+ if (isFunction(value)) {
166
+ return true;
167
+ }
168
+ throw new TypeError(formatError(value, errorMessage ?? "Expected a function. Got type: %t, value: %v"));
169
+ }
170
+ function isNumber(value) {
171
+ return typeof value === "number" && !isNaN(value);
172
+ }
173
+ function isPromise(value) {
174
+ if (value == null)
175
+ return false;
176
+ const obj = value;
177
+ return obj instanceof Promise || isFunction(obj.then) && isFunction(obj.catch) && isFunction(obj.finally);
178
+ }
179
+ function isClass(value) {
180
+ return typeof value === "function" && /^\s*class\s+/.test(value.toString());
181
+ }
182
+ function assertInstanceOf(...args) {
183
+ const constructor = args[0];
184
+ const errorMessage = isString(args[2]) ? args[2] : `Expected instance of ${constructor.name}. Got type: %t, value: %v`;
185
+ const test = (value) => {
186
+ if (value instanceof constructor) {
187
+ return true;
188
+ }
189
+ throw new TypeError(formatError(value, errorMessage));
190
+ };
191
+ if (args.length < 2) {
192
+ return test;
193
+ } else {
194
+ return test(args[1]);
195
+ }
196
+ }
197
+ function isObject(value) {
198
+ return value != null && typeof value === "object" && !isArray(value);
199
+ }
200
+ function assertObject(value, errorMessage) {
201
+ if (isObject(value)) {
202
+ return true;
203
+ }
204
+ throw new TypeError(formatError(value, errorMessage ?? "Expected an object. Got type: %t, value: %v"));
205
+ }
206
+ function formatError(value, message) {
207
+ const typeName = typeOf(value);
208
+ const valueString = value?.toString?.() || String(value);
209
+ return message.replaceAll("%t", typeName).replaceAll("%v", valueString);
210
+ }
211
+
212
+ // node_modules/@borf/bedrock/lib/routing.js
213
+ var FragTypes;
214
+ (function(FragTypes2) {
215
+ FragTypes2[FragTypes2["Literal"] = 1] = "Literal";
216
+ FragTypes2[FragTypes2["Param"] = 2] = "Param";
217
+ FragTypes2[FragTypes2["Wildcard"] = 3] = "Wildcard";
218
+ FragTypes2[FragTypes2["NumericParam"] = 4] = "NumericParam";
219
+ })(FragTypes || (FragTypes = {}));
220
+ function splitPath(path) {
221
+ assertString(path, "Expected `path` to be a string. Got type: %t, value: %v");
222
+ return path.split("/").map((f) => f.trim()).filter((f) => f !== "");
223
+ }
224
+ function joinPath(parts) {
225
+ assertArrayOf((part) => isFunction(part?.toString), parts, "Expected `parts` to be an array of objects with a .toString() method. Got type: %t, value: %v");
226
+ parts = parts.filter((x) => x).flatMap(String);
227
+ let joined = parts.shift()?.toString();
228
+ if (joined) {
229
+ for (const part of parts.map((p) => p.toString())) {
230
+ if (part.startsWith(".")) {
231
+ joined = resolvePath(joined, part);
232
+ } else if (joined[joined.length - 1] !== "/") {
233
+ if (part[0] !== "/") {
234
+ joined += "/" + part;
235
+ } else {
236
+ joined += part;
237
+ }
238
+ } else {
239
+ if (part[0] === "/") {
240
+ joined += part.slice(1);
241
+ } else {
242
+ joined += part;
243
+ }
244
+ }
245
+ }
246
+ if (joined && joined !== "/" && joined.endsWith("/")) {
247
+ joined = joined.slice(0, joined.length - 1);
248
+ }
249
+ }
250
+ return joined ?? "";
251
+ }
252
+ function resolvePath(base, part) {
253
+ assertString(base, "Expected `base` to be a string. Got type: %t, value: %v");
254
+ if (part == null) {
255
+ part = base;
256
+ base = "";
257
+ }
258
+ if (part.startsWith("/")) {
259
+ return part;
260
+ }
261
+ let resolved = base;
262
+ while (true) {
263
+ if (part.startsWith("..")) {
264
+ for (let i = resolved.length; i > 0; --i) {
265
+ if (resolved[i] === "/" || i === 0) {
266
+ resolved = resolved.slice(0, i);
267
+ part = part.replace(/^\.\.\/?/, "");
268
+ break;
269
+ }
270
+ }
271
+ } else if (part.startsWith(".")) {
272
+ part = part.replace(/^\.\/?/, "");
273
+ } else {
274
+ break;
275
+ }
276
+ }
277
+ return joinPath([resolved, part]);
278
+ }
279
+ function parseQueryParams(query) {
280
+ if (!query)
281
+ return {};
282
+ const entries = query.split("&").filter((x) => x.trim() !== "").map((entry) => {
283
+ const [key, value] = entry.split("=").map((x) => x.trim());
284
+ if (value.toLowerCase() === "true") {
285
+ return [key, true];
286
+ }
287
+ if (value.toLowerCase() === "false") {
288
+ return [key, false];
289
+ }
290
+ if (!isNaN(Number(value))) {
291
+ return [key, Number(value)];
292
+ }
293
+ return [key, value];
294
+ });
295
+ return Object.fromEntries(entries);
296
+ }
297
+ function matchRoutes(routes, url, options = {}) {
298
+ const [path, query] = url.split("?");
299
+ const parts = splitPath(path);
300
+ routes:
301
+ for (const route of routes) {
302
+ const { fragments } = route;
303
+ const hasWildcard = fragments[fragments.length - 1]?.type === FragTypes.Wildcard;
304
+ if (!hasWildcard && fragments.length !== parts.length) {
305
+ continue routes;
306
+ }
307
+ if (options.willMatch && !options.willMatch(route)) {
308
+ continue routes;
309
+ }
310
+ const matched = [];
311
+ fragments:
312
+ for (let i = 0; i < fragments.length; i++) {
313
+ const part = parts[i];
314
+ const frag = fragments[i];
315
+ if (part == null && frag.type !== FragTypes.Wildcard) {
316
+ continue routes;
317
+ }
318
+ switch (frag.type) {
319
+ case FragTypes.Literal:
320
+ if (frag.name.toLowerCase() === part.toLowerCase()) {
321
+ matched.push(frag);
322
+ break;
323
+ } else {
324
+ continue routes;
325
+ }
326
+ case FragTypes.Param:
327
+ matched.push({ ...frag, value: part });
328
+ break;
329
+ case FragTypes.Wildcard:
330
+ matched.push({ ...frag, value: parts.slice(i).join("/") });
331
+ break fragments;
332
+ case FragTypes.NumericParam:
333
+ if (!isNaN(Number(part))) {
334
+ matched.push({ ...frag, value: Number(part) });
335
+ break;
336
+ } else {
337
+ continue routes;
338
+ }
339
+ default:
340
+ throw new Error(`Unknown fragment type: ${frag.type}`);
341
+ }
342
+ }
343
+ const params = /* @__PURE__ */ Object.create(null);
344
+ for (const frag of matched) {
345
+ if (frag.type === FragTypes.Param) {
346
+ params[frag.name] = decodeURIComponent(frag.value);
347
+ }
348
+ if (frag.type === FragTypes.NumericParam) {
349
+ params[frag.name] = frag.value;
350
+ }
351
+ if (frag.type === FragTypes.Wildcard) {
352
+ params.wildcard = "/" + decodeURIComponent(frag.value);
353
+ }
354
+ }
355
+ return {
356
+ path: "/" + matched.map((f) => f.value).join("/"),
357
+ pattern: "/" + fragments.map((f) => {
358
+ if (f.type === FragTypes.Param) {
359
+ return `{${f.name}}`;
360
+ }
361
+ if (f.type === FragTypes.NumericParam) {
362
+ return `{#${f.name}}`;
363
+ }
364
+ return f.name;
365
+ }).join("/"),
366
+ params,
367
+ query: parseQueryParams(query),
368
+ meta: route.meta
369
+ };
370
+ }
371
+ }
372
+ function sortRoutes(routes) {
373
+ const withoutParams = [];
374
+ const withNumericParams = [];
375
+ const withParams = [];
376
+ const wildcard = [];
377
+ for (const route of routes) {
378
+ const { fragments } = route;
379
+ if (fragments.some((f) => f.type === FragTypes.Wildcard)) {
380
+ wildcard.push(route);
381
+ } else if (fragments.some((f) => f.type === FragTypes.NumericParam)) {
382
+ withNumericParams.push(route);
383
+ } else if (fragments.some((f) => f.type === FragTypes.Param)) {
384
+ withParams.push(route);
385
+ } else {
386
+ withoutParams.push(route);
387
+ }
388
+ }
389
+ const bySizeDesc = (a, b) => {
390
+ if (a.fragments.length > b.fragments.length) {
391
+ return -1;
392
+ } else {
393
+ return 1;
394
+ }
395
+ };
396
+ withoutParams.sort(bySizeDesc);
397
+ withNumericParams.sort(bySizeDesc);
398
+ withParams.sort(bySizeDesc);
399
+ wildcard.sort(bySizeDesc);
400
+ return [...withoutParams, ...withNumericParams, ...withParams, ...wildcard];
401
+ }
402
+ function patternToFragments(pattern) {
403
+ const parts = splitPath(pattern);
404
+ const fragments = [];
405
+ for (let i = 0; i < parts.length; i++) {
406
+ const part = parts[i];
407
+ if (part === "*") {
408
+ if (i !== parts.length - 1) {
409
+ throw new Error(`Wildcard must be at the end of a pattern. Received: ${pattern}`);
410
+ }
411
+ fragments.push({
412
+ type: FragTypes.Wildcard,
413
+ name: "*",
414
+ value: null
415
+ });
416
+ } else if (part.at(0) === "{" && part.at(-1) === "}") {
417
+ fragments.push({
418
+ type: part[1] === "#" ? FragTypes.NumericParam : FragTypes.Param,
419
+ name: part[1] === "#" ? part.slice(2, -1) : part.slice(1, -1),
420
+ value: null
421
+ });
422
+ } else {
423
+ fragments.push({
424
+ type: FragTypes.Literal,
425
+ name: part,
426
+ value: part
427
+ });
428
+ }
429
+ }
430
+ return fragments;
431
+ }
432
+
433
+ // src/classes/CrashCollector.ts
434
+ var CrashCollector = class {
435
+ #errors = [];
436
+ #errorCallbacks = [];
437
+ /**
438
+ * Registers a callback to receive all errors that pass through the CrashCollector.
439
+ * Returns a function that cancels this listener when called.
440
+ */
441
+ onError(callback) {
442
+ this.#errorCallbacks.push(callback);
443
+ return () => {
444
+ this.#errorCallbacks.splice(this.#errorCallbacks.indexOf(callback), 1);
445
+ };
446
+ }
447
+ /**
448
+ * Reports an unrecoverable error that requires crashing the whole app.
449
+ */
450
+ crash({ error, componentName }) {
451
+ const ctx = {
452
+ error,
453
+ severity: "crash",
454
+ componentName: componentName ?? "anonymous component"
455
+ };
456
+ this.#errors.push(ctx);
457
+ for (const callback of this.#errorCallbacks) {
458
+ callback(ctx);
459
+ }
460
+ throw error;
461
+ }
462
+ /**
463
+ * Reports a recoverable error.
464
+ */
465
+ error({ error, componentName }) {
466
+ const ctx = {
467
+ error,
468
+ severity: "error",
469
+ componentName: componentName ?? "anonymous component"
470
+ };
471
+ this.#errors.push(ctx);
472
+ for (const callback of this.#errorCallbacks) {
473
+ callback(ctx);
474
+ }
475
+ }
476
+ };
477
+
478
+ // src/classes/DebugHub.ts
479
+ var import_simple_color_hash = __toESM(require_lib(), 1);
480
+ var DebugHub = class {
481
+ #filter = "*,-dolla/*";
482
+ #matcher;
483
+ #console;
484
+ #options;
485
+ constructor(options, _console = getDefaultConsole()) {
486
+ if (options.filter) {
487
+ this.#filter = options.filter;
488
+ }
489
+ this.#matcher = makeMatcher(this.#filter);
490
+ this.#console = _console;
491
+ this.#options = options;
492
+ }
493
+ /**
494
+ * Returns a debug channel labelled by `name`. Used for logging from components.
495
+ */
496
+ channel(options) {
497
+ const _console = this.#console;
498
+ const hubOptions = this.#options;
499
+ const match = (value) => {
500
+ return this.#matcher(value);
501
+ };
502
+ return {
503
+ get info() {
504
+ const name = options.name;
505
+ if (hubOptions.info === false || isString(hubOptions.info) && hubOptions.info !== hubOptions.mode || !match(name)) {
506
+ return noOp;
507
+ } else {
508
+ const label = `%c${name}`;
509
+ return _console.info.bind(_console, label, `color:${hash(label)};font-weight:bold`);
510
+ }
511
+ },
512
+ get log() {
513
+ const name = options.name;
514
+ if (hubOptions.log === false || isString(hubOptions.log) && hubOptions.log !== hubOptions.mode || !match(name)) {
515
+ return noOp;
516
+ } else {
517
+ const label = `%c${name}`;
518
+ return _console.log.bind(_console, label, `color:${hash(label)};font-weight:bold`);
519
+ }
520
+ },
521
+ get warn() {
522
+ const name = options.name;
523
+ if (hubOptions.warn === false || isString(hubOptions.warn) && hubOptions.warn !== hubOptions.mode || !match(name)) {
524
+ return noOp;
525
+ } else {
526
+ const label = `%c${name}`;
527
+ return _console.warn.bind(_console, label, `color:${hash(label)};font-weight:bold`);
528
+ }
529
+ },
530
+ get error() {
531
+ const name = options.name;
532
+ if (hubOptions.error === false || isString(hubOptions.error) && hubOptions.error !== hubOptions.mode || !match(name)) {
533
+ return noOp;
534
+ } else {
535
+ const label = `%c${name}`;
536
+ return _console.error.bind(_console, label, `color:${hash(label)};font-weight:bold`);
537
+ }
538
+ }
539
+ };
540
+ }
541
+ get filter() {
542
+ return this.#filter;
543
+ }
544
+ set filter(pattern) {
545
+ this.#filter = pattern;
546
+ this.#matcher = makeMatcher(pattern);
547
+ }
548
+ };
549
+ function getDefaultConsole() {
550
+ if (typeof window !== "undefined" && window.console) {
551
+ return window.console;
552
+ }
553
+ if (typeof global !== "undefined" && global.console) {
554
+ return global.console;
555
+ }
556
+ }
557
+ var noOp = () => {
558
+ };
559
+ function hash(value) {
560
+ return (0, import_simple_color_hash.default)({
561
+ str: value,
562
+ sat: { min: 0.35, max: 0.55 },
563
+ light: { min: 0.6, max: 0.6 }
564
+ });
565
+ }
566
+ function makeMatcher(pattern) {
567
+ if (pattern instanceof RegExp) {
568
+ return (value) => pattern.test(value);
569
+ }
570
+ const matchers = {
571
+ positive: [],
572
+ negative: []
573
+ };
574
+ const parts = pattern.split(",").map((p) => p.trim()).filter((p) => p !== "");
575
+ for (let part of parts) {
576
+ let section = "positive";
577
+ if (part.startsWith("-")) {
578
+ section = "negative";
579
+ part = part.slice(1);
580
+ }
581
+ if (part === "*") {
582
+ matchers[section].push(function() {
583
+ return true;
584
+ });
585
+ } else if (part.endsWith("*")) {
586
+ matchers[section].push(function(value) {
587
+ return value.startsWith(part.slice(0, part.length - 1));
588
+ });
589
+ } else {
590
+ matchers[section].push(function(value) {
591
+ return value === part;
592
+ });
593
+ }
594
+ }
595
+ return function(name) {
596
+ const { positive, negative } = matchers;
597
+ if (negative.some((fn) => fn(name))) {
598
+ return false;
599
+ }
600
+ if (positive.length > 0 && !positive.some((fn) => fn(name))) {
601
+ return false;
602
+ }
603
+ return true;
604
+ };
605
+ }
606
+
607
+ // src/utils.ts
608
+ function isPlainObject(value) {
609
+ return value != null && typeof value === "object" && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.getPrototypeOf({});
610
+ }
611
+ function deepEqual(one, two) {
612
+ if (one === two) {
613
+ return true;
614
+ }
615
+ if (isPlainObject(one) && isPlainObject(two)) {
616
+ const keysOne = Object.keys(one);
617
+ const keysTwo = Object.keys(two);
618
+ if (keysOne.length !== keysTwo.length) {
619
+ return false;
620
+ }
621
+ for (const key in one) {
622
+ if (!deepEqual(one[key], two[key])) {
623
+ return false;
624
+ }
625
+ }
626
+ return true;
627
+ }
628
+ if (Array.isArray(one) && Array.isArray(two)) {
629
+ if (one.length !== two.length) {
630
+ return false;
631
+ }
632
+ for (const index in one) {
633
+ if (!deepEqual(one[index], two[index])) {
634
+ return false;
635
+ }
636
+ }
637
+ return true;
638
+ }
639
+ return one === two;
640
+ }
641
+ function merge(one, two) {
642
+ if (isObject(one)) {
643
+ if (!isObject(two)) {
644
+ return two;
645
+ }
646
+ const merged = Object.assign({}, one);
647
+ for (const key in two) {
648
+ merged[key] = merge(merged[key], two[key]);
649
+ }
650
+ return merged;
651
+ } else {
652
+ return two;
653
+ }
654
+ }
655
+ function omit(keys, object) {
656
+ const process2 = (object2) => {
657
+ const newObject = {};
658
+ for (const key in object2) {
659
+ if (!keys.includes(key)) {
660
+ newObject[key] = object2[key];
661
+ }
662
+ }
663
+ return newObject;
664
+ };
665
+ if (object == null) {
666
+ return process2;
667
+ }
668
+ return process2(object);
669
+ }
670
+
671
+ // src/state.ts
672
+ var UNOBSERVED = Symbol("Unobserved");
673
+ var OBSERVE = Symbol("Observe");
674
+ function isReadable(value) {
675
+ return value != null && typeof value === "object" && typeof value[OBSERVE] === "function" && typeof value.get === "function";
676
+ }
677
+ function isWritable(value) {
678
+ return isReadable(value) && typeof value.set === "function" && typeof value.update === "function";
679
+ }
680
+ function readable(value) {
681
+ if (isWritable(value)) {
682
+ return {
683
+ get: value.get,
684
+ [OBSERVE]: value[OBSERVE]
685
+ };
686
+ }
687
+ if (isReadable(value)) {
688
+ return value;
689
+ }
690
+ return {
691
+ get: () => value,
692
+ [OBSERVE]: (callback) => {
693
+ callback(value, void 0);
694
+ return function stop() {
695
+ };
696
+ }
697
+ };
698
+ }
699
+ function writable(value) {
700
+ if (isWritable(value)) {
701
+ return value;
702
+ }
703
+ if (isReadable(value)) {
704
+ throw new TypeError(`Failed to convert Readable into a Writable; can't add write access to a read-only value.`);
705
+ }
706
+ const observers = [];
707
+ let currentValue = value;
708
+ return {
709
+ // ----- Readable ----- //
710
+ get: () => currentValue,
711
+ [OBSERVE]: (callback) => {
712
+ observers.push(callback);
713
+ function stop() {
714
+ observers.splice(observers.indexOf(callback), 1);
715
+ }
716
+ callback(currentValue, void 0);
717
+ return stop;
718
+ },
719
+ // ----- Writable ----- //
720
+ set: (newValue) => {
721
+ if (!deepEqual(currentValue, newValue)) {
722
+ const previousValue = currentValue;
723
+ currentValue = newValue;
724
+ for (const callback of observers) {
725
+ callback(currentValue, previousValue);
726
+ }
727
+ }
728
+ },
729
+ update: (callback) => {
730
+ const newValue = callback(currentValue);
731
+ if (!deepEqual(currentValue, newValue)) {
732
+ const previousValue = currentValue;
733
+ currentValue = newValue;
734
+ for (const callback2 of observers) {
735
+ callback2(currentValue, previousValue);
736
+ }
737
+ }
738
+ }
739
+ };
740
+ }
741
+ function observe(readable2, callback) {
742
+ const readables = [];
743
+ if (Array.isArray(readable2) && readable2.every(isReadable)) {
744
+ readables.push(...readable2);
745
+ } else if (isReadable(readable2)) {
746
+ readables.push(readable2);
747
+ } else {
748
+ console.warn(readable2);
749
+ throw new TypeError(
750
+ `Expected one Readable or an array of Readables as the first argument. Got value: ${readable2}, type: ${typeOf(
751
+ readable2
752
+ )}`
753
+ );
754
+ }
755
+ if (readables.length === 0) {
756
+ throw new TypeError(`Expected at least one readable.`);
757
+ }
758
+ if (readables.length > 1) {
759
+ return computed(readables, callback)[OBSERVE](() => {
760
+ });
761
+ } else {
762
+ return readables[0][OBSERVE](callback);
763
+ }
764
+ }
765
+ function computed(...args) {
766
+ if (isReadable(args[0])) {
767
+ if (typeof args[1] !== "function") {
768
+ throw new TypeError(
769
+ `When first argument is a Readable the second argument must be a callback function. Got type: ${typeOf(
770
+ args[1]
771
+ )}, value: ${args[1]}`
772
+ );
773
+ }
774
+ const readable2 = args[0];
775
+ const compute = args[1];
776
+ return {
777
+ get: () => compute(readable2.get()),
778
+ [OBSERVE]: (callback) => {
779
+ let lastComputedValue = UNOBSERVED;
780
+ let lastObservedValue;
781
+ return readable2[OBSERVE]((currentValue) => {
782
+ const computedValue = compute(currentValue, lastObservedValue);
783
+ if (!deepEqual(computedValue, lastComputedValue)) {
784
+ const previousValue = lastComputedValue === UNOBSERVED ? void 0 : lastComputedValue;
785
+ callback(computedValue, previousValue);
786
+ lastComputedValue = computedValue;
787
+ lastObservedValue = currentValue;
788
+ }
789
+ });
790
+ }
791
+ };
792
+ } else if (Array.isArray(args[0])) {
793
+ let updateValue2 = function() {
794
+ const computedValue = compute(observedValues, previousObservedValues);
795
+ if (!deepEqual(computedValue, latestComputedValue)) {
796
+ const previousValue = latestComputedValue === UNOBSERVED ? void 0 : latestComputedValue;
797
+ latestComputedValue = computedValue;
798
+ previousObservedValues = observedValues;
799
+ for (const callback of observers) {
800
+ callback(computedValue, previousValue);
801
+ }
802
+ }
803
+ }, startObserving2 = function() {
804
+ if (isObserving)
805
+ return;
806
+ for (let i = 0; i < readables.length; i++) {
807
+ const readable2 = readables[i];
808
+ stopCallbacks.push(
809
+ observe(readable2, (value) => {
810
+ observedValues[i] = value;
811
+ if (isObserving) {
812
+ updateValue2();
813
+ }
814
+ })
815
+ );
816
+ }
817
+ previousObservedValues = new Array().fill(void 0, 0, readables.length);
818
+ observedValues = readables.map((x) => x.get());
819
+ isObserving = true;
820
+ updateValue2();
821
+ }, stopObserving2 = function() {
822
+ isObserving = false;
823
+ for (const callback of stopCallbacks) {
824
+ callback();
825
+ }
826
+ stopCallbacks = [];
827
+ };
828
+ var updateValue = updateValue2, startObserving = startObserving2, stopObserving = stopObserving2;
829
+ if (typeof args[1] !== "function") {
830
+ throw new TypeError(
831
+ `When first argument is an array of Readables the second argument must be a callback function. Got type: ${typeOf(
832
+ args[1]
833
+ )}, value: ${args[1]}`
834
+ );
835
+ }
836
+ if (!args[0].every(isReadable)) {
837
+ throw new TypeError(
838
+ `Computed expected an array of Readables. Got: [${args[0].map((x) => isReadable(x) ? `Readable<${typeOf(x.get())}>` : typeof x).join(", ")}]`
839
+ );
840
+ }
841
+ const readables = args[0];
842
+ const compute = args[1];
843
+ const observers = [];
844
+ let stopCallbacks = [];
845
+ let isObserving = false;
846
+ let previousObservedValues = [];
847
+ let observedValues = [];
848
+ let latestComputedValue = UNOBSERVED;
849
+ return {
850
+ get: () => {
851
+ if (isObserving) {
852
+ return latestComputedValue;
853
+ } else {
854
+ return compute(
855
+ readables.map((x) => x.get()),
856
+ new Array().fill(void 0, 0, readables.length)
857
+ );
858
+ }
859
+ },
860
+ [OBSERVE]: (callback) => {
861
+ if (!isObserving) {
862
+ startObserving2();
863
+ }
864
+ callback(latestComputedValue, void 0);
865
+ observers.push(callback);
866
+ return function stop() {
867
+ observers.splice(observers.indexOf(callback), 1);
868
+ if (observers.length === 0) {
869
+ stopObserving2();
870
+ }
871
+ };
872
+ }
873
+ };
874
+ } else {
875
+ throw new TypeError(
876
+ `Expected a Readable or array of Readables as a first argument. Got: ${typeOf(args[0])}, value: ${args[0]}`
877
+ );
878
+ }
879
+ }
880
+ function proxy(source, config) {
881
+ if (!isReadable(source)) {
882
+ throw new TypeError(`Proxy source must be a Readable.`);
883
+ }
884
+ const observers = [];
885
+ const currentValue = () => config.get(source);
886
+ return {
887
+ // ----- Readable ----- //
888
+ get: () => config.get(source),
889
+ [OBSERVE]: (callback) => {
890
+ let lastComputedValue = UNOBSERVED;
891
+ return source[OBSERVE]((_) => {
892
+ const computedValue = config.get(source);
893
+ if (!deepEqual(computedValue, lastComputedValue)) {
894
+ const previousValue = lastComputedValue === UNOBSERVED ? void 0 : lastComputedValue;
895
+ callback(computedValue, previousValue);
896
+ lastComputedValue = computedValue;
897
+ }
898
+ });
899
+ },
900
+ // ----- Writable ----- //
901
+ set: (newValue) => {
902
+ config.set(source, newValue);
903
+ },
904
+ update: (callback) => {
905
+ const newValue = callback(config.get(source));
906
+ config.set(source, newValue);
907
+ }
908
+ };
909
+ }
910
+ function unwrap(value) {
911
+ if (isReadable(value)) {
912
+ return value.get();
913
+ }
914
+ return value;
915
+ }
916
+
917
+ // src/nodes/cond.ts
918
+ var Conditional = class {
919
+ node;
920
+ endNode;
921
+ $predicate;
922
+ stopCallback;
923
+ thenContent;
924
+ elseContent;
925
+ connectedContent = [];
926
+ appContext;
927
+ elementContext;
928
+ constructor(config) {
929
+ this.$predicate = config.$predicate;
930
+ this.thenContent = config.thenContent ? toMarkup(config.thenContent) : void 0;
931
+ this.elseContent = config.elseContent ? toMarkup(config.elseContent) : void 0;
932
+ this.appContext = config.appContext;
933
+ this.elementContext = config.elementContext;
934
+ if (this.appContext.mode === "development") {
935
+ this.node = document.createComment("Conditional");
936
+ this.endNode = document.createComment("/Conditional");
937
+ } else {
938
+ this.node = document.createTextNode("");
939
+ this.endNode = document.createTextNode("");
940
+ }
941
+ }
942
+ get connected() {
943
+ return this.node.parentNode != null;
944
+ }
945
+ connect(parent, after) {
946
+ if (!this.connected) {
947
+ parent.insertBefore(this.node, after?.nextSibling ?? null);
948
+ if (this.appContext.mode === "development") {
949
+ parent.insertBefore(this.endNode, this.node.nextSibling);
950
+ }
951
+ this.stopCallback = observe(this.$predicate, (value) => {
952
+ this.update(value);
953
+ });
954
+ }
955
+ }
956
+ disconnect() {
957
+ if (this.stopCallback) {
958
+ this.stopCallback();
959
+ this.stopCallback = void 0;
960
+ }
961
+ for (const handle of this.connectedContent) {
962
+ handle.disconnect();
963
+ }
964
+ this.connectedContent = [];
965
+ if (this.connected) {
966
+ this.node.parentNode?.removeChild(this.node);
967
+ this.endNode.parentNode?.removeChild(this.endNode);
968
+ }
969
+ }
970
+ update(value) {
971
+ for (const handle of this.connectedContent) {
972
+ handle.disconnect();
973
+ }
974
+ this.connectedContent = [];
975
+ if (value && this.thenContent) {
976
+ this.connectedContent = renderMarkupToDOM(this.thenContent, this);
977
+ } else if (!value && this.elseContent) {
978
+ this.connectedContent = renderMarkupToDOM(this.elseContent, this);
979
+ }
980
+ for (let i = 0; i < this.connectedContent.length; i++) {
981
+ const handle = this.connectedContent[i];
982
+ const previous = this.connectedContent[i - 1]?.node ?? this.node;
983
+ handle.connect(this.node.parentNode, previous);
984
+ }
985
+ if (this.appContext.mode === "development") {
986
+ this.node.textContent = `Conditional (${value ? "truthy" : "falsy"})`;
987
+ }
988
+ }
989
+ async setChildren(children) {
990
+ }
991
+ };
992
+
993
+ // node_modules/nanoid/index.browser.js
994
+ var nanoid = (size = 21) => crypto.getRandomValues(new Uint8Array(size)).reduce((id, byte) => {
995
+ byte &= 63;
996
+ if (byte < 36) {
997
+ id += byte.toString(36);
998
+ } else if (byte < 62) {
999
+ id += (byte - 26).toString(36).toUpperCase();
1000
+ } else if (byte > 62) {
1001
+ id += "-";
1002
+ } else {
1003
+ id += "_";
1004
+ }
1005
+ return id;
1006
+ }, "");
1007
+
1008
+ // src/nodes/html.ts
1009
+ var isCamelCaseEventName = (key) => /^on[A-Z]/.test(key);
1010
+ var HTML = class {
1011
+ node;
1012
+ props;
1013
+ children;
1014
+ stopCallbacks = [];
1015
+ appContext;
1016
+ elementContext;
1017
+ uniqueId = nanoid();
1018
+ // Prevents 'onClickOutside' handlers from firing in the same cycle in which the element is connected.
1019
+ canClickAway = false;
1020
+ get connected() {
1021
+ return this.node.parentNode != null;
1022
+ }
1023
+ constructor({ tag, props, children, appContext, elementContext }) {
1024
+ elementContext = { ...elementContext };
1025
+ if (tag.toLowerCase() === "svg") {
1026
+ elementContext.isSVG = true;
1027
+ }
1028
+ if (elementContext.isSVG) {
1029
+ this.node = document.createElementNS("http://www.w3.org/2000/svg", tag);
1030
+ } else {
1031
+ this.node = document.createElement(tag);
1032
+ }
1033
+ if (appContext.mode === "development") {
1034
+ this.node.dataset.uniqueId = this.uniqueId;
1035
+ }
1036
+ if (props.ref) {
1037
+ if (isWritable(props.ref)) {
1038
+ props.ref.set(this.node);
1039
+ } else if (isFunction(props.ref)) {
1040
+ props.ref(this.node);
1041
+ } else {
1042
+ throw new Error("Expected an instance of Ref. Got: " + props.ref);
1043
+ }
1044
+ }
1045
+ this.props = {
1046
+ ...omit(["ref", "class", "className"], props),
1047
+ class: props.className ?? props.class
1048
+ };
1049
+ this.children = children ? renderMarkupToDOM(children, { appContext, elementContext }) : [];
1050
+ this.appContext = appContext;
1051
+ this.elementContext = elementContext;
1052
+ }
1053
+ connect(parent, after) {
1054
+ if (parent == null) {
1055
+ throw new Error(`HTML element requires a parent element as the first argument to connect. Got: ${parent}`);
1056
+ }
1057
+ if (!this.connected) {
1058
+ for (const child of this.children) {
1059
+ child.connect(this.node);
1060
+ }
1061
+ this.applyProps(this.node, this.props);
1062
+ if (this.props.style)
1063
+ this.applyStyles(this.node, this.props.style, this.stopCallbacks);
1064
+ if (this.props.class)
1065
+ this.applyClasses(this.node, this.props.class, this.stopCallbacks);
1066
+ }
1067
+ parent.insertBefore(this.node, after?.nextSibling ?? null);
1068
+ setTimeout(() => {
1069
+ this.canClickAway = true;
1070
+ }, 0);
1071
+ }
1072
+ disconnect() {
1073
+ if (this.connected) {
1074
+ for (const child of this.children) {
1075
+ child.disconnect();
1076
+ }
1077
+ this.node.parentNode?.removeChild(this.node);
1078
+ this.canClickAway = false;
1079
+ for (const stop of this.stopCallbacks) {
1080
+ stop();
1081
+ }
1082
+ this.stopCallbacks = [];
1083
+ }
1084
+ }
1085
+ setChildren(next) {
1086
+ const current = this.children;
1087
+ const patched = [];
1088
+ const length = Math.max(current.length, next.length);
1089
+ for (let i = 0; i < length; i++) {
1090
+ if (!current[i] && next[i]) {
1091
+ patched[i] = next[i];
1092
+ patched[i].connect(this.node, patched[i - 1]?.node);
1093
+ } else if (current[i] && !next[i]) {
1094
+ current[i].disconnect();
1095
+ } else if (current[i] != next[i]) {
1096
+ patched[i] = next[i];
1097
+ current[i].disconnect();
1098
+ patched[i].connect(this.node, patched[i - 1]?.node);
1099
+ }
1100
+ }
1101
+ this.children = patched;
1102
+ }
1103
+ getUpdateKey(type, value) {
1104
+ return `${this.uniqueId}:${type}:${value}`;
1105
+ }
1106
+ applyProps(element, props) {
1107
+ const render = this.appContext.stores.get("render").instance?.exports;
1108
+ const attachProp = (value, callback, updateKey) => {
1109
+ if (isReadable(value)) {
1110
+ this.stopCallbacks.push(
1111
+ observe(value, (value2) => {
1112
+ render.update(() => {
1113
+ callback(value2);
1114
+ }, updateKey);
1115
+ })
1116
+ );
1117
+ } else {
1118
+ render.update(() => {
1119
+ callback(value);
1120
+ }, updateKey);
1121
+ }
1122
+ };
1123
+ for (const key in props) {
1124
+ const value = props[key];
1125
+ if (key === "attributes") {
1126
+ const values = value;
1127
+ for (const name in values) {
1128
+ attachProp(
1129
+ values[name],
1130
+ (current) => {
1131
+ if (current == null) {
1132
+ element.removeAttribute(name);
1133
+ } else {
1134
+ element.setAttribute(name, String(current));
1135
+ }
1136
+ },
1137
+ this.getUpdateKey("attr", name)
1138
+ );
1139
+ }
1140
+ } else if (key === "eventListeners") {
1141
+ const values = value;
1142
+ for (const name in values) {
1143
+ const listener = isReadable(value) ? (e) => value.get()(e) : value;
1144
+ element.addEventListener(name, listener);
1145
+ this.stopCallbacks.push(() => {
1146
+ element.removeEventListener(name, listener);
1147
+ });
1148
+ }
1149
+ } else if (key === "$$value") {
1150
+ if (!isWritable(value)) {
1151
+ throw new TypeError(`$$value property must be a Writable. Got: ${value} (${typeof value})`);
1152
+ }
1153
+ attachProp(
1154
+ value,
1155
+ (current) => {
1156
+ element.value = String(current);
1157
+ },
1158
+ this.getUpdateKey("prop", "value")
1159
+ );
1160
+ const listener = (e) => {
1161
+ const updated = toTypeOf(value.get(), e.currentTarget.value);
1162
+ value.set(updated);
1163
+ };
1164
+ element.addEventListener("input", listener);
1165
+ this.stopCallbacks.push(() => {
1166
+ element.removeEventListener("input", listener);
1167
+ });
1168
+ } else if (key === "onClickOutside" || key === "onclickoutside") {
1169
+ const listener = (e) => {
1170
+ if (this.canClickAway && !element.contains(e.target)) {
1171
+ if (isReadable(value)) {
1172
+ value.get()(e);
1173
+ } else {
1174
+ value(e);
1175
+ }
1176
+ }
1177
+ };
1178
+ const options = { capture: true };
1179
+ window.addEventListener("click", listener, options);
1180
+ this.stopCallbacks.push(() => {
1181
+ window.removeEventListener("click", listener, options);
1182
+ });
1183
+ } else if (isCamelCaseEventName(key)) {
1184
+ const eventName = key.slice(2).toLowerCase();
1185
+ const listener = isReadable(value) ? (e) => value.get()(e) : value;
1186
+ element.addEventListener(eventName, listener);
1187
+ this.stopCallbacks.push(() => {
1188
+ element.removeEventListener(eventName, listener);
1189
+ });
1190
+ } else if (key.includes("-")) {
1191
+ attachProp(
1192
+ value,
1193
+ (current) => {
1194
+ if (current == null) {
1195
+ element.removeAttribute(key);
1196
+ } else {
1197
+ element.setAttribute(key, String(current));
1198
+ }
1199
+ },
1200
+ this.getUpdateKey("attr", key)
1201
+ );
1202
+ } else if (!privateProps.includes(key)) {
1203
+ if (this.elementContext.isSVG) {
1204
+ attachProp(
1205
+ value,
1206
+ (current) => {
1207
+ if (current != null) {
1208
+ element.setAttribute(key, String(props[key]));
1209
+ } else {
1210
+ element.removeAttribute(key);
1211
+ }
1212
+ },
1213
+ this.getUpdateKey("attr", key)
1214
+ );
1215
+ } else {
1216
+ switch (key) {
1217
+ case "contentEditable":
1218
+ case "value":
1219
+ attachProp(
1220
+ value,
1221
+ (current) => {
1222
+ element[key] = String(current);
1223
+ },
1224
+ this.getUpdateKey("prop", key)
1225
+ );
1226
+ break;
1227
+ case "for":
1228
+ attachProp(
1229
+ value,
1230
+ (current) => {
1231
+ element.htmlFor = current;
1232
+ },
1233
+ this.getUpdateKey("prop", "htmlFor")
1234
+ );
1235
+ break;
1236
+ case "checked":
1237
+ attachProp(
1238
+ value,
1239
+ (current) => {
1240
+ element.checked = current;
1241
+ if (current) {
1242
+ element.setAttribute("checked", "");
1243
+ } else {
1244
+ element.removeAttribute("checked");
1245
+ }
1246
+ },
1247
+ this.getUpdateKey("prop", "checked")
1248
+ );
1249
+ break;
1250
+ case "exportParts":
1251
+ case "part":
1252
+ case "translate":
1253
+ case "title": {
1254
+ const _key = key.toLowerCase();
1255
+ attachProp(
1256
+ value,
1257
+ (current) => {
1258
+ if (current == void 0) {
1259
+ element.removeAttribute(_key);
1260
+ } else {
1261
+ element.setAttribute(_key, String(current));
1262
+ }
1263
+ },
1264
+ this.getUpdateKey("attr", _key)
1265
+ );
1266
+ break;
1267
+ }
1268
+ case "autocomplete":
1269
+ case "autocapitalize":
1270
+ attachProp(
1271
+ value,
1272
+ (current) => {
1273
+ if (typeof current === "string") {
1274
+ element.autocomplete = current;
1275
+ } else if (current) {
1276
+ element.autocomplete = "on";
1277
+ } else {
1278
+ element.autocomplete = "off";
1279
+ }
1280
+ },
1281
+ this.getUpdateKey("prop", key)
1282
+ );
1283
+ break;
1284
+ default: {
1285
+ attachProp(
1286
+ value,
1287
+ (current) => {
1288
+ element[key] = current;
1289
+ },
1290
+ this.getUpdateKey("prop", key)
1291
+ );
1292
+ break;
1293
+ }
1294
+ }
1295
+ }
1296
+ }
1297
+ }
1298
+ }
1299
+ applyStyles(element, styles, stopCallbacks) {
1300
+ const render = this.appContext.stores.get("render").instance?.exports;
1301
+ const propStopCallbacks = [];
1302
+ if (styles == void 0) {
1303
+ element.style.cssText = "";
1304
+ } else if (isReadable(styles)) {
1305
+ let unapply;
1306
+ const stop = observe(styles, (current) => {
1307
+ render.update(() => {
1308
+ if (isFunction(unapply)) {
1309
+ unapply();
1310
+ }
1311
+ element.style.cssText = "";
1312
+ unapply = this.applyStyles(element, current, stopCallbacks);
1313
+ }, this.getUpdateKey("styles", "*"));
1314
+ });
1315
+ stopCallbacks.push(stop);
1316
+ propStopCallbacks.push(stop);
1317
+ } else if (isObject(styles)) {
1318
+ styles = styles;
1319
+ for (const key in styles) {
1320
+ const value = styles[key];
1321
+ const setProperty = key.startsWith("--") ? (key2, value2) => value2 == null ? element.style.removeProperty(key2) : element.style.setProperty(key2, value2) : (key2, value2) => element.style[key2] = value2 ?? "";
1322
+ if (isReadable(value)) {
1323
+ const stop = observe(value, (current) => {
1324
+ render.update(() => {
1325
+ if (current != null) {
1326
+ setProperty(key, current);
1327
+ } else {
1328
+ element.style.removeProperty(key);
1329
+ }
1330
+ }, this.getUpdateKey("style", key));
1331
+ });
1332
+ stopCallbacks.push(stop);
1333
+ propStopCallbacks.push(stop);
1334
+ } else if (isString(value)) {
1335
+ setProperty(key, value);
1336
+ } else if (isNumber(value)) {
1337
+ setProperty(key, value + "px");
1338
+ } else {
1339
+ throw new TypeError(`Style properties should be strings, $states or numbers. Got (${key}: ${value})`);
1340
+ }
1341
+ }
1342
+ } else {
1343
+ throw new TypeError(`Expected style property to be a string, $state, or object. Got: ${styles}`);
1344
+ }
1345
+ return function unapply() {
1346
+ for (const stop of propStopCallbacks) {
1347
+ stop();
1348
+ stopCallbacks.splice(stopCallbacks.indexOf(stop), 1);
1349
+ }
1350
+ };
1351
+ }
1352
+ applyClasses(element, classes, stopCallbacks) {
1353
+ const render = this.appContext.stores.get("render").instance?.exports;
1354
+ const classStopCallbacks = [];
1355
+ if (isReadable(classes)) {
1356
+ let unapply;
1357
+ const stop = observe(classes, (current) => {
1358
+ render.update(() => {
1359
+ if (isFunction(unapply)) {
1360
+ unapply();
1361
+ }
1362
+ element.removeAttribute("class");
1363
+ unapply = this.applyClasses(element, current, stopCallbacks);
1364
+ }, this.getUpdateKey("attr", "class"));
1365
+ });
1366
+ stopCallbacks.push(stop);
1367
+ classStopCallbacks.push(stop);
1368
+ } else {
1369
+ const mapped = getClassMap(classes);
1370
+ for (const name in mapped) {
1371
+ const value = mapped[name];
1372
+ if (isReadable(value)) {
1373
+ const stop = observe(value, (current) => {
1374
+ render.update(() => {
1375
+ if (current) {
1376
+ element.classList.add(name);
1377
+ } else {
1378
+ element.classList.remove(name);
1379
+ }
1380
+ });
1381
+ });
1382
+ stopCallbacks.push(stop);
1383
+ classStopCallbacks.push(stop);
1384
+ } else if (value) {
1385
+ element.classList.add(name);
1386
+ }
1387
+ }
1388
+ }
1389
+ return function unapply() {
1390
+ for (const stop of classStopCallbacks) {
1391
+ stop();
1392
+ stopCallbacks.splice(stopCallbacks.indexOf(stop), 1);
1393
+ }
1394
+ };
1395
+ }
1396
+ };
1397
+ function getClassMap(classes) {
1398
+ let mapped = {};
1399
+ if (isString(classes)) {
1400
+ const names = classes.split(" ");
1401
+ for (const name of names) {
1402
+ mapped[name] = true;
1403
+ }
1404
+ } else if (isObject(classes)) {
1405
+ Object.assign(mapped, classes);
1406
+ } else if (Array.isArray(classes)) {
1407
+ Array.from(classes).filter((item) => item != null).forEach((item) => {
1408
+ Object.assign(mapped, getClassMap(item));
1409
+ });
1410
+ }
1411
+ return mapped;
1412
+ }
1413
+ function toTypeOf(target, source) {
1414
+ const type = typeof target;
1415
+ if (type === "string") {
1416
+ return String(source);
1417
+ }
1418
+ if (type === "number") {
1419
+ return Number(source);
1420
+ }
1421
+ if (type === "boolean") {
1422
+ return Boolean(source);
1423
+ }
1424
+ return source;
1425
+ }
1426
+ var privateProps = ["ref", "children", "class", "style", "data"];
1427
+
1428
+ // src/nodes/observer.ts
1429
+ var Observer = class {
1430
+ node;
1431
+ endNode;
1432
+ connectedViews = [];
1433
+ renderFn;
1434
+ appContext;
1435
+ elementContext;
1436
+ observerControls;
1437
+ get connected() {
1438
+ return this.node.parentNode != null;
1439
+ }
1440
+ constructor({ readables, renderFn, appContext, elementContext }) {
1441
+ this.appContext = appContext;
1442
+ this.elementContext = elementContext;
1443
+ this.renderFn = renderFn;
1444
+ this.node = document.createComment("Observer");
1445
+ this.endNode = document.createComment("/Observer");
1446
+ let _stop;
1447
+ this.observerControls = {
1448
+ start: () => {
1449
+ if (_stop != null)
1450
+ return;
1451
+ _stop = observe(readables, (...values) => {
1452
+ const rendered = this.renderFn(...values);
1453
+ if (!isRenderable(rendered)) {
1454
+ console.error(rendered);
1455
+ throw new TypeError(
1456
+ `Observer received invalid value to render. Got type: ${typeOf(rendered)}, value: ${rendered}`
1457
+ );
1458
+ }
1459
+ if (Array.isArray(rendered)) {
1460
+ this.update(...rendered);
1461
+ } else {
1462
+ this.update(rendered);
1463
+ }
1464
+ });
1465
+ },
1466
+ stop: () => {
1467
+ if (_stop == null)
1468
+ return;
1469
+ _stop();
1470
+ _stop = void 0;
1471
+ }
1472
+ };
1473
+ }
1474
+ connect(parent, after) {
1475
+ if (!this.connected) {
1476
+ parent.insertBefore(this.node, after?.nextSibling ?? null);
1477
+ this.observerControls.start();
1478
+ }
1479
+ }
1480
+ disconnect() {
1481
+ this.observerControls.stop();
1482
+ if (this.connected) {
1483
+ this.cleanup();
1484
+ this.node.parentNode?.removeChild(this.node);
1485
+ }
1486
+ }
1487
+ async setChildren() {
1488
+ console.warn("setChildren is not implemented for Dynamic");
1489
+ }
1490
+ cleanup() {
1491
+ while (this.connectedViews.length > 0) {
1492
+ this.connectedViews.pop()?.disconnect();
1493
+ }
1494
+ }
1495
+ update(...children) {
1496
+ this.cleanup();
1497
+ if (children == null || !this.connected) {
1498
+ return;
1499
+ }
1500
+ const handles = children.map((c) => {
1501
+ if (isDOMHandle(c)) {
1502
+ return c;
1503
+ } else if (isMarkup(c)) {
1504
+ return getRenderHandle(renderMarkupToDOM(c, this));
1505
+ } else {
1506
+ return getRenderHandle(renderMarkupToDOM(toMarkup(c), this));
1507
+ }
1508
+ });
1509
+ for (const handle of handles) {
1510
+ const previous = this.connectedViews.at(-1)?.node || this.node;
1511
+ handle.connect(this.node.parentNode, previous);
1512
+ this.connectedViews.push(handle);
1513
+ }
1514
+ if (this.appContext.mode === "development") {
1515
+ const lastNode = this.connectedViews.at(-1)?.node;
1516
+ if (this.endNode.previousSibling !== lastNode) {
1517
+ this.node.parentNode.insertBefore(this.endNode, lastNode?.nextSibling ?? null);
1518
+ }
1519
+ }
1520
+ }
1521
+ };
1522
+
1523
+ // src/nodes/outlet.ts
1524
+ var Outlet = class {
1525
+ node;
1526
+ endNode;
1527
+ $children;
1528
+ stopCallback;
1529
+ connectedChildren = [];
1530
+ appContext;
1531
+ elementContext;
1532
+ constructor(config) {
1533
+ this.$children = config.$children;
1534
+ this.appContext = config.appContext;
1535
+ this.elementContext = config.elementContext;
1536
+ if (this.appContext.mode === "development") {
1537
+ this.node = document.createComment("Outlet");
1538
+ this.endNode = document.createComment("/Outlet");
1539
+ } else {
1540
+ this.node = document.createTextNode("");
1541
+ this.endNode = document.createTextNode("");
1542
+ }
1543
+ }
1544
+ get connected() {
1545
+ return this.node?.parentNode != null;
1546
+ }
1547
+ connect(parent, after) {
1548
+ if (!this.connected) {
1549
+ parent.insertBefore(this.node, after?.nextSibling ?? null);
1550
+ this.stopCallback = observe(this.$children, (children) => {
1551
+ this.update(children);
1552
+ });
1553
+ }
1554
+ }
1555
+ disconnect() {
1556
+ if (this.stopCallback) {
1557
+ this.stopCallback();
1558
+ this.stopCallback = void 0;
1559
+ }
1560
+ if (this.connected) {
1561
+ for (const child of this.connectedChildren) {
1562
+ child.disconnect();
1563
+ }
1564
+ this.connectedChildren = [];
1565
+ this.endNode.parentNode?.removeChild(this.endNode);
1566
+ }
1567
+ }
1568
+ update(newChildren) {
1569
+ for (const child of this.connectedChildren) {
1570
+ child.disconnect();
1571
+ }
1572
+ this.connectedChildren = newChildren;
1573
+ for (let i = 0; i < this.connectedChildren.length; i++) {
1574
+ const child = this.connectedChildren[i];
1575
+ const previous = i > 0 ? this.connectedChildren[i] : void 0;
1576
+ child.connect(this.node.parentElement, previous?.node);
1577
+ }
1578
+ if (this.appContext.mode === "development") {
1579
+ this.node.textContent = `Outlet (${newChildren.length} ${newChildren.length === 1 ? "child" : "children"})`;
1580
+ this.node.parentElement?.insertBefore(
1581
+ this.endNode,
1582
+ this.connectedChildren[this.connectedChildren.length - 1]?.node?.nextSibling ?? null
1583
+ );
1584
+ }
1585
+ }
1586
+ setChildren(children) {
1587
+ }
1588
+ };
1589
+
1590
+ // src/nodes/portal.ts
1591
+ var Portal = class {
1592
+ config;
1593
+ handle;
1594
+ get connected() {
1595
+ if (!this.handle) {
1596
+ return false;
1597
+ }
1598
+ return this.handle.connected;
1599
+ }
1600
+ constructor(config) {
1601
+ this.config = config;
1602
+ }
1603
+ connect(_parent, _after) {
1604
+ const { content, parent } = this.config;
1605
+ if (isDOMHandle(content)) {
1606
+ this.handle = content;
1607
+ } else if (isMarkup(content)) {
1608
+ this.handle = getRenderHandle(renderMarkupToDOM(content, this.config));
1609
+ } else {
1610
+ this.handle = getRenderHandle(renderMarkupToDOM(toMarkup(content), this.config));
1611
+ }
1612
+ this.handle.connect(parent);
1613
+ }
1614
+ disconnect() {
1615
+ if (this.handle?.connected) {
1616
+ this.handle.disconnect();
1617
+ }
1618
+ }
1619
+ setChildren(children) {
1620
+ this.handle?.setChildren(children);
1621
+ }
1622
+ };
1623
+
1624
+ // src/view.ts
1625
+ var SECRETS = Symbol("VIEW_SECRETS");
1626
+ function getViewSecrets(ctx) {
1627
+ return ctx[SECRETS];
1628
+ }
1629
+ function initView(config) {
1630
+ const appContext = config.appContext;
1631
+ const elementContext = {
1632
+ ...config.elementContext,
1633
+ stores: /* @__PURE__ */ new Map(),
1634
+ parent: config.elementContext
1635
+ };
1636
+ const $$children = writable(renderMarkupToDOM(config.children ?? [], { appContext, elementContext }));
1637
+ let isConnected = false;
1638
+ const stopObserverCallbacks = [];
1639
+ const connectedCallbacks = [];
1640
+ const disconnectedCallbacks = [];
1641
+ const beforeConnectCallbacks = [];
1642
+ const beforeDisconnectCallbacks = [];
1643
+ const uniqueId = nanoid();
1644
+ const ctx = {
1645
+ get uniqueId() {
1646
+ return uniqueId;
1647
+ },
1648
+ name: config.view.name ?? "anonymous",
1649
+ getStore(store) {
1650
+ let name;
1651
+ if (typeof store === "string") {
1652
+ name = store;
1653
+ } else {
1654
+ name = store.name;
1655
+ }
1656
+ if (typeof store !== "string") {
1657
+ let ec = elementContext;
1658
+ while (ec) {
1659
+ if (ec.stores.has(store)) {
1660
+ return ec.stores.get(store)?.instance.exports;
1661
+ }
1662
+ ec = ec.parent;
1663
+ }
1664
+ }
1665
+ if (appContext.stores.has(store)) {
1666
+ const _store = appContext.stores.get(store);
1667
+ if (!_store.instance) {
1668
+ appContext.crashCollector.crash({
1669
+ componentName: ctx.name,
1670
+ error: new Error(`Store '${name}' is not registered on this app.`)
1671
+ });
1672
+ }
1673
+ return _store.instance.exports;
1674
+ }
1675
+ appContext.crashCollector.crash({
1676
+ componentName: ctx.name,
1677
+ error: new Error(`Store '${name}' is not registered on this app.`)
1678
+ });
1679
+ },
1680
+ onConnected(callback) {
1681
+ connectedCallbacks.push(callback);
1682
+ },
1683
+ onDisconnected(callback) {
1684
+ disconnectedCallbacks.push(callback);
1685
+ },
1686
+ beforeConnect(callback) {
1687
+ beforeConnectCallbacks.push(callback);
1688
+ },
1689
+ beforeDisconnect(callback) {
1690
+ beforeDisconnectCallbacks.push(callback);
1691
+ },
1692
+ crash(error) {
1693
+ config.appContext.crashCollector.crash({ error, componentName: ctx.name });
1694
+ },
1695
+ observe(readables, callback) {
1696
+ if (isConnected) {
1697
+ const stop = observe(readables, callback);
1698
+ stopObserverCallbacks.push(stop);
1699
+ } else {
1700
+ connectedCallbacks.push(() => {
1701
+ const stop = observe(readables, callback);
1702
+ stopObserverCallbacks.push(stop);
1703
+ });
1704
+ }
1705
+ },
1706
+ outlet() {
1707
+ return m("$outlet", { $children: readable($$children) });
1708
+ }
1709
+ };
1710
+ const debugChannel = appContext.debugHub.channel({
1711
+ get name() {
1712
+ return ctx.name;
1713
+ }
1714
+ });
1715
+ Object.defineProperties(ctx, Object.getOwnPropertyDescriptors(debugChannel));
1716
+ Object.defineProperty(ctx, SECRETS, {
1717
+ enumerable: false,
1718
+ configurable: false,
1719
+ value: {
1720
+ appContext,
1721
+ elementContext
1722
+ }
1723
+ });
1724
+ let rendered;
1725
+ function initialize() {
1726
+ let result;
1727
+ try {
1728
+ result = config.view(config.props, ctx);
1729
+ } catch (error) {
1730
+ if (error instanceof Error) {
1731
+ appContext.crashCollector.crash({ error, componentName: ctx.name });
1732
+ }
1733
+ throw error;
1734
+ }
1735
+ if (result instanceof Promise) {
1736
+ appContext.crashCollector.crash({
1737
+ error: new TypeError(`View function cannot return a Promise.`),
1738
+ componentName: ctx.name
1739
+ });
1740
+ }
1741
+ if (result === null) {
1742
+ } else if (result instanceof Node) {
1743
+ rendered = getRenderHandle(renderMarkupToDOM(m("$node", { value: result }), { appContext, elementContext }));
1744
+ } else if (isMarkup(result) || isArrayOf(isMarkup, result)) {
1745
+ rendered = getRenderHandle(renderMarkupToDOM(result, { appContext, elementContext }));
1746
+ } else if (isReadable(result)) {
1747
+ rendered = getRenderHandle(
1748
+ renderMarkupToDOM(m("$observer", { readables: [result], renderFn: (x) => x }), { appContext, elementContext })
1749
+ );
1750
+ } else {
1751
+ console.warn(result, config);
1752
+ appContext.crashCollector.crash({
1753
+ error: new TypeError(
1754
+ `Expected '${config.view.name}' function to return a DOM node, Markup element, Readable or null. Got: ${typeOf(result)}`
1755
+ ),
1756
+ componentName: ctx.name
1757
+ });
1758
+ }
1759
+ }
1760
+ const handle = {
1761
+ get node() {
1762
+ return rendered?.node;
1763
+ },
1764
+ get connected() {
1765
+ return isConnected;
1766
+ },
1767
+ connect(parent, after) {
1768
+ const wasConnected = isConnected;
1769
+ if (!wasConnected) {
1770
+ initialize();
1771
+ while (beforeConnectCallbacks.length > 0) {
1772
+ const callback = beforeConnectCallbacks.shift();
1773
+ callback();
1774
+ }
1775
+ }
1776
+ if (rendered) {
1777
+ rendered.connect(parent, after);
1778
+ }
1779
+ if (!wasConnected) {
1780
+ isConnected = true;
1781
+ requestAnimationFrame(() => {
1782
+ while (connectedCallbacks.length > 0) {
1783
+ const callback = connectedCallbacks.shift();
1784
+ callback();
1785
+ }
1786
+ });
1787
+ }
1788
+ },
1789
+ disconnect() {
1790
+ while (beforeDisconnectCallbacks.length > 0) {
1791
+ const callback = beforeDisconnectCallbacks.shift();
1792
+ callback();
1793
+ }
1794
+ if (rendered) {
1795
+ rendered.disconnect();
1796
+ }
1797
+ isConnected = false;
1798
+ while (disconnectedCallbacks.length > 0) {
1799
+ const callback = disconnectedCallbacks.shift();
1800
+ callback();
1801
+ }
1802
+ while (stopObserverCallbacks.length > 0) {
1803
+ const callback = stopObserverCallbacks.shift();
1804
+ callback();
1805
+ }
1806
+ },
1807
+ async setChildren(children) {
1808
+ $$children.set(children);
1809
+ }
1810
+ };
1811
+ return handle;
1812
+ }
1813
+
1814
+ // src/nodes/repeat.ts
1815
+ var Repeat = class {
1816
+ node;
1817
+ endNode;
1818
+ $items;
1819
+ stopCallback;
1820
+ connectedItems = [];
1821
+ appContext;
1822
+ elementContext;
1823
+ renderFn;
1824
+ keyFn;
1825
+ get connected() {
1826
+ return this.node.parentNode != null;
1827
+ }
1828
+ constructor({ appContext, elementContext, $items, renderFn, keyFn }) {
1829
+ this.appContext = appContext;
1830
+ this.elementContext = elementContext;
1831
+ this.$items = $items;
1832
+ this.renderFn = renderFn;
1833
+ this.keyFn = keyFn;
1834
+ if (appContext.mode === "development") {
1835
+ this.node = document.createComment("Repeat");
1836
+ this.endNode = document.createComment("/Repeat");
1837
+ } else {
1838
+ this.node = document.createTextNode("");
1839
+ this.endNode = document.createTextNode("");
1840
+ }
1841
+ }
1842
+ connect(parent, after) {
1843
+ if (!this.connected) {
1844
+ parent.insertBefore(this.node, after?.nextSibling ?? null);
1845
+ this.stopCallback = observe(this.$items, (value) => {
1846
+ this._update(Array.from(value));
1847
+ });
1848
+ }
1849
+ }
1850
+ disconnect() {
1851
+ if (this.stopCallback) {
1852
+ this.stopCallback();
1853
+ this.stopCallback = void 0;
1854
+ }
1855
+ if (this.connected) {
1856
+ this.node.parentNode?.removeChild(this.node);
1857
+ this.endNode.parentNode?.removeChild(this.endNode);
1858
+ }
1859
+ this._cleanup();
1860
+ }
1861
+ setChildren() {
1862
+ console.warn("setChildren is not implemented for repeat()");
1863
+ }
1864
+ _cleanup() {
1865
+ for (const item of this.connectedItems) {
1866
+ item.handle.disconnect();
1867
+ }
1868
+ this.connectedItems = [];
1869
+ }
1870
+ _update(value) {
1871
+ if (value.length === 0 || !this.connected) {
1872
+ return this._cleanup();
1873
+ }
1874
+ const potentialItems = [];
1875
+ let index = 0;
1876
+ for (const item of value) {
1877
+ potentialItems.push({
1878
+ key: this.keyFn(item, index),
1879
+ value: item,
1880
+ index: index++
1881
+ });
1882
+ }
1883
+ const newItems = [];
1884
+ for (const connected of this.connectedItems) {
1885
+ const potentialItem = potentialItems.find((p) => p.key === connected.key);
1886
+ if (!potentialItem) {
1887
+ connected.handle.disconnect();
1888
+ }
1889
+ }
1890
+ for (const potential of potentialItems) {
1891
+ const connected = this.connectedItems.find((item) => item.key === potential.key);
1892
+ if (connected) {
1893
+ connected.$$value.set(potential.value);
1894
+ connected.$$index.set(potential.index);
1895
+ newItems[potential.index] = connected;
1896
+ } else {
1897
+ const $$value = writable(potential.value);
1898
+ const $$index = writable(potential.index);
1899
+ newItems[potential.index] = {
1900
+ key: potential.key,
1901
+ $$value,
1902
+ $$index,
1903
+ handle: initView({
1904
+ view: RepeatItemView,
1905
+ appContext: this.appContext,
1906
+ elementContext: this.elementContext,
1907
+ props: { $value: readable($$value), $index: readable($$index), renderFn: this.renderFn }
1908
+ })
1909
+ };
1910
+ }
1911
+ }
1912
+ for (let i = 0; i < newItems.length; i++) {
1913
+ const item = newItems[i];
1914
+ const previous = newItems[i - 1]?.handle.node ?? this.node;
1915
+ item.handle.connect(this.node.parentNode, previous);
1916
+ }
1917
+ this.connectedItems = newItems;
1918
+ if (this.appContext.mode === "development") {
1919
+ this.node.textContent = `Repeat (${newItems.length} item${newItems.length === 1 ? "" : "s"})`;
1920
+ const lastItem = newItems.at(-1)?.handle.node ?? this.node;
1921
+ this.node.parentNode?.insertBefore(this.endNode, lastItem.nextSibling);
1922
+ }
1923
+ }
1924
+ };
1925
+ function RepeatItemView({ $value, $index, renderFn }, ctx) {
1926
+ return renderFn($value, $index, ctx);
1927
+ }
1928
+
1929
+ // src/nodes/text.ts
1930
+ var Text = class {
1931
+ node = document.createTextNode("");
1932
+ value = "";
1933
+ stopCallback;
1934
+ get connected() {
1935
+ return this.node.parentNode != null;
1936
+ }
1937
+ constructor({ value }) {
1938
+ this.value = value;
1939
+ }
1940
+ async connect(parent, after = null) {
1941
+ if (!this.connected) {
1942
+ if (isReadable(this.value)) {
1943
+ this.stopCallback = observe(this.value, (value) => {
1944
+ this.update(value);
1945
+ });
1946
+ } else {
1947
+ this.update(this.value);
1948
+ }
1949
+ }
1950
+ parent.insertBefore(this.node, after?.nextSibling ?? null);
1951
+ }
1952
+ async disconnect() {
1953
+ if (this.connected) {
1954
+ if (this.stopCallback) {
1955
+ this.stopCallback();
1956
+ this.stopCallback = void 0;
1957
+ }
1958
+ this.node.parentNode.removeChild(this.node);
1959
+ }
1960
+ }
1961
+ update(value) {
1962
+ if (value != null) {
1963
+ this.node.textContent = value.toString();
1964
+ } else {
1965
+ this.node.textContent = "";
1966
+ }
1967
+ }
1968
+ async setChildren() {
1969
+ }
1970
+ };
1971
+
1972
+ // src/markup.ts
1973
+ var MARKUP = Symbol("Markup");
1974
+ function isMarkup(value) {
1975
+ return isObject(value) && value[MARKUP] === true;
1976
+ }
1977
+ function isDOMHandle(value) {
1978
+ return isObject(value) && isFunction(value.connect) && isFunction(value.disconnect);
1979
+ }
1980
+ function toMarkup(renderables) {
1981
+ if (!isArray(renderables)) {
1982
+ renderables = [renderables];
1983
+ }
1984
+ return renderables.flat(Infinity).filter((x) => x !== null && x !== void 0 && x !== false).map((x) => {
1985
+ if (x instanceof Node) {
1986
+ return m("$node", { value: x });
1987
+ }
1988
+ if (isMarkup(x)) {
1989
+ return x;
1990
+ }
1991
+ if (isString(x) || isNumber(x)) {
1992
+ return m("$text", { value: x });
1993
+ }
1994
+ if (isReadable(x)) {
1995
+ return m("$observer", {
1996
+ readables: [x],
1997
+ renderFn: (x2) => x2
1998
+ });
1999
+ }
2000
+ console.error(x);
2001
+ throw new TypeError(`Unexpected child type. Got: ${x}`);
2002
+ });
2003
+ }
2004
+ function m(type, props, ...children) {
2005
+ return {
2006
+ [MARKUP]: true,
2007
+ type,
2008
+ props,
2009
+ children: toMarkup(children)
2010
+ };
2011
+ }
2012
+ function cond(predicate, thenContent, elseContent) {
2013
+ const $predicate = readable(predicate);
2014
+ return m("$cond", {
2015
+ $predicate,
2016
+ thenContent,
2017
+ elseContent
2018
+ });
2019
+ }
2020
+ function repeat(items, keyFn, renderFn) {
2021
+ const $items = readable(items);
2022
+ return m("$repeat", { $items, keyFn, renderFn });
2023
+ }
2024
+ function portal(content, parent) {
2025
+ return m("$portal", { content, parent });
2026
+ }
2027
+ var NodeHandle = class {
2028
+ node;
2029
+ get connected() {
2030
+ return this.node.parentNode != null;
2031
+ }
2032
+ constructor(node) {
2033
+ this.node = node;
2034
+ }
2035
+ async connect(parent, after) {
2036
+ parent.insertBefore(this.node, after?.nextSibling ?? null);
2037
+ }
2038
+ async disconnect() {
2039
+ if (this.node.parentNode) {
2040
+ this.node.parentNode.removeChild(this.node);
2041
+ }
2042
+ }
2043
+ async setChildren(children) {
2044
+ }
2045
+ };
2046
+ function renderMarkupToDOM(markup, ctx) {
2047
+ const items = isArray(markup) ? markup : [markup];
2048
+ return items.map((item) => {
2049
+ if (isFunction(item.type)) {
2050
+ return initView({
2051
+ view: item.type,
2052
+ props: item.props,
2053
+ children: item.children,
2054
+ appContext: ctx.appContext,
2055
+ elementContext: ctx.elementContext
2056
+ });
2057
+ } else if (isString(item.type)) {
2058
+ switch (item.type) {
2059
+ case "$node": {
2060
+ const attrs = item.props;
2061
+ return new NodeHandle(attrs.value);
2062
+ }
2063
+ case "$text": {
2064
+ const attrs = item.props;
2065
+ return new Text({
2066
+ value: attrs.value
2067
+ });
2068
+ }
2069
+ case "$cond": {
2070
+ const attrs = item.props;
2071
+ return new Conditional({
2072
+ $predicate: attrs.$predicate,
2073
+ thenContent: attrs.thenContent,
2074
+ elseContent: attrs.elseContent,
2075
+ appContext: ctx.appContext,
2076
+ elementContext: ctx.elementContext
2077
+ });
2078
+ }
2079
+ case "$repeat": {
2080
+ const attrs = item.props;
2081
+ return new Repeat({
2082
+ $items: attrs.$items,
2083
+ keyFn: attrs.keyFn,
2084
+ renderFn: attrs.renderFn,
2085
+ appContext: ctx.appContext,
2086
+ elementContext: ctx.elementContext
2087
+ });
2088
+ }
2089
+ case "$observer": {
2090
+ const attrs = item.props;
2091
+ return new Observer({
2092
+ readables: attrs.readables,
2093
+ renderFn: attrs.renderFn,
2094
+ appContext: ctx.appContext,
2095
+ elementContext: ctx.elementContext
2096
+ });
2097
+ }
2098
+ case "$outlet": {
2099
+ const attrs = item.props;
2100
+ return new Outlet({
2101
+ $children: attrs.$children,
2102
+ appContext: ctx.appContext,
2103
+ elementContext: ctx.elementContext
2104
+ });
2105
+ }
2106
+ case "$portal": {
2107
+ const attrs = item.props;
2108
+ return new Portal({
2109
+ content: attrs.content,
2110
+ parent: attrs.parent,
2111
+ appContext: ctx.appContext,
2112
+ elementContext: ctx.elementContext
2113
+ });
2114
+ }
2115
+ default:
2116
+ if (item.type.startsWith("$")) {
2117
+ throw new Error(`Unknown markup type: ${item.type}`);
2118
+ }
2119
+ return new HTML({
2120
+ tag: item.type,
2121
+ props: item.props,
2122
+ children: item.children,
2123
+ appContext: ctx.appContext,
2124
+ elementContext: ctx.elementContext
2125
+ });
2126
+ }
2127
+ } else {
2128
+ throw new TypeError(`Expected a string or view function. Got: ${item.type}`);
2129
+ }
2130
+ });
2131
+ }
2132
+ function getRenderHandle(handles) {
2133
+ if (handles.length === 1) {
2134
+ return handles[0];
2135
+ }
2136
+ const node = document.createComment("renderHandle");
2137
+ let isConnected = false;
2138
+ return {
2139
+ get node() {
2140
+ return node;
2141
+ },
2142
+ get connected() {
2143
+ return isConnected;
2144
+ },
2145
+ async connect(parent, after) {
2146
+ parent.insertBefore(node, after ? after : null);
2147
+ for (const handle of handles) {
2148
+ const previous = handles[handles.length - 1]?.node ?? node;
2149
+ await handle.connect(parent, previous);
2150
+ }
2151
+ isConnected = true;
2152
+ },
2153
+ async disconnect() {
2154
+ if (isConnected) {
2155
+ for (const handle of handles) {
2156
+ handle.disconnect();
2157
+ }
2158
+ node.remove();
2159
+ }
2160
+ isConnected = false;
2161
+ },
2162
+ async setChildren() {
2163
+ }
2164
+ };
2165
+ }
2166
+ function isRenderable(value) {
2167
+ return value == null || value === false || typeof value === "string" || typeof value === "number" || isMarkup(value) || isReadable(value) || isArrayOf(isRenderable, value);
2168
+ }
2169
+
2170
+ // src/store.ts
2171
+ var SECRETS2 = Symbol("STORE_SECRETS");
2172
+ function getStoreSecrets(c) {
2173
+ return c[SECRETS2];
2174
+ }
2175
+ function initStore(config) {
2176
+ const appContext = config.appContext;
2177
+ const elementContext = config.elementContext;
2178
+ let isConnected = false;
2179
+ const stopObserverCallbacks = [];
2180
+ const connectedCallbacks = [];
2181
+ const disconnectedCallbacks = [];
2182
+ const ctx = {
2183
+ name: config.store.name ?? "anonymous",
2184
+ options: config.options,
2185
+ getStore(store) {
2186
+ let name;
2187
+ if (typeof store === "string") {
2188
+ name = store;
2189
+ } else {
2190
+ name = store.name;
2191
+ }
2192
+ if (typeof store !== "string") {
2193
+ let ec = elementContext;
2194
+ while (ec) {
2195
+ if (ec.stores.has(store)) {
2196
+ return ec.stores.get(store)?.instance.exports;
2197
+ }
2198
+ ec = ec.parent;
2199
+ }
2200
+ }
2201
+ if (appContext.stores.has(store)) {
2202
+ const _store = appContext.stores.get(store);
2203
+ if (!_store.instance) {
2204
+ appContext.crashCollector.crash({
2205
+ componentName: ctx.name,
2206
+ error: new Error(
2207
+ `Store '${name}' was accessed before it was set up. Make sure '${name}' is registered before components that access it.`
2208
+ )
2209
+ });
2210
+ }
2211
+ return _store.instance.exports;
2212
+ }
2213
+ appContext.crashCollector.crash({
2214
+ componentName: ctx.name,
2215
+ error: new Error(`Store '${name}' is not registered on this app.`)
2216
+ });
2217
+ },
2218
+ onConnected(callback) {
2219
+ connectedCallbacks.push(callback);
2220
+ },
2221
+ onDisconnected(callback) {
2222
+ disconnectedCallbacks.push(callback);
2223
+ },
2224
+ crash(error) {
2225
+ config.appContext.crashCollector.crash({ error, componentName: ctx.name });
2226
+ },
2227
+ observe(readables, callback) {
2228
+ if (isConnected) {
2229
+ const stop = observe(readables, callback);
2230
+ stopObserverCallbacks.push(stop);
2231
+ } else {
2232
+ connectedCallbacks.push(() => {
2233
+ const stop = observe(readables, callback);
2234
+ stopObserverCallbacks.push(stop);
2235
+ });
2236
+ }
2237
+ }
2238
+ };
2239
+ const debugChannel = appContext.debugHub.channel({
2240
+ get name() {
2241
+ return ctx.name;
2242
+ }
2243
+ });
2244
+ Object.defineProperties(ctx, Object.getOwnPropertyDescriptors(debugChannel));
2245
+ Object.defineProperty(ctx, SECRETS2, {
2246
+ enumerable: false,
2247
+ configurable: false,
2248
+ value: {
2249
+ appContext,
2250
+ elementContext
2251
+ }
2252
+ });
2253
+ let exports;
2254
+ return {
2255
+ get name() {
2256
+ return ctx.name;
2257
+ },
2258
+ get exports() {
2259
+ return exports;
2260
+ },
2261
+ setup() {
2262
+ let result;
2263
+ try {
2264
+ result = config.store(ctx);
2265
+ } catch (error) {
2266
+ if (error instanceof Error) {
2267
+ appContext.crashCollector.crash({ error, componentName: ctx.name });
2268
+ } else {
2269
+ throw error;
2270
+ }
2271
+ }
2272
+ if (result instanceof Promise) {
2273
+ appContext.crashCollector.crash({
2274
+ error: new TypeError(`Store function cannot return a Promise`),
2275
+ componentName: ctx.name
2276
+ });
2277
+ }
2278
+ if (!isObject(result)) {
2279
+ const error = new TypeError(`Expected ${ctx.name} function to return an object. Got: ${typeOf(result)}`);
2280
+ appContext.crashCollector.crash({ error, componentName: ctx.name });
2281
+ }
2282
+ exports = result;
2283
+ },
2284
+ connect() {
2285
+ while (connectedCallbacks.length > 0) {
2286
+ const callback = connectedCallbacks.shift();
2287
+ callback();
2288
+ }
2289
+ },
2290
+ disconnect() {
2291
+ while (disconnectedCallbacks.length > 0) {
2292
+ const callback = disconnectedCallbacks.shift();
2293
+ callback();
2294
+ }
2295
+ }
2296
+ };
2297
+ }
2298
+
2299
+ // src/stores/dialog.ts
2300
+ function DialogStore(ctx) {
2301
+ ctx.name = "dolla/dialog";
2302
+ const { appContext, elementContext } = getStoreSecrets(ctx);
2303
+ const container = document.createElement("div");
2304
+ container.style.position = "fixed";
2305
+ container.style.top = "0";
2306
+ container.style.right = "0";
2307
+ container.style.bottom = "0";
2308
+ container.style.left = "0";
2309
+ container.style.zIndex = "99999";
2310
+ const $$dialogs = writable([]);
2311
+ let activeDialogs = [];
2312
+ function dialogChangedCallback() {
2313
+ if (activeDialogs.length > 0) {
2314
+ if (!container.parentNode) {
2315
+ document.body.appendChild(container);
2316
+ }
2317
+ } else {
2318
+ if (container.parentNode) {
2319
+ document.body.removeChild(container);
2320
+ }
2321
+ }
2322
+ }
2323
+ ctx.observe($$dialogs, (dialogs) => {
2324
+ requestAnimationFrame(() => {
2325
+ let removed = [];
2326
+ let added = [];
2327
+ for (const dialog of activeDialogs) {
2328
+ if (!dialogs.includes(dialog)) {
2329
+ removed.push(dialog);
2330
+ }
2331
+ }
2332
+ for (const dialog of dialogs) {
2333
+ if (!activeDialogs.includes(dialog)) {
2334
+ added.push(dialog);
2335
+ }
2336
+ }
2337
+ for (const dialog of removed) {
2338
+ if (dialog.transitionOutCallback) {
2339
+ dialog.transitionOutCallback().then(() => {
2340
+ dialog.instance.disconnect();
2341
+ activeDialogs.splice(activeDialogs.indexOf(dialog), 1);
2342
+ dialogChangedCallback();
2343
+ });
2344
+ } else {
2345
+ dialog.instance.disconnect();
2346
+ activeDialogs.splice(activeDialogs.indexOf(dialog), 1);
2347
+ }
2348
+ }
2349
+ for (const dialog of added) {
2350
+ dialog.instance.connect(container);
2351
+ if (dialog.transitionInCallback) {
2352
+ dialog.transitionInCallback();
2353
+ }
2354
+ activeDialogs.push(dialog);
2355
+ }
2356
+ dialogChangedCallback();
2357
+ });
2358
+ });
2359
+ ctx.onDisconnected(() => {
2360
+ if (container.parentNode) {
2361
+ document.body.removeChild(container);
2362
+ }
2363
+ });
2364
+ function open(view, props) {
2365
+ const $$open = writable(true);
2366
+ let dialog;
2367
+ let transitionInCallback;
2368
+ let transitionOutCallback;
2369
+ let instance = initView({
2370
+ view,
2371
+ appContext,
2372
+ elementContext,
2373
+ props: {
2374
+ ...props,
2375
+ $$open,
2376
+ transitionIn: (callback) => {
2377
+ transitionInCallback = callback;
2378
+ },
2379
+ transitionOut: (callback) => {
2380
+ transitionOutCallback = callback;
2381
+ }
2382
+ }
2383
+ });
2384
+ dialog = {
2385
+ instance,
2386
+ // These must be getters because the fns passed to props aren't called until before connect.
2387
+ get transitionInCallback() {
2388
+ return transitionInCallback;
2389
+ },
2390
+ get transitionOutCallback() {
2391
+ return transitionOutCallback;
2392
+ }
2393
+ };
2394
+ $$dialogs.update((current) => {
2395
+ return [...current, dialog];
2396
+ });
2397
+ const stopObserver = observe($$open, (value) => {
2398
+ if (!value) {
2399
+ closeDialog();
2400
+ }
2401
+ });
2402
+ function closeDialog() {
2403
+ $$dialogs.update((current) => {
2404
+ return current.filter((x) => x !== dialog);
2405
+ });
2406
+ dialog = void 0;
2407
+ stopObserver();
2408
+ }
2409
+ return closeDialog;
2410
+ }
2411
+ return {
2412
+ open
2413
+ };
2414
+ }
2415
+
2416
+ // src/stores/document.ts
2417
+ function DocumentStore(ctx) {
2418
+ ctx.name = "dolla/document";
2419
+ const $$title = writable(document.title);
2420
+ const $$visibility = writable(document.visibilityState);
2421
+ const $$orientation = writable("landscape");
2422
+ const $$colorScheme = writable("light");
2423
+ ctx.observe($$title, (current) => {
2424
+ document.title = current;
2425
+ });
2426
+ const onVisibilityChange = () => {
2427
+ $$visibility.set(document.visibilityState);
2428
+ };
2429
+ const onFocus = () => {
2430
+ $$visibility.set("visible");
2431
+ };
2432
+ const landscapeQuery = window.matchMedia("(orientation: landscape)");
2433
+ function onOrientationChange(e) {
2434
+ $$orientation.set(e.matches ? "landscape" : "portrait");
2435
+ }
2436
+ onOrientationChange(landscapeQuery);
2437
+ const colorSchemeQuery = window.matchMedia("(prefers-color-scheme: dark)");
2438
+ function onColorChange(e) {
2439
+ $$colorScheme.set(e.matches ? "dark" : "light");
2440
+ }
2441
+ onColorChange(colorSchemeQuery);
2442
+ ctx.onConnected(function() {
2443
+ landscapeQuery.addEventListener("change", onOrientationChange);
2444
+ colorSchemeQuery.addEventListener("change", onColorChange);
2445
+ document.addEventListener("visibilitychange", onVisibilityChange);
2446
+ window.addEventListener("focus", onFocus);
2447
+ });
2448
+ ctx.onDisconnected(function() {
2449
+ landscapeQuery.removeEventListener("change", onOrientationChange);
2450
+ colorSchemeQuery.removeEventListener("change", onColorChange);
2451
+ document.removeEventListener("visibilitychange", onVisibilityChange);
2452
+ window.removeEventListener("focus", onFocus);
2453
+ });
2454
+ return {
2455
+ $$title,
2456
+ $visibility: readable($$visibility),
2457
+ $orientation: readable($$orientation),
2458
+ $colorScheme: readable($$colorScheme)
2459
+ };
2460
+ }
2461
+
2462
+ // src/stores/http.ts
2463
+ function HTTPStore(ctx) {
2464
+ ctx.name = "dolla/http";
2465
+ const fetch = ctx.options.fetch ?? getDefaultFetch();
2466
+ const middleware = [];
2467
+ async function request(method, uri, options) {
2468
+ return makeRequest({ ...options, method, uri, middleware, fetch });
2469
+ }
2470
+ return {
2471
+ /**
2472
+ * Adds a new middleware that will apply to subsequent requests.
2473
+ * Returns a function to remove this middleware.
2474
+ *
2475
+ * @param middleware - A middleware function that will intercept requests.
2476
+ */
2477
+ middleware(fn) {
2478
+ middleware.push(fn);
2479
+ return function remove() {
2480
+ middleware.splice(middleware.indexOf(fn), 1);
2481
+ };
2482
+ },
2483
+ async get(uri, options) {
2484
+ return request("get", uri, options);
2485
+ },
2486
+ async put(uri, options) {
2487
+ return request("put", uri, options);
2488
+ },
2489
+ async patch(uri, options) {
2490
+ return request("patch", uri, options);
2491
+ },
2492
+ async post(uri, options) {
2493
+ return request("post", uri, options);
2494
+ },
2495
+ async delete(uri, options) {
2496
+ return request("delete", uri, options);
2497
+ },
2498
+ async head(uri, options) {
2499
+ return request("head", uri, options);
2500
+ },
2501
+ async options(uri, options) {
2502
+ return request("options", uri, options);
2503
+ },
2504
+ async trace(uri, options) {
2505
+ return request("trace", uri, options);
2506
+ }
2507
+ };
2508
+ }
2509
+ function getDefaultFetch() {
2510
+ if (typeof window !== "undefined" && window.fetch) {
2511
+ return window.fetch.bind(window);
2512
+ }
2513
+ if (typeof global !== "undefined" && global.fetch) {
2514
+ return global.fetch.bind(global);
2515
+ }
2516
+ throw new Error("Running in neither browser nor node. Please run this app in one of the supported environments.");
2517
+ }
2518
+ var HTTPResponseError = class extends Error {
2519
+ response;
2520
+ constructor(response) {
2521
+ const { status, statusText, method, uri } = response;
2522
+ const message = `${status} ${statusText}: Request failed (${method.toUpperCase()} ${uri})`;
2523
+ super(message);
2524
+ this.response = response;
2525
+ }
2526
+ };
2527
+ async function makeRequest(config) {
2528
+ const { headers, query, fetch, middleware } = config;
2529
+ const request = {
2530
+ method: config.method,
2531
+ uri: config.uri,
2532
+ get sameOrigin() {
2533
+ return !request.uri.startsWith("http");
2534
+ },
2535
+ query: new URLSearchParams(),
2536
+ headers: new Headers(),
2537
+ body: config.body
2538
+ };
2539
+ if (headers) {
2540
+ if (headers instanceof Map || headers instanceof Headers) {
2541
+ headers.forEach((value, key) => {
2542
+ request.headers.set(key, value);
2543
+ });
2544
+ } else if (headers != null && typeof headers === "object" && !Array.isArray(headers)) {
2545
+ for (const name in headers) {
2546
+ request.headers.set(name, String(headers[name]));
2547
+ }
2548
+ } else {
2549
+ throw new TypeError(`Unknown headers type. Got: ${headers}`);
2550
+ }
2551
+ }
2552
+ if (query) {
2553
+ if (query instanceof Map || query instanceof URLSearchParams) {
2554
+ query.forEach((value, key) => {
2555
+ request.query.set(key, value);
2556
+ });
2557
+ } else if (query != null && typeof query === "object" && !Array.isArray(query)) {
2558
+ for (const name in query) {
2559
+ request.query.set(name, String(query[name]));
2560
+ }
2561
+ } else {
2562
+ throw new TypeError(`Unknown query params type. Got: ${query}`);
2563
+ }
2564
+ }
2565
+ let response;
2566
+ const handler = async () => {
2567
+ const query2 = request.query.toString();
2568
+ const fullURL = request.query.keys.length > 0 ? request.uri + "?" + query2 : request.uri;
2569
+ let reqBody;
2570
+ if (!request.headers.has("content-type") && isObject(request.body)) {
2571
+ request.headers.set("content-type", "application/json");
2572
+ reqBody = JSON.stringify(request.body);
2573
+ } else {
2574
+ reqBody = request.body;
2575
+ }
2576
+ const fetched = await fetch(fullURL, {
2577
+ method: request.method,
2578
+ headers: request.headers,
2579
+ body: reqBody
2580
+ });
2581
+ const headers2 = Object.fromEntries(fetched.headers.entries());
2582
+ const contentType = headers2["content-type"];
2583
+ let body;
2584
+ if (contentType?.includes("application/json")) {
2585
+ body = await fetched.json();
2586
+ } else if (contentType?.includes("application/x-www-form-urlencoded")) {
2587
+ body = await fetched.formData();
2588
+ } else {
2589
+ body = await fetched.text();
2590
+ }
2591
+ response = {
2592
+ method: request.method,
2593
+ uri: request.uri,
2594
+ status: fetched.status,
2595
+ statusText: fetched.statusText,
2596
+ headers: headers2,
2597
+ body
2598
+ };
2599
+ };
2600
+ if (middleware.length > 0) {
2601
+ const mount = (index = 0) => {
2602
+ const current = middleware[index];
2603
+ const next = middleware[index + 1] ? mount(index + 1) : handler;
2604
+ return async () => current(request, async () => {
2605
+ await next();
2606
+ return response;
2607
+ });
2608
+ };
2609
+ await mount()();
2610
+ } else {
2611
+ await handler();
2612
+ }
2613
+ if (response.status < 200 || response.status >= 400) {
2614
+ throw new HTTPResponseError(response);
2615
+ }
2616
+ return response;
2617
+ }
2618
+
2619
+ // src/stores/language.ts
2620
+ function LanguageStore(ctx) {
2621
+ ctx.name = "dolla/language";
2622
+ const languages = /* @__PURE__ */ new Map();
2623
+ Object.entries(ctx.options.languages).forEach(([tag, config]) => {
2624
+ languages.set(tag, new Language(tag, config));
2625
+ });
2626
+ ctx.info(
2627
+ `App supports ${languages.size} language${languages.size === 1 ? "" : "s"}: '${[...languages.keys()].join("', '")}'`
2628
+ );
2629
+ const $$isLoaded = writable(false);
2630
+ const $$language = writable(void 0);
2631
+ const $$translation = writable(void 0);
2632
+ const $noLanguageValue = readable("[NO LANGUAGE SET]");
2633
+ const translationCache = [];
2634
+ function getCached(key, values) {
2635
+ for (const entry of translationCache) {
2636
+ if (entry[0] === key && deepEqual(entry[1], values)) {
2637
+ return entry[2];
2638
+ }
2639
+ }
2640
+ }
2641
+ function replaceMustaches(template, values) {
2642
+ for (const name in values) {
2643
+ template = template.replace(`{{${name}}}`, String(values[name]));
2644
+ }
2645
+ return template;
2646
+ }
2647
+ const currentLanguage = ctx.options.currentLanguage ? languages.get(ctx.options.currentLanguage) : languages.get([...languages.keys()][0]);
2648
+ if (currentLanguage == null) {
2649
+ $$isLoaded.set(true);
2650
+ } else {
2651
+ ctx.info(`Current language is '${currentLanguage.tag}'.`);
2652
+ currentLanguage.getTranslation().then((translation) => {
2653
+ $$language.set(currentLanguage.tag);
2654
+ $$translation.set(translation);
2655
+ $$isLoaded.set(true);
2656
+ });
2657
+ }
2658
+ return {
2659
+ $isLoaded: readable($$isLoaded),
2660
+ $currentLanguage: readable($$language),
2661
+ supportedLanguages: [...languages.keys()],
2662
+ async setLanguage(tag) {
2663
+ if (!languages.has(tag)) {
2664
+ throw new Error(`Language '${tag}' is not supported.`);
2665
+ }
2666
+ const lang = languages.get(tag);
2667
+ try {
2668
+ const translation = await lang.getTranslation();
2669
+ $$translation.set(translation);
2670
+ $$language.set(tag);
2671
+ ctx.info("set language to " + tag);
2672
+ } catch (error) {
2673
+ if (error instanceof Error) {
2674
+ ctx.crash(error);
2675
+ }
2676
+ }
2677
+ },
2678
+ /**
2679
+ * Returns a Readable of the translated value.
2680
+
2681
+ * @param key - Key to the translated value.
2682
+ * @param values - A map of {{placeholder}} names and the values to replace them with.
2683
+ */
2684
+ translate(key, values) {
2685
+ if (!$$language.get()) {
2686
+ return $noLanguageValue;
2687
+ }
2688
+ const cached = getCached(key, values);
2689
+ if (cached) {
2690
+ return cached;
2691
+ }
2692
+ if (values) {
2693
+ const readableValues = {};
2694
+ for (const [key2, value] of Object.entries(values)) {
2695
+ if (typeof value?.observe === "function") {
2696
+ readableValues[key2] = value;
2697
+ }
2698
+ }
2699
+ const readableEntries = Object.entries(readableValues);
2700
+ if (readableEntries.length > 0) {
2701
+ const $merged = computed([$$translation, ...readableEntries.map((x) => x[1])], ([t, ...entryValues]) => {
2702
+ const entries = entryValues.map((_, i) => readableEntries[i]);
2703
+ const mergedValues = {
2704
+ ...values
2705
+ };
2706
+ for (let i = 0; i < entries.length; i++) {
2707
+ const key2 = entries[i][0];
2708
+ mergedValues[key2] = entryValues[i];
2709
+ }
2710
+ const result = resolve(t, key) || `[NO TRANSLATION: ${key}]`;
2711
+ return replaceMustaches(result, mergedValues);
2712
+ });
2713
+ translationCache.push([key, values, $merged]);
2714
+ return $merged;
2715
+ }
2716
+ }
2717
+ const $replaced = computed($$translation, (t) => {
2718
+ let result = resolve(t, key) || `[NO TRANSLATION: ${key}]`;
2719
+ if (values) {
2720
+ result = replaceMustaches(result, values);
2721
+ }
2722
+ return result;
2723
+ });
2724
+ translationCache.push([key, values, $replaced]);
2725
+ return $replaced;
2726
+ }
2727
+ };
2728
+ }
2729
+ function resolve(object, key) {
2730
+ const parsed = String(key).split(/[\.\[\]]/).filter((part) => part.trim() !== "");
2731
+ let value = object;
2732
+ while (parsed.length > 0) {
2733
+ const part = parsed.shift();
2734
+ if (value != null) {
2735
+ value = value[part];
2736
+ } else {
2737
+ value = void 0;
2738
+ }
2739
+ }
2740
+ return value;
2741
+ }
2742
+ var Language = class {
2743
+ #tag;
2744
+ #config;
2745
+ #translation;
2746
+ get tag() {
2747
+ return this.#tag;
2748
+ }
2749
+ constructor(tag, config) {
2750
+ this.#tag = tag;
2751
+ this.#config = config;
2752
+ }
2753
+ async getTranslation() {
2754
+ if (!this.#translation) {
2755
+ if (isFunction(this.#config.translation)) {
2756
+ const result = this.#config.translation();
2757
+ if (isPromise(result)) {
2758
+ const resolved = await result;
2759
+ assertObject(
2760
+ resolved,
2761
+ `Translation promise of language '${this.#tag}' must resolve to an object of translated strings. Got type: %t, value: %v`
2762
+ );
2763
+ this.#translation = resolved;
2764
+ } else if (isObject(result)) {
2765
+ this.#translation = result;
2766
+ } else {
2767
+ throw new TypeError(
2768
+ `Translation function of '${this.#tag}' must return an object or promise. Got type: ${typeOf(
2769
+ result
2770
+ )}, value: ${result}`
2771
+ );
2772
+ }
2773
+ } else if (isObject(this.#config.translation)) {
2774
+ this.#translation = this.#config.translation;
2775
+ } else {
2776
+ throw new TypeError(
2777
+ `Translation of '${this.#tag}' must be an object of translated strings, a function that returns one, or an async function that resolves to one. Got type: ${typeOf(
2778
+ this.#config.translation
2779
+ )}, value: ${this.#config.translation}`
2780
+ );
2781
+ }
2782
+ }
2783
+ return this.#translation;
2784
+ }
2785
+ };
2786
+
2787
+ // src/stores/render.ts
2788
+ function RenderStore(ctx) {
2789
+ ctx.name = "dolla/render";
2790
+ const keyedUpdates = /* @__PURE__ */ new Map();
2791
+ let unkeyedUpdates = [];
2792
+ let reads = [];
2793
+ let isUpdating = false;
2794
+ let isConnected = false;
2795
+ ctx.onConnected(() => {
2796
+ isConnected = true;
2797
+ });
2798
+ ctx.onDisconnected(() => {
2799
+ isConnected = false;
2800
+ });
2801
+ function runUpdates() {
2802
+ const totalQueued = keyedUpdates.size + unkeyedUpdates.length;
2803
+ if (!isConnected || totalQueued === 0) {
2804
+ isUpdating = false;
2805
+ }
2806
+ if (!isUpdating) {
2807
+ for (const callback of reads) {
2808
+ callback();
2809
+ }
2810
+ reads = [];
2811
+ return;
2812
+ }
2813
+ requestAnimationFrame(() => {
2814
+ ctx.info(`Batching ${keyedUpdates.size + unkeyedUpdates.length} queued DOM update(s).`);
2815
+ for (const callback of keyedUpdates.values()) {
2816
+ callback();
2817
+ }
2818
+ keyedUpdates.clear();
2819
+ for (const callback of unkeyedUpdates) {
2820
+ callback();
2821
+ }
2822
+ unkeyedUpdates = [];
2823
+ runUpdates();
2824
+ });
2825
+ }
2826
+ return {
2827
+ /**
2828
+ * Queues a callback to run in the next render batch.
2829
+ * Running your DOM mutations in update callbacks reduces layout thrashing.
2830
+ * Returns a Promise that resolves once the callback has run.
2831
+ */
2832
+ update(callback, key) {
2833
+ return new Promise((resolve2) => {
2834
+ if (key) {
2835
+ keyedUpdates.set(key, () => {
2836
+ callback();
2837
+ resolve2();
2838
+ });
2839
+ } else {
2840
+ unkeyedUpdates.push(() => {
2841
+ callback();
2842
+ resolve2();
2843
+ });
2844
+ }
2845
+ if (!isUpdating && isConnected) {
2846
+ isUpdating = true;
2847
+ runUpdates();
2848
+ }
2849
+ });
2850
+ },
2851
+ /**
2852
+ * Queues a callback that reads DOM information to run after the next render batch,
2853
+ * ensuring all writes have been performed before reading.
2854
+ * Returns a Promise that resolves once the callback has run.
2855
+ */
2856
+ read(callback) {
2857
+ return new Promise((resolve2) => {
2858
+ reads.push(() => {
2859
+ callback();
2860
+ resolve2();
2861
+ });
2862
+ if (!isUpdating && isConnected) {
2863
+ isUpdating = true;
2864
+ runUpdates();
2865
+ }
2866
+ });
2867
+ }
2868
+ };
2869
+ }
2870
+
2871
+ // node_modules/@babel/runtime/helpers/esm/extends.js
2872
+ function _extends() {
2873
+ _extends = Object.assign || function(target) {
2874
+ for (var i = 1; i < arguments.length; i++) {
2875
+ var source = arguments[i];
2876
+ for (var key in source) {
2877
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
2878
+ target[key] = source[key];
2879
+ }
2880
+ }
2881
+ }
2882
+ return target;
2883
+ };
2884
+ return _extends.apply(this, arguments);
2885
+ }
2886
+
2887
+ // node_modules/history/index.js
2888
+ var Action;
2889
+ (function(Action2) {
2890
+ Action2["Pop"] = "POP";
2891
+ Action2["Push"] = "PUSH";
2892
+ Action2["Replace"] = "REPLACE";
2893
+ })(Action || (Action = {}));
2894
+ var readOnly = true ? function(obj) {
2895
+ return Object.freeze(obj);
2896
+ } : function(obj) {
2897
+ return obj;
2898
+ };
2899
+ function warning(cond2, message) {
2900
+ if (!cond2) {
2901
+ if (typeof console !== "undefined")
2902
+ console.warn(message);
2903
+ try {
2904
+ throw new Error(message);
2905
+ } catch (e) {
2906
+ }
2907
+ }
2908
+ }
2909
+ var BeforeUnloadEventType = "beforeunload";
2910
+ var HashChangeEventType = "hashchange";
2911
+ var PopStateEventType = "popstate";
2912
+ function createBrowserHistory(options) {
2913
+ if (options === void 0) {
2914
+ options = {};
2915
+ }
2916
+ var _options = options, _options$window = _options.window, window2 = _options$window === void 0 ? document.defaultView : _options$window;
2917
+ var globalHistory = window2.history;
2918
+ function getIndexAndLocation() {
2919
+ var _window$location = window2.location, pathname = _window$location.pathname, search = _window$location.search, hash2 = _window$location.hash;
2920
+ var state = globalHistory.state || {};
2921
+ return [state.idx, readOnly({
2922
+ pathname,
2923
+ search,
2924
+ hash: hash2,
2925
+ state: state.usr || null,
2926
+ key: state.key || "default"
2927
+ })];
2928
+ }
2929
+ var blockedPopTx = null;
2930
+ function handlePop() {
2931
+ if (blockedPopTx) {
2932
+ blockers.call(blockedPopTx);
2933
+ blockedPopTx = null;
2934
+ } else {
2935
+ var nextAction = Action.Pop;
2936
+ var _getIndexAndLocation = getIndexAndLocation(), nextIndex = _getIndexAndLocation[0], nextLocation = _getIndexAndLocation[1];
2937
+ if (blockers.length) {
2938
+ if (nextIndex != null) {
2939
+ var delta = index - nextIndex;
2940
+ if (delta) {
2941
+ blockedPopTx = {
2942
+ action: nextAction,
2943
+ location: nextLocation,
2944
+ retry: function retry() {
2945
+ go(delta * -1);
2946
+ }
2947
+ };
2948
+ go(delta);
2949
+ }
2950
+ } else {
2951
+ true ? warning(
2952
+ false,
2953
+ // TODO: Write up a doc that explains our blocking strategy in
2954
+ // detail and link to it here so people can understand better what
2955
+ // is going on and how to avoid it.
2956
+ "You are trying to block a POP navigation to a location that was not created by the history library. The block will fail silently in production, but in general you should do all navigation with the history library (instead of using window.history.pushState directly) to avoid this situation."
2957
+ ) : void 0;
2958
+ }
2959
+ } else {
2960
+ applyTx(nextAction);
2961
+ }
2962
+ }
2963
+ }
2964
+ window2.addEventListener(PopStateEventType, handlePop);
2965
+ var action = Action.Pop;
2966
+ var _getIndexAndLocation2 = getIndexAndLocation(), index = _getIndexAndLocation2[0], location = _getIndexAndLocation2[1];
2967
+ var listeners = createEvents();
2968
+ var blockers = createEvents();
2969
+ if (index == null) {
2970
+ index = 0;
2971
+ globalHistory.replaceState(_extends({}, globalHistory.state, {
2972
+ idx: index
2973
+ }), "");
2974
+ }
2975
+ function createHref(to) {
2976
+ return typeof to === "string" ? to : createPath(to);
2977
+ }
2978
+ function getNextLocation(to, state) {
2979
+ if (state === void 0) {
2980
+ state = null;
2981
+ }
2982
+ return readOnly(_extends({
2983
+ pathname: location.pathname,
2984
+ hash: "",
2985
+ search: ""
2986
+ }, typeof to === "string" ? parsePath(to) : to, {
2987
+ state,
2988
+ key: createKey()
2989
+ }));
2990
+ }
2991
+ function getHistoryStateAndUrl(nextLocation, index2) {
2992
+ return [{
2993
+ usr: nextLocation.state,
2994
+ key: nextLocation.key,
2995
+ idx: index2
2996
+ }, createHref(nextLocation)];
2997
+ }
2998
+ function allowTx(action2, location2, retry) {
2999
+ return !blockers.length || (blockers.call({
3000
+ action: action2,
3001
+ location: location2,
3002
+ retry
3003
+ }), false);
3004
+ }
3005
+ function applyTx(nextAction) {
3006
+ action = nextAction;
3007
+ var _getIndexAndLocation3 = getIndexAndLocation();
3008
+ index = _getIndexAndLocation3[0];
3009
+ location = _getIndexAndLocation3[1];
3010
+ listeners.call({
3011
+ action,
3012
+ location
3013
+ });
3014
+ }
3015
+ function push(to, state) {
3016
+ var nextAction = Action.Push;
3017
+ var nextLocation = getNextLocation(to, state);
3018
+ function retry() {
3019
+ push(to, state);
3020
+ }
3021
+ if (allowTx(nextAction, nextLocation, retry)) {
3022
+ var _getHistoryStateAndUr = getHistoryStateAndUrl(nextLocation, index + 1), historyState = _getHistoryStateAndUr[0], url = _getHistoryStateAndUr[1];
3023
+ try {
3024
+ globalHistory.pushState(historyState, "", url);
3025
+ } catch (error) {
3026
+ window2.location.assign(url);
3027
+ }
3028
+ applyTx(nextAction);
3029
+ }
3030
+ }
3031
+ function replace(to, state) {
3032
+ var nextAction = Action.Replace;
3033
+ var nextLocation = getNextLocation(to, state);
3034
+ function retry() {
3035
+ replace(to, state);
3036
+ }
3037
+ if (allowTx(nextAction, nextLocation, retry)) {
3038
+ var _getHistoryStateAndUr2 = getHistoryStateAndUrl(nextLocation, index), historyState = _getHistoryStateAndUr2[0], url = _getHistoryStateAndUr2[1];
3039
+ globalHistory.replaceState(historyState, "", url);
3040
+ applyTx(nextAction);
3041
+ }
3042
+ }
3043
+ function go(delta) {
3044
+ globalHistory.go(delta);
3045
+ }
3046
+ var history = {
3047
+ get action() {
3048
+ return action;
3049
+ },
3050
+ get location() {
3051
+ return location;
3052
+ },
3053
+ createHref,
3054
+ push,
3055
+ replace,
3056
+ go,
3057
+ back: function back() {
3058
+ go(-1);
3059
+ },
3060
+ forward: function forward() {
3061
+ go(1);
3062
+ },
3063
+ listen: function listen(listener) {
3064
+ return listeners.push(listener);
3065
+ },
3066
+ block: function block(blocker) {
3067
+ var unblock = blockers.push(blocker);
3068
+ if (blockers.length === 1) {
3069
+ window2.addEventListener(BeforeUnloadEventType, promptBeforeUnload);
3070
+ }
3071
+ return function() {
3072
+ unblock();
3073
+ if (!blockers.length) {
3074
+ window2.removeEventListener(BeforeUnloadEventType, promptBeforeUnload);
3075
+ }
3076
+ };
3077
+ }
3078
+ };
3079
+ return history;
3080
+ }
3081
+ function createHashHistory(options) {
3082
+ if (options === void 0) {
3083
+ options = {};
3084
+ }
3085
+ var _options2 = options, _options2$window = _options2.window, window2 = _options2$window === void 0 ? document.defaultView : _options2$window;
3086
+ var globalHistory = window2.history;
3087
+ function getIndexAndLocation() {
3088
+ var _parsePath = parsePath(window2.location.hash.substr(1)), _parsePath$pathname = _parsePath.pathname, pathname = _parsePath$pathname === void 0 ? "/" : _parsePath$pathname, _parsePath$search = _parsePath.search, search = _parsePath$search === void 0 ? "" : _parsePath$search, _parsePath$hash = _parsePath.hash, hash2 = _parsePath$hash === void 0 ? "" : _parsePath$hash;
3089
+ var state = globalHistory.state || {};
3090
+ return [state.idx, readOnly({
3091
+ pathname,
3092
+ search,
3093
+ hash: hash2,
3094
+ state: state.usr || null,
3095
+ key: state.key || "default"
3096
+ })];
3097
+ }
3098
+ var blockedPopTx = null;
3099
+ function handlePop() {
3100
+ if (blockedPopTx) {
3101
+ blockers.call(blockedPopTx);
3102
+ blockedPopTx = null;
3103
+ } else {
3104
+ var nextAction = Action.Pop;
3105
+ var _getIndexAndLocation4 = getIndexAndLocation(), nextIndex = _getIndexAndLocation4[0], nextLocation = _getIndexAndLocation4[1];
3106
+ if (blockers.length) {
3107
+ if (nextIndex != null) {
3108
+ var delta = index - nextIndex;
3109
+ if (delta) {
3110
+ blockedPopTx = {
3111
+ action: nextAction,
3112
+ location: nextLocation,
3113
+ retry: function retry() {
3114
+ go(delta * -1);
3115
+ }
3116
+ };
3117
+ go(delta);
3118
+ }
3119
+ } else {
3120
+ true ? warning(
3121
+ false,
3122
+ // TODO: Write up a doc that explains our blocking strategy in
3123
+ // detail and link to it here so people can understand better
3124
+ // what is going on and how to avoid it.
3125
+ "You are trying to block a POP navigation to a location that was not created by the history library. The block will fail silently in production, but in general you should do all navigation with the history library (instead of using window.history.pushState directly) to avoid this situation."
3126
+ ) : void 0;
3127
+ }
3128
+ } else {
3129
+ applyTx(nextAction);
3130
+ }
3131
+ }
3132
+ }
3133
+ window2.addEventListener(PopStateEventType, handlePop);
3134
+ window2.addEventListener(HashChangeEventType, function() {
3135
+ var _getIndexAndLocation5 = getIndexAndLocation(), nextLocation = _getIndexAndLocation5[1];
3136
+ if (createPath(nextLocation) !== createPath(location)) {
3137
+ handlePop();
3138
+ }
3139
+ });
3140
+ var action = Action.Pop;
3141
+ var _getIndexAndLocation6 = getIndexAndLocation(), index = _getIndexAndLocation6[0], location = _getIndexAndLocation6[1];
3142
+ var listeners = createEvents();
3143
+ var blockers = createEvents();
3144
+ if (index == null) {
3145
+ index = 0;
3146
+ globalHistory.replaceState(_extends({}, globalHistory.state, {
3147
+ idx: index
3148
+ }), "");
3149
+ }
3150
+ function getBaseHref() {
3151
+ var base = document.querySelector("base");
3152
+ var href = "";
3153
+ if (base && base.getAttribute("href")) {
3154
+ var url = window2.location.href;
3155
+ var hashIndex = url.indexOf("#");
3156
+ href = hashIndex === -1 ? url : url.slice(0, hashIndex);
3157
+ }
3158
+ return href;
3159
+ }
3160
+ function createHref(to) {
3161
+ return getBaseHref() + "#" + (typeof to === "string" ? to : createPath(to));
3162
+ }
3163
+ function getNextLocation(to, state) {
3164
+ if (state === void 0) {
3165
+ state = null;
3166
+ }
3167
+ return readOnly(_extends({
3168
+ pathname: location.pathname,
3169
+ hash: "",
3170
+ search: ""
3171
+ }, typeof to === "string" ? parsePath(to) : to, {
3172
+ state,
3173
+ key: createKey()
3174
+ }));
3175
+ }
3176
+ function getHistoryStateAndUrl(nextLocation, index2) {
3177
+ return [{
3178
+ usr: nextLocation.state,
3179
+ key: nextLocation.key,
3180
+ idx: index2
3181
+ }, createHref(nextLocation)];
3182
+ }
3183
+ function allowTx(action2, location2, retry) {
3184
+ return !blockers.length || (blockers.call({
3185
+ action: action2,
3186
+ location: location2,
3187
+ retry
3188
+ }), false);
3189
+ }
3190
+ function applyTx(nextAction) {
3191
+ action = nextAction;
3192
+ var _getIndexAndLocation7 = getIndexAndLocation();
3193
+ index = _getIndexAndLocation7[0];
3194
+ location = _getIndexAndLocation7[1];
3195
+ listeners.call({
3196
+ action,
3197
+ location
3198
+ });
3199
+ }
3200
+ function push(to, state) {
3201
+ var nextAction = Action.Push;
3202
+ var nextLocation = getNextLocation(to, state);
3203
+ function retry() {
3204
+ push(to, state);
3205
+ }
3206
+ true ? warning(nextLocation.pathname.charAt(0) === "/", "Relative pathnames are not supported in hash history.push(" + JSON.stringify(to) + ")") : void 0;
3207
+ if (allowTx(nextAction, nextLocation, retry)) {
3208
+ var _getHistoryStateAndUr3 = getHistoryStateAndUrl(nextLocation, index + 1), historyState = _getHistoryStateAndUr3[0], url = _getHistoryStateAndUr3[1];
3209
+ try {
3210
+ globalHistory.pushState(historyState, "", url);
3211
+ } catch (error) {
3212
+ window2.location.assign(url);
3213
+ }
3214
+ applyTx(nextAction);
3215
+ }
3216
+ }
3217
+ function replace(to, state) {
3218
+ var nextAction = Action.Replace;
3219
+ var nextLocation = getNextLocation(to, state);
3220
+ function retry() {
3221
+ replace(to, state);
3222
+ }
3223
+ true ? warning(nextLocation.pathname.charAt(0) === "/", "Relative pathnames are not supported in hash history.replace(" + JSON.stringify(to) + ")") : void 0;
3224
+ if (allowTx(nextAction, nextLocation, retry)) {
3225
+ var _getHistoryStateAndUr4 = getHistoryStateAndUrl(nextLocation, index), historyState = _getHistoryStateAndUr4[0], url = _getHistoryStateAndUr4[1];
3226
+ globalHistory.replaceState(historyState, "", url);
3227
+ applyTx(nextAction);
3228
+ }
3229
+ }
3230
+ function go(delta) {
3231
+ globalHistory.go(delta);
3232
+ }
3233
+ var history = {
3234
+ get action() {
3235
+ return action;
3236
+ },
3237
+ get location() {
3238
+ return location;
3239
+ },
3240
+ createHref,
3241
+ push,
3242
+ replace,
3243
+ go,
3244
+ back: function back() {
3245
+ go(-1);
3246
+ },
3247
+ forward: function forward() {
3248
+ go(1);
3249
+ },
3250
+ listen: function listen(listener) {
3251
+ return listeners.push(listener);
3252
+ },
3253
+ block: function block(blocker) {
3254
+ var unblock = blockers.push(blocker);
3255
+ if (blockers.length === 1) {
3256
+ window2.addEventListener(BeforeUnloadEventType, promptBeforeUnload);
3257
+ }
3258
+ return function() {
3259
+ unblock();
3260
+ if (!blockers.length) {
3261
+ window2.removeEventListener(BeforeUnloadEventType, promptBeforeUnload);
3262
+ }
3263
+ };
3264
+ }
3265
+ };
3266
+ return history;
3267
+ }
3268
+ function promptBeforeUnload(event) {
3269
+ event.preventDefault();
3270
+ event.returnValue = "";
3271
+ }
3272
+ function createEvents() {
3273
+ var handlers = [];
3274
+ return {
3275
+ get length() {
3276
+ return handlers.length;
3277
+ },
3278
+ push: function push(fn) {
3279
+ handlers.push(fn);
3280
+ return function() {
3281
+ handlers = handlers.filter(function(handler) {
3282
+ return handler !== fn;
3283
+ });
3284
+ };
3285
+ },
3286
+ call: function call(arg) {
3287
+ handlers.forEach(function(fn) {
3288
+ return fn && fn(arg);
3289
+ });
3290
+ }
3291
+ };
3292
+ }
3293
+ function createKey() {
3294
+ return Math.random().toString(36).substr(2, 8);
3295
+ }
3296
+ function createPath(_ref) {
3297
+ var _ref$pathname = _ref.pathname, pathname = _ref$pathname === void 0 ? "/" : _ref$pathname, _ref$search = _ref.search, search = _ref$search === void 0 ? "" : _ref$search, _ref$hash = _ref.hash, hash2 = _ref$hash === void 0 ? "" : _ref$hash;
3298
+ if (search && search !== "?")
3299
+ pathname += search.charAt(0) === "?" ? search : "?" + search;
3300
+ if (hash2 && hash2 !== "#")
3301
+ pathname += hash2.charAt(0) === "#" ? hash2 : "#" + hash2;
3302
+ return pathname;
3303
+ }
3304
+ function parsePath(path) {
3305
+ var parsedPath = {};
3306
+ if (path) {
3307
+ var hashIndex = path.indexOf("#");
3308
+ if (hashIndex >= 0) {
3309
+ parsedPath.hash = path.substr(hashIndex);
3310
+ path = path.substr(0, hashIndex);
3311
+ }
3312
+ var searchIndex = path.indexOf("?");
3313
+ if (searchIndex >= 0) {
3314
+ parsedPath.search = path.substr(searchIndex);
3315
+ path = path.substr(0, searchIndex);
3316
+ }
3317
+ if (path) {
3318
+ parsedPath.pathname = path;
3319
+ }
3320
+ }
3321
+ return parsedPath;
3322
+ }
3323
+
3324
+ // src/stores/router.ts
3325
+ function RouterStore(ctx) {
3326
+ ctx.name = "dolla/router";
3327
+ const { appContext, elementContext } = getStoreSecrets(ctx);
3328
+ let history;
3329
+ if (ctx.options.history) {
3330
+ history = ctx.options.history;
3331
+ } else if (ctx.options.hash) {
3332
+ history = createHashHistory();
3333
+ } else {
3334
+ history = createBrowserHistory();
3335
+ }
3336
+ for (const route of ctx.options.routes) {
3337
+ if (route.meta.redirect) {
3338
+ let redirectPath;
3339
+ if (isFunction(route.meta.redirect)) {
3340
+ throw new Error(`Redirect functions are not yet supported.`);
3341
+ } else if (isString(route.meta.redirect)) {
3342
+ redirectPath = route.meta.redirect;
3343
+ } else {
3344
+ throw new TypeError(`Expected a string or redirect function. Got: ${route.meta.redirect}`);
3345
+ }
3346
+ const match = matchRoutes(ctx.options.routes, redirectPath, {
3347
+ willMatch(r) {
3348
+ return r !== route;
3349
+ }
3350
+ });
3351
+ if (!match) {
3352
+ throw new Error(`Found a redirect to an undefined URL. From '${route.pattern}' to '${route.meta.redirect}'`);
3353
+ }
3354
+ }
3355
+ }
3356
+ const $$pattern = writable(null);
3357
+ const $$path = writable("");
3358
+ const $$params = writable({});
3359
+ const $$query = writable({});
3360
+ let isRouteChange = false;
3361
+ ctx.observe($$query, (current) => {
3362
+ if (isRouteChange) {
3363
+ isRouteChange = false;
3364
+ return;
3365
+ }
3366
+ const params = new URLSearchParams();
3367
+ for (const key in current) {
3368
+ params.set(key, String(current[key]));
3369
+ }
3370
+ history.replace({
3371
+ pathname: history.location.pathname,
3372
+ search: "?" + params.toString()
3373
+ });
3374
+ });
3375
+ ctx.onConnected(() => {
3376
+ history.listen(onRouteChange);
3377
+ onRouteChange(history);
3378
+ catchLinks(appContext.rootElement, (anchor) => {
3379
+ let href = anchor.getAttribute("href");
3380
+ if (!/^https?:\/\/|^\//.test(href)) {
3381
+ href = joinPath([history.location.pathname, href]);
3382
+ }
3383
+ history.push(href);
3384
+ });
3385
+ });
3386
+ let activeLayers = [];
3387
+ let lastQuery;
3388
+ const onRouteChange = async ({ location }) => {
3389
+ if (location.search !== lastQuery) {
3390
+ lastQuery = location.search;
3391
+ isRouteChange = true;
3392
+ $$query.set(parseQueryParams(location.search));
3393
+ }
3394
+ const matched = matchRoutes(ctx.options.routes, location.pathname);
3395
+ if (!matched) {
3396
+ $$pattern.set(null);
3397
+ $$path.set(location.pathname);
3398
+ $$params.set({
3399
+ wildcard: location.pathname
3400
+ });
3401
+ return;
3402
+ }
3403
+ ctx.info(`Matched route: '${matched.pattern}'`);
3404
+ if (matched.meta.redirect != null) {
3405
+ if (typeof matched.meta.redirect === "string") {
3406
+ let path = matched.meta.redirect;
3407
+ for (const key in matched.params) {
3408
+ path = path.replace(":" + key, matched.params[key].toString());
3409
+ }
3410
+ ctx.info(`Redirecting to: '${path}'`);
3411
+ history.replace(path);
3412
+ } else if (typeof matched.meta.redirect === "function") {
3413
+ throw new Error(`Redirect functions aren't implemented yet.`);
3414
+ } else {
3415
+ throw new TypeError(`Redirect must either be a path string or a function.`);
3416
+ }
3417
+ } else {
3418
+ $$path.set(matched.path);
3419
+ $$params.set(matched.params);
3420
+ if (matched.pattern !== $$pattern.get()) {
3421
+ $$pattern.set(matched.pattern);
3422
+ const layers = matched.meta.layers;
3423
+ for (let i = 0; i < layers.length; i++) {
3424
+ const matchedLayer = layers[i];
3425
+ const activeLayer = activeLayers[i];
3426
+ if (activeLayer?.id !== matchedLayer.id) {
3427
+ ctx.info(`Replacing layer ${i} (active ID: ${activeLayer?.id}, matched ID: ${matchedLayer.id})`);
3428
+ activeLayers = activeLayers.slice(0, i);
3429
+ const parentLayer = activeLayers[activeLayers.length - 1];
3430
+ const renderContext = { appContext, elementContext };
3431
+ const rendered = renderMarkupToDOM(matchedLayer.markup, renderContext);
3432
+ const handle = getRenderHandle(rendered);
3433
+ requestAnimationFrame(() => {
3434
+ if (activeLayer && activeLayer.handle.connected) {
3435
+ activeLayer.handle.disconnect();
3436
+ }
3437
+ if (parentLayer) {
3438
+ parentLayer.handle.setChildren(rendered);
3439
+ } else {
3440
+ appContext.rootView.setChildren(rendered);
3441
+ }
3442
+ });
3443
+ activeLayers.push({ id: matchedLayer.id, handle });
3444
+ }
3445
+ }
3446
+ }
3447
+ }
3448
+ };
3449
+ function navigate(path, options = {}) {
3450
+ let joined;
3451
+ if (Array.isArray(path)) {
3452
+ joined = joinPath(path);
3453
+ } else {
3454
+ joined = path.toString();
3455
+ }
3456
+ joined = resolvePath(history.location.pathname, joined);
3457
+ if (options.replace) {
3458
+ history.replace(joined);
3459
+ } else {
3460
+ history.push(joined);
3461
+ }
3462
+ }
3463
+ return {
3464
+ /**
3465
+ * The currently matched route pattern, if any.
3466
+ */
3467
+ $pattern: readable($$pattern),
3468
+ /**
3469
+ * The current URL path.
3470
+ */
3471
+ $path: readable($$path),
3472
+ /**
3473
+ * The current named path params.
3474
+ */
3475
+ $params: readable($$params),
3476
+ /**
3477
+ * The current query params. Changes to this object will be reflected in the URL.
3478
+ */
3479
+ $$query,
3480
+ /**
3481
+ * Navigate backward. Pass a number of steps to hit the back button that many times.
3482
+ */
3483
+ back(steps = 1) {
3484
+ history.go(-steps);
3485
+ },
3486
+ /**
3487
+ * Navigate forward. Pass a number of steps to hit the forward button that many times.
3488
+ */
3489
+ forward(steps = 1) {
3490
+ history.go(steps);
3491
+ },
3492
+ /**
3493
+ * Navigates to another route.
3494
+ *
3495
+ * @example
3496
+ * navigate("/login"); // navigate to `/login`
3497
+ * navigate(["/users", 215], { replace: true }); // replace current history entry with `/users/215`
3498
+ *
3499
+ * @param args - One or more path segments optionally followed by an options object.
3500
+ */
3501
+ navigate
3502
+ };
3503
+ }
3504
+ var safeExternalLink = /(noopener|noreferrer) (noopener|noreferrer)/;
3505
+ var protocolLink = /^[\w-_]+:/;
3506
+ function catchLinks(root, callback, _window = window) {
3507
+ function traverse(node) {
3508
+ if (!node || node === root) {
3509
+ return null;
3510
+ }
3511
+ if (node.localName !== "a" || node.href === void 0) {
3512
+ return traverse(node.parentNode);
3513
+ }
3514
+ return node;
3515
+ }
3516
+ function handler(e) {
3517
+ if (e.button && e.button !== 0 || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey || e.defaultPrevented) {
3518
+ return;
3519
+ }
3520
+ const anchor = traverse(e.target);
3521
+ if (!anchor) {
3522
+ return;
3523
+ }
3524
+ if (_window.location.protocol !== anchor.protocol || _window.location.hostname !== anchor.hostname || _window.location.port !== anchor.port || anchor.hasAttribute("data-router-ignore") || anchor.hasAttribute("download") || anchor.getAttribute("target") === "_blank" && safeExternalLink.test(anchor.getAttribute("rel")) || protocolLink.test(anchor.getAttribute("href"))) {
3525
+ return;
3526
+ }
3527
+ e.preventDefault();
3528
+ callback(anchor);
3529
+ }
3530
+ root.addEventListener("click", handler);
3531
+ return function cancel() {
3532
+ root.removeEventListener("click", handler);
3533
+ };
3534
+ }
3535
+
3536
+ // src/app.ts
3537
+ function DefaultRootView(_, ctx) {
3538
+ return ctx.outlet();
3539
+ }
3540
+ function makeApp(options) {
3541
+ if (options && !isObject(options)) {
3542
+ throw new TypeError(`App options must be an object. Got: ${options}`);
3543
+ }
3544
+ let isConnected = false;
3545
+ let mainView = m(DefaultRootView);
3546
+ let configureCallback;
3547
+ const settings = merge(
3548
+ {
3549
+ debug: {
3550
+ filter: "*,-dolla/*",
3551
+ log: "development",
3552
+ // Only print logs in development.
3553
+ warn: "development",
3554
+ // Only print warnings in development.
3555
+ error: true
3556
+ // Always print errors.
3557
+ },
3558
+ router: {
3559
+ hash: false
3560
+ },
3561
+ mode: "production"
3562
+ },
3563
+ options ?? {}
3564
+ );
3565
+ const stores = /* @__PURE__ */ new Map([
3566
+ ["dialog", { store: DialogStore }],
3567
+ ["router", { store: RouterStore }],
3568
+ ["document", { store: DocumentStore }],
3569
+ ["http", { store: HTTPStore }],
3570
+ ["language", { store: LanguageStore }],
3571
+ ["render", { store: RenderStore }]
3572
+ ]);
3573
+ const languages = /* @__PURE__ */ new Map();
3574
+ let currentLanguage;
3575
+ let layerId = 0;
3576
+ let routes = [];
3577
+ function prepareRoute(route, layers = []) {
3578
+ if (!isObject(route) || !isString(route.pattern)) {
3579
+ throw new TypeError(`Route configs must be objects with a 'pattern' string property. Got: ${route}`);
3580
+ }
3581
+ const parts = splitPath(route.pattern);
3582
+ if (parts[parts.length - 1] === "*") {
3583
+ parts.pop();
3584
+ }
3585
+ const routes2 = [];
3586
+ if (route.redirect) {
3587
+ let redirect = route.redirect;
3588
+ if (isString(redirect)) {
3589
+ redirect = resolvePath(joinPath(parts), redirect);
3590
+ if (!redirect.startsWith("/")) {
3591
+ redirect = "/" + redirect;
3592
+ }
3593
+ }
3594
+ routes2.push({
3595
+ pattern: route.pattern,
3596
+ meta: {
3597
+ redirect
3598
+ }
3599
+ });
3600
+ return routes2;
3601
+ }
3602
+ let view;
3603
+ if (!route.view) {
3604
+ view = DefaultRootView;
3605
+ } else if (typeof route.view === "function") {
3606
+ view = route.view;
3607
+ } else {
3608
+ throw new TypeError(`Route '${route.pattern}' expected a view function. Got: ${route.view}`);
3609
+ }
3610
+ const markup = m(view);
3611
+ const layer = { id: layerId++, markup };
3612
+ if (route.subroutes) {
3613
+ const router = {
3614
+ route: (pattern, view2, subroutes) => {
3615
+ pattern = joinPath([...parts, pattern]);
3616
+ routes2.push(...prepareRoute({ pattern, view: view2, subroutes }));
3617
+ return router;
3618
+ },
3619
+ redirect: (pattern, redirect) => {
3620
+ pattern = joinPath([...parts, pattern]);
3621
+ routes2.push(...prepareRoute({ pattern, redirect }));
3622
+ return router;
3623
+ }
3624
+ };
3625
+ route.subroutes(router);
3626
+ } else {
3627
+ routes2.push({
3628
+ pattern: route.pattern,
3629
+ meta: {
3630
+ pattern: route.pattern,
3631
+ layers: [...layers, layer]
3632
+ }
3633
+ });
3634
+ }
3635
+ return routes2;
3636
+ }
3637
+ const crashCollector = new CrashCollector();
3638
+ const debugHub = new DebugHub({ ...settings.debug, crashCollector, mode: settings.mode });
3639
+ const debugChannel = debugHub.channel({ name: "dolla/App" });
3640
+ crashCollector.onError(async ({ error, severity, componentName }) => {
3641
+ if (severity === "crash") {
3642
+ await disconnect();
3643
+ const instance = initView({
3644
+ view: DefaultCrashPage,
3645
+ appContext,
3646
+ elementContext,
3647
+ props: {
3648
+ message: error.message,
3649
+ error,
3650
+ componentName
3651
+ }
3652
+ });
3653
+ instance.connect(appContext.rootElement);
3654
+ }
3655
+ });
3656
+ async function connect(selector) {
3657
+ return new Promise(async (resolve2) => {
3658
+ let element = null;
3659
+ if (isString(selector)) {
3660
+ element = document.querySelector(selector);
3661
+ assertInstanceOf(HTMLElement, element, `Selector string '${selector}' did not match any element.`);
3662
+ }
3663
+ assertInstanceOf(HTMLElement, element, "Expected a DOM node or a selector string. Got type: %t, value: %v");
3664
+ appContext.rootElement = element;
3665
+ routes = sortRoutes(routes);
3666
+ const language = stores.get("language");
3667
+ stores.set("language", {
3668
+ ...language,
3669
+ options: {
3670
+ languages: Object.fromEntries(languages.entries()),
3671
+ currentLanguage
3672
+ }
3673
+ });
3674
+ const router = stores.get("router");
3675
+ stores.set("router", {
3676
+ ...router,
3677
+ options: {
3678
+ options: settings.router,
3679
+ routes
3680
+ }
3681
+ });
3682
+ debugChannel.info(`Total routes: ${routes.length}`);
3683
+ appContext.rootView = initView({
3684
+ view: mainView.type,
3685
+ props: mainView.props,
3686
+ appContext,
3687
+ elementContext
3688
+ });
3689
+ for (let [key, item] of stores.entries()) {
3690
+ const { store, options: options2 } = item;
3691
+ const channelPrefix = isString(key) ? "dolla/store" : "store";
3692
+ const label = isString(key) ? key : store.name ?? "(anonymous)";
3693
+ const config = {
3694
+ store,
3695
+ appContext,
3696
+ elementContext,
3697
+ channelPrefix,
3698
+ label,
3699
+ options: options2 ?? {}
3700
+ };
3701
+ const instance = initStore(config);
3702
+ instance.setup();
3703
+ stores.set(key, { ...item, instance });
3704
+ }
3705
+ for (const { instance } of stores.values()) {
3706
+ instance.connect();
3707
+ }
3708
+ if (configureCallback) {
3709
+ await configureCallback({
3710
+ // TODO: Add context methods
3711
+ });
3712
+ }
3713
+ const { $isLoaded } = stores.get("language").instance.exports;
3714
+ const done = () => {
3715
+ appContext.rootView.connect(appContext.rootElement);
3716
+ isConnected = true;
3717
+ resolve2();
3718
+ };
3719
+ if ($isLoaded.get()) {
3720
+ return done();
3721
+ }
3722
+ const stop = observe($isLoaded, (isLoaded) => {
3723
+ if (isLoaded) {
3724
+ stop();
3725
+ done();
3726
+ }
3727
+ });
3728
+ });
3729
+ }
3730
+ async function disconnect() {
3731
+ if (isConnected) {
3732
+ appContext.rootView.disconnect();
3733
+ isConnected = false;
3734
+ for (const { instance } of stores.values()) {
3735
+ instance.disconnect();
3736
+ }
3737
+ }
3738
+ }
3739
+ const appContext = {
3740
+ crashCollector,
3741
+ debugHub,
3742
+ stores,
3743
+ mode: settings.mode ?? "production"
3744
+ // $dialogs - added by dialog store
3745
+ };
3746
+ const elementContext = {
3747
+ stores: /* @__PURE__ */ new Map()
3748
+ };
3749
+ const app = {
3750
+ connect,
3751
+ disconnect,
3752
+ get isConnected() {
3753
+ return isConnected;
3754
+ },
3755
+ main(view, attributes) {
3756
+ if (mainView.type !== DefaultRootView) {
3757
+ debugChannel.warn(`Root view is already defined. Only the final main call will take effect.`);
3758
+ }
3759
+ if (typeof view === "function") {
3760
+ mainView = m(view, attributes);
3761
+ } else {
3762
+ throw new TypeError(`Expected a view function. Got type: ${typeOf(view)}, value: ${view}`);
3763
+ }
3764
+ return app;
3765
+ },
3766
+ store(store, options2) {
3767
+ let config;
3768
+ if (isFunction(store)) {
3769
+ config = { store, options: options2 };
3770
+ } else {
3771
+ throw new TypeError(`Expected a store function. Got type: ${typeOf(store)}, value: ${store}`);
3772
+ }
3773
+ assertFunction(store, "Expected a store function or a store config object. Got type: %t, value: %v");
3774
+ stores.set(store, config);
3775
+ return app;
3776
+ },
3777
+ getStore(store) {
3778
+ const match = stores.get(store);
3779
+ const name = isString(store) ? store : store.name;
3780
+ if (!match) {
3781
+ throw new Error(`Store '${name}' is not registered on this app.`);
3782
+ }
3783
+ if (!match.instance) {
3784
+ throw new Error(`Store '${name}' is not yet initialized. App must be connected first.`);
3785
+ }
3786
+ return match.instance.exports;
3787
+ },
3788
+ language(tag, config) {
3789
+ languages.set(tag, config);
3790
+ return app;
3791
+ },
3792
+ setLanguage(tag, fallback) {
3793
+ if (tag === "auto") {
3794
+ let tags = [];
3795
+ if (typeof navigator === "object") {
3796
+ const nav = navigator;
3797
+ if (nav.languages?.length > 0) {
3798
+ tags.push(...nav.languages);
3799
+ } else if (nav.language) {
3800
+ tags.push(nav.language);
3801
+ } else if (nav.browserLanguage) {
3802
+ tags.push(nav.browserLanguage);
3803
+ } else if (nav.userLanguage) {
3804
+ tags.push(nav.userLanguage);
3805
+ }
3806
+ }
3807
+ for (const tag2 of tags) {
3808
+ if (languages.has(tag2)) {
3809
+ currentLanguage = tag2;
3810
+ return this;
3811
+ }
3812
+ }
3813
+ if (!currentLanguage && fallback) {
3814
+ if (languages.has(fallback)) {
3815
+ currentLanguage = fallback;
3816
+ }
3817
+ }
3818
+ } else {
3819
+ if (languages.has(tag)) {
3820
+ currentLanguage = tag;
3821
+ } else {
3822
+ throw new Error(`Language '${tag}' has not been added to this app yet.`);
3823
+ }
3824
+ }
3825
+ return app;
3826
+ },
3827
+ route(pattern, view, subroutes) {
3828
+ assertString(pattern, "Pattern must be a string. Got type: %t, value: %v");
3829
+ if (view == null) {
3830
+ assertFunction(subroutes, "Sub routes must be defined when `view` is null.");
3831
+ }
3832
+ prepareRoute({ pattern, view, subroutes }).forEach((route) => {
3833
+ routes.push({
3834
+ pattern: route.pattern,
3835
+ meta: route.meta,
3836
+ fragments: patternToFragments(route.pattern)
3837
+ });
3838
+ });
3839
+ return app;
3840
+ },
3841
+ redirect(pattern, redirect) {
3842
+ if (!isFunction(redirect) && !isString(redirect)) {
3843
+ throw new TypeError(`Expected a redirect path or function. Got type: ${typeOf(redirect)}, value: ${redirect}`);
3844
+ }
3845
+ prepareRoute({ pattern, redirect }).forEach((route) => {
3846
+ routes.push({
3847
+ pattern: route.pattern,
3848
+ meta: route.meta,
3849
+ fragments: patternToFragments(route.pattern)
3850
+ });
3851
+ });
3852
+ return app;
3853
+ },
3854
+ configure(callback) {
3855
+ if (configureCallback !== void 0) {
3856
+ debugChannel.warn(`Configure callback is already defined. Only the final configure call will take effect.`);
3857
+ }
3858
+ configureCallback = callback;
3859
+ return app;
3860
+ }
3861
+ };
3862
+ return app;
3863
+ }
3864
+ function DefaultCrashPage({ message, error, componentName }) {
3865
+ return m(
3866
+ "div",
3867
+ {
3868
+ style: {
3869
+ backgroundColor: "#880000",
3870
+ color: "#fff",
3871
+ padding: "2rem",
3872
+ position: "fixed",
3873
+ inset: 0,
3874
+ fontSize: "20px"
3875
+ }
3876
+ },
3877
+ m("h1", { style: { marginBottom: "0.5rem" } }, "The app has crashed"),
3878
+ m(
3879
+ "p",
3880
+ { style: { marginBottom: "0.25rem" } },
3881
+ m("span", { style: { fontFamily: "monospace" } }, componentName),
3882
+ " says:"
3883
+ ),
3884
+ m(
3885
+ "blockquote",
3886
+ {
3887
+ style: {
3888
+ backgroundColor: "#991111",
3889
+ padding: "0.25em",
3890
+ borderRadius: "6px",
3891
+ fontFamily: "monospace",
3892
+ marginBottom: "1rem"
3893
+ }
3894
+ },
3895
+ m(
3896
+ "span",
3897
+ {
3898
+ style: {
3899
+ display: "inline-block",
3900
+ backgroundColor: "red",
3901
+ padding: "0.1em 0.4em",
3902
+ marginRight: "0.5em",
3903
+ borderRadius: "4px",
3904
+ fontSize: "0.9em",
3905
+ fontWeight: "bold"
3906
+ }
3907
+ },
3908
+ error.name
3909
+ ),
3910
+ message
3911
+ ),
3912
+ m("p", {}, "Please see the browser console for details.")
3913
+ );
3914
+ }
3915
+
3916
+ // src/spring.ts
3917
+ function spring(initialValue, options) {
3918
+ const mass = options?.mass ?? 2;
3919
+ const stiffness = options?.stiffness ?? 1200;
3920
+ const damping = options?.damping ?? 160;
3921
+ const velocity = options?.velocity ?? 5;
3922
+ const endAmplitude = options?.endAmplitude ?? 1e-3;
3923
+ const endWindow = options?.endWindow ?? 20;
3924
+ const $$currentValue = writable(initialValue);
3925
+ let nextId = 0;
3926
+ let currentAnimationId;
3927
+ const snapTo = (newValue) => {
3928
+ currentAnimationId = void 0;
3929
+ $$currentValue.set(newValue);
3930
+ };
3931
+ const animateTo = async (endValue, options2) => {
3932
+ const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
3933
+ if (mediaQuery.matches) {
3934
+ return snapTo(endValue);
3935
+ }
3936
+ const _endAmplitude = readable(options2?.endAmplitude ?? endAmplitude).get();
3937
+ const _endWindow = readable(options2?.endWindow ?? endWindow).get();
3938
+ return new Promise((resolve2) => {
3939
+ const id = nextId++;
3940
+ const amplitude = makeAmplitudeMeasurer(_endWindow);
3941
+ const springParams = {
3942
+ mass: options2?.mass ?? mass,
3943
+ stiffness: options2?.stiffness ?? stiffness,
3944
+ damping: options2?.damping ?? damping,
3945
+ velocity: options2?.velocity ?? velocity
3946
+ };
3947
+ const startTime = Date.now();
3948
+ const startValue = $$currentValue.get();
3949
+ const step = () => {
3950
+ if (currentAnimationId !== id) {
3951
+ resolve2();
3952
+ return;
3953
+ }
3954
+ const elapsedTime = Date.now() - startTime;
3955
+ const proportion = solve(springParams, elapsedTime / 1e3);
3956
+ $$currentValue.set(startValue + (endValue - startValue) * proportion);
3957
+ amplitude.sample(proportion);
3958
+ if (amplitude.value && amplitude.value < _endAmplitude) {
3959
+ currentAnimationId = void 0;
3960
+ $$currentValue.set(endValue);
3961
+ }
3962
+ window.requestAnimationFrame(step);
3963
+ };
3964
+ currentAnimationId = id;
3965
+ window.requestAnimationFrame(step);
3966
+ });
3967
+ };
3968
+ return {
3969
+ get: $$currentValue.get,
3970
+ set: snapTo,
3971
+ update: (callback) => {
3972
+ const newValue = callback($$currentValue.get());
3973
+ snapTo(newValue);
3974
+ },
3975
+ [OBSERVE]: $$currentValue[OBSERVE],
3976
+ animateTo
3977
+ };
3978
+ }
3979
+ function solve(parameters, elapsedSeconds) {
3980
+ const mass = unwrap(parameters.mass);
3981
+ const stiffness = unwrap(parameters.stiffness);
3982
+ const damping = unwrap(parameters.damping);
3983
+ const initialVelocity = unwrap(parameters.velocity);
3984
+ const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass));
3985
+ const speed = Math.sqrt(stiffness / mass);
3986
+ let B;
3987
+ let position;
3988
+ if (dampingRatio < 1) {
3989
+ const dampedSpeed = speed * Math.sqrt(1 - dampingRatio * dampingRatio);
3990
+ B = (dampingRatio * speed + -initialVelocity) / dampedSpeed;
3991
+ position = (Math.cos(dampedSpeed * elapsedSeconds) + B * Math.sin(dampedSpeed * elapsedSeconds)) * Math.exp(-elapsedSeconds * speed * dampingRatio);
3992
+ } else {
3993
+ B = speed + -initialVelocity;
3994
+ position = (1 + B * elapsedSeconds) * Math.exp(-elapsedSeconds * speed);
3995
+ }
3996
+ return 1 - position;
3997
+ }
3998
+ function makeAmplitudeMeasurer(resolution) {
3999
+ const samples = [];
4000
+ return {
4001
+ sample(value) {
4002
+ samples.push(value);
4003
+ while (samples.length > resolution) {
4004
+ samples.shift();
4005
+ }
4006
+ },
4007
+ get value() {
4008
+ if (samples.length < resolution) {
4009
+ return null;
4010
+ }
4011
+ return Math.max(...samples) - Math.min(...samples);
4012
+ }
4013
+ };
4014
+ }
4015
+
4016
+ // src/views/fragment.ts
4017
+ function Fragment(_, ctx) {
4018
+ return ctx.outlet();
4019
+ }
4020
+
4021
+ // src/views/store-scope.ts
4022
+ function StoreScope(props, ctx) {
4023
+ const { appContext, elementContext } = getViewSecrets(ctx);
4024
+ const instance = initStore({
4025
+ store: props.store,
4026
+ options: props.options,
4027
+ appContext,
4028
+ elementContext
4029
+ });
4030
+ instance.setup();
4031
+ elementContext.stores.set(props.store, {
4032
+ store: props.store,
4033
+ options: props.options,
4034
+ instance
4035
+ });
4036
+ ctx.beforeConnect(() => {
4037
+ return instance.connect();
4038
+ });
4039
+ ctx.onDisconnected(() => {
4040
+ instance.disconnect();
4041
+ });
4042
+ return ctx.outlet();
4043
+ }
4044
+ export {
4045
+ Fragment,
4046
+ StoreScope,
4047
+ computed,
4048
+ cond,
4049
+ isReadable,
4050
+ isWritable,
4051
+ m,
4052
+ makeApp,
4053
+ observe,
4054
+ portal,
4055
+ proxy,
4056
+ readable,
4057
+ repeat,
4058
+ spring,
4059
+ unwrap,
4060
+ writable
4061
+ };
4062
+ //# sourceMappingURL=index.js.map