@manyducks.co/dolla 2.0.0 → 3.1.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 (112) hide show
  1. package/README.md +133 -284
  2. package/dist/context-B5blupD2.js +363 -0
  3. package/dist/context-B5blupD2.js.map +1 -0
  4. package/dist/core/context.d.ts +29 -144
  5. package/dist/core/debug.d.ts +19 -0
  6. package/dist/core/index.d.ts +15 -16
  7. package/dist/core/markup/helpers.d.ts +34 -0
  8. package/dist/core/markup/html.d.ts +3 -0
  9. package/dist/core/{nodes → markup/nodes}/dom.d.ts +5 -4
  10. package/dist/core/markup/nodes/dynamic.d.ts +16 -0
  11. package/dist/core/markup/nodes/element.d.ts +14 -0
  12. package/dist/core/markup/nodes/portal.d.ts +15 -0
  13. package/dist/core/markup/nodes/repeat.d.ts +21 -0
  14. package/dist/core/markup/nodes/view.d.ts +17 -0
  15. package/dist/core/markup/scheduler.d.ts +1 -0
  16. package/dist/core/markup/types.d.ts +62 -0
  17. package/dist/core/markup/utils.d.ts +22 -0
  18. package/dist/core/ref.d.ts +6 -12
  19. package/dist/core/root.d.ts +36 -0
  20. package/dist/core/signals.d.ts +46 -76
  21. package/dist/core/symbols.d.ts +2 -0
  22. package/dist/core-JHktdqjt.js +242 -0
  23. package/dist/core-JHktdqjt.js.map +1 -0
  24. package/dist/http/index.d.ts +21 -33
  25. package/dist/http.js +89 -149
  26. package/dist/http.js.map +1 -1
  27. package/dist/index.js +4 -174
  28. package/dist/jsx-dev-runtime.d.ts +4 -3
  29. package/dist/jsx-dev-runtime.js +12 -9
  30. package/dist/jsx-dev-runtime.js.map +1 -1
  31. package/dist/jsx-runtime.d.ts +5 -4
  32. package/dist/jsx-runtime.js +17 -12
  33. package/dist/jsx-runtime.js.map +1 -1
  34. package/dist/router/index.d.ts +4 -3
  35. package/dist/router/router.d.ts +19 -162
  36. package/dist/router/store.d.ts +12 -0
  37. package/dist/router/types.d.ts +152 -0
  38. package/dist/router/utils.d.ts +99 -0
  39. package/dist/router/utils.test.d.ts +1 -0
  40. package/dist/router.js +428 -5
  41. package/dist/router.js.map +1 -1
  42. package/dist/signals-CMJPGr_M.js +354 -0
  43. package/dist/signals-CMJPGr_M.js.map +1 -0
  44. package/dist/translate/index.d.ts +82 -0
  45. package/dist/translate.js +125 -0
  46. package/dist/translate.js.map +1 -0
  47. package/dist/types.d.ts +21 -39
  48. package/dist/utils.d.ts +41 -29
  49. package/dist/utils.test.d.ts +1 -0
  50. package/dist/virtual/index.d.ts +1 -0
  51. package/dist/virtual/list.d.ts +53 -0
  52. package/package.json +19 -16
  53. package/dist/core/app.d.ts +0 -24
  54. package/dist/core/env.d.ts +0 -3
  55. package/dist/core/hooks.d.ts +0 -70
  56. package/dist/core/logger.d.ts +0 -42
  57. package/dist/core/logger.test.d.ts +0 -0
  58. package/dist/core/markup.d.ts +0 -82
  59. package/dist/core/markup.test.d.ts +0 -0
  60. package/dist/core/nodes/_markup.d.ts +0 -36
  61. package/dist/core/nodes/dynamic.d.ts +0 -22
  62. package/dist/core/nodes/element.d.ts +0 -27
  63. package/dist/core/nodes/portal.d.ts +0 -18
  64. package/dist/core/nodes/repeat.d.ts +0 -27
  65. package/dist/core/nodes/view.d.ts +0 -25
  66. package/dist/core/views/default-crash-view.d.ts +0 -25
  67. package/dist/core/views/for.d.ts +0 -21
  68. package/dist/core/views/fragment.d.ts +0 -7
  69. package/dist/core/views/portal.d.ts +0 -16
  70. package/dist/core/views/show.d.ts +0 -25
  71. package/dist/fragment-BahD_BJA.js +0 -7
  72. package/dist/fragment-BahD_BJA.js.map +0 -1
  73. package/dist/i18n/index.d.ts +0 -134
  74. package/dist/i18n.js +0 -309
  75. package/dist/i18n.js.map +0 -1
  76. package/dist/index-DRJlxs-Q.js +0 -535
  77. package/dist/index-DRJlxs-Q.js.map +0 -1
  78. package/dist/index.js.map +0 -1
  79. package/dist/logger-Aqi9m1CF.js +0 -565
  80. package/dist/logger-Aqi9m1CF.js.map +0 -1
  81. package/dist/markup-8jNhoqDe.js +0 -1089
  82. package/dist/markup-8jNhoqDe.js.map +0 -1
  83. package/dist/router/hooks.d.ts +0 -2
  84. package/dist/router/router.utils.d.ts +0 -93
  85. package/dist/typeChecking-5kmX0ulW.js +0 -65
  86. package/dist/typeChecking-5kmX0ulW.js.map +0 -1
  87. package/dist/typeChecking.d.ts +0 -95
  88. package/docs/buildless.md +0 -132
  89. package/docs/components.md +0 -238
  90. package/docs/hooks.md +0 -356
  91. package/docs/http.md +0 -178
  92. package/docs/i18n.md +0 -220
  93. package/docs/index.md +0 -10
  94. package/docs/markup.md +0 -136
  95. package/docs/mixins.md +0 -176
  96. package/docs/ref.md +0 -77
  97. package/docs/router.md +0 -281
  98. package/docs/setup.md +0 -137
  99. package/docs/signals.md +0 -262
  100. package/docs/stores.md +0 -113
  101. package/docs/views.md +0 -356
  102. package/notes/atomic.md +0 -452
  103. package/notes/elimination.md +0 -33
  104. package/notes/observable.md +0 -180
  105. package/notes/scratch.md +0 -565
  106. package/notes/splitting.md +0 -5
  107. package/notes/views.md +0 -195
  108. package/vite.config.js +0 -22
  109. /package/dist/core/{hooks.test.d.ts → markup/html.test.d.ts} +0 -0
  110. /package/dist/core/{ref.test.d.ts → markup/utils.test.d.ts} +0 -0
  111. /package/dist/router/{router.utils.test.d.ts → matcher.test.d.ts} +0 -0
  112. /package/dist/{typeChecking.test.d.ts → router/router.test.d.ts} +0 -0
