@manyducks.co/dolla 2.0.0-alpha.53 → 2.0.0-alpha.55

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 (52) hide show
  1. package/README.md +1 -12
  2. package/dist/core/context.d.ts +80 -54
  3. package/dist/core/index.d.ts +8 -7
  4. package/dist/core/logger.d.ts +9 -4
  5. package/dist/core/markup.d.ts +10 -10
  6. package/dist/core/mount.d.ts +11 -6
  7. package/dist/core/nodes/dynamic.d.ts +3 -3
  8. package/dist/core/nodes/html.d.ts +6 -5
  9. package/dist/core/nodes/outlet.d.ts +3 -4
  10. package/dist/core/nodes/portal.d.ts +2 -2
  11. package/dist/core/nodes/repeat.d.ts +6 -6
  12. package/dist/core/nodes/view.d.ts +13 -81
  13. package/dist/core/symbols.d.ts +0 -2
  14. package/dist/core/views/default-crash-view.d.ts +5 -1
  15. package/dist/core/views/fragment.d.ts +2 -2
  16. package/dist/fragment-VXM-P2tT.js +7 -0
  17. package/dist/fragment-VXM-P2tT.js.map +1 -0
  18. package/dist/http.js +1 -1
  19. package/dist/i18n.js +14 -14
  20. package/dist/i18n.js.map +1 -1
  21. package/dist/index.js +54 -61
  22. package/dist/index.js.map +1 -1
  23. package/dist/jsx-dev-runtime.js +8 -8
  24. package/dist/jsx-dev-runtime.js.map +1 -1
  25. package/dist/jsx-runtime.js +9 -9
  26. package/dist/jsx-runtime.js.map +1 -1
  27. package/dist/{logger-CByUPmlz.js → logger-CXdzxt1e.js} +178 -176
  28. package/dist/{logger-CByUPmlz.js.map → logger-CXdzxt1e.js.map} +1 -1
  29. package/dist/markup-yTuFdC0t.js +923 -0
  30. package/dist/markup-yTuFdC0t.js.map +1 -0
  31. package/dist/router/router.d.ts +9 -6
  32. package/dist/router-B-rtBG7i.js +488 -0
  33. package/dist/router-B-rtBG7i.js.map +1 -0
  34. package/dist/router.js +1 -1
  35. package/dist/router.js.map +1 -1
  36. package/dist/{typeChecking-EAVNeFyB.js → typeChecking-lgllKIVq.js} +5 -5
  37. package/dist/{typeChecking-EAVNeFyB.js.map → typeChecking-lgllKIVq.js.map} +1 -1
  38. package/dist/types.d.ts +21 -0
  39. package/docs/mixins.md +32 -0
  40. package/docs/ref.md +93 -0
  41. package/index.d.ts +1 -1
  42. package/notes/mixins.md +22 -0
  43. package/notes/scratch.md +24 -0
  44. package/package.json +2 -2
  45. package/dist/core/store.d.ts +0 -57
  46. package/dist/core/views/passthrough.d.ts +0 -5
  47. package/dist/fragment-DFnx8z2z.js +0 -8
  48. package/dist/fragment-DFnx8z2z.js.map +0 -1
  49. package/dist/router-W2HPWbeI.js +0 -482
  50. package/dist/router-W2HPWbeI.js.map +0 -1
  51. package/dist/view-CAEIbcZt.js +0 -932
  52. package/dist/view-CAEIbcZt.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"typeChecking-EAVNeFyB.js","sources":["../src/typeChecking.ts"],"sourcesContent":["type TypeNames =\n // These values can be returned by `typeof`.\n | \"string\"\n | \"number\"\n | \"bigint\"\n | \"boolean\"\n | \"symbol\"\n | \"undefined\"\n | \"object\"\n | \"function\"\n // These values are more specific ones that the `typeOf` function can return.\n | \"null\"\n | \"array\"\n | \"class\"\n | \"promise\"\n | \"map\"\n | \"set\"\n | \"NaN\";\n\n/**\n * Extends `typeof` operator with more specific and useful type distinctions.\n */\nexport function typeOf(value: any): TypeNames {\n const type = typeof value;\n switch (type) {\n case \"undefined\":\n return type;\n case \"number\":\n if (isNaN(value as any)) return \"NaN\";\n return type;\n case \"function\":\n if (/^\\s*class\\s+/.test(value.toString())) return \"class\";\n return type;\n case \"object\":\n if (value === null) return \"null\";\n if (value instanceof Promise) return \"promise\";\n if (value instanceof Map) return \"map\";\n if (value instanceof Set) return \"set\";\n if (Array.isArray(value)) return \"array\";\n return type;\n default:\n return type;\n }\n}\n\n/**\n * Throws a TypeError unless `condition` is truthy.\n *\n * @param condition - Value whose truthiness is in question.\n * @param errorMessage - Optional message for the thrown TypeError.\n */\nexport function assert(condition: any, errorMessage?: string): void {\n if (!condition) {\n throw new TypeError(\n formatError(condition, errorMessage || \"Failed assertion. Value is not truthy. Got type: %t, value: %v\"),\n );\n }\n}\n\n/**\n * Returns true if `value` is an array.\n */\nexport function isArray(value: unknown): value is Array<unknown> {\n return Array.isArray(value);\n}\n\n/**\n * Throws an error if `value` is not an array.\n */\nexport function assertArray(value: unknown, errorMessage?: string): value is Array<unknown> {\n if (isArray(value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage || \"Expected array. Got type: %t, value: %v\"));\n}\n\n/**\n * Returns true when `value` is an array and `check` returns true for every item.\n *\n * @param check - Function to check items against.\n * @param value - A possible array.\n */\n\nexport function isArrayOf<T>(check: (item: unknown) => boolean, value: unknown): value is T[] {\n return isArray(value) && value.every((item) => check(item));\n}\n\n/**\n * Throws a TypeError unless `value` is an array and `check` returns true for every item.\n *\n * @param check - Function to check items against.\n * @param value - A possible array.\n * @param errorMessage - A custom error message.\n */\nexport function assertArrayOf<T>(\n check: (item: unknown) => boolean,\n value: unknown,\n errorMessage?: string,\n): value is T[] {\n if (isArrayOf(check, value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage ?? \"Expected an array of valid items. Got type: %t, value: %v\"));\n}\n\n/**\n * Returns true if `value` is a string.\n */\nexport function isString(value: unknown): value is string {\n return typeof value === \"string\";\n}\n\n/**\n * Throws a TypeError unless `value` is a string.\n */\nexport function assertString(value: unknown, errorMessage?: string): value is string {\n if (isString(value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage ?? \"Expected a string. Got type: %t, value: %v\"));\n}\n\n// TODO: More specific validation for common types of strings? Email address, URL, UUID, etc?\n\n/**\n * Returns true if `value` is a function (but not a class).\n */\nexport function isFunction<T = (...args: unknown[]) => unknown>(value: unknown): value is T {\n return typeOf(value) === \"function\";\n}\n\n/**\n * Throws a TypeError unless `value` is a function.\n */\nexport function assertFunction<T = (...args: unknown[]) => unknown>(value: unknown, errorMessage?: string): value is T {\n if (isFunction(value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage ?? \"Expected a function. Got type: %t, value: %v\"));\n}\n\n/**\n * Returns true if `value` is a number.\n */\nexport function isNumber(value: unknown): value is number {\n return typeof value === \"number\" && !isNaN(value);\n}\n\n/**\n * Throws a TypeError unless `value` is a number.\n */\nexport function assertNumber(value: unknown, errorMessage?: string): value is number {\n if (isNumber(value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage ?? \"Expected a number. Got type: %t, value: %v\"));\n}\n\n/**\n * Returns a function that takes a `value` and returns true if `value` is an instance of `constructor`.\n *\n * @param constructor - The constructor a value must be an instance of to match.\n */\nexport function isInstanceOf<T extends Function>(constructor: T): (value: unknown) => value is T;\n\n/**\n * Returns `true` if `value` is an instance of `constructor`.\n *\n * @param constructor - The constructor `value` must be an instance of.\n * @param value - A value that may be an instance of `constructor`.\n */\nexport function isInstanceOf<T extends Function>(constructor: T, value: unknown): value is T;\n\nexport function isInstanceOf<T extends Function>(...args: unknown[]) {\n const constructor = args[0] as T;\n\n const test = (value: unknown): value is T => {\n return value instanceof constructor;\n };\n\n if (args.length < 2) {\n return test;\n } else {\n return test(args[1]);\n }\n}\n\n/**\n * Returns a function that takes a `value` and throws a TypeError unless `value` is an instance of `constructor`.\n *\n * @param constructor - The constructor a value must be an instance of to match.\n */\nexport function assertInstanceOf<T extends Function>(constructor: T): (value: unknown) => value is T;\n\n/**\n * Throws a TypeError unless `value` is an instance of `constructor`.\n *\n * @param constructor - The constructor `value` must be an instance of.\n * @param value - A value that may be an instance of `constructor`.\n * @param errorMessage - A custom error message for when the assertion fails.\n */\nexport function assertInstanceOf<T extends Function>(constructor: T, value: unknown, errorMessage?: string): value is T;\n\nexport function assertInstanceOf<T extends Function>(...args: unknown[]) {\n const constructor = args[0] as T;\n const errorMessage = isString(args[2])\n ? args[2]\n : `Expected instance of ${constructor.name}. Got type: %t, value: %v`;\n\n const test = (value: unknown): value is T => {\n if (value instanceof constructor) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage));\n };\n\n if (args.length < 2) {\n return test;\n } else {\n return test(args[1]);\n }\n}\n\n/**\n * Returns true if `value` is a plain JavaScript object.\n */\nexport function isObject(value: unknown): value is Record<string | number | symbol, unknown> {\n return value != null && typeof value === \"object\" && !isArray(value);\n}\n\n/**\n * Throws a TypeError unless `value` is a plain JavaScript object.\n */\nexport function assertObject(value: unknown, errorMessage?: string): value is object {\n if (isObject(value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage ?? \"Expected an object. Got type: %t, value: %v\"));\n}\n\n/**\n * Replaces `%t` and `%v` placeholders in a message with real values.\n */\nfunction formatError(value: unknown, message: string) {\n const typeName = typeOf(value);\n\n // TODO: Pretty format value as string based on type.\n const valueString = value?.toString?.() || String(value);\n\n return message.replaceAll(\"%t\", typeName).replaceAll(\"%v\", valueString);\n}\n"],"names":["typeOf","value","type","isArray","isArrayOf","check","item","assertArrayOf","errorMessage","formatError","isString","assertString","isFunction","isNumber","assertInstanceOf","args","constructor","test","isObject","assertObject","message","_a","typeName","valueString"],"mappings":"AAsBO,SAASA,EAAOC,GAAuB;AAC5C,QAAMC,IAAO,OAAOD;AACpB,UAAQC,GAAM;AAAA,IACZ,KAAK;AACI,aAAAA;AAAA,IACT,KAAK;AACC,aAAA,MAAMD,CAAY,IAAU,QACzBC;AAAA,IACT,KAAK;AACH,aAAI,eAAe,KAAKD,EAAM,SAAU,CAAA,IAAU,UAC3CC;AAAA,IACT,KAAK;AACC,aAAAD,MAAU,OAAa,SACvBA,aAAiB,UAAgB,YACjCA,aAAiB,MAAY,QAC7BA,aAAiB,MAAY,QAC7B,MAAM,QAAQA,CAAK,IAAU,UAC1BC;AAAA,IACT;AACS,aAAAA;AAAA,EAAA;AAEb;AAmBO,SAASC,EAAQF,GAAyC;AACxD,SAAA,MAAM,QAAQA,CAAK;AAC5B;AAoBgB,SAAAG,EAAaC,GAAmCJ,GAA8B;AACrF,SAAAE,EAAQF,CAAK,KAAKA,EAAM,MAAM,CAACK,MAASD,EAAMC,CAAI,CAAC;AAC5D;AASgB,SAAAC,EACdF,GACAJ,GACAO,GACc;AACV,MAAAJ,EAAUC,GAAOJ,CAAK;AACjB,WAAA;AAGT,QAAM,IAAI,UAAUQ,EAAYR,GAAOO,CAA2E,CAAC;AACrH;AAKO,SAASE,EAAST,GAAiC;AACxD,SAAO,OAAOA,KAAU;AAC1B;AAKgB,SAAAU,EAAaV,GAAgBO,GAAwC;AAC/E,MAAAE,EAAST,CAAK;AACT,WAAA;AAGT,QAAM,IAAI,UAAUQ,EAAYR,GAAOO,KAAgB,4CAA4C,CAAC;AACtG;AAOO,SAASI,EAAgDX,GAA4B;AACnF,SAAAD,EAAOC,CAAK,MAAM;AAC3B;AAgBO,SAASY,EAASZ,GAAiC;AACxD,SAAO,OAAOA,KAAU,YAAY,CAAC,MAAMA,CAAK;AAClD;AA0DO,SAASa,KAAwCC,GAAiB;AACjE,QAAAC,IAAcD,EAAK,CAAC,GACpBP,IAAeE,EAASK,EAAK,CAAC,CAAC,IACjCA,EAAK,CAAC,IACN,wBAAwBC,EAAY,IAAI,6BAEtCC,IAAO,CAAChB,MAA+B;AAC3C,QAAIA,aAAiBe;AACZ,aAAA;AAGT,UAAM,IAAI,UAAUP,EAAYR,GAAOO,CAAY,CAAC;AAAA,EACtD;AAEI,SAAAO,EAAK,SAAS,IACTE,IAEAA,EAAKF,EAAK,CAAC,CAAC;AAEvB;AAKO,SAASG,EAASjB,GAAoE;AAC3F,SAAOA,KAAS,QAAQ,OAAOA,KAAU,YAAY,CAACE,EAAQF,CAAK;AACrE;AAKgB,SAAAkB,EAAalB,GAAgBO,GAAwC;AAC/E,MAAAU,EAASjB,CAAK;AACT,WAAA;AAGT,QAAM,IAAI,UAAUQ,EAAYR,GAAOO,CAA6D,CAAC;AACvG;AAKA,SAASC,EAAYR,GAAgBmB,GAAiB;AApO/C,MAAAC;AAqOC,QAAAC,IAAWtB,EAAOC,CAAK,GAGvBsB,MAAcF,IAAApB,KAAA,gBAAAA,EAAO,aAAP,gBAAAoB,EAAA,KAAApB,OAAuB,OAAOA,CAAK;AAEvD,SAAOmB,EAAQ,WAAW,MAAME,CAAQ,EAAE,WAAW,MAAMC,CAAW;AACxE;"}
