@manyducks.co/dolla 2.0.0-alpha.52 → 2.0.0-alpha.54

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.
@@ -1,8 +1,10 @@
1
1
  export { $, effect, get, peek } from "./signals.js";
2
2
  export type { MaybeSignal, Signal, Source } from "./signals.js";
3
+ export { ref, type Ref } from "./ref.js";
3
4
  export { constructView } from "./nodes/view.js";
4
5
  export { deepEqual, shallowEqual, strictEqual } from "../utils.js";
5
6
  export { Stores, type StoreContext, type StoreFunction } from "./store.js";
7
+ export { type Mixin, type MixinContext } from "./mixin.js";
6
8
  export { markup, portal, repeat, unless, when, constructMarkup } from "./markup.js";
7
9
  export type { Markup, MarkupElement } from "./markup.js";
8
10
  export { getEnv, setEnv } from "./env.js";
@@ -15,9 +15,13 @@ export interface Logger {
15
15
  }
16
16
  export interface LoggerOptions {
17
17
  /**
18
- * Unique ID to print with logs. Makes it easier to track down messages from specific view instances.
18
+ * Tag value to print with logs.
19
19
  */
20
- uid?: string;
20
+ tag?: string;
21
+ /**
22
+ * Label for tag value. Will be printed without a label if not specified.
23
+ */
24
+ tagName?: string;
21
25
  /**
22
26
  * Console object to use for logging (mostly for testing). Uses window.console by default.
23
27
  */
@@ -26,7 +30,8 @@ export interface LoggerOptions {
26
30
  export interface LoggerErrorContext {
27
31
  error: Error;
28
32
  loggerName: string;
29
- uid?: string;
33
+ tag?: string;
34
+ tagName?: string;
30
35
  }
31
36
  export declare function onLoggerCrash(listener: (context: LoggerErrorContext) => void): () => void;
32
37
  export declare function createLogger(name: MaybeSignal<string>, options?: LoggerOptions): Logger;
@@ -0,0 +1,62 @@
1
+ import type { StoreConsumerContext } from "./context";
2
+ import { type Logger } from "./logger";
3
+ import type { HTML } from "./nodes/html";
4
+ import { type EffectFn, type UnsubscribeFn } from "./signals";
5
+ import { StoreFunction } from "./store";
6
+ export interface MixinContext extends Logger, StoreConsumerContext {
7
+ /**
8
+ * An ID unique to this element.
9
+ */
10
+ readonly uid: string;
11
+ /**
12
+ * True while this element is connected to the DOM.
13
+ */
14
+ readonly isMounted: boolean;
15
+ /**
16
+ * Registers a callback to run just before this element is mounted. DOM nodes are not yet attached to the page.
17
+ */
18
+ beforeMount(callback: () => void): void;
19
+ /**
20
+ * Registers a callback to run just after this element is mounted.
21
+ */
22
+ onMount(callback: () => void): void;
23
+ /**
24
+ * Registers a callback to run just before this element is unmounted. DOM nodes are still attached to the page.
25
+ */
26
+ beforeUnmount(callback: () => void): void;
27
+ /**
28
+ * Registers a callback to run just after this element is unmounted.
29
+ */
30
+ onUnmount(callback: () => void): void;
31
+ /**
32
+ * Passes a getter function to `callback` that will track reactive states and return their current values.
33
+ * Callback will be run each time a tracked state gets a new value.
34
+ */
35
+ effect(callback: EffectFn): UnsubscribeFn;
36
+ }
37
+ export type Mixin<E extends Element = Element> = (element: E, context: MixinContext) => void;
38
+ interface Context extends Logger {
39
+ }
40
+ declare class Context implements MixinContext {
41
+ private html;
42
+ private controller;
43
+ constructor(html: HTML, controller: MixinController);
44
+ readonly uid: string;
45
+ get isMounted(): boolean;
46
+ get<Value>(store: StoreFunction<any, Value>): Value;
47
+ beforeMount(callback: () => void): void;
48
+ onMount(callback: () => void): void;
49
+ beforeUnmount(callback: () => void): void;
50
+ onUnmount(callback: () => void): void;
51
+ effect(callback: EffectFn): UnsubscribeFn;
52
+ }
53
+ export declare class MixinController {
54
+ context: Context;
55
+ lifecycleListeners: Record<string, (() => void)[]>;
56
+ constructor(html: HTML, mixins: Mixin[]);
57
+ beforeMount(): void;
58
+ onMount(): void;
59
+ beforeUnmount(): void;
60
+ onUnmount(): void;
61
+ }
62
+ export {};
@@ -9,12 +9,13 @@ type HTMLOptions = {
9
9
  };
10
10
  export declare class HTML implements MarkupElement {
11
11
  [IS_MARKUP_ELEMENT]: boolean;
12
- domNode: HTMLElement | SVGElement;
12
+ domNode: SVGElement | HTMLElement;
13
+ elementContext: ElementContext;
13
14
  private props;
14
15
  private childMarkup;
15
16
  private children;
16
17
  private unsubscribers;
17
- private elementContext;
18
+ private mixin?;
18
19
  private logger;
19
20
  private ref?;
20
21
  private canClickAway;
@@ -16,7 +16,7 @@ export type ViewFunction<P> = (this: ViewContext, props: P, context: ViewContext
16
16
  export interface ViewElement extends MarkupElement {
17
17
  setRouteView(view: ViewFunction<{}>): ViewElement;
18
18
  }
19
- export interface ViewContext extends Omit<Logger, "setName">, ComponentContext, StoreProviderContext, StoreConsumerContext {
19
+ export interface ViewContext extends Logger, ComponentContext, StoreProviderContext, StoreConsumerContext {
20
20
  /**
21
21
  * An ID unique to this view.
22
22
  */
@@ -51,7 +51,7 @@ export interface ViewContext extends Omit<Logger, "setName">, ComponentContext,
51
51
  */
52
52
  outlet(): Markup;
53
53
  }
54
- interface Context extends Omit<Logger, "setName"> {
54
+ interface Context extends Logger {
55
55
  }
56
56
  declare class Context implements ViewContext {
57
57
  private view;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * A hybrid getter/setter function that stores the last value it was called with.
3
+ * Guarantees a value is held at runtime by throwing an error if no value is set.
4
+ */
5
+ export interface Ref<T> {
6
+ /**
7
+ * Returns the currently stored value of the ref, or throws an error if no value has been set.
8
+ */
9
+ (): T;
10
+ /**
11
+ * Stores a new value to the ref and returns that value.
12
+ */
13
+ (value: T): T;
14
+ }
15
+ /**
16
+ * Creates a ref with no initial value.
17
+ */
18
+ export declare function ref<T>(): Ref<T>;
19
+ /**
20
+ * Creates a ref with an initial value.
21
+ */
22
+ export declare function ref<T>(value: T): Ref<T>;
@@ -13,6 +13,10 @@ export type CrashViewProps = {
13
13
  /**
14
14
  * Unique identifier to pinpoint the specific view that reported the crash.
15
15
  */
16
- uid?: string;
16
+ tag?: string;
17
+ /**
18
+ * Label for the tag.
19
+ */
20
+ tagName?: string;
17
21
  };
18
22
  export declare function DefaultCrashView(props: CrashViewProps): import("../markup.js").Markup;
@@ -1,8 +1,8 @@
1
- import { m } from "./view-CY19Cf0X.js";
1
+ import { m } from "./view-BKpHFpWG.js";
2
2
  function a(r, n) {
3
3
  return m("$dynamic", { source: () => r.children });
4
4
  }
5
5
  export {
6
6
  a as F
7
7
  };
8
- //# sourceMappingURL=fragment-DSGTP-XE.js.map
8
+ //# sourceMappingURL=fragment-CmWsN-4Y.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fragment-DSGTP-XE.js","sources":["../src/core/views/fragment.ts"],"sourcesContent":["import type { Renderable } from \"../../types.js\";\nimport { markup } from \"../markup.js\";\nimport { type ViewContext } from \"../nodes/view.js\";\n\n/**\n * A utility view that displays its children.\n */\nexport function Fragment(props: { children?: Renderable }, ctx: ViewContext) {\n return markup(\"$dynamic\", { source: () => props.children });\n}\n"],"names":["Fragment","props","ctx","markup"],"mappings":";AAOgB,SAAAA,EAASC,GAAkCC,GAAkB;AAC3E,SAAOC,EAAO,YAAY,EAAE,QAAQ,MAAMF,EAAM,UAAU;AAC5D;"}
1
+ {"version":3,"file":"fragment-CmWsN-4Y.js","sources":["../src/core/views/fragment.ts"],"sourcesContent":["import type { Renderable } from \"../../types.js\";\nimport { markup } from \"../markup.js\";\nimport { type ViewContext } from \"../nodes/view.js\";\n\n/**\n * A utility view that displays its children.\n */\nexport function Fragment(props: { children?: Renderable }, ctx: ViewContext) {\n return markup(\"$dynamic\", { source: () => props.children });\n}\n"],"names":["Fragment","props","ctx","markup"],"mappings":";AAOgB,SAAAA,EAASC,GAAkCC,GAAkB;AAC3E,SAAOC,EAAO,YAAY,EAAE,QAAQ,MAAMF,EAAM,UAAU;AAC5D;"}
package/dist/i18n.js CHANGED
@@ -5,7 +5,7 @@ var z = (o) => {
5
5
  var J = (o, t, e) => t in o ? B(o, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[t] = e;
6
6
  var O = (o, t, e) => J(o, typeof t != "symbol" ? t + "" : t, e), _ = (o, t, e) => t.has(o) || z("Cannot " + e);
7
7
  var i = (o, t, e) => (_(o, t, "read from private field"), e ? e.call(o) : t.get(o)), m = (o, t, e) => t.has(o) ? z("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(o) : t.set(o, e), N = (o, t, e, n) => (_(o, t, "write to private field"), n ? n.call(o, e) : t.set(o, e), e), g = (o, t, e) => (_(o, t, "access private method"), e);
8
- import { $, f as K, d as Q, g as x } from "./logger-CSRDjb4e.js";
8
+ import { $, f as K, d as Q, g as x } from "./logger-CBfhf3fA.js";
9
9
  import { i as C, b as j, c as U, t as P } from "./typeChecking-EAVNeFyB.js";
10
10
  var I, F, p, S, G;
11
11
  class W {
package/dist/index.js CHANGED
@@ -1,11 +1,24 @@
1
- import { o as d } from "./logger-CSRDjb4e.js";
2
- import { $ as O, f as v, d as F, e as N, g as T, b as U, p as B, c as P, h as $, i as z, s as D, a as I } from "./logger-CSRDjb4e.js";
3
- import { m as t, w as p, c, r as g } from "./view-CY19Cf0X.js";
4
- import { S as A, b as G, p as _, a as j, u as H } from "./view-CY19Cf0X.js";
5
- import { R as h, a as y, M as E, U as b } from "./router-BYOH-To5.js";
6
- import { i as w, a as u } from "./typeChecking-EAVNeFyB.js";
7
- function k(e) {
8
- return t(
1
+ import { o as d } from "./logger-CBfhf3fA.js";
2
+ import { $ as L, f as O, d as P, e as $, g as B, b as U, p as v, c as z, h as D, i as I, s as W, a as Y } from "./logger-CBfhf3fA.js";
3
+ import { m as a, w as h, c, r as p } from "./view-BKpHFpWG.js";
4
+ import { S as A, b as G, p as j, a as H, u as J } from "./view-BKpHFpWG.js";
5
+ import { R as y, a as E, M as w, U as b } from "./router-BoJac1lD.js";
6
+ import { i as x, a as u } from "./typeChecking-EAVNeFyB.js";
7
+ const f = Symbol("Ref.EMPTY");
8
+ function N(e = f) {
9
+ return function() {
10
+ if (arguments.length === 0) {
11
+ if (e === f)
12
+ throw new Error("Ref getter was called, but ref has no value! Be sure to set your refs before accessing them.");
13
+ } else if (arguments.length === 1)
14
+ e = arguments[0];
15
+ else
16
+ throw new Error("Ref called with too many arguments. Expected 0 or 1 arguments.");
17
+ return e;
18
+ };
19
+ }
20
+ function R(e) {
21
+ return a(
9
22
  "div",
10
23
  {
11
24
  style: {
@@ -17,15 +30,22 @@ function k(e) {
17
30
  fontSize: "20px"
18
31
  }
19
32
  },
20
- t("h1", { style: { marginBottom: "0.5rem" } }, "The app has crashed"),
21
- t(
33
+ a("h1", { style: { marginBottom: "0.5rem" } }, "The app has crashed"),
34
+ a(
22
35
  "p",
23
36
  { style: { marginBottom: "0.25rem" } },
24
- t("span", { style: { fontFamily: "monospace" } }, e.loggerName),
25
- p(e.uid, t("span", { style: { fontFamily: "monospace", opacity: 0.5 } }, ` [uid: ${e.uid}]`)),
37
+ a("span", { style: { fontFamily: "monospace" } }, e.loggerName),
38
+ h(
39
+ e.tag,
40
+ a(
41
+ "span",
42
+ { style: { fontFamily: "monospace", opacity: 0.5 } },
43
+ ` [${e.tagName ? `${e.tagName}: ` : ""}${e.tag}]`
44
+ )
45
+ ),
26
46
  " says:"
27
47
  ),
28
- t(
48
+ a(
29
49
  "blockquote",
30
50
  {
31
51
  style: {
@@ -36,7 +56,7 @@ function k(e) {
36
56
  marginBottom: "1rem"
37
57
  }
38
58
  },
39
- t(
59
+ a(
40
60
  "span",
41
61
  {
42
62
  style: {
@@ -53,57 +73,58 @@ function k(e) {
53
73
  ),
54
74
  e.error.message
55
75
  ),
56
- t("p", {}, "Please see the browser console for details.")
76
+ a("p", {}, "Please see the browser console for details.")
57
77
  );
58
78
  }
59
- let r = !1;
60
- async function R(e, n, i) {
61
- if (r)
79
+ let s = !1;
80
+ async function T(e, n, m) {
81
+ if (s)
62
82
  throw new Error("A Dolla app is already mounted.");
63
- let o, l, s, f = (i == null ? void 0 : i.crashView) ?? k;
64
- if (w(e)) {
65
- const a = document.querySelector(e);
66
- u(Element, a, `Selector '${e}' did not match any element.`), o = a;
83
+ let o, l, r, g = (m == null ? void 0 : m.crashView) ?? R;
84
+ if (x(e)) {
85
+ const t = document.querySelector(e);
86
+ u(Element, t, `Selector '${e}' did not match any element.`), o = t;
67
87
  } else
68
88
  u(Element, e, "Expected an element or a selector string. Got type: %t, value: %v"), o = e;
69
- if (n instanceof h)
70
- s = n, l = n[y];
89
+ if (n instanceof y)
90
+ r = n, l = n[E];
71
91
  else {
72
- const a = t(n);
73
- l = c(a.type, a.props);
92
+ const t = a(n);
93
+ l = c(t.type, t.props);
74
94
  }
75
- d((a) => {
76
- r && (m(), c(f, a).mount(o));
95
+ d((t) => {
96
+ s && (i(), c(g, t).mount(o));
77
97
  });
78
- for (const a of g.stores.values())
79
- a.handleMount();
80
- s && await s[E](o), l.mount(o), r = !0;
81
- async function m() {
82
- r && (l.unmount(!1), s && await s[b](), r = !1);
98
+ for (const t of p.stores.values())
99
+ t.handleMount();
100
+ r && await r[w](o), l.mount(o), s = !0;
101
+ async function i() {
102
+ s && (l.unmount(!1), r && await r[b](), s = !1);
83
103
  }
84
- return m;
104
+ return i;
85
105
  }
86
106
  export {
87
- O as $,
107
+ L as $,
88
108
  A as Stores,
89
109
  G as constructMarkup,
90
110
  c as constructView,
91
- v as createLogger,
92
- F as deepEqual,
93
- N as effect,
94
- T as get,
111
+ O as createLogger,
112
+ P as deepEqual,
113
+ $ as effect,
114
+ B as get,
95
115
  U as getEnv,
96
- t as markup,
97
- R as mount,
98
- B as peek,
99
- _ as portal,
100
- j as repeat,
101
- P as setEnv,
102
- $ as setLogFilter,
103
- z as setLogLevels,
104
- D as shallowEqual,
105
- I as strictEqual,
106
- H as unless,
107
- p as when
116
+ a as markup,
117
+ T as mount,
118
+ v as peek,
119
+ j as portal,
120
+ N as ref,
121
+ H as repeat,
122
+ z as setEnv,
123
+ D as setLogFilter,
124
+ I as setLogLevels,
125
+ W as shallowEqual,
126
+ Y as strictEqual,
127
+ J as unless,
128
+ h as when
108
129
  };
109
130
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/core/views/default-crash-view.ts","../src/core/mount.ts"],"sourcesContent":["import { when, markup as m } from \"../markup.js\";\n\n/**\n * Props passed to the crash view when a crash occurs.\n */\nexport type CrashViewProps = {\n /**\n * JavaScript Error object.\n */\n error: Error;\n\n /**\n * A string to identify the logger that reported this error.\n */\n loggerName: string;\n\n /**\n * Unique identifier to pinpoint the specific view that reported the crash.\n */\n uid?: string;\n};\n\nexport function DefaultCrashView(props: CrashViewProps) {\n return m(\n \"div\",\n {\n style: {\n backgroundColor: \"#880000\",\n color: \"#fff\",\n padding: \"2rem\",\n position: \"fixed\",\n inset: 0,\n fontSize: \"20px\",\n },\n },\n m(\"h1\", { style: { marginBottom: \"0.5rem\" } }, \"The app has crashed\"),\n m(\n \"p\",\n { style: { marginBottom: \"0.25rem\" } },\n m(\"span\", { style: { fontFamily: \"monospace\" } }, props.loggerName),\n when(props.uid, m(\"span\", { style: { fontFamily: \"monospace\", opacity: 0.5 } }, ` [uid: ${props.uid}]`)),\n \" says:\",\n ),\n m(\n \"blockquote\",\n {\n style: {\n backgroundColor: \"#991111\",\n padding: \"0.25em\",\n borderRadius: \"6px\",\n fontFamily: \"monospace\",\n marginBottom: \"1rem\",\n },\n },\n m(\n \"span\",\n {\n style: {\n display: \"inline-block\",\n backgroundColor: \"red\",\n padding: \"0.1em 0.4em\",\n marginRight: \"0.5em\",\n borderRadius: \"4px\",\n fontSize: \"0.9em\",\n fontWeight: \"bold\",\n },\n },\n props.error.name,\n ),\n props.error.message,\n ),\n m(\"p\", {}, \"Please see the browser console for details.\"),\n );\n}\n","import { MOUNT, ROOT_VIEW, UNMOUNT, Router } from \"../router/router\";\nimport { assertInstanceOf, isString } from \"../typeChecking\";\nimport { rootElementContext } from \"./context\";\nimport { type LoggerErrorContext, onLoggerCrash } from \"./logger\";\nimport { markup } from \"./markup\";\nimport { constructView, type ViewElement, type ViewFunction } from \"./nodes/view\";\nimport { DefaultCrashView } from \"./views/default-crash-view\";\n\nlet isMounted = false;\n\nexport type UnmountFn = () => Promise<void>;\nexport interface MountOptions {\n crashView?: ViewFunction<LoggerErrorContext>;\n}\n\nexport async function mount(parent: Element, view: any, options?: MountOptions): Promise<UnmountFn>;\nexport async function mount(parent: Element, router: any, options?: MountOptions): Promise<UnmountFn>;\n\nexport async function mount(parent: string, view: any, options?: MountOptions): Promise<UnmountFn>;\nexport async function mount(parent: string, router: any, options?: MountOptions): Promise<UnmountFn>;\n\nexport async function mount(target: any, view: any, options?: MountOptions): Promise<UnmountFn> {\n if (isMounted) {\n throw new Error(`A Dolla app is already mounted.`);\n }\n\n let rootElement: Element;\n let rootView: ViewElement;\n let router: any | undefined;\n let crashView = options?.crashView ?? DefaultCrashView;\n\n if (isString(target)) {\n const match = document.querySelector<Element>(target);\n assertInstanceOf(Element, match, `Selector '${target}' did not match any element.`);\n rootElement = match!;\n } else {\n assertInstanceOf(Element, target, \"Expected an element or a selector string. Got type: %t, value: %v\");\n rootElement = target;\n }\n\n if (view instanceof Router) {\n router = view;\n rootView = view[ROOT_VIEW];\n } else {\n // First, initialize the root view. The router store needs this to connect the initial route.\n const rootViewMarkup = markup(view);\n rootView = constructView(rootViewMarkup.type as ViewFunction<any>, rootViewMarkup.props);\n }\n\n onLoggerCrash((ctx) => {\n if (isMounted) {\n // Unmount the app.\n unmount();\n\n // Mount the crash page\n const crashPage = constructView(crashView, ctx);\n crashPage.mount(rootElement!);\n }\n });\n\n // Run onMount for stores.\n for (const store of rootElementContext.stores.values()) {\n store.handleMount();\n }\n\n if (router) {\n await router[MOUNT](rootElement);\n }\n\n rootView.mount(rootElement);\n isMounted = true;\n\n async function unmount() {\n if (!isMounted) return;\n\n rootView.unmount(false);\n\n if (router) {\n await router[UNMOUNT]();\n }\n\n isMounted = false;\n }\n\n return unmount;\n}\n"],"names":["DefaultCrashView","props","m","when","isMounted","mount","target","view","options","rootElement","rootView","router","crashView","isString","match","assertInstanceOf","Router","ROOT_VIEW","rootViewMarkup","markup","constructView","onLoggerCrash","ctx","unmount","store","rootElementContext","MOUNT","UNMOUNT"],"mappings":";;;;;;AAsBO,SAASA,EAAiBC,GAAuB;AAC/C,SAAAC;AAAAA,IACL;AAAA,IACA;AAAA,MACE,OAAO;AAAA,QACL,iBAAiB;AAAA,QACjB,OAAO;AAAA,QACP,SAAS;AAAA,QACT,UAAU;AAAA,QACV,OAAO;AAAA,QACP,UAAU;AAAA,MAAA;AAAA,IAEd;AAAA,IACAA,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,SAAA,EAAW,GAAG,qBAAqB;AAAA,IACpEA;AAAAA,MACE;AAAA,MACA,EAAE,OAAO,EAAE,cAAc,YAAY;AAAA,MACrCA,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,YAAY,EAAA,GAAKD,EAAM,UAAU;AAAA,MAClEE,EAAKF,EAAM,KAAKC,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,aAAa,SAAS,IAAM,EAAA,GAAG,UAAUD,EAAM,GAAG,GAAG,CAAC;AAAA,MACvG;AAAA,IACF;AAAA,IACAC;AAAAA,MACE;AAAA,MACA;AAAA,QACE,OAAO;AAAA,UACL,iBAAiB;AAAA,UACjB,SAAS;AAAA,UACT,cAAc;AAAA,UACd,YAAY;AAAA,UACZ,cAAc;AAAA,QAAA;AAAA,MAElB;AAAA,MACAA;AAAAA,QACE;AAAA,QACA;AAAA,UACE,OAAO;AAAA,YACL,SAAS;AAAA,YACT,iBAAiB;AAAA,YACjB,SAAS;AAAA,YACT,aAAa;AAAA,YACb,cAAc;AAAA,YACd,UAAU;AAAA,YACV,YAAY;AAAA,UAAA;AAAA,QAEhB;AAAA,QACAD,EAAM,MAAM;AAAA,MACd;AAAA,MACAA,EAAM,MAAM;AAAA,IACd;AAAA,IACAC,EAAE,KAAK,CAAA,GAAI,6CAA6C;AAAA,EAC1D;AACF;ACjEA,IAAIE,IAAY;AAaM,eAAAC,EAAMC,GAAaC,GAAWC,GAA4C;AAC9F,MAAIJ;AACI,UAAA,IAAI,MAAM,iCAAiC;AAG/C,MAAAK,GACAC,GACAC,GACAC,KAAYJ,KAAA,gBAAAA,EAAS,cAAaR;AAElC,MAAAa,EAASP,CAAM,GAAG;AACd,UAAAQ,IAAQ,SAAS,cAAuBR,CAAM;AACpD,IAAAS,EAAiB,SAASD,GAAO,aAAaR,CAAM,8BAA8B,GACpEG,IAAAK;AAAA,EAAA;AAEG,IAAAC,EAAA,SAAST,GAAQ,mEAAmE,GACvFG,IAAAH;AAGhB,MAAIC,aAAgBS;AACT,IAAAL,IAAAJ,GACTG,IAAWH,EAAKU,CAAS;AAAA,OACpB;AAEC,UAAAC,IAAiBC,EAAOZ,CAAI;AAClC,IAAAG,IAAWU,EAAcF,EAAe,MAA2BA,EAAe,KAAK;AAAA,EAAA;AAGzF,EAAAG,EAAc,CAACC,MAAQ;AACrB,IAAIlB,MAEMmB,EAAA,GAGUH,EAAcR,GAAWU,CAAG,EACpC,MAAMb,CAAY;AAAA,EAC9B,CACD;AAGD,aAAWe,KAASC,EAAmB,OAAO,OAAA;AAC5C,IAAAD,EAAM,YAAY;AAGpB,EAAIb,KACI,MAAAA,EAAOe,CAAK,EAAEjB,CAAW,GAGjCC,EAAS,MAAMD,CAAW,GACdL,IAAA;AAEZ,iBAAemB,IAAU;AACvB,IAAKnB,MAELM,EAAS,QAAQ,EAAK,GAElBC,KACI,MAAAA,EAAOgB,CAAO,EAAE,GAGZvB,IAAA;AAAA,EAAA;AAGP,SAAAmB;AACT;"}
1
+ {"version":3,"file":"index.js","sources":["../src/core/ref.ts","../src/core/views/default-crash-view.ts","../src/core/mount.ts"],"sourcesContent":["const EMPTY_REF = Symbol(\"Ref.EMPTY\");\n\n/**\n * A hybrid getter/setter function that stores the last value it was called with.\n * Guarantees a value is held at runtime by throwing an error if no value is set.\n */\nexport interface Ref<T> {\n /**\n * Returns the currently stored value of the ref, or throws an error if no value has been set.\n */\n (): T;\n\n /**\n * Stores a new value to the ref and returns that value.\n */\n (value: T): T;\n}\n\n/**\n * Creates a ref with no initial value.\n */\nexport function ref<T>(): Ref<T>;\n\n/**\n * Creates a ref with an initial value.\n */\nexport function ref<T>(value: T): Ref<T>;\n\nexport function ref(value = EMPTY_REF) {\n return function () {\n if (arguments.length === 0) {\n if (value === EMPTY_REF) {\n throw new Error(`Ref getter was called, but ref has no value! Be sure to set your refs before accessing them.`);\n }\n } else if (arguments.length === 1) {\n value = arguments[0];\n } else {\n throw new Error(`Ref called with too many arguments. Expected 0 or 1 arguments.`);\n }\n\n return value;\n };\n}\n","import { when, markup as m } from \"../markup.js\";\n\n/**\n * Props passed to the crash view when a crash occurs.\n */\nexport type CrashViewProps = {\n /**\n * JavaScript Error object.\n */\n error: Error;\n\n /**\n * A string to identify the logger that reported this error.\n */\n loggerName: string;\n\n /**\n * Unique identifier to pinpoint the specific view that reported the crash.\n */\n tag?: string;\n\n /**\n * Label for the tag.\n */\n tagName?: string;\n};\n\nexport function DefaultCrashView(props: CrashViewProps) {\n return m(\n \"div\",\n {\n style: {\n backgroundColor: \"#880000\",\n color: \"#fff\",\n padding: \"2rem\",\n position: \"fixed\",\n inset: 0,\n fontSize: \"20px\",\n },\n },\n m(\"h1\", { style: { marginBottom: \"0.5rem\" } }, \"The app has crashed\"),\n m(\n \"p\",\n { style: { marginBottom: \"0.25rem\" } },\n m(\"span\", { style: { fontFamily: \"monospace\" } }, props.loggerName),\n when(\n props.tag,\n m(\n \"span\",\n { style: { fontFamily: \"monospace\", opacity: 0.5 } },\n ` [${props.tagName ? `${props.tagName}: ` : \"\"}${props.tag}]`,\n ),\n ),\n \" says:\",\n ),\n m(\n \"blockquote\",\n {\n style: {\n backgroundColor: \"#991111\",\n padding: \"0.25em\",\n borderRadius: \"6px\",\n fontFamily: \"monospace\",\n marginBottom: \"1rem\",\n },\n },\n m(\n \"span\",\n {\n style: {\n display: \"inline-block\",\n backgroundColor: \"red\",\n padding: \"0.1em 0.4em\",\n marginRight: \"0.5em\",\n borderRadius: \"4px\",\n fontSize: \"0.9em\",\n fontWeight: \"bold\",\n },\n },\n props.error.name,\n ),\n props.error.message,\n ),\n m(\"p\", {}, \"Please see the browser console for details.\"),\n );\n}\n","import { MOUNT, ROOT_VIEW, UNMOUNT, Router } from \"../router/router\";\nimport { assertInstanceOf, isString } from \"../typeChecking\";\nimport { rootElementContext } from \"./context\";\nimport { type LoggerErrorContext, onLoggerCrash } from \"./logger\";\nimport { markup } from \"./markup\";\nimport { constructView, type ViewElement, type ViewFunction } from \"./nodes/view\";\nimport { DefaultCrashView } from \"./views/default-crash-view\";\n\nlet isMounted = false;\n\nexport type UnmountFn = () => Promise<void>;\nexport interface MountOptions {\n crashView?: ViewFunction<LoggerErrorContext>;\n}\n\nexport async function mount(parent: Element, view: any, options?: MountOptions): Promise<UnmountFn>;\nexport async function mount(parent: Element, router: any, options?: MountOptions): Promise<UnmountFn>;\n\nexport async function mount(parent: string, view: any, options?: MountOptions): Promise<UnmountFn>;\nexport async function mount(parent: string, router: any, options?: MountOptions): Promise<UnmountFn>;\n\nexport async function mount(target: any, view: any, options?: MountOptions): Promise<UnmountFn> {\n if (isMounted) {\n throw new Error(`A Dolla app is already mounted.`);\n }\n\n let rootElement: Element;\n let rootView: ViewElement;\n let router: any | undefined;\n let crashView = options?.crashView ?? DefaultCrashView;\n\n if (isString(target)) {\n const match = document.querySelector<Element>(target);\n assertInstanceOf(Element, match, `Selector '${target}' did not match any element.`);\n rootElement = match!;\n } else {\n assertInstanceOf(Element, target, \"Expected an element or a selector string. Got type: %t, value: %v\");\n rootElement = target;\n }\n\n if (view instanceof Router) {\n router = view;\n rootView = view[ROOT_VIEW];\n } else {\n // First, initialize the root view. The router store needs this to connect the initial route.\n const rootViewMarkup = markup(view);\n rootView = constructView(rootViewMarkup.type as ViewFunction<any>, rootViewMarkup.props);\n }\n\n onLoggerCrash((ctx) => {\n if (isMounted) {\n // Unmount the app.\n unmount();\n\n // Mount the crash page\n const crashPage = constructView(crashView, ctx);\n crashPage.mount(rootElement!);\n }\n });\n\n // Run onMount for stores.\n for (const store of rootElementContext.stores.values()) {\n store.handleMount();\n }\n\n if (router) {\n await router[MOUNT](rootElement);\n }\n\n rootView.mount(rootElement);\n isMounted = true;\n\n async function unmount() {\n if (!isMounted) return;\n\n rootView.unmount(false);\n\n if (router) {\n await router[UNMOUNT]();\n }\n\n isMounted = false;\n }\n\n return unmount;\n}\n"],"names":["EMPTY_REF","ref","value","DefaultCrashView","props","m","when","isMounted","mount","target","view","options","rootElement","rootView","router","crashView","isString","match","assertInstanceOf","Router","ROOT_VIEW","rootViewMarkup","markup","constructView","onLoggerCrash","ctx","unmount","store","rootElementContext","MOUNT","UNMOUNT"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { m as s } from "./view-CY19Cf0X.js";
2
- import { F as h } from "./fragment-DSGTP-XE.js";
1
+ import { m as s } from "./view-BKpHFpWG.js";
2
+ import { F as h } from "./fragment-CmWsN-4Y.js";
3
3
  function d(e, r, t, n, l, u) {
4
4
  const i = { ...o(["children", "key"], r) }, c = Array.isArray(r.children) ? r.children : [r.children];
5
5
  return s(e, i, ...c);
@@ -1,5 +1,5 @@
1
- import { m as t } from "./view-CY19Cf0X.js";
2
- import { F as k } from "./fragment-DSGTP-XE.js";
1
+ import { m as t } from "./view-BKpHFpWG.js";
2
+ import { F as k } from "./fragment-CmWsN-4Y.js";
3
3
  function d(e, n, r) {
4
4
  return t(e, n ? { ...u(["children", "key"], n) } : void 0, n.children);
5
5
  }