@@ -0,0 +1,125 @@
1
+ import { n as e, r as t, s as n, u as r } from "./signals-CMJPGr_M.js";
2
+ //#region src/translate/index.ts
3
+ var i = Symbol("Dolla.Translator");
4
+ function a(e) {
5
+ return async function(t) {
6
+ let n = s(e);
7
+ t[i] = n, await n.setLocale(e.locale);
8
+ };
9
+ }
10
+ function o(e) {
11
+ if (!e[i]) throw Error("Translate plugin isn't loaded.");
12
+ return e[i];
13
+ }
14
+ function s(r) {
15
+ let i = /* @__PURE__ */ new Map();
16
+ if (i.set("number", (e, t, n) => new Intl.NumberFormat(e, n).format(Number(t))), i.set("datetime", (e, t, n) => new Intl.DateTimeFormat(e, n).format(new Date(t))), i.set("list", (e, t, n) => new Intl.ListFormat(e, n).format(t)), r.formatters) for (let e in r.formatters) i.set(e, r.formatters[e]);
17
+ let a, [o, s] = t("en"), l = [...Object.keys(r.translations)];
18
+ async function u(e) {
19
+ let t;
20
+ if (e === void 0) {
21
+ let e = [];
22
+ if (typeof navigator < "u") {
23
+ let t = navigator;
24
+ t.languages?.length > 0 ? e.push(...t.languages) : t.language ? e.push(t.language) : t.browserLanguage ? e.push(t.browserLanguage) : t.userLanguage && e.push(t.userLanguage);
25
+ }
26
+ for (let n of e) if (n in r.translations) {
27
+ t = n;
28
+ break;
29
+ }
30
+ } else e in r.translations && (t = e);
31
+ if (t == null) {
32
+ let e = Object.keys(r.translations).at(0);
33
+ e && (t = e);
34
+ }
35
+ if (!t || !(t in r.translations)) throw Error(`Locale '${e}' has no translation.`);
36
+ a = await c(t, i, r.translations[t]), s(t);
37
+ }
38
+ function d(t, n) {
39
+ return e(() => (o(), a?.(t, n) ?? t));
40
+ }
41
+ function f(t, r, a) {
42
+ let s = i.get(t);
43
+ if (!s) throw Error(`Unknown format: ${t}`);
44
+ return e(() => s(o(), n(r), a ?? {}));
45
+ }
46
+ return {
47
+ supportedLocales: l,
48
+ currentLocale: o,
49
+ setLocale: u,
50
+ t: d,
51
+ format: f
52
+ };
53
+ }
54
+ async function c(e, t, i) {
55
+ let a = l(r(i) ? await i() : i), o = new Map(a);
56
+ return function(r, i) {
57
+ if (i && (i.context != null && (r += "_" + i.context), i.count != null)) if (i.ordinal) {
58
+ let t = `${r}_ordinal_(=${i.count})`;
59
+ o.has(t) ? r = t : r += "_ordinal_" + new Intl.PluralRules(e, { type: "ordinal" }).select(n(i.count));
60
+ } else {
61
+ let t = `${r}_(=${i.count})`;
62
+ o.has(t) ? r = t : r += "_" + new Intl.PluralRules(e).select(n(i.count));
63
+ }
64
+ let a = o.get(r);
65
+ if (!a) return r;
66
+ let s = "";
67
+ for (let n = 0; n < a.length; n++) s += a[n](i, t, e);
68
+ return s;
69
+ };
70
+ }
71
+ function l(e, t = []) {
72
+ let n = [];
73
+ for (let r in e) switch (typeof e[r]) {
74
+ case "string":
75
+ n.push([[...t, r].join("."), u(e[r])]);
76
+ break;
77
+ case "object":
78
+ n.push(...l(e[r], [...t, r]));
79
+ break;
80
+ default: throw Error(`Expected to find a string or object at ${[...t, r].join(".")}. Got: ${typeof e[r]}`);
81
+ }
82
+ return n;
83
+ }
84
+ function u(e) {
85
+ let t = e.split(/(\{\{.*?\}\})/g), r = [];
86
+ for (let e = 0; e < t.length; e++) {
87
+ let i = t[e];
88
+ if (i) if (i.startsWith("{{") && i.endsWith("}}")) {
89
+ let e = i.slice(2, -2).trim().split("|").map((e) => e.trim()), t = e[0], a = [];
90
+ for (let t = 1; t < e.length; t++) {
91
+ let n = e[t], r = n.match(/^([a-zA-Z0-9_]+)(?:\((.*)\))?$/);
92
+ if (r) {
93
+ let e = r[1], t = r[2], n = {};
94
+ if (t) {
95
+ let e = t.split(",");
96
+ for (let t = 0; t < e.length; t++) {
97
+ let r = e[t], i = r.indexOf(":");
98
+ i > -1 && (n[r.slice(0, i).trim()] = r.slice(i + 1).trim());
99
+ }
100
+ }
101
+ a.push({
102
+ name: e,
103
+ options: n
104
+ });
105
+ } else a.push({
106
+ name: n,
107
+ options: {}
108
+ });
109
+ }
110
+ r.push((e, r, i) => {
111
+ let o = e ? n(e[t]) : void 0;
112
+ for (let e = 0; e < a.length; e++) {
113
+ let t = a[e], n = r.get(t.name);
114
+ n && (o = n(i, o, t.options));
115
+ }
116
+ return o == null ? "" : String(o);
117
+ });
118
+ } else r.push(() => i);
119
+ }
120
+ return r;
121
+ }
122
+ //#endregion
123
+ export { l as compile, a as createTranslatePlugin, o as getTranslate, u as parseTemplate };
124
+
125
+ //# sourceMappingURL=translate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translate.js","names":[],"sources":["../src/translate/index.ts"],"sourcesContent":["import { Context } from \"../core/context.js\";\nimport { DollaPlugin } from \"../core/root.js\";\nimport { unwrap, compose, createAtom, type Getter } from \"../core/signals.js\";\nimport { isFunction } from \"../utils.js\";\n\n// ----- Types ----- //\n\n/**\n * A JSON object of translated strings. Values can be string templates or nested objects.\n */\nexport interface LocalizedStrings extends Record<string, string | LocalizedStrings> {}\n\n/**\n * A function that returns an object of localized strings.\n */\nexport type TranslationFetchFn = () => LocalizedStrings | Promise<LocalizedStrings>;\n\nexport type TOptions = {\n /**\n *\n */\n count?: Getter<number> | number;\n\n /**\n *\n */\n context?: Getter<string> | string;\n\n [value: string]: Getter<any> | any;\n};\n\nexport type LookupFn = (selector: string, options?: TOptions) => string;\n\nexport type Formatter = (locale: string, value: any, options: Record<string, any>) => string;\n\ntype BuiltInFormatters = {\n number: [number | bigint, Intl.NumberFormatOptions?];\n datetime: [Date, Intl.DateTimeFormatOptions?];\n list: [Iterable<string>, Intl.ListFormatOptions?];\n};\n\nexport interface Translator {\n /**\n * An array of locale names for all translations the app supports.\n */\n supportedLocales: string[];\n\n /**\n * A Readable containing the currently loaded locale.\n */\n currentLocale: Getter<string>;\n\n /**\n * Updates the locale, fetching any translation files as required.\n * Returns a promise that resolves when the new locale is applied.\n *\n * If `name` is undefined the library will try to match the browser language automatically.\n */\n setLocale(name?: string): Promise<void>;\n\n /**\n * Returns a Readable of the value at `key`.\n\n * @param selector - Key to the translated value.\n * @param options - A map of `{{placeholder}}` names and the values to replace them with.\n *\n * @example\n * const value = t(\"your.key.here\", { count: 5 });\n */\n t(selector: string, options?: TOptions): Getter<string>;\n\n format<K extends keyof BuiltInFormatters, V extends BuiltInFormatters[K][0], O extends BuiltInFormatters[K][1]>(\n name: K,\n value: Getter<V> | V,\n options?: O,\n ): Getter<string>;\n\n format<V, O>(name: string, value: Getter<V> | V, options?: O): Getter<string>;\n}\n\nexport interface TranslatorOptions {\n translations: Record<string, LocalizedStrings | TranslationFetchFn>;\n\n /**\n * Default locale to load on startup. The translator will try to match the user's browser language if left undefined.\n */\n locale?: string;\n\n formatters?: Record<string, Formatter>;\n}\n\nconst TRANSLATE = Symbol(\"Dolla.Translator\");\n\nexport function createTranslatePlugin(options: TranslatorOptions): DollaPlugin {\n return async function (context) {\n const translator = createTranslator(options);\n context[TRANSLATE] = translator;\n await translator.setLocale(options.locale);\n };\n}\n\nexport function getTranslate(context: Context): Translator {\n if (!context[TRANSLATE]) throw new Error(\"Translate plugin isn't loaded.\");\n return context[TRANSLATE];\n}\n\n// ----- Code ----- //\n\nfunction createTranslator(options: TranslatorOptions): Translator {\n const formatters = new Map<string, Formatter>();\n\n formatters.set(\"number\", (locale, value, options) => {\n return new Intl.NumberFormat(locale, options).format(Number(value));\n });\n formatters.set(\"datetime\", (locale, value, options) => {\n return new Intl.DateTimeFormat(locale, options).format(new Date(value));\n });\n formatters.set(\"list\", (locale, value, options) => {\n return new Intl.ListFormat(locale, options).format(value);\n });\n\n if (options.formatters) {\n for (const key in options.formatters) {\n formatters.set(key, options.formatters[key]);\n }\n }\n\n let lookup: LookupFn | undefined;\n\n const [currentLocale, setCurrentLocale] = createAtom(\"en\");\n const supportedLocales = [...Object.keys(options.translations)];\n\n /**\n * Loads translation for the locale.\n */\n async function setLocale(name?: string) {\n let locale!: string;\n\n if (name === undefined) {\n let names = [];\n\n if (typeof navigator !== \"undefined\") {\n const nav = navigator as any;\n\n if (nav.languages?.length > 0) {\n names.push(...nav.languages);\n } else if (nav.language) {\n names.push(nav.language);\n } else if (nav.browserLanguage) {\n names.push(nav.browserLanguage);\n } else if (nav.userLanguage) {\n names.push(nav.userLanguage);\n }\n }\n\n for (const name of names) {\n if (name in options.translations) {\n // Found a matching language.\n locale = name;\n break;\n }\n }\n } else {\n // Tag is the actual tag to set.\n if (name in options.translations) {\n locale = name;\n }\n }\n\n if (locale == null) {\n const firstLanguage = Object.keys(options.translations).at(0);\n if (firstLanguage) {\n locale = firstLanguage;\n }\n }\n\n if (!locale || !(locale in options.translations)) {\n throw new Error(`Locale '${name}' has no translation.`);\n }\n\n lookup = await createLookup(locale, formatters, options.translations[locale]);\n\n // Update locale string after init so t() signals will update.\n setCurrentLocale(locale);\n }\n\n function t(selector: string, options?: TOptions): Getter<string> {\n return compose(() => {\n currentLocale(); // track locale\n return lookup?.(selector, options) ?? selector;\n });\n }\n\n function format<\n K extends keyof BuiltInFormatters,\n V extends BuiltInFormatters[K][0],\n O extends BuiltInFormatters[K][1],\n >(name: K, value: Getter<V> | V, options?: O): Getter<string>;\n\n function format<V, O>(name: string, value: Getter<V> | V, options?: O): Getter<string>;\n\n function format(name: string, value: unknown, options?: Record<string, any>): Getter<string> {\n const callback = formatters.get(name);\n if (!callback) {\n throw new Error(`Unknown format: ${name}`);\n }\n\n return compose(() => callback(currentLocale(), unwrap(value), options ?? {}));\n }\n\n return {\n supportedLocales,\n currentLocale,\n setLocale,\n t,\n format,\n };\n}\n\n/**\n * Loads the translation and produces an efficient lookup function.\n */\nasync function createLookup(\n locale: string,\n formatters: Map<string, Formatter>,\n translation: TranslationFetchFn | LocalizedStrings,\n) {\n const strings = isFunction(translation) ? await translation() : translation;\n const entries = compile(strings);\n const templates = new Map(entries);\n\n /**\n * Looks up the template and produces the output. Any reactive values in `options` are tracked when used.\n */\n return function lookup(selector: string, options?: TOptions): string {\n if (options) {\n // Handle count (pluralization) and context. Keys become \"key_context_pluralization\".\n if (options.context != null) {\n selector += \"_\" + options.context;\n }\n if (options.count != null) {\n if (options.ordinal) {\n // Try to match the exact number key if there is one (e.g. \"myExampleKey_ordinal_(=2)\" when count is 2).\n const exact = `${selector}_ordinal_(=${options.count})`;\n if (templates.has(exact)) {\n selector = exact;\n } else {\n selector += \"_ordinal_\" + new Intl.PluralRules(locale, { type: \"ordinal\" }).select(unwrap(options.count));\n }\n } else {\n // Try to match the exact number key if there is one (e.g. \"myExampleKey_(=2)\" when count is 2).\n const exact = `${selector}_(=${options.count})`;\n if (templates.has(exact)) {\n selector = exact;\n } else {\n selector += \"_\" + new Intl.PluralRules(locale).select(unwrap(options.count));\n }\n }\n }\n }\n\n const template = templates.get(selector);\n if (!template) return selector;\n\n let output = \"\";\n\n for (let i = 0; i < template.length; i++) {\n output += template[i](options, formatters, locale);\n }\n\n return output;\n };\n}\n\n/**\n * Compiles an object of translated strings into a set of function templates.\n */\nexport function compile(strings: { [key: string]: any }, path: string[] = []): [string, CompiledTemplate][] {\n const entries: [string, CompiledTemplate][] = [];\n\n for (const key in strings) {\n switch (typeof strings[key]) {\n case \"string\":\n entries.push([[...path, key].join(\".\"), parseTemplate(strings[key])]);\n break;\n case \"object\":\n entries.push(...compile(strings[key], [...path, key]));\n break;\n default:\n throw new Error(\n `Expected to find a string or object at ${[...path, key].join(\".\")}. Got: ${typeof strings[key]}`,\n );\n }\n }\n\n return entries;\n}\n\nexport type TemplateSegmentFn = (\n options: Record<string, any> | undefined,\n formatters: Map<string, Formatter>,\n locale: string,\n) => string;\n\nexport type CompiledTemplate = TemplateSegmentFn[];\n\n/**\n * Parse a string template into an array of functions that will produce each piece of the output when called.\n */\nexport function parseTemplate(template: string): CompiledTemplate {\n const tokens = template.split(/(\\{\\{.*?\\}\\})/g);\n const segments: TemplateSegmentFn[] = [];\n\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n if (!token) continue;\n\n if (token.startsWith(\"{{\") && token.endsWith(\"}}\")) {\n const inner = token.slice(2, -2).trim();\n const parts = inner.split(\"|\").map((p) => p.trim());\n\n const name = parts[0];\n const parsedFormats: { name: string; options: Record<string, string> }[] = [];\n\n // Parse formatters at build-time to prevent string splitting on every render\n for (let j = 1; j < parts.length; j++) {\n const formatStr = parts[j];\n const match = formatStr.match(/^([a-zA-Z0-9_]+)(?:\\((.*)\\))?$/);\n\n if (match) {\n const formatName = match[1];\n const optionsStr = match[2];\n const optsObj: Record<string, string> = {};\n\n if (optionsStr) {\n const pairs = optionsStr.split(\",\");\n for (let k = 0; k < pairs.length; k++) {\n const pair = pairs[k];\n const colonIndex = pair.indexOf(\":\");\n if (colonIndex > -1) {\n optsObj[pair.slice(0, colonIndex).trim()] = pair.slice(colonIndex + 1).trim();\n }\n }\n }\n parsedFormats.push({ name: formatName, options: optsObj });\n } else {\n parsedFormats.push({ name: formatStr, options: {} });\n }\n }\n\n // Push the dynamic closure\n segments.push((options, formatters, locale) => {\n // Evaluate and track the specific option at runtime.\n // This code runs in the t() computed context.\n let value = options ? unwrap(options[name]) : undefined;\n\n for (let k = 0; k < parsedFormats.length; k++) {\n const fmt = parsedFormats[k];\n const formatterFn = formatters.get(fmt.name);\n if (formatterFn) {\n value = formatterFn(locale, value, fmt.options);\n }\n }\n\n return value != null ? String(value) : \"\";\n });\n } else {\n // Push a static closure that just returns the token\n segments.push(() => token);\n }\n }\n\n return segments;\n}\n"],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -1,30 +1,21 @@
1
1
  import type * as CSS from "csstype";