1
+ {"version":3,"file":"typeChecking-lgllKIVq.js","sources":["../src/typeChecking.ts"],"sourcesContent":["type TypeNames =\n // These values can be returned by `typeof`.\n | \"string\"\n | \"number\"\n | \"bigint\"\n | \"boolean\"\n | \"symbol\"\n | \"undefined\"\n | \"object\"\n | \"function\"\n // These values are more specific ones that the `typeOf` function can return.\n | \"null\"\n | \"array\"\n | \"class\"\n | \"promise\"\n | \"map\"\n | \"set\"\n | \"NaN\";\n\n/**\n * Extends `typeof` operator with more specific and useful type distinctions.\n */\nexport function typeOf(value: any): TypeNames {\n const type = typeof value;\n switch (type) {\n case \"undefined\":\n return type;\n case \"number\":\n if (isNaN(value as any)) return \"NaN\";\n return type;\n case \"function\":\n if (/^\\s*class\\s+/.test(value.toString())) return \"class\";\n return type;\n case \"object\":\n if (value === null) return \"null\";\n if (value instanceof Promise) return \"promise\";\n if (value instanceof Map) return \"map\";\n if (value instanceof Set) return \"set\";\n if (Array.isArray(value)) return \"array\";\n return type;\n default:\n return type;\n }\n}\n\n/**\n * Throws a TypeError unless `condition` is truthy.\n *\n * @param condition - Value whose truthiness is in question.\n * @param errorMessage - Optional message for the thrown TypeError.\n */\nexport function assert(condition: any, errorMessage?: string): void {\n if (!condition) {\n throw new TypeError(\n formatError(condition, errorMessage || \"Failed assertion. Value is not truthy. Got type: %t, value: %v\"),\n );\n }\n}\n\n/**\n * Returns true if `value` is an array.\n */\nexport function isArray(value: unknown): value is Array<unknown> {\n return Array.isArray(value);\n}\n\n/**\n * Throws an error if `value` is not an array.\n */\nexport function assertArray(value: unknown, errorMessage?: string): value is Array<unknown> {\n if (isArray(value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage || \"Expected array. Got type: %t, value: %v\"));\n}\n\n/**\n * Returns true when `value` is an array and `check` returns true for every item.\n *\n * @param check - Function to check items against.\n * @param value - A possible array.\n */\n\nexport function isArrayOf<T>(check: (item: unknown) => boolean, value: unknown): value is T[] {\n return isArray(value) && value.every((item) => check(item));\n}\n\n/**\n * Throws a TypeError unless `value` is an array and `check` returns true for every item.\n *\n * @param check - Function to check items against.\n * @param value - A possible array.\n * @param errorMessage - A custom error message.\n */\nexport function assertArrayOf<T>(\n check: (item: unknown) => boolean,\n value: unknown,\n errorMessage?: string,\n): value is T[] {\n if (isArrayOf(check, value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage ?? \"Expected an array of valid items. Got type: %t, value: %v\"));\n}\n\n/**\n * Returns true if `value` is a string.\n */\nexport function isString(value: unknown): value is string {\n return typeof value === \"string\";\n}\n\n/**\n * Throws a TypeError unless `value` is a string.\n */\nexport function assertString(value: unknown, errorMessage?: string): value is string {\n if (isString(value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage ?? \"Expected a string. Got type: %t, value: %v\"));\n}\n\n// TODO: More specific validation for common types of strings? Email address, URL, UUID, etc?\n\n/**\n * Returns true if `value` is a function (but not a class).\n */\nexport function isFunction<T = (...args: unknown[]) => unknown>(value: unknown): value is T {\n return typeOf(value) === \"function\";\n}\n\n/**\n * Throws a TypeError unless `value` is a function.\n */\nexport function assertFunction<T = (...args: unknown[]) => unknown>(value: unknown, errorMessage?: string): value is T {\n if (isFunction(value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage ?? \"Expected a function. Got type: %t, value: %v\"));\n}\n\n/**\n * Returns true if `value` is a number.\n */\nexport function isNumber(value: unknown): value is number {\n return typeof value === \"number\" && !isNaN(value);\n}\n\n/**\n * Throws a TypeError unless `value` is a number.\n */\nexport function assertNumber(value: unknown, errorMessage?: string): value is number {\n if (isNumber(value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage ?? \"Expected a number. Got type: %t, value: %v\"));\n}\n\n/**\n * Returns a function that takes a `value` and returns true if `value` is an instance of `constructor`.\n *\n * @param constructor - The constructor a value must be an instance of to match.\n */\nexport function isInstanceOf<T extends Function>(constructor: T): (value: unknown) => value is T;\n\n/**\n * Returns `true` if `value` is an instance of `constructor`.\n *\n * @param constructor - The constructor `value` must be an instance of.\n * @param value - A value that may be an instance of `constructor`.\n */\nexport function isInstanceOf<T extends Function>(constructor: T, value: unknown): value is T;\n\nexport function isInstanceOf<T extends Function>(...args: unknown[]) {\n const constructor = args[0] as T;\n\n const test = (value: unknown): value is T => {\n return value instanceof constructor;\n };\n\n if (args.length < 2) {\n return test;\n } else {\n return test(args[1]);\n }\n}\n\n/**\n * Returns a function that takes a `value` and throws a TypeError unless `value` is an instance of `constructor`.\n *\n * @param constructor - The constructor a value must be an instance of to match.\n */\nexport function assertInstanceOf<T extends Function>(constructor: T): (value: unknown) => value is T;\n\n/**\n * Throws a TypeError unless `value` is an instance of `constructor`.\n *\n * @param constructor - The constructor `value` must be an instance of.\n * @param value - A value that may be an instance of `constructor`.\n * @param errorMessage - A custom error message for when the assertion fails.\n */\nexport function assertInstanceOf<T extends Function>(constructor: T, value: unknown, errorMessage?: string): value is T;\n\nexport function assertInstanceOf<T extends Function>(...args: unknown[]) {\n const constructor = args[0] as T;\n const errorMessage = isString(args[2])\n ? args[2]\n : `Expected instance of ${constructor.name}. Got type: %t, value: %v`;\n\n const test = (value: unknown): value is T => {\n if (value instanceof constructor) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage));\n };\n\n if (args.length < 2) {\n return test;\n } else {\n return test(args[1]);\n }\n}\n\n/**\n * Returns true if `value` is a plain JavaScript object.\n */\nexport function isObject(value: unknown): value is Record<string | number | symbol, unknown> {\n return value != null && typeof value === \"object\" && !isArray(value);\n}\n\n/**\n * Throws a TypeError unless `value` is a plain JavaScript object.\n */\nexport function assertObject(value: unknown, errorMessage?: string): value is object {\n if (isObject(value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage ?? \"Expected an object. Got type: %t, value: %v\"));\n}\n\n/**\n * Replaces `%t` and `%v` placeholders in a message with real values.\n */\nfunction formatError(value: unknown, message: string) {\n const typeName = typeOf(value);\n\n // TODO: Pretty format value as string based on type.\n const valueString = value?.toString?.() || String(value);\n\n return message.replaceAll(\"%t\", typeName).replaceAll(\"%v\", valueString);\n}\n"],"names":["typeOf","value","type","isArray","isArrayOf","check","item","assertArrayOf","errorMessage","formatError","isString","assertString","isFunction","isNumber","assertInstanceOf","args","constructor","test","isObject","assertObject","message","_a","typeName","valueString"],"mappings":"AAsBO,SAASA,EAAOC,GAAuB;AAC5C,QAAMC,IAAO,OAAOD;AACpB,UAAQC,GAAM;AAAA,IACZ,KAAK;AACI,aAAAA;AAAA,IACT,KAAK;AACC,aAAA,MAAMD,CAAY,IAAU,QACzBC;AAAA,IACT,KAAK;AACH,aAAI,eAAe,KAAKD,EAAM,SAAU,CAAA,IAAU,UAC3CC;AAAA,IACT,KAAK;AACC,aAAAD,MAAU,OAAa,SACvBA,aAAiB,UAAgB,YACjCA,aAAiB,MAAY,QAC7BA,aAAiB,MAAY,QAC7B,MAAM,QAAQA,CAAK,IAAU,UAC1BC;AAAA,IACT;AACS,aAAAA;AAAA,EAAA;AAEb;AAmBO,SAASC,EAAQF,GAAyC;AACxD,SAAA,MAAM,QAAQA,CAAK;AAC5B;AAoBgB,SAAAG,EAAaC,GAAmCJ,GAA8B;AACrF,SAAAE,EAAQF,CAAK,KAAKA,EAAM,MAAM,CAACK,MAASD,EAAMC,CAAI,CAAC;AAC5D;AASgB,SAAAC,EACdF,GACAJ,GACAO,GACc;AACV,MAAAJ,EAAUC,GAAOJ,CAAK;AACjB,WAAA;AAGT,QAAM,IAAI,UAAUQ,EAAYR,GAAOO,CAA2E,CAAC;AACrH;AAKO,SAASE,EAAST,GAAiC;AACxD,SAAO,OAAOA,KAAU;AAC1B;AAKgB,SAAAU,EAAaV,GAAgBO,GAAwC;AAC/E,MAAAE,EAAST,CAAK;AACT,WAAA;AAGT,QAAM,IAAI,UAAUQ,EAAYR,GAAOO,KAAgB,4CAA4C,CAAC;AACtG;AAOO,SAASI,EAAgDX,GAA4B;AACnF,SAAAD,EAAOC,CAAK,MAAM;AAC3B;AAgBO,SAASY,EAASZ,GAAiC;AACxD,SAAO,OAAOA,KAAU,YAAY,CAAC,MAAMA,CAAK;AAClD;AA0DO,SAASa,KAAwCC,GAAiB;AACjE,QAAAC,IAAcD,EAAK,CAAC,GACpBP,IAAeE,EAASK,EAAK,CAAC,CAAC,IACjCA,EAAK,CAAC,IACN,wBAAwBC,EAAY,IAAI,6BAEtCC,IAAO,CAAChB,MAA+B;AAC3C,QAAIA,aAAiBe;AACZ,aAAA;AAGT,UAAM,IAAI,UAAUP,EAAYR,GAAOO,CAAY,CAAC;AAAA,EACtD;AAEI,SAAAO,EAAK,SAAS,IACTE,IAEAA,EAAKF,EAAK,CAAC,CAAC;AAEvB;AAKO,SAASG,EAASjB,GAAoE;AAC3F,SAAOA,KAAS,QAAQ,OAAOA,KAAU,YAAY,CAACE,EAAQF,CAAK;AACrE;AAKgB,SAAAkB,EAAalB,GAAgBO,GAAwC;AAC/E,MAAAU,EAASjB,CAAK;AACT,WAAA;AAGT,QAAM,IAAI,UAAUQ,EAAYR,GAAOO,CAA6D,CAAC;AACvG;AAKA,SAASC,EAAYR,GAAgBmB,GAAiB;AApO/C,MAAAC;AAqOC,QAAAC,IAAWtB,EAAOC,CAAK,GAGvBsB,MAAcF,IAAApB,KAAA,gBAAAA,EAAO,aAAP,gBAAAoB,EAAA,KAAApB,OAAuB,OAAOA,CAAK;AAEvD,SAAOmB,EAAQ,WAAW,MAAME,CAAQ,EAAE,WAAW,MAAMC,CAAW;AACxE;"}
package/dist/types.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type * as CSS from "csstype";
2
2
  import type { Markup } from "./core/markup.js";
