@manyducks.co/dolla 1.1.0 → 2.0.0-alpha.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 (78) hide show
  1. package/README.md +47 -23
  2. package/build.js +5 -5
  3. package/dist/fragment-s33qZBzz.js +1241 -0
  4. package/dist/fragment-s33qZBzz.js.map +1 -0
  5. package/dist/index.d.ts +42 -0
  6. package/dist/index.js +1308 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/jsx-dev-runtime.d.ts +2 -0
  9. package/dist/jsx-dev-runtime.js +17 -0
  10. package/dist/jsx-dev-runtime.js.map +1 -0
  11. package/{lib/jsx → dist}/jsx-runtime.d.ts +3 -4
  12. package/dist/jsx-runtime.js +20 -0
  13. package/dist/jsx-runtime.js.map +1 -0
  14. package/{lib → dist}/markup.d.ts +12 -13
  15. package/dist/modules/dolla.d.ts +87 -0
  16. package/dist/modules/http.d.ts +57 -0
  17. package/dist/modules/language.d.ts +41 -0
  18. package/{lib/stores → dist/modules}/render.d.ts +5 -6
  19. package/{lib/stores → dist/modules}/router.d.ts +37 -39
  20. package/{lib → dist}/nodes/cond.d.ts +1 -4
  21. package/{lib → dist}/nodes/html.d.ts +2 -5
  22. package/{lib → dist}/nodes/observer.d.ts +2 -5
  23. package/{lib → dist}/nodes/outlet.d.ts +1 -4
  24. package/{lib → dist}/nodes/portal.d.ts +1 -3
  25. package/{lib → dist}/nodes/repeat.d.ts +2 -5
  26. package/{lib → dist}/nodes/text.d.ts +1 -1
  27. package/{lib → dist}/signals.d.ts +35 -46
  28. package/{lib → dist}/types.d.ts +0 -8
  29. package/{lib → dist}/utils.d.ts +10 -0
  30. package/dist/view.d.ts +44 -0
  31. package/dist/views/default-crash-page.d.ts +8 -0
  32. package/notes/scratch.md +120 -0
  33. package/package.json +11 -12
  34. package/vite.config.js +27 -0
  35. package/lib/app.d.ts +0 -83
  36. package/lib/classes/CrashCollector.d.ts +0 -30
  37. package/lib/classes/DebugHub.d.ts +0 -61
  38. package/lib/classes/EventEmitter.d.ts +0 -44
  39. package/lib/index.d.ts +0 -21
  40. package/lib/index.js +0 -4176
  41. package/lib/index.js.map +0 -7
  42. package/lib/jsx/jsx-dev-runtime.d.ts +0 -3
  43. package/lib/jsx/jsx-dev-runtime.js +0 -20
  44. package/lib/jsx/jsx-dev-runtime.js.map +0 -7
  45. package/lib/jsx/jsx-runtime.js +0 -22
  46. package/lib/jsx/jsx-runtime.js.map +0 -7
  47. package/lib/signals.test.d.ts +0 -1
  48. package/lib/spring.d.ts +0 -0
  49. package/lib/state.d.ts +0 -103
  50. package/lib/store.d.ts +0 -59
  51. package/lib/stores/dialog.d.ts +0 -32
  52. package/lib/stores/document.d.ts +0 -11
  53. package/lib/stores/http.d.ts +0 -60
  54. package/lib/stores/language.d.ts +0 -36
  55. package/lib/testing/classes/MockHTTP.d.ts +0 -10
  56. package/lib/testing/index.d.ts +0 -4
  57. package/lib/testing/makeMockDOMNode.d.ts +0 -10
  58. package/lib/testing/makeMockFetch._test.d.ts +0 -1
  59. package/lib/testing/makeMockFetch.d.ts +0 -36
  60. package/lib/testing/makeMockFetch.test.d.ts +0 -1
  61. package/lib/testing/makeMockFetch.test_skip.d.ts +0 -1
  62. package/lib/testing/stores/dialog.d.ts +0 -6
  63. package/lib/testing/stores/http.d.ts +0 -13
  64. package/lib/testing/stores/page.d.ts +0 -7
  65. package/lib/testing/stores/router.d.ts +0 -12
  66. package/lib/testing/wrapStore._test.d.ts +0 -1
  67. package/lib/testing/wrapStore.d.ts +0 -8
  68. package/lib/testing/wrapStore.test.d.ts +0 -1
  69. package/lib/testing/wrapStore.test_skip.d.ts +0 -1
  70. package/lib/testing/wrapView.d.ts +0 -0
  71. package/lib/view.d.ts +0 -88
  72. package/lib/views/default-crash-page.d.ts +0 -7
  73. package/lib/views/store-scope.d.ts +0 -13
  74. /package/{lib → dist}/routing.d.ts +0 -0
  75. /package/{lib → dist}/routing.test.d.ts +0 -0
  76. /package/{lib → dist}/typeChecking.d.ts +0 -0
  77. /package/{lib → dist}/views/default-view.d.ts +0 -0
  78. /package/{lib → dist}/views/fragment.d.ts +0 -0