2
- import type { Markup, MarkupNode } from "./core/markup.js";
3
- import type { Signal } from "./core/signals.js";
2
+ import type { ComponentState, Context } from "./core/context.js";
3
+ import type { Markup, MarkupNode } from "./core/markup/types.js";
4
+ import type { Getter } from "./core/signals.js";
4
5
  export type Env = "production" | "development";
5
6
  /**
6
7
  * Represents everything that can be handled as a DOM node.
7
8
  * These are all the items considered valid to pass as children to any element.
8
9
  */
9
- export type Renderable = string | number | Node | Markup | MarkupNode | false | null | undefined | Signal<any> | (string | number | Node | Markup | MarkupNode | false | null | undefined | Signal<any>)[];
10
+ export type Renderable = string | number | Node | Markup | MarkupNode | false | null | undefined | void | Getter<any> | Renderable[];
10
11
  export interface BaseProps {
11
12
  children?: Renderable;
12
13
  }
13
- /**
14
- *
15
- */
16
- export type View<Props> = (props: Props) => Renderable;
17
- /**
18
- *
19
- */
20
- export type Store<Options, Value> = (options: Options) => Value;
21
- /**
22
- *
23
- */
24
- export type Mixin<E extends Element = Element> = (element: E) => void;
25
- type MaybeSignal<T> = T | Signal<T> | Signal<T | undefined>;
26
- type OptionalProperty<T> = MaybeSignal<T>;
27
- type RequiredProperty<T> = T | Signal<T>;
14
+ export type View<Props = {}, State = Record<string | symbol, any>> = (this: Context<ComponentState & State>, props: Props, context: Context<ComponentState & State>) => Renderable;
15
+ export type Store<Props, Value, State = Record<string | symbol, any>> = (this: Context<ComponentState & State>, props: Props, context: Context<ComponentState & State>) => Value;
16
+ export type MaybeGetter<T> = Getter<T> | T;
17
+ type RequiredProperty<T> = Getter<T> | T;
18
+ type OptionalProperty<T> = Getter<T> | Getter<T | undefined> | T;
28
19
  type AutocapitalizeValues = "off" | "on" | "none" | "sentences" | "words" | "characters";