3
3
  import { Signal } from "./core/signals.js";
4
+ import { Mixin } from "./core/nodes/html.js";
4
5
  /**
5
6
  * Represents everything that can be handled as a DOM node.
6
7
  * These are all the items considered valid to pass as children to any element.
@@ -197,6 +198,12 @@ export interface ElementProps {
197
198
  * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/compositionupdate_event
198
199
  */
199
200
  onCompositionUpdate?: OptionalProperty<EventHandler<CompositionEvent>>;
201
+ /**
202
+ * Fired when the user attempts to open a context menu. Typically triggered by clicking the right mouse button.
203
+ *
204
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/contextmenu_event
205
+ */
206
+ onContextMenu?: OptionalProperty<EventHandler<PointerEvent>>;
200
207
  /**
201
208
  * Fired when a pointing device button is rapidly clicked twice while the pointer is inside the element.
202
209
  *
@@ -471,6 +478,12 @@ export interface ElementProps {
471
478
  * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/compositionupdate_event
472
479
  */
473
480
  oncompositionupdate?: OptionalProperty<EventHandler<CompositionEvent>>;
481
+ /**
482
+ * Fired when the user attempts to open a context menu. Typically triggered by clicking the right mouse button.
483
+ *
484
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/contextmenu_event
485
+ */
486
+ oncontextmenu?: OptionalProperty<EventHandler<PointerEvent>>;
474
487
  /**
475
488
  * Fired when a pointing device button is rapidly clicked twice while the pointer is inside the element.
476
489
  *
@@ -957,6 +970,10 @@ export interface HTMLElementProps extends ElementProps {
957
970
  onpaste?: OptionalProperty<EventHandler<ClipboardEvent>>;
958
971
  }
959
972
  export interface SVGElementProps extends ElementProps {
973
+ /**
974
+ * A mixin function or an array of mixin functions to be applied to this element.
975
+ */
976
+ mixin?: Mixin<SVGElement> | Mixin<SVGElement>[];
960
977
  }