@@ -0,0 +1,41 @@
1
+ import { type Signal } from "../signals.js";
2
+ import type { Stringable } from "../types.js";
3
+ import type { Dolla } from "./dolla.js";
4
+ /**
5
+ * An object where values are either a translated string or another nested Translation object.
6
+ */
7
+ type LocalizedStrings = Record<string, string | Record<string, string | Record<string, string | Record<string, string>>>>;
8
+ export interface LanguageConfig {
9
+ name: string;
10
+ /**
11
+ * Path to a JSON file with translated strings for this language.
12
+ */
13
+ path?: string;
14
+ /**
15
+ * A callback function that returns a Promise that resolves to the translation object for this language.
16
+ */
17
+ fetch?: () => Promise<LocalizedStrings>;
18
+ }
19
+ export type LanguageSetupOptions = {
20
+ /**
21
+ * Default language to load on startup
22
+ */
23
+ initialLanguage?: string | null;
24
+ languages: LanguageConfig[];
25
+ };
26
+ export declare class Language {
27
+ #private;
28
+ $current: Signal<string | undefined>;
29
+ constructor(dolla: Dolla);
30
+ get supportedLanguages(): string[];
31
+ setup(options: LanguageSetupOptions): void;
32
+ setLanguage(name: string): Promise<void>;
33
+ /**
34
+ * Returns a Signal containing the value at `key`.
35
+
36
+ * @param key - Key to the translated value.
37
+ * @param values - A map of {{placeholder}} names and the values to replace them with.
38
+ */
39
+ t(key: string, values?: Record<string, Stringable | Signal<Stringable>>): Signal<string>;
40
+ }
41
+ export {};
@@ -1,8 +1,7 @@
1
- import { type StoreContext } from "../store.js";
2
- /**
3
- * Batches DOM updates for better performance.
4
- */
5
- export declare function RenderStore(ctx: StoreContext): {
1
+ import type { Dolla } from "./dolla.js";
2
+ export declare class Render {
3
+ #private;
4
+ constructor(dolla: Dolla);
6
5
  /**
7
6
  * Queues a callback to run in the next render batch.
8
7
  * Running your DOM mutations in update callbacks reduces layout thrashing.
@@ -15,4 +14,4 @@ export declare function RenderStore(ctx: StoreContext): {
15
14
  * Returns a Promise that resolves once the callback has run.
16
15
  */
17
16
  read(callback: () => void): Promise<void>;
18
- };
17
+ }
@@ -1,17 +1,8 @@
1
- import { type History } from "history";
2
- import { type Markup } from "../markup.js";
3
- import { type Store, type StoreContext } from "../store.js";
4
- import { type BuiltInStores, type Stringable } from "../types.js";
5
- import { type View } from "../view.js";
1
+ import { type DOMHandle, type Markup } from "../markup.js";
2
+ import { type Stringable } from "../types.js";
3
+ import { type ViewFunction } from "../view.js";
4
+ import type { Dolla } from "./dolla.js";
6
5
  export interface RouteMatchContext {
7
- /**
8
- * Returns the shared instance of `store`.
9
- */
10
- getStore<T extends Store<any, any>>(store: T): ReturnType<T>;
11
- /**
12
- * Returns the shared instance of a built-in store.
13
- */
14
- getStore<N extends keyof BuiltInStores>(name: N): BuiltInStores[N];
15
6
  /**
16
7
  * Redirects the user to a different route instead of matching the current one.
17
8
  */
@@ -29,7 +20,7 @@ export interface Route {
29
20
  /**
30
21
  * View to display when this route is matched.
31
22
  */
32
- view?: View<any>;
23
+ view?: ViewFunction<any>;
33
24
  /**
34
25
  * Subroutes.
35
26
  */
@@ -78,7 +69,7 @@ interface ParsedParams {
78
69
  }
79
70
  interface ParsedQuery extends ParsedParams {
80
71
  }
81
- interface NavigateOptions {
72
+ export interface NavigateOptions {
82
73
  /**
83
74
  * Replace the current item in the history stack instead of adding a new one.
84
75
  * The back button will send the user to the page they visited before this. Defaults to false.
@@ -89,20 +80,31 @@ interface NavigateOptions {
89
80
  */
90
81
  preserveQuery?: boolean;
91
82
  }
92
- interface RouterStoreOptions {
93
- routes: Route[];
83
+ export declare enum RoutingStyle {
94
84
  /**
95
- * Use hash-based routing if true.
85
+ * Constructs routes like "https://www.example.com/#/sub/route" which work without any server-side setup.
86
+ * A good choice if your app has no backend.
96
87
  */
97
- hash?: boolean;
88
+ hash = "hash",
98
89
  /**
99
- * A history object from the `history` package.
100
- *
101
- * @see https://www.npmjs.com/package/history
90
+ * Constructs routes like "https://www.example.com/sub/route" which look nicer (subjective?) than hash routes and are what most users will expect URLs to look like, but require additional backend setup.
91
+ * Path routing requires you to configure your backend to redirect to the app's index.html when subpaths are requested.
92
+ */
93
+ path = "path"
94
+ }
95
+ export interface RouterSetupOptions {
96
+ routes: Route[];
97
+ /**
98
+ * The routing style to use; "hash" will construct routes like "https://www.example.com/#/sub/route" which work without any server-side setup, while "path" will construct routes that use paths directly.
102
99
  */
103
- history?: History;
100
+ style?: RoutingStyle;
101
+ }
102
+ export interface RouterElements {
103
+ readonly rootElement?: HTMLElement;
104
+ readonly rootView?: DOMHandle;
104
105
  }
105
- export declare function RouterStore(ctx: StoreContext<RouterStoreOptions>): {
106
+ export declare class Router {
107
+ #private;
106
108
  /**
107
109
  * The currently matched route pattern, if any.
108
110
  */
@@ -119,7 +121,16 @@ export declare function RouterStore(ctx: StoreContext<RouterStoreOptions>): {
119
121
  * The current query params. Changes to this object will be reflected in the URL.
120
122
  */
121
123
  $query: import("../signals.js").Signal<ParsedQuery>;
122
- setQuery: import("../signals.js").SignalSetter<ParsedQuery, ParsedQuery>;
124
+ constructor(dolla: Dolla, elements: RouterElements);
125
+ setup(options: RouterSetupOptions): void;
126
+ /**
127
+ * Navigates to another route.
128
+ *
129
+ * @example
130
+ * navigate("/login"); // navigate to `/login`
131
+ * navigate(["/users", 215], { replace: true }); // replace current history entry with `/users/215`
132
+ */
133
+ go(path: Stringable | Stringable[], options?: NavigateOptions): void;
123
134
  /**
124
135
  * Navigate backward. Pass a number of steps to hit the back button that many times.
125
136
  */
@@ -128,20 +139,7 @@ export declare function RouterStore(ctx: StoreContext<RouterStoreOptions>): {
128
139
  * Navigate forward. Pass a number of steps to hit the forward button that many times.
129
140
  */
130
141
  forward(steps?: number): void;
131
- /**
132
- * Navigates to another route.
133
- *
134
- * @example
135
- * navigate("/login"); // navigate to `/login`
136
- * navigate(["/users", 215], { replace: true }); // replace current history entry with `/users/215`
137
- *
138
- * @param args - One or more path segments optionally followed by an options object.
139
- */
140
- navigate: {
141
- (path: Stringable, options?: NavigateOptions): void;
142
- (fragments: Stringable[], options?: NavigateOptions): void;
143
- };
144
- };
142
+ }
145
143
  /**
146
144
  * Intercepts links within the root node.
147
145
  *
@@ -1,12 +1,10 @@
1
- import { type AppContext, type ElementContext } from "../app.js";
2
- import { type DOMHandle, type Markup } from "../markup.js";
1
+ import { type DOMHandle, type ElementContext, type Markup } from "../markup.js";
3
2
  import { type Signal, type StopFunction } from "../signals.js";
4
3
  import { type Renderable } from "../types.js";
5
4
  export interface ConditionalConfig {
6
5
  $predicate: Signal<any>;
7
6
  thenContent?: Renderable;
8
7
  elseContent?: Renderable;
9
- appContext: AppContext;
10
8
  elementContext: ElementContext;
11
9
  }
12
10
  export declare class Conditional implements DOMHandle {
@@ -17,7 +15,6 @@ export declare class Conditional implements DOMHandle {
17
15
  thenContent?: Markup[];
18
16
  elseContent?: Markup[];
19
17
  connectedContent: DOMHandle[];
20
- appContext: AppContext;
21
18
  elementContext: ElementContext;
22
19
  initialUpdateHappened: boolean;
23
20
  previousValue?: any;
@@ -1,8 +1,6 @@
1
- import { type AppContext, type ElementContext } from "../app.js";
2
- import { type DOMHandle, type Markup } from "../markup.js";
1
+ import { type DOMHandle, type ElementContext, type Markup } from "../markup.js";
3
2
  import { type StopFunction } from "../signals.js";
4
3
  type HTMLOptions = {
5
- appContext: AppContext;
6
4
  elementContext: ElementContext;
7
5
  tag: string;
8
6
  props?: any;
@@ -13,12 +11,11 @@ export declare class HTML implements DOMHandle {
13
11
  props: Record<string, any>;
14
12
  children: DOMHandle[];
15
13
  stopCallbacks: StopFunction[];
16
- appContext: AppContext;
17
14
  elementContext: ElementContext;
18
15
  uniqueId: string;
19
16
  canClickAway: boolean;
20
17
  get connected(): boolean;
21
- constructor({ tag, props, children, appContext, elementContext }: HTMLOptions);
18
+ constructor({ tag, props, children, elementContext }: HTMLOptions);
22
19
  connect(parent: Node, after?: Node): void;
23
20
  disconnect(): void;
24
21
  setChildren(next: DOMHandle[]): void;
@@ -1,9 +1,7 @@
1
- import { type AppContext, type ElementContext } from "../app.js";
2
- import { type DOMHandle } from "../markup.js";
1
+ import { type DOMHandle, type ElementContext } from "../markup.js";
3
2
  import { type Signal } from "../signals.js";
4
3
  import type { Renderable } from "../types.js";
5
4
  interface ObserverOptions {
6
- appContext: AppContext;
7
5
  elementContext: ElementContext;
8
6
  signals: Signal<any>[];
9
7
  renderFn: (...values: any) => Renderable;
@@ -16,14 +14,13 @@ export declare class Observer implements DOMHandle {
16
14
  endNode: Node;
17
15
  connectedViews: DOMHandle[];
18
16
  renderFn: (...values: any) => Renderable;
19
- appContext: AppContext;
20
17
  elementContext: ElementContext;
21
18
  observerControls: {
22
19
  start: () => void;
23
20
  stop: () => void;
24
21
  };
25
22
  get connected(): boolean;
26
- constructor({ signals, renderFn, appContext, elementContext }: ObserverOptions);
23
+ constructor({ signals, renderFn, elementContext }: ObserverOptions);
27
24
  connect(parent: Node, after?: Node): void;
28
25
  disconnect(): void;
29
26
  setChildren(): Promise<void>;
@@ -1,9 +1,7 @@
1
- import { type AppContext, type ElementContext } from "../app.js";
2
- import { type DOMHandle } from "../markup.js";
1
+ import { type DOMHandle, type ElementContext } from "../markup.js";
3
2
  import { type Signal, type StopFunction } from "../signals.js";
4
3
  export interface OutletConfig {
5
4
  $children: Signal<DOMHandle[]>;
6
- appContext: AppContext;
7
5
  elementContext: ElementContext;
8
6
  }
9
7
  /**
@@ -15,7 +13,6 @@ export declare class Outlet implements DOMHandle {
15
13
  $children: Signal<DOMHandle[]>;
16
14
  stopCallback?: StopFunction;
17
15
  connectedChildren: DOMHandle[];
18
- appContext: AppContext;
19
16
  elementContext: ElementContext;
20
17
  constructor(config: OutletConfig);
21
18
  get connected(): boolean;
@@ -1,10 +1,8 @@
1
- import { type AppContext, type ElementContext } from "../app.js";
2
- import { type DOMHandle } from "../markup.js";
1
+ import { type DOMHandle, type ElementContext } from "../markup.js";
3
2
  import { type Renderable } from "../types.js";
4
3
  interface PortalConfig {
5
4
  content: Renderable;
6
5
  parent: Node;
7
- appContext: AppContext;
8
6
  elementContext: ElementContext;
9
7
  }
10
8
  /**
@@ -1,9 +1,7 @@
1
- import { type AppContext, type ElementContext } from "../app.js";
2
- import { type DOMHandle } from "../markup.js";
1
+ import { type DOMHandle, type ElementContext } from "../markup.js";
3
2
  import { type Signal, type SignalSetter, type StopFunction } from "../signals.js";
4
3
  import { type ViewContext, type ViewResult } from "../view.js";
5
4
  interface RepeatOptions<T> {
6
- appContext: AppContext;
7
5
  elementContext: ElementContext;
8
6
  $items: Signal<T[]>;
9
7
  keyFn: (value: T, index: number) => string | number | symbol;
@@ -23,12 +21,11 @@ export declare class Repeat<T> implements DOMHandle {
23
21
  $items: Signal<T[]>;
24
22
  stopCallback?: StopFunction;
25
23
  connectedItems: ConnectedItem<T>[];
26
- appContext: AppContext;
27
24
  elementContext: ElementContext;
28
25
  renderFn: ($value: Signal<T>, $index: Signal<number>, ctx: ViewContext) => ViewResult;
29
26
  keyFn: (value: T, index: number) => string | number | symbol;
30
27
  get connected(): boolean;
31
- constructor({ appContext, elementContext, $items, renderFn, keyFn }: RepeatOptions<T>);
28
+ constructor({ elementContext, $items, renderFn, keyFn }: RepeatOptions<T>);
32
29
  connect(parent: Node, after?: Node): void;
33
30
  disconnect(): void;
34
31
  setChildren(): void;
@@ -1,5 +1,5 @@
1
1
  import { type DOMHandle } from "../markup.js";
2
- import { MaybeSignal, type StopFunction } from "../signals.js";
2
+ import { type MaybeSignal, type StopFunction } from "../signals.js";
3
3
  interface Stringable {
4
4
  toString(): string;
5
5
  }
@@ -9,16 +9,16 @@ type Unwrapped<T> = T extends Signal<infer V> ? V : T;
9
9
  export type SignalValues<T extends MaybeSignal<any>[]> = {
10
10
  [K in keyof T]: Unwrapped<T[K]>;
11
11
  };
12
- export interface SignalCreateOptions<T> {
12
+ export interface CreateSignalOptions<T> {
13
13
  /**
14
- * Determines if the `next` value is equal to the `previous` value.
14
+ * Determines if the `next` value is equal to the `current` value.
15
15
  * If this function returns true, watchers will be notified of changes. If it returns false, watchers will not be notified.
16
16
  * By default equality is defined as deep equality.
17
17
  *
18
18
  * @param next - The new value being set.
19
- * @param previous - The previous value being replaced.
19
+ * @param current - The current value being replaced.
20
20
  */
21
- equality?: (next: T, previous: T) => boolean;
21
+ equality?: (next: T, current: T) => boolean;
22
22
  }
23
23
  export interface SignalWatchOptions<T> {
24
24
  /**
@@ -34,7 +34,7 @@ export interface Signal<T> {
34
34
  get(): T;
35
35
  /**
36
36
  * Watch this signal's value with a `callback` function.
37
- * The `callback` is only called if the value is not equal to the previous value.
37
+ * The `callback` is only called if the value is not equal to the current value.
38
38
  *
39
39
  * > NOTE: If watching a signal inside a view, use the `.watch` method on the `ViewContext`. That method will automatically
40
40
  * clean up all watchers when the view is disconnected. Watchers created here must be cleaned up manually.
@@ -42,9 +42,9 @@ export interface Signal<T> {
42
42
  watch(callback: (value: T) => void, options?: SignalWatchOptions<T>): StopFunction;
43
43
  }
44
44
  /** A new value for a signal, or a callback that receives the current value and returns a new one. */
45
- export type SetSignalAction<I, O = I> = O | ((current: I) => O);
45
+ export type SignalSetAction<I, O = I> = O | ((current: I) => O);
46
46
  /** Callback that updates the value of a signal. */
47
- export type SignalSetter<I, O = I> = (value: SetSignalAction<I, O>) => void;
47
+ export type SignalSetter<I, O = I> = (value: SignalSetAction<I, O>) => void;
48
48
  export type MaybeSignal<T> = Signal<T> | T;
49
49
  /**
50
50
  * A signal and setter in one. Useful for passing signals that are intended to be updated by subviews.
@@ -57,7 +57,7 @@ export interface SettableSignal<I, O = I> extends Signal<I> {
57
57
  /**
58
58
  * Takes a callback that recieves the signal's current value and returns a new one.
59
59
  */
60
- set(callback: (previous: I) => O): void;
60
+ set(callback: (current: I) => O): void;
61
61
  }
62
62
  export declare function isSignal<T>(value: any): value is Signal<T>;
63
63
  export declare function isSettableSignal<T>(value: any): value is Signal<T>;
@@ -69,44 +69,33 @@ export declare function designalify<T>(value: MaybeSignal<T>): T;
69
69
  * Ensures a variable that may be a signal or plain value is a signal.
70
70
  */
71
71
  export declare function signalify<T>(value: MaybeSignal<T>): Signal<T>;
72
- export interface signal {
73
- /**
74
- * Creates a new Signal and setter.
75
- */
76
- /**
77
- * Creates a new Signal and setter.
78
- */
79
- /**
80
- * Creates a SettableSignal with an initial value.
81
- */
82
- settable<T>(initialValue: T, options?: SignalCreateOptions<T>): SettableSignal<T>;
83
- /**
84
- * Creates a SettableSignal.
85
- */
86
- settable<T>(initialValue?: T, options?: SignalCreateOptions<T | undefined>): SettableSignal<T | undefined>;
87
- /**
88
- * Combines a Signal and setter into a SettableSignal.
89
- */
90
- toSettable<I, O = I>(signal: Signal<I>, setter: SignalSetter<I, O>): SettableSignal<I>;
91
- /**
92
- * Creates a SignalSetter with custom logic provided by `callback`.
93
- */
94
- createSetter<I, O = I>(signal: Signal<I>, callback: (next: O, previous: I) => void): SignalSetter<I, O>;
95
- }
96
- export declare function signal<T>(initialValue: T, options?: SignalCreateOptions<T>): [Signal<T>, SignalSetter<T>];
97
- export declare function signal<T>(initialValue?: T, options?: SignalCreateOptions<T | undefined>): [Signal<T | undefined>, SignalSetter<T | undefined>];
98
- export declare namespace signal {
99
- var settable: typeof createSettableSignal;
100
- var toSettable: typeof createSettableSignalFrom;
101
- var createSetter: typeof createSignalSetter;
102
- }
103
- declare function createSettableSignal<T>(initialValue: T, options?: SignalCreateOptions<T>): SettableSignal<T>;
104
- declare function createSettableSignal<T>(initialValue?: T, options?: SignalCreateOptions<T | undefined>): SettableSignal<T | undefined>;
105
- declare function createSettableSignalFrom<I, O = I>(signal: Signal<I>, setter: SignalSetter<I, O>): SettableSignal<I, O>;
106
- declare function createSignalSetter<I, O = I>(signal: Signal<I>, callback: (next: O, previous: I) => void): SignalSetter<I, O>;
107
- export interface SignalDeriveOptions {
108
- equality?: (next: unknown, previous: unknown) => boolean;
72
+ /**
73
+ * Creates a SettableSignal.
74
+ */
75
+ export declare function createSettableSignal<T>(initialValue: T, options?: CreateSignalOptions<T>): SettableSignal<T>;
76
+ /**
77
+ * Creates a SettableSignal.
78
+ */
79
+ export declare function createSettableSignal<T>(initialValue?: T, options?: CreateSignalOptions<T | undefined>): SettableSignal<T | undefined>;
80
+ /**
81
+ * Join a signal and its setter into a single SettableSignal object.
82
+ */
83
+ export declare function toSettableSignal<I, O = I>(signal: Signal<I>, setter: SignalSetter<I, O>): SettableSignal<I, O>;
84
+ /**
85
+ * Creates a SignalSetter with custom logic provided by `callback`.
86
+ */
87
+ export declare function createSignalSetter<I, O = I>(signal: Signal<I>, callback: (next: O, current: I) => void): SignalSetter<I, O>;
88
+ /**
89
+ * Creates a signal and setter.
90
+ */
91
+ export declare function createSignal<T>(initialValue: T, options?: CreateSignalOptions<T>): [Signal<T>, SignalSetter<T>];
92
+ /**
93
+ * Creates a signal and setter.
94
+ */
95
+ export declare function createSignal<T>(initialValue?: T, options?: CreateSignalOptions<T | undefined>): [Signal<T | undefined>, SignalSetter<T | undefined>];
96
+ export interface DeriveSignalOptions {
97
+ equality?: (next: unknown, current: unknown) => boolean;
109
98
  }
110
- export declare function derive<Inputs extends MaybeSignal<any>[], T>(signals: [...Inputs], fn: (...currentValues: SignalValues<Inputs>) => T | Signal<T>, options?: SignalDeriveOptions): Signal<T>;
99
+ export declare function derive<Inputs extends MaybeSignal<any>[], T>(signals: [...Inputs], fn: (...currentValues: SignalValues<Inputs>) => T | Signal<T>, options?: DeriveSignalOptions): Signal<T>;
111
100
  export declare function watch<I extends MaybeSignal<any>[]>(signals: [...I], fn: (...currentValues: SignalValues<I>) => void): StopFunction;
112
101
  export {};
@@ -1,19 +1,11 @@
1
1
  import type * as CSS from "csstype";
2
2
  import { Ref, type Markup } from "./markup.js";
3
- import { type Store } from "./store.js";
4
- import { type DocumentStore } from "./stores/document.js";
5
- import { type RenderStore } from "./stores/render.js";
6
3
  import { SettableSignal, Signal } from "./signals.js";
7
4
  /**
8
5
  * Represents everything that can be handled as a DOM node.
9
6
  * These are all the items considered valid to pass as children to any element.
10
7
  */
11
8
  export type Renderable = string | number | Markup | false | null | undefined | Signal<any> | (string | number | Markup | false | null | undefined | Signal<any>)[];
12
- export type StoreExports<T> = T extends Store<any, infer O> ? O : unknown;
13
- export interface BuiltInStores {
14
- document: StoreExports<typeof DocumentStore>;
15
- render: StoreExports<typeof RenderStore>;
16
- }
17
9
  export type Stringable = {
18
10
  toString(): string;
19
11
  };
@@ -1,3 +1,4 @@
1
+ export declare const noOp: () => void;
1
2
  export declare function deepEqual(one: any, two: any): boolean;
2
3
  /**
3
4
  * Takes an old value and a new value. Returns a merged copy if both are objects, otherwise returns the new value.
@@ -12,3 +13,12 @@ export declare function merge(one: unknown, two: unknown): any;
12
13
  * @param object - An object to clone without the omitted keys.
13
14
  */
14
15
  export declare function omit<O extends Record<any, any>>(keys: (keyof O)[], object: O): Record<any, any>;
16
+ export declare function getDefaultConsole(): any;
17
+ export declare function colorFromString(value: string): string;
18
+ export type MatcherFunction = (value: string) => boolean;
19
+ /**
20
+ * Parses a filter string into a match function.
21
+ *
22
+ * @param pattern - A string or regular expression that specifies a pattern for names of debug channels you want to display.
23
+ */
24
+ export declare function createMatcher(pattern: string | RegExp): (value: string) => boolean;
package/dist/view.d.ts ADDED
@@ -0,0 +1,44 @@
1
+ import { type DOMHandle, type ElementContext, type Markup } from "./markup.js";
2
+ import type { Logger } from "./modules/dolla.js";
3
+ import { type MaybeSignal, Signal, type SignalValues, type StopFunction } from "./signals.js";
4
+ /**
5
+ * Any valid value that a View can return.
6
+ */
7
+ export type ViewResult = Node | Signal<any> | Markup | Markup[] | null;
8
+ export type ViewFunction<P> = (props: P, context: ViewContext) => ViewResult;
9
+ export interface ViewContext extends Logger {
10
+ /**
11
+ * A string ID unique to this view.
12
+ */
13
+ readonly uid: string;
14
+ /**
15
+ * Sets the name of the view's built in logger.
16
+ */
17
+ setName(name: string): void;
18
+ /**
19
+ * Registers a callback to run just before this view is mounted. DOM nodes are not yet attached to the page.
20
+ */
21
+ beforeMount(callback: () => void): void;
22
+ /**
23
+ * Registers a callback to run just after this view is mounted.
24
+ */
25
+ onMount(callback: () => void): void;
26
+ /**
27
+ * Registers a callback to run just before this view is unmounted. DOM nodes are still attached to the page.
28
+ */
29
+ beforeUnmount(callback: () => void): void;
30
+ /**
31
+ * Registers a callback to run just after this view is unmounted.
32
+ */
33
+ onUnmount(callback: () => void): void;
34
+ /**
35
+ * Watch a set of signals. The callback is called when any of the signals receive a new value.
36
+ * Watchers will be stopped when this view is unmounted. Returns a function to stop watching early.
37
+ */
38
+ watch<T extends MaybeSignal<any>[]>(signals: [...T], callback: (...values: SignalValues<T>) => void): StopFunction;
39
+ /**
40
+ * Returns a Markup element that displays this view's children.
41
+ */
42
+ outlet(): Markup;
43
+ }
44
+ export declare function constructView<P>(elementContext: ElementContext, view: ViewFunction<P>, props: P, children?: Markup[]): DOMHandle;
@@ -0,0 +1,8 @@
1
+ type CrashPageProps = {
2
+ message: string;
3
+ error: Error;
4
+ loggerName: string;
5
+ uid?: string;
6
+ };
7
+ export declare function DefaultCrashPage(props: CrashPageProps): import("../markup.js").Markup;
8
+ export {};
package/notes/scratch.md CHANGED
@@ -1,5 +1,125 @@
1
1
  # Scratch Note
2
2
 
3
+ What if Dolla was just a global object that you don't instantiate. I have never personally run into a use case for having more than one app on a page at once. In all my projects, the page and the app are synonymous.
4
+
5
+ Doing this would make it possible to access things inside the Dolla app from _outside_ code such as Quill blots. Effectively all code that has access to your Dolla import is _inside_ the app.
6
+
7
+ - Remove stores in favor of just exporting variables and functions from ES modules and importing them where desired.
8
+ -
9
+
10
+ ```jsx
11
+ import Dolla from "@manyducks.co/dolla";
12
+
13
+ // Languages: add translation, set language and get localized string as a signal
14
+ Dolla.language.setup({
15
+ initialLanguage: Dolla.language.detect({ fallback: "ja" }), // Detect user's language and fall back to passed value
16
+ languages: [
17
+ { name: "ja", path: "/static/locales/ja.json" },
18
+ {
19
+ name: "en",
20
+ fetch: async () => {
21
+ // Pass a path string, or if additional logic is needed, a fetch function.
22
+ const res = await Dolla.http.get("/static/locales/en.json");
23
+ return res.body;
24
+ }
25
+ }
26
+ ]
27
+ });
28
+
29
+ Dolla.language.$current
30
+ Dolla.language.t$()
31
+
32
+ // A single setup call to keep things contained (must happen before mount)
33
+ Dolla.router.setup({
34
+ // Initial path must point to a route that actually exists (will be validated on mount) (initialPath is "/" by default)
35
+ initialPath: "/",
36
+ routes: [
37
+ { path: "/", view: SomeView }
38
+ ]
39
+ });
40
+ // And then you can route from anywhere.
41
+ Dolla.router.go("/some/path");
42
+ // Or get route information from anywhere.
43
+ Dolla.router.$path;
44
+ Dolla.router.$params;
45
+
46
+ // Also utils are available
47
+ const joinedPath = Dolla.router.utils.joinPath("/api/records", "5");
48
+ const resolvedPath = Dolla.router.utils.resolvePath("../"); // Resolves with window.location.href as the base
49
+
50
+ // Initializes the app and matches first route
51
+ Dolla.mount("#app");
52
+ // If you pass a view as the second argument it becomes the root view (this works for simple apps without a router)
53
+ Dolla.mount("#app", MyRootView);
54
+ // If router setup function wasn't called then the root view is mounted equivalent to the following:
55
+ Dolla.router.setup({
56
+ defaultPath: "/",
57
+ routes: [
58
+ { path: "/*", view: MyRootView },
59
+ ]
60
+ });
61
+
62
+ // Add HTTP middleware
63
+ Dolla.http.use(async (req, next) => {
64
+ const res = await next()
65
+ });
66
+ // Make HTTP calls
67
+ const res = await Dolla.get("/some/path");
68
+
69
+ // Adjust log level
70
+ Dolla.setLogLevel(Dolla.LOG_LEVEL_INFO);
71
+ Dolla.setLogFilter("*,-Dolla/*")
72
+ // Create a scoped logger
73
+ const debug = Dolla.createLogger("debug-logger");
74
+ debug.log("HELLO");
75
+ debug.warn("THIS IS A SCOPED LOGGER");
76
+
77
+ // Efficiently and safely read and mutate the DOM using Dolla's render batching
78
+ Dolla.render.read(() => {
79
+ // Reference DOM nodes
80
+ });
81
+ Dolla.render.update(() => {
82
+ // Mutate the DOM as part of Dolla's next batch
83
+ }, "some-key");
84
+
85
+ // Respond to lifecycle events
86
+ Dolla.onMount(() => {});
87
+ Dolla.onRouteMatch(() => {});
88
+ // Dolla.onWhatever(() => {});
89
+
90
+ interface SomeViewProps {}
91
+
92
+ function SomeView (props: SomeViewProps, ctx: Dolla.ViewContext) {
93
+ const debug = Dolla.createLogger("SomeView");
94
+
95
+ // returns a signal and a setter function
96
+ const [$someValue, setSomeValue] = Dolla.createSignal(4);
97
+
98
+ // Router is now a part of the Dolla object
99
+ Dolla.router.$path;
100
+ Dolla.router.$params;
101
+
102
+ Dolla.router.go("/some-other-path");
103
+
104
+ ctx.watch([$someValue], (value) => {
105
+ debug.log(value);
106
+ });
107
+
108
+ // View helpers are on ViewContext
109
+ ctx.repeat()
110
+ ctx.cond()
111
+ ctx.render([...states], (...values) => {
112
+ // return Renderable (equivalent to Dolla.derive(states, (...values) => Renderable))
113
+ })
114
+ ctx.portal()
115
+ ctx.outlet()
116
+
117
+ // TODO: Add Dolla.dialog.show() and Dolla.toast.show() or create separate libraries?
118
+
119
+ return <h1>{ctx.t$("home.headerText")}</h1>;
120
+ }
121
+ ```
122
+
3
123
  ```tsx
4
124
  // import { signal, computed } from "@manyducks.co/dolla";
5
125