29
20
  type ContentEditableValues = true | false | "true" | "false" | "plaintext-only" | "inherit";
30
21
  type ClassListValues = string | ClassMap | Array<string | ClassMap | (string | ClassMap)[]>;
@@ -48,12 +39,6 @@ export interface ElementProps {
48
39
  * Attaches an event listener to the element (with `addEventListener`).
49
40
  */
50
41
  [key: `on:${string}`]: OptionalProperty<EventHandler<Event>>;
51
- /**
52
- * HTML attributes to assign to the element.
53
- */
54
- /**
55
- * Object of event listeners.
56
- */
57
42
  /**
58
43
  * CSS classes to be applied to this element. In addition to the standard space-separated list of class names,
59
44
  * this property also supports a class map object with class names as keys and booleans as values.
@@ -158,7 +143,7 @@ export interface ElementProps {
158
143
  *
159
144
  * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/style
160
145
  */
161
- style?: string | CSSProperties | Signal<string> | Signal<CSSProperties> | Signal<string | CSSProperties> | Signal<string | undefined> | Signal<CSSProperties | undefined> | Signal<string | CSSProperties | undefined>;
146
+ style?: string | CSSProperties | Getter<string> | Getter<CSSProperties> | Getter<string | CSSProperties> | Getter<string | undefined> | Getter<CSSProperties | undefined> | Getter<string | CSSProperties | undefined>;
162
147
  /**
163
148
  * Fired when a CSS animation unexpectedly aborts.
164
149
  *
@@ -721,6 +706,10 @@ export interface ElementProps {
721
706
  onwheel?: OptionalProperty<EventHandler<WheelEvent>>;
722
707
  }
723
708
  export interface HTMLElementProps extends ElementProps {
709
+ /**
710
+ * Data attribute.
711
+ */
712
+ [key: `data-${string}`]: OptionalProperty<any>;
724
713
  /**
725
714
  * Sets the key a user can press to jump to this element.
726
715
  *
@@ -1002,12 +991,6 @@ export interface HTMLElementProps extends ElementProps {
1002
991
  */
1003
992
  onpaste?: OptionalProperty<EventHandler<ClipboardEvent>>;
1004
993
  }