961
978
  /**
962
979
  * Mapping of event props to event names.
@@ -1241,6 +1258,10 @@ export interface PropertiesOf<E extends HTMLElement> extends HTMLElementProps {
1241
1258
  * Receives a reference to the DOM node when rendered.
1242
1259
  */
1243
1260
  ref?: ((value: E | undefined) => void) | ((value: HTMLElement | undefined) => void) | ((value: Element | undefined) => void) | ((value: Node | undefined) => void);
1261
+ /**
1262
+ * A mixin function or an array of mixin functions to be applied to this element.
1263
+ */
1264
+ mixin?: Mixin<E> | Mixin<E>[];
1244
1265
  }
1245
1266
  /**
1246
1267
  * The following elements are defined based on the WHATWG HTML spec:
package/docs/mixins.md ADDED
@@ -0,0 +1,32 @@
1
+ # Mixins
2
+
3
+ Mixins are a way to add custom lifecycle handlers to plain DOM nodes without creating an entire view. You can encapsulate reusable logic in mixin functions and apply them like CSS classes.
4
+
5
+ Mixin functions take a reference to the element and a `MixinContext` object which adds lifecycle hooks similar to those of `ViewContext`.
6
+
7
+ ```tsx
8
+ import { type Mixin } from "@manyducks.co/dolla";
9
+
10
+ const logMe: Mixin = (element, ctx) => {
11
+ ctx.onMount(() => {
12
+ ctx.log("element mounted");
13
+ });
14
+ ctx.onUnmount(() => {
15
+ ctx.log("element unmounted");
16
+ });
17
+ };
18
+
19
+ // Pass one mixin
20
+ <h1 mixin={logMe}>Title</h1>;
21
+
22
+ // Or an array of mixins
23
+ <p mixin={[logMe, anotherMixin, yetAnotherMixin]}>Text goes here...</p>;
24
+ ```
25
+
26
+ ---
27
+
28
+ End.
29
+
30
+ - [🗂️ Docs](./index.md)
31
+ - [🏠 README](../README.md)
32
+ - [🦆 That's a lot of ducks.](https://www.manyducks.co)
package/docs/ref.md ADDED
@@ -0,0 +1,93 @@
1
+ # Ref
2
+
3
+ Refs are functions that serve as a getter and setter for a stored value. Calling a ref with no arguments will return its stored value, or throw an error if no value has yet been stored. Calling a ref with a single argument will store a new value.
4
+
5
+ This signature is very similar to that of a `Source` signal, with the differences being their error throwing behavior while empty and that refs are _not_ trackable in a signal context.
6
+
7
+ ## Pattern #1: Referencing DOM nodes
8
+
9
+ The main pattern for refs is as a DOM node reference. Markup elements take a `ref` attribute to which they will pass their DOM node when they are mounted.
10
+
11
+ Once you have this reference you can manipulate the node outside the usual declarative template workflow.
12
+
13
+ ```tsx
14
+ import { ref } from "@manyducks.co/dolla";
15
+
16
+ function ExampleView() {
17
+ const element = ref<HTMLElement>();
18
+
19
+ ctx.onMount(() => {
20
+ element().innerText = "GOODBYE THERE";
21
+ });
22
+
23
+ return <div ref={element}>HELLO THERE</div>;
24
+ }
25
+ ```
26
+
27
+ ## Pattern #2: Controlling a child view from a parent view
28
+
29
+ Another useful pattern is to pass an API object from a child view to the parent, allowing the parent to call methods to control the child view in an imperative way.
30
+
31
+ ```tsx
32
+ import { ref } from "@manyducks.co/dolla";
33
+
34
+ // First we'll define the view to be controlled.
35
+
36
+ interface CounterViewControls {
37
+ increment(): void;
38
+ decrement(): void;
39
+ reset(): void;
40
+ }
41
+
42
+ interface CounterViewProps {
43
+ controls: Ref<CounterViewControls>;
44
+ }
45
+
46
+ function CounterView({ controls }: CounterViewProps) {
47
+ const $count = $(count);
48
+
49
+ // Passing a `controls` object to the ref whose methods reference internal state.
50
+ controls({
51
+ increment() {
52
+ $count((current) => current + 1);
53
+ },
54
+ decrement() {
55
+ $count((current) => current - 1);
56
+ },
57
+ reset() {
58
+ $count(0);
59
+ },
60
+ });
61
+
62
+ return <span>Count: {$count}</span>;
63
+ }
64
+
65
+ // Then we'll use it in the parent:
66
+
67
+ function ParentView() {
68
+ // Create a Ref to store the controls object.
69
+ const controls = ref<CounterViewControls>();
70
+
71
+ return (
72
+ <section>
73
+ <h1>Counter</h1>
74
+
75
+ {/* CounterView will set the controls object */}
76
+ <CounterView controls={controls} />
77
+
78
+ {/* Our buttons will call the methods on the controls object causing state changes within CounterView */}
79
+ <button onClick={() => controls.increment()}>+1</button>
80
+ <button onClick={() => controls.decrement()}>-1</button>
81
+ <button onClick={() => controls.reset()}>=0</button>
82
+ </section>
83
+ );
84
+ }
85
+ ```
86
+
87
+ ---
88
+
89
+ End.
90
+
91
+ - [🗂️ Docs](./index.md)
92
+ - [🏠 README](../README.md)
93
+ - [🦆 That's a lot of ducks.](https://www.manyducks.co)
package/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export * from "./src/index";
1
+ export * from "./src/core/index";
2
2
 
3
3
  import type { IntrinsicElements as Elements } from "./src/types";
4
4
 
@@ -0,0 +1,22 @@
1
+ # Mixins
2
+
3
+ Sometimes you want to attach logic to a DOM node without writing a whole view around it.
4
+
5
+ ```js
6
+ function myMixin(options: any): Mixin {
7
+ return function(element: Element, ctx: MixinContext) {
8
+ ctx.onMount(() => {
9
+
10
+ })
11
+
12
+ ctx.onUnmount(() => {
13
+
14
+ })
15
+ }
16
+
17
+
18
+ // Returns nothing. Use context methods to attach event listeners / behavior / whatever.
19
+ }
20
+
21
+ <h1 mixins={[myMixin({ /* options */ }), /* ... */]}>Whatever</h1>
22
+ ```
package/notes/scratch.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Scratch Note
2
2
 
3
+ Library needs to be easier to render standalone elements. Idea to replace constructView and a lot of the store management weirdness with a `createContext` function and a `render` function that takes markup and a context.
4
+
5
+ The context is basically a refactor of the old ElementContext and serves the same purpose.
6
+
7
+ ```jsx
8
+ import { m, render, createContext } from "@manyducks.co/dolla";
9
+
10
+ const context = createContext();
11
+ context.addStore(SomeStore);
12
+
13
+ function ExampleView(props, ctx) {
14
+ // Views now access the Context directly.
15
+ const store = ctx.getStore(SomeStore);
16
+
17
+ return <h1>Hello World</h1>;
18
+ }
19
+
20
+ const element = render(ExampleView, context);
21
+
22
+ element.mount(document.body);
23
+ ```
24
+
25
+ ---
26
+
3
27
  Idea: Monomorphic app context. Replaces StoreContext, ViewContext, etc.
4
28
 
5
29
  Routes are baked into the app once again, but
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@manyducks.co/dolla",
3
- "version": "2.0.0-alpha.53",
3
+ "version": "2.0.0-alpha.55",
4
4
  "description": "Front-end components, routing and state management.",
5
5
  "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
6
+ "types": "dist/core/index.d.ts",
7
7
  "type": "module",
8
8
  "sideEffects": false,
9
9
  "repository": {
@@ -1,57 +0,0 @@
1
- import { type ComponentContext, type ElementContext, type StoreConsumerContext, type StoreProviderContext } from "./context.js";
2
- import { type Logger } from "./logger.js";
3
- import { type EffectFn, type UnsubscribeFn } from "./signals.js";
4
- export type StoreFunction<Options, Value> = (this: StoreContext, options: Options, context: StoreContext) => Value;
5
- export type StoreFactory<Options, Value> = Options extends undefined ? () => Store<Options, Value> : (options: Options) => Store<Options, Value>;
6
- export interface StoreContext extends Omit<Logger, "setName">, ComponentContext, StoreConsumerContext {
7
- /**
8
- * True while this store is attached to a context that is currently mounted in the view tree.
9
- */
10
- readonly isMounted: boolean;
11
- /**
12
- * Registers a callback to run just after this store is mounted.
13
- */
14
- onMount(callback: () => void): void;
15
- /**
16
- * Registers a callback to run just after this store is unmounted.
17
- */
18
- onUnmount(callback: () => void): void;
19
- /**
20
- * Passes a getter function to `callback` that will track reactive states and return their current values.
21
- * Callback will be run each time a tracked state gets a new value.
22
- */
23
- effect(callback: EffectFn): UnsubscribeFn;
24
- }
25
- export declare class Store<Options, Value> {
26
- readonly fn: StoreFunction<Options, Value>;
27
- private _options;
28
- /**
29
- * Value is guaranteed to be set after `attach` is called.
30
- */
31
- value: Value;
32
- isMounted: boolean;
33
- elementContext: ElementContext;
34
- lifecycleListeners: {
35
- mount: (() => any)[];
36
- unmount: (() => any)[];
37
- };
38
- logger: Logger;
39
- id: string;
40
- name: import("./signals.js").Source<string>;
41
- constructor(fn: StoreFunction<Options, Value>, options: Options);
42
- /**
43
- * Attaches this Store to the elementContext.
44
- * Returns false if there was already an instance attached, and true otherwise.
45
- */
46
- attach(elementContext: ElementContext): boolean;
47
- handleMount(): void;
48
- handleUnmount(): void;
49
- }
50
- export declare function isStore<Options, Value>(value: any): value is Store<Options, Value>;
51
- export declare class StoreError extends Error {
52
- }
53
- export type Stores = StoreProviderContext & StoreConsumerContext;
54
- /**
55
- * Global store registry.
56
- */
57
- export declare const Stores: Stores;
@@ -1,5 +0,0 @@
1
- import { type ViewContext } from "../nodes/view.js";
2
- /**
3
- * A utility view that simply displays a route.
4
- */
5
- export declare function Passthrough(_: {}, ctx: ViewContext): import("../markup.js").Markup;
@@ -1,8 +0,0 @@
1
- import { m } from "./view-CAEIbcZt.js";
2
- function a(r, n) {
3
- return m("$dynamic", { source: () => r.children });
4
- }
5
- export {
6
- a as F
7
- };
8
- //# sourceMappingURL=fragment-DFnx8z2z.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fragment-DFnx8z2z.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;"}