1005
- export interface SVGElementProps extends ElementProps {
1006
- /**
1007
- * A mixin function or an array of mixin functions to be applied to this element.
1008
- */
1009
- mixin?: Mixin<SVGElement> | Mixin<SVGElement>[];
1010
- }
1011
994
  /**
1012
995
  * Mapping of event props to event names.
1013
996
  */
@@ -1279,7 +1262,7 @@ export type CSSProperties = {
1279
1262
  [K in keyof Styles]: OptionalProperty<Styles[K]>;
1280
1263
  };
1281
1264
  export interface ClassMap {
1282
- [className: string]: MaybeSignal<any>;
1265
+ [className: string]: OptionalProperty<any>;
1283
1266
  }
1284
1267
  export type EventHandler<E> = (event: E) => void;
1285
1268
  export interface PropertiesOf<E extends HTMLElement> extends HTMLElementProps {
@@ -1289,12 +1272,9 @@ export interface PropertiesOf<E extends HTMLElement> extends HTMLElementProps {
1289
1272
  children?: any;
1290
1273
  /**
1291
1274
  * Receives a reference to the DOM node when rendered.
1275
+ * Returns a cleanup function that is called when the node is removed.
1292
1276
  */
1293
- ref?: ((value: E | undefined) => void) | ((value: HTMLElement | undefined) => void) | ((value: Element | undefined) => void) | ((value: Node | undefined) => void);
1294
- /**
1295
- * A mixin function or an array of mixin functions to be applied to this element.
1296
- */
1297
- mixin?: Mixin<E> | Mixin<E>[];
1277
+ ref?: ((value: E) => () => void) | ((value: HTMLElement) => () => void) | ((value: Element) => () => void) | ((value: Node) => () => void);
1298
1278
  }
1299
1279
  /**
1300
1280
  * The following elements are defined based on the WHATWG HTML spec:
@@ -2171,7 +2151,7 @@ interface HTMLMediaElementProps<T extends HTMLMediaElement> extends HTMLElementP
2171
2151
  *
2172
2152
  * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/srcObject
2173
2153
  */
2174
- srcObject?: MediaStream | MediaSource | Blob | File | Signal<MediaStream> | Signal<MediaStream | undefined> | Signal<MediaSource> | Signal<MediaSource | undefined> | Signal<Blob> | Signal<Blob | undefined> | Signal<File> | Signal<File | undefined>;
2154
+ srcObject?: MediaStream | MediaSource | Blob | File | Getter<MediaStream> | Getter<MediaStream | undefined> | Getter<MediaSource> | Getter<MediaSource | undefined> | Getter<Blob> | Getter<Blob | undefined> | Getter<File> | Getter<File | undefined>;
2175
2155
  /**
2176
2156
  * The current audio volume of the media element. Must be a number between 0 and 1.
2177
2157
  *
@@ -2670,7 +2650,7 @@ interface HTMLImageElementProps extends PropertiesOf<HTMLImageElement> {
2670
2650
  *
2671
2651
  * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/sizes
2672
2652
  */
2673
- sizes?: MaybeSignal<string>;
2653
+ sizes?: OptionalProperty<string>;
2674
2654
  /**
2675
2655
  * The image URL.
2676
2656
  *
@@ -3425,4 +3405,6 @@ interface HTMLCanvasElementProps extends PropertiesOf<HTMLCanvasElement> {
3425
3405
  */
3426
3406
  height?: OptionalProperty<string | number> | OptionalProperty<string> | OptionalProperty<number>;
3427
3407
  }
3408
+ export interface IntrinsicElements {
3409
+ }
3428
3410
  export {};
package/dist/utils.d.ts CHANGED
@@ -1,46 +1,58 @@
1
- export declare const noOp: () => void;
2
- export declare function getUniqueId(): string;
3
- export declare function getIntegerId(): number;
1
+ export declare function uniqueId(): string;
4
2
  /**
5
- * Equality check that passes if both values are the same object.
6
- * This is the default equality check for states.
3
+ * Returns a new object without the specified keys.
4
+ * If called without object, returns a function that takes an object
5
+ * and returns a version with the original keys omitted.
6
+ *
7
+ * @param keys - An array of keys to omit.
8
+ * @param object - An object to clone without the omitted keys.
7
9
  */
8
- export declare function strictEqual(a: any, b: any): boolean;
10
+ export declare function omit<O extends Record<any, any>>(keys: (keyof O)[], object: O): Record<any, any>;
9
11
  /**
10
- * Equality check that passes if both values are the same object, or if both are objects or arrays with equal keys and values.
12
+ * Throws a TypeError unless `condition` is truthy.
13
+ *
14
+ * @param value - Value whose truthiness is in question.
15
+ * @param errorMessage - Optional message for the thrown TypeError.
11
16
  */
12
- export declare function shallowEqual(a: any, b: any): boolean;
17
+ export declare function assert<T = any>(value: T, errorMessage: string): asserts value is NonNullable<T>;
13
18
  /**
14
- * Equality check that passes if two objects have equal values, even if they are not the same object.
19
+ * Returns true if `value` is an array.
15
20
  */
16
- export declare function deepEqual(a: any, b: any): boolean;
21
+ export declare function isArray(value: unknown): value is Array<unknown>;
17
22
  /**
18
- * Takes an old value and a new value. Returns a merged copy if both are objects, otherwise returns the new value.
23
+ * Returns true when `value` is an array and `check` returns true for every item.
24
+ *
25
+ * @param check - Function to check items against.
26
+ * @param value - A possible array.
19
27
  */
20
- export declare function merge(one: unknown, two: unknown): any;
28
+ export declare function isArrayOf<T>(check: (item: unknown) => boolean, value: unknown): value is T[];
29
+ export declare function isArrayOf<T>(check: (item: unknown) => boolean): (value: unknown) => value is T[];
21
30
  /**
22
- * Returns a new object without the specified keys.
23
- * If called without object, returns a function that takes an object
24
- * and returns a version with the original keys omitted.
25
- *
26
- * @param keys - An array of keys to omit.
27
- * @param object - An object to clone without the omitted keys.
31
+ * Returns true if `value` is a string.
28
32
  */
29
- export declare function omit<O extends Record<any, any>>(keys: (keyof O)[], object: O): Record<any, any>;
30
- export declare function toArray<T>(value: T | T[]): T[];
31
- export declare function toCamelCase(s: string): string;
33
+ export declare function isString(value: unknown): value is string;
32
34
  /**
33
- * Moves an element using `moveBefore` if the browser supports it, otherwise falls back to `insertBefore`.
35
+ * Returns true if `value` is a function (but not a class).
34
36
  */
35
- export declare function moveBefore(parent: Node, node: Node, child: Node | null): void;
37
+ export declare function isFunction<T = (...args: unknown[]) => unknown>(value: unknown): value is T;
38
+ export declare function isClass(value: unknown): boolean;
36
39
  /**
37
- * Takes any string and returns an OKLCH color.
40
+ * Returns true if `value` is a number.
38
41
  */
39
- export declare function okhash(value: string): string;
40
- export type MatcherFunction = (value: string) => boolean;
42
+ export declare function isNumber(value: unknown): value is number;
41
43
  /**
42
- * Parses a filter string into a matcher function.
44
+ * Returns `true` if `value` is an instance of `constructor`.
43
45
  *
44
- * @param pattern - A string or regular expression that specifies a pattern for names of loggers whose messages you want to display.
46
+ * @param constructor - The constructor `value` must be an instance of.
47
+ * @param value - A value that may be an instance of `constructor`.
48
+ */
49
+ export declare function isInstanceOf<T extends Function>(constructor: T, value: unknown): value is T;
50
+ export declare function isInstanceOf<T extends Function>(constructor: T): (value: unknown) => value is T;
51
+ /**
52
+ * Returns true if `value` is a JavaScript Promise.
53
+ */
54
+ export declare function isPromise<T = unknown>(value: unknown): value is Promise<T>;
55
+ /**
56
+ * Returns true if `value` is a plain JavaScript object.
45
57
  */
46
- export declare function createMatcher(pattern: string | RegExp): MatcherFunction;
58
+ export declare function isObject<T = Record<string | number | symbol, unknown>>(value: unknown): value is T;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export { createVirtualList } from "./list";
@@ -0,0 +1,53 @@
1
+ import { type Getter } from "../core/signals.js";
2
+ import { View } from "../types.js";
3
+ export interface VirtualListAPI<T> {
4
+ scrollToBottom: (smooth?: boolean) => void;
5
+ scrollToTop: (smooth?: boolean) => void;
6
+ scrollToIndex: (index: number, options?: {
7
+ smooth?: boolean;
8
+ align?: "start" | "center" | "end";
9
+ }) => void;
10
+ scrollToItem: (item: T, options?: {
11
+ smooth?: boolean;
12
+ align?: "start" | "center" | "end";
13
+ }) => void;
14
+ isAtBottom: Getter<boolean>;
15
+ }
16
+ export interface VirtualListContext {
17
+ isEntering: Getter<boolean>;
18
+ }
19
+ export interface VirtualListOptions<T> {
20
+ items: Getter<T[]>;
21
+ /** A stable identifier for each item, crucial for detecting changes accurately */
22
+ keyFn: (item: T) => string | number;
23
+ bottomUp?: boolean;
24
+ enterAnimationMs?: number;
25
+ /** Configuration for the virtual pool */
26
+ estimatedItemHeight?: number;
27
+ poolSize?: number;
28
+ /** Infinite scroll callbacks */
29
+ onTopReached?: () => void;
30
+ onBottomReached?: () => void;
31
+ threshold?: number;
32
+ render: (item: Getter<T>, index: Getter<number>, context: VirtualListContext) => any;
33
+ renderEmpty?: () => any;
34
+ isSticky?: (item: T) => boolean;
35
+ renderSticky?: (item: Getter<T>) => any;
36
+ }
37
+ export declare function createVirtualList<T>(props: VirtualListOptions<T>): [View, VirtualListAPI<T>];
38
+ export declare function createOffsetEngine(defaultAssumption: number): {
39
+ averageHeight: Getter<number>;
40
+ getTotalHeight: (totalItems: number) => number;
41
+ getOffset: (index: number, avg: number) => number;
42
+ findIndexAtScroll: (scrollPos: number, totalItems: number, avg: number) => number;
43
+ findSticky: (scrollPos: number, indices: number[], avg: number) => {
44
+ activeIdx: number;
45
+ nextIdx: number;
46
+ };
47
+ updateHeights: (entries: {
48
+ index: number;
49
+ height: number;
50
+ }[], avg: number) => boolean;
51
+ clearCache: () => void;
52
+ getItemHeight: (index: number) => number | undefined;
53
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@manyducks.co/dolla",
3
- "version": "2.0.0",
4
- "description": "A fast, batteries-included JavaScript framework with a React-like API and the power of Signals.",
3
+ "version": "3.1.0",
4
+ "description": "A fast, batteries-included JavaScript framework with a React-inspired API and the power of signals.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/core/index.d.ts",
7
7
  "type": "module",
@@ -21,7 +21,8 @@
21
21
  "web app",
22
22
  "front end framework",
23
23
  "functional",
24
- "reactive state"
24
+ "reactive state",
25
+ "signals"
25
26
  ],
26
27
  "author": "tony@manyducks.co",
27
28
  "license": "MIT",
@@ -34,14 +35,14 @@
34
35
  "import": "./dist/router.js",
35
36
  "types": "./dist/router/index.d.ts"
36
37
  },
38
+ "./translate": {
39
+ "import": "./dist/translate.js",
40
+ "types": "./dist/translate/index.d.ts"
41
+ },
37
42
  "./http": {
38
43
  "import": "./dist/http.js",
39
44
  "types": "./dist/http/index.d.ts"
40
45
  },
41
- "./i18n": {
42
- "import": "./dist/i18n.js",
43
- "types": "./dist/i18n/index.d.ts"
44
- },
45
46
  "./jsx-runtime": {
46
47
  "import": "./dist/jsx-runtime.js",
47
48
  "types": "./jsx-runtime.d.ts"
@@ -51,15 +52,17 @@
51
52
  "types": "./jsx-dev-runtime.d.ts"
52
53
  }
53
54
  },
54
- "dependencies": {
55
- "alien-signals": "^2.0.5"
56
- },
55
+ "files": [
56
+ "dist",
57
+ "*.d.ts"
58
+ ],
57
59
  "devDependencies": {
58
- "@types/node": "^24.1.0",
59
- "csstype": "^3.1.3",
60
- "prettier": "^3.6.2",
61
- "typescript": "^5.8.3",
62
- "vite": "^7.0.6",
63
- "vitest": "^3.2.4"
60
+ "@types/node": "^25.6.0",
61
+ "csstype": "^3.2.3",
62
+ "jsdom": "^29.0.2",
63
+ "prettier": "^3.8.3",
64
+ "typescript": "^6.0.3",
65
+ "vite": "^8.0.10",
66
+ "vitest": "^4.1.5"
64
67
  }
65
68
  }
@@ -1,24 +0,0 @@
1
- import { Router, RouterOptions } from "../router/router";
2
- import { View } from "../types";
3
- import { Context } from "./context";
4
- import { LoggerCrashProps } from "./logger";
5
- interface AppOptions {
6
- view?: View<{}>;
7
- router?: Router;
8
- context?: Context;
9
- }
10
- declare class App {
11
- #private;
12
- get context(): Context;
13
- constructor(options: AppOptions);
14
- setCrashView(view: View<LoggerCrashProps>): this;
15
- mount(element: string | Element): Promise<void>;
16
- unmount(): Promise<void>;
17
- }
18
- export interface CreateAppOptions {
19
- context?: Context;
20
- }
21
- export declare function createApp(view: View<{}>, options?: CreateAppOptions): App;
22
- export declare function createApp(routerOptions: RouterOptions, options?: CreateAppOptions): App;
23
- export declare function createApp(router: Router, options?: CreateAppOptions): App;
24
- export {};
@@ -1,3 +0,0 @@
1
- import type { Env } from "../types";
2
- export declare function getEnv(): string;
3
- export declare function setEnv(value: Env): void;
@@ -1,70 +0,0 @@
1
- import { type Context, type Ref, type Store } from "../core";
2
- import { type EffectFn, type MaybeSignal, type Setter, type Signal, type SignalOptions } from "../core/signals";
3
- /**
4
- * Returns the Context object of the `View`, `Store` or `Mixin` this hook is called in.
5
- *
6
- * @param name - If passed, the context will be renamed. Context takes the name of the component function by default.
7
- */
8
- export declare function useContext(name?: MaybeSignal<string>): Context;
9
- /**
10
- * Returns the nearest instance of a Store provided to this context.
11
- */
12
- export declare function useStore<T>(store: Store<any, T>): T;
13
- /**
14
- * Adds a store to this context and returns the store instance.
15
- */
16
- export declare function useStoreProvider<T, O>(store: Store<O, T>, options?: O): T;
17
- /**
18
- * Schedules `callback` to run just after the component is mounted.
19
- * If `callback` returns a function, that function will run when the context is unmounted.
20
- */
21
- export declare function useMount(callback: () => void | (() => void)): void;
22
- /**
23
- * Schedules `callback` to run when the context is unmounted.
24
- */
25
- export declare function useUnmount(callback: () => void): void;
26
- /**
27
- * Creates a new read-only Signal. Returns bound Getter and Setter functions.
28
- *
29
- * @example
30
- * const [$count, setCount] = useSignal(5);
31
- * $count(); // 5
32
- * setCount(6);
33
- * setCount((current) => current + 1);
34
- * $count(); // 7
35
- */
36
- export declare function useSignal<T>(value: T, options?: SignalOptions<T>): [Signal<T>, Setter<T>];
37
- export declare function useSignal<T>(value: undefined, options: SignalOptions<T>): [Signal<T | undefined>, Setter<T | undefined>];
38
- export declare function useSignal<T>(): [Signal<T | undefined>, Setter<T | undefined>];
39
- export declare function useMemo<T>(compute: (current?: T) => MaybeSignal<T>, deps?: Signal<any>[], options?: SignalOptions<T>): Signal<T>;
40
- /**
41
- * Takes the current state and a dispatched action. Returns a new state based on the action.
42
- * Typically the body of this function will be a large switch statement.
43
- */
44
- export type Reducer<State, Action> = (state: State, action: Action) => State;
45
- /**
46
- * Dispatches an action to this reducer, causing the state to update.
47
- */
48
- export type Dispatcher<Action> = (action: Action) => void;
49
- /**
50
- *
51
- */
52
- export declare function useReducer<State, Action>(reducer: Reducer<State, Action>, initialState: State): [Signal<State>, Dispatcher<Action>];
53
- /**
54
- * Creates an effect bound to the current context.
55
- * The `fn` is called when the component is mounted, then again each time the dependencies are updated until the component is unmounted.
56
- */
57
- export declare function useEffect(fn: EffectFn, deps?: Signal<any>[]): void;
58
- /**
59
- * A hybrid Ref which is both a function ref and a React-style object ref with a `current` property.
60
- * Both the `current` property and the function syntax access the same value.
61
- */
62
- export interface HybridRef<T> extends Ref<T> {
63
- current: T;
64
- }
65
- /**
66
- * Creates a Ref. Useful for getting references to DOM nodes.
67
- *
68
- * @deprecated use ref()
69
- */
70
- export declare function useRef<T>(initialValue?: T): HybridRef<T>;
@@ -1,42 +0,0 @@
1
- import type { Env } from "../types.js";
2
- import { type MaybeSignal } from "./signals.js";
3
- export interface LogLevels {
4
- info: boolean | Env;
5
- log: boolean | Env;
6
- warn: boolean | Env;
7
- error: boolean | Env;
8
- }
9
- export interface Logger {
10
- info(...args: any[]): void;
11
- log(...args: any[]): void;
12
- warn(...args: any[]): void;
13
- error(...args: any[]): void;
14
- crash(error: Error): Error;
15
- }
16
- export interface LoggerOptions {
17
- /**
18
- * Tag value to print with logs.
19
- */
20
- tag?: string;
21
- /**
22
- * Label for tag value. Will be printed without a label if not specified.
23
- */
24
- tagName?: string;
25
- /**
26
- * Console object to use for logging (mostly for testing). Uses window.console by default.
27
- */
28
- console?: any;
29
- }
30
- export interface LoggerCrashProps {
31
- error: Error;
32
- loggerName: string;
33
- tag?: string;
34
- tagName?: string;
35
- }
36
- /**
37
- * Listen for logged crashes.
38
- */
39
- export declare function onLoggerCrash(listener: (context: LoggerCrashProps) => void): () => void;
40
- export declare function createLogger(name: MaybeSignal<string>, options?: LoggerOptions): Logger;
41
- export declare function setLogFilter(filter: string | RegExp): void;
42
- export declare function setLogLevels(options: Partial<LogLevels>): void;
File without changes