@manyducks.co/dolla 2.0.0-alpha.64 → 2.0.0-alpha.66

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 (57) hide show
  1. package/dist/core/app.d.ts +24 -0
  2. package/dist/core/index.d.ts +3 -2
  3. package/dist/core/markup.d.ts +9 -1
  4. package/dist/core/nodes/element.d.ts +1 -0
  5. package/dist/core/scheduler.d.ts +12 -4
  6. package/dist/core/signals.d.ts +10 -9
  7. package/dist/core/views/portal.d.ts +17 -0
  8. package/dist/hooks/index.d.ts +21 -5
  9. package/dist/hooks.js +27 -21
  10. package/dist/hooks.js.map +1 -1
  11. package/dist/http.js +1 -1
  12. package/dist/i18n.js +3 -3
  13. package/dist/index-BEDDzyd9.js +556 -0
  14. package/dist/index-BEDDzyd9.js.map +1 -0
  15. package/dist/index.js +125 -70
  16. package/dist/index.js.map +1 -1
  17. package/dist/jsx-dev-runtime.js +1 -1
  18. package/dist/jsx-runtime.js +1 -1
  19. package/dist/{logger-B7RBYtzP.js → logger-CmXtRdEI.js} +7 -7
  20. package/dist/{logger-B7RBYtzP.js.map → logger-CmXtRdEI.js.map} +1 -1
  21. package/dist/markup-DjDexAN5.js +1179 -0
  22. package/dist/markup-DjDexAN5.js.map +1 -0
  23. package/dist/router/hooks.d.ts +2 -0
  24. package/dist/router/index.d.ts +1 -0
  25. package/dist/router/router.d.ts +1 -0
  26. package/dist/router.js +3 -5
  27. package/dist/router.js.map +1 -1
  28. package/dist/{signals-DbDmN2gr.js → signals-CkfFHd0d.js} +264 -255
  29. package/dist/signals-CkfFHd0d.js.map +1 -0
  30. package/dist/typeChecking-_dGK_0uR.js +62 -0
  31. package/dist/{typeChecking-CbltMOUt.js.map → typeChecking-_dGK_0uR.js.map} +1 -1
  32. package/dist/utils.d.ts +5 -0
  33. package/docs/components.md +21 -0
  34. package/docs/hooks.md +3 -3
  35. package/docs/signals.md +67 -53
  36. package/docs/stores.md +13 -4
  37. package/package.json +4 -4
  38. package/dist/core/mount.d.ts +0 -15
  39. package/dist/core/mount.test.d.ts +0 -0
  40. package/dist/markup-DeZDwQ9F.js +0 -1117
  41. package/dist/markup-DeZDwQ9F.js.map +0 -1
  42. package/dist/router-C35XmU3k.js +0 -543
  43. package/dist/router-C35XmU3k.js.map +0 -1
  44. package/dist/signals-DbDmN2gr.js.map +0 -1
  45. package/dist/typeChecking-CbltMOUt.js +0 -71
  46. package/docs/state.md +0 -141
  47. package/examples/webcomponent/index.html +0 -14
  48. package/examples/webcomponent/main.js +0 -165
  49. package/notes/TODO.md +0 -6
  50. package/notes/context-routes.md +0 -61
  51. package/notes/custom-nodes.md +0 -17
  52. package/notes/effection-idea.md +0 -34
  53. package/notes/mixins.md +0 -22
  54. package/notes/molecule.md +0 -35
  55. package/notes/readme-scratch.md +0 -260
  56. package/notes/route-middleware.md +0 -42
  57. package/notes/stores.md +0 -79
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-BEDDzyd9.js","sources":["../src/router/router.utils.ts","../src/router/router.ts","../src/router/hooks.ts","../src/router/index.ts"],"sourcesContent":["import { assertString, assertArrayOf, isFunction } from \"../typeChecking.js\";\n\nexport type RouteMatch<T = Record<string, any>> = {\n /**\n * The path string that triggered this match.\n */\n path: string;\n\n /**\n * The pattern satisfied by `path`.\n */\n pattern: string;\n\n /**\n * Named params as parsed from `path`.\n */\n params: Record<string, string>;\n\n /**\n * Query params as parsed from `path`.\n */\n query: Record<string, string>;\n\n /**\n * Metadata registered to this route.\n */\n meta: T;\n};\n\nexport enum FragTypes {\n Literal = 1,\n Param = 2,\n Wildcard = 3,\n NumericParam = 4,\n}\n\nexport type RouteFragment = {\n name: string;\n type: FragTypes;\n value: string | number | null;\n};\n\nexport type ParsedRoute<T> = {\n pattern: string;\n fragments: RouteFragment[];\n meta: T;\n};\n\nexport type RouteMatchOptions<T> = {\n willMatch?: (route: ParsedRoute<T>) => boolean;\n};\n\n/**\n * Separates a URL path into multiple fragments.\n *\n * @param path - A path string (e.g. `\"/api/users/5\"`)\n * @returns an array of fragments (e.g. `[\"api\", \"users\", \"5\"]`)\n */\nexport function splitPath(path: string): string[] {\n assertString(path, \"Expected `path` to be a string. Got type: %t, value: %v\");\n\n return path\n .split(\"/\")\n .map((f) => f.trim())\n .filter((f) => f !== \"\");\n}\n\n/**\n * Joins multiple URL path fragments into a single string.\n *\n * @param parts - One or more URL fragments (e.g. `[\"api\", \"users\", 5]`)\n * @returns a joined path (e.g. `\"api/users/5\"`)\n */\nexport function joinPath(parts: { toString(): string }[]): string {\n assertArrayOf(\n (part) => isFunction(part?.toString),\n parts,\n \"Expected `parts` to be an array of objects with a .toString() method. Got type: %t, value: %v\",\n );\n\n parts = parts.filter((x) => x).flatMap(String);\n\n let joined = parts.shift()?.toString();\n\n if (joined) {\n for (const part of parts.map((p) => p.toString())) {\n if (part.startsWith(\".\")) {\n // Resolve relative path against joined\n joined = resolvePath(joined, part);\n } else if (joined[joined.length - 1] !== \"/\") {\n if (part[0] !== \"/\") {\n joined += \"/\" + part;\n } else {\n joined += part;\n }\n } else {\n if (part[0] === \"/\") {\n joined += part.slice(1);\n } else {\n joined += part;\n }\n }\n }\n\n // Remove trailing slash (unless path is just '/')\n if (joined && joined !== \"/\" && joined.endsWith(\"/\")) {\n joined = joined.slice(0, joined.length - 1);\n }\n }\n\n return joined ?? \"\";\n}\n\nexport function resolvePath(base: string, part: string | null) {\n assertString(base, \"Expected `base` to be a string. Got type: %t, value: %v\");\n\n if (part == null) {\n part = base;\n base = \"\";\n }\n\n if (part.startsWith(\"/\")) {\n return part;\n }\n\n let resolved = base;\n\n while (true) {\n if (part.startsWith(\"..\")) {\n for (let i = resolved.length; i > 0; --i) {\n if (resolved[i] === \"/\" || i === 0) {\n resolved = resolved.slice(0, i);\n part = part.replace(/^\\.\\.\\/?/, \"\");\n break;\n }\n }\n } else if (part.startsWith(\".\")) {\n part = part.replace(/^\\.\\/?/, \"\");\n } else {\n break;\n }\n }\n\n return joinPath([resolved, part]);\n}\n\nexport function parseQueryParams(query: string): Record<string, string> {\n if (!query) return {};\n\n if (query.startsWith(\"?\")) {\n query = query.slice(1);\n }\n\n const entries = query\n .split(\"&\")\n .filter((x) => x.trim() !== \"\")\n .map((entry) =>\n entry\n .split(\"=\")\n .map((x) => x.trim())\n .slice(0, 2),\n );\n\n return Object.fromEntries(entries);\n}\n\n/**\n * Returns the nearest match, or undefined if the path matches no route.\n *\n * @param url - Path to match against routes.\n * @param options - Options to customize how matching operates.\n */\nexport function matchRoutes<T>(\n routes: ParsedRoute<T>[],\n url: string,\n options: RouteMatchOptions<T> = {},\n): RouteMatch<T> | undefined {\n const [path, query] = url.split(\"?\");\n const parts = splitPath(path);\n\n routes: for (const route of routes) {\n const { fragments } = route;\n const hasWildcard = fragments[fragments.length - 1]?.type === FragTypes.Wildcard;\n\n if (!hasWildcard && fragments.length !== parts.length) {\n continue routes;\n }\n\n if (options.willMatch && !options.willMatch(route)) {\n continue routes;\n }\n\n const matched: RouteFragment[] = [];\n\n fragments: for (let i = 0; i < fragments.length; i++) {\n const part = parts[i];\n const frag = fragments[i];\n\n if (part == null && frag.type !== FragTypes.Wildcard) {\n continue routes;\n }\n\n switch (frag.type) {\n case FragTypes.Literal:\n if (frag.name.toLowerCase() === part.toLowerCase()) {\n matched.push(frag);\n break;\n } else {\n continue routes;\n }\n case FragTypes.Param:\n matched.push({ ...frag, value: part });\n break;\n case FragTypes.Wildcard:\n matched.push({ ...frag, value: parts.slice(i).join(\"/\") });\n break fragments;\n case FragTypes.NumericParam:\n if (!isNaN(Number(part))) {\n matched.push({ ...frag, value: part });\n break;\n } else {\n continue routes;\n }\n default:\n throw new Error(`Unknown fragment type: ${frag.type}`);\n }\n }\n\n const params: Record<string, string> = {};\n\n for (const frag of matched) {\n if (frag.type === FragTypes.Param) {\n params[frag.name] = decodeURIComponent(frag.value as string);\n }\n\n if (frag.type === FragTypes.NumericParam) {\n params[frag.name] = String(frag.value);\n }\n\n if (frag.type === FragTypes.Wildcard) {\n params.wildcard = \"/\" + decodeURIComponent(frag.value as string);\n }\n }\n\n return {\n path: \"/\" + matched.map((f) => f.value).join(\"/\"),\n pattern:\n \"/\" +\n fragments\n .map((f) => {\n if (f.type === FragTypes.Param) {\n return `{${f.name}}`;\n }\n\n if (f.type === FragTypes.NumericParam) {\n return `{#${f.name}}`;\n }\n\n return f.name;\n })\n .join(\"/\"),\n params,\n query: parseQueryParams(query),\n meta: route.meta,\n };\n }\n}\n\n/**\n * Sort routes descending by specificity. Guarantees that the most specific route matches first\n * no matter the order in which they were added.\n *\n * Routes without named params and routes with more fragments are weighted more heavily.\n */\nexport function sortRoutes<T>(routes: ParsedRoute<T>[]): ParsedRoute<T>[] {\n const withoutParams = [];\n const withNumericParams = [];\n const withParams = [];\n const wildcard = [];\n\n for (const route of routes) {\n const { fragments } = route;\n\n if (fragments.some((f) => f.type === FragTypes.Wildcard)) {\n wildcard.push(route);\n } else if (fragments.some((f) => f.type === FragTypes.NumericParam)) {\n withNumericParams.push(route);\n } else if (fragments.some((f) => f.type === FragTypes.Param)) {\n withParams.push(route);\n } else {\n withoutParams.push(route);\n }\n }\n\n const bySizeDesc = (a: ParsedRoute<T>, b: ParsedRoute<T>) => {\n if (a.fragments.length > b.fragments.length) {\n return -1;\n } else {\n return 1;\n }\n };\n\n withoutParams.sort(bySizeDesc);\n withNumericParams.sort(bySizeDesc);\n withParams.sort(bySizeDesc);\n wildcard.sort(bySizeDesc);\n\n return [...withoutParams, ...withNumericParams, ...withParams, ...wildcard];\n}\n\n/**\n * Converts a route pattern into a set of matchable fragments.\n *\n * @param route - A route string (e.g. \"/api/users/{id}\")\n */\nexport function patternToFragments(pattern: string): RouteFragment[] {\n const parts = splitPath(pattern);\n const fragments = [];\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n\n if (part === \"*\") {\n if (i !== parts.length - 1) {\n throw new Error(`Wildcard must be at the end of a pattern. Received: ${pattern}`);\n }\n fragments.push({\n type: FragTypes.Wildcard,\n name: \"*\",\n value: null,\n });\n } else if (part.at(0) === \"{\" && part.at(-1) === \"}\") {\n fragments.push({\n type: part[1] === \"#\" ? FragTypes.NumericParam : FragTypes.Param,\n name: part[1] === \"#\" ? part.slice(2, -1) : part.slice(1, -1),\n value: null,\n });\n } else {\n fragments.push({\n type: FragTypes.Literal,\n name: part,\n value: part,\n });\n }\n }\n\n return fragments;\n}\n\nconst safeExternalLink = /(noopener|noreferrer) (noopener|noreferrer)/;\nconst protocolLink = /^[\\w-_]+:/;\n\n/**\n * Intercepts links within the root node.\n *\n * This is adapted from https://github.com/choojs/nanohref/blob/master/index.js\n *\n * @param root - Element under which to intercept link clicks\n * @param callback - Function to call when a click event is intercepted\n * @param _window - (optional) Override for global window object\n */\nexport function catchLinks(root: Element, callback: (anchor: HTMLAnchorElement) => void, _window = window) {\n function traverse(node: HTMLElement | null): HTMLAnchorElement | null {\n if (!node || node === root) {\n return null;\n }\n\n if (node.localName !== \"a\" || (node as any).href === undefined) {\n return traverse(node.parentNode as HTMLElement | null);\n }\n\n return node as HTMLAnchorElement;\n }\n\n function handler(e: MouseEvent) {\n if ((e.button && e.button !== 0) || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey || e.defaultPrevented) {\n return;\n }\n\n const anchor = traverse(e.target as HTMLElement);\n\n if (!anchor) {\n return;\n }\n\n if (\n _window.location.protocol !== anchor.protocol ||\n _window.location.hostname !== anchor.hostname ||\n _window.location.port !== anchor.port ||\n anchor.hasAttribute(\"data-router-ignore\") ||\n anchor.hasAttribute(\"download\") ||\n (anchor.getAttribute(\"target\") === \"_blank\" && safeExternalLink.test(anchor.getAttribute(\"rel\")!)) ||\n protocolLink.test(anchor.getAttribute(\"href\")!)\n ) {\n return;\n }\n\n e.preventDefault();\n callback(anchor);\n }\n\n root.addEventListener(\"click\", handler as any);\n\n return function cancel() {\n root.removeEventListener(\"click\", handler as any);\n };\n}\n\n/**\n * Replace route pattern param placeholders with real matched values.\n */\nexport function replaceParams(path: string, params: Record<string, string | number>) {\n for (const key in params) {\n const value = params[key].toString();\n path = path.replace(`{${key}}`, value).replace(`{#${key}}`, value);\n }\n\n return path;\n}\n","import { Context } from \"../core/context.js\";\nimport { createLogger } from \"../core/logger.js\";\nimport { m, MarkupType, type MarkupNode } from \"../core/markup.js\";\nimport { DynamicNode } from \"../core/nodes/dynamic.js\";\nimport { ViewNode } from \"../core/nodes/view.js\";\nimport { writable, memo, batch, untracked, type Writable, type Signal } from \"../core/signals.js\";\nimport { assertObject, isArray, isArrayOf, isFunction, isObject, isString } from \"../typeChecking.js\";\nimport type { View } from \"../types.js\";\nimport { deepEqual, shallowEqual } from \"../utils.js\";\nimport {\n catchLinks,\n joinPath,\n matchRoutes,\n patternToFragments,\n replaceParams,\n resolvePath,\n sortRoutes,\n splitPath,\n type ParsedRoute,\n type RouteMatch,\n} from \"./router.utils.js\";\n\n// ----- Types ----- //\n\nexport type Stringable = { toString(): string };\n\nexport interface Match {\n /**\n * The path as it appears in the URL bar.\n */\n path: string;\n\n /**\n * The pattern that this path was matched with.\n */\n pattern: string;\n\n /**\n * Named route params parsed from `path`.\n */\n params: Record<string, string>;\n\n /**\n * Query params parsed from `path`.\n */\n query: Record<string, string>;\n\n /**\n * Freeform data you wish to store with this route.\n * Merged `data` from all matched layers are available from `router.$match()`.\n */\n data: Record<string, any>;\n}\n\nexport interface RouteMatchContext extends Match {\n /**\n * Stores `value` at `key` in this context's state.\n */\n setState<T>(key: any, value: T): void;\n\n /**\n * For each tuple in `entries`, stores `value` at `key` in this context's state.\n */\n setState(entries: [key: any, value: any][]): void;\n\n /**\n * Redirects the user to a different route instead of matching the current one.\n */\n redirect(path: string): void;\n}\n\nexport interface Route {\n /**\n * The path or path fragment to match.\n */\n path: string;\n\n /**\n * Path to redirect to when this route is matched, or a callback function that returns such path.\n */\n redirect?: string | ((ctx: RouteRedirectContext) => string) | ((ctx: RouteRedirectContext) => Promise<string>);\n\n /**\n * View to display when this route is matched.\n */\n view?: View<any>;\n\n /**\n * Subroutes.\n */\n routes?: Route[];\n\n /**\n * Called after the match is identified but before it is acted on. Use this to set state, load data, etc.\n */\n beforeMatch?: (ctx: RouteMatchContext) => void | Promise<void>;\n\n /**\n * Arbitrary data you'd like to store on this route.\n * This object will be available at `router.$match` while the route is active.\n *\n * In the case of nested routes, data from all layers will be merged into a single data object.\n */\n data?: Record<string, any>;\n}\n\nexport interface RouteMeta {\n redirect?: string | ((ctx: RouteRedirectContext) => string) | ((ctx: RouteRedirectContext) => Promise<string>);\n pattern?: string;\n layers?: RouteLayer[];\n beforeMatch?: { fn: (ctx: RouteMatchContext) => void | Promise<void>; layerId: number }[];\n data?: Record<string, any>;\n}\n\nexport interface RouteConfig {\n pattern: string;\n meta: RouteMeta;\n}\n\nexport interface RouteLayer {\n id: number;\n view: View<{}>;\n}\n\n/**\n * An active route layer whose markup has been initialized into a view.\n */\ninterface ActiveLayer {\n id: number;\n node: MarkupNode;\n context: Context;\n $slot: Writable<MarkupNode | undefined>;\n}\n\n/**\n * Object passed to redirect callbacks. Contains information useful for determining how to redirect.\n */\nexport interface RouteRedirectContext extends Match {}\n\n/**\n * A log for a single step in the route resolution process.\n */\ninterface JourneyStep {\n kind: \"match\" | \"redirect\" | \"miss\";\n message: string;\n}\n\nexport interface NavigateOptions {\n /**\n * Replace the current item in the history stack instead of adding a new one.\n * The back button will send the user to the page they visited before this. Defaults to false.\n */\n replace?: boolean;\n\n /**\n * Preserve existing query params (if any) when navigating. Defaults to false.\n * If true, all existing query params are preserved and merged with new ones.\n * If an array of strings is passed only those keys will be preserved, then merged with any new ones.\n */\n preserveQuery?: boolean | string[];\n}\n\nexport interface RouterOptions {\n routes: Route[];\n\n /**\n * When true, the router will construct routes like \"https://www.example.com/#/sub/route\" which work without any backend intervention.\n */\n hash?: boolean;\n}\n\n// ----- Code ----- //\n\nexport const ROUTER = Symbol(\"Router\");\nexport const MOUNT = Symbol();\nexport const UNMOUNT = Symbol();\nexport const ROOT_VIEW = Symbol();\n\nexport class Router {\n #logger = createLogger(\"dolla.router\");\n\n #nextLayerId = 0;\n #activeLayers: ActiveLayer[] = [];\n #routes: ParsedRoute<RouteMeta>[] = [];\n\n #isMounted = false;\n\n #rootLayer!: ActiveLayer;\n\n /**\n * Use hash routing when true. Configured in router options.\n */\n #hash = false;\n\n /**\n * Cleanup functions to call on unmount.\n */\n #cleanup: (() => void)[] = [];\n\n /**\n * The current match object (internal).\n */\n #match = writable<RouteMatch>();\n\n /**\n * The current match object.\n */\n readonly $match = memo<Match | undefined>(\n () => {\n const match = this.#match();\n if (match) {\n return {\n path: match.path,\n pattern: match.pattern,\n params: { ...match.params },\n query: { ...match.query },\n data: match.meta.data ?? {},\n };\n }\n },\n { equals: deepEqual },\n );\n\n /**\n * The currently matched route pattern, if any.\n */\n readonly $pattern = memo(() => this.#match()?.pattern);\n\n /**\n * The current URL path.\n */\n readonly $path = memo(() => this.#match()?.path ?? window.location.pathname);\n\n /**\n * The current named path params.\n */\n readonly $params = memo(() => this.#match()?.params ?? {}, { equals: shallowEqual });\n\n /**\n * The current query params.\n */\n readonly $query = memo(() => this.#match()?.query ?? {}, { equals: shallowEqual });\n\n constructor(options: RouterOptions) {\n assertObject(options, \"Options must be an object. Got: %t\");\n\n if (options.hash) {\n this.#hash = true;\n }\n\n // Add routes.\n this.#routes = sortRoutes(\n options.routes\n .flatMap((route) => this.#prepareRoute(route))\n .map((route) => ({\n pattern: route.pattern,\n meta: route.meta,\n fragments: patternToFragments(route.pattern),\n })),\n );\n\n assertValidRedirects(this.#routes);\n }\n\n async [MOUNT](parent: Element, context: Context): Promise<MarkupNode> {\n const $slot = writable<MarkupNode>();\n this.#rootLayer = {\n id: this.#nextLayerId++,\n node: new DynamicNode(context, $slot),\n context,\n $slot,\n };\n\n // Listen for popstate events and update route accordingly.\n const onPopState = () => this.#updateRoute();\n window.addEventListener(\"popstate\", onPopState);\n this.#cleanup.push(() => window.removeEventListener(\"popstate\", onPopState));\n\n // Listen for clicks on <a> tags within the app.\n this.#cleanup.push(\n catchLinks(parent, (anchor) => {\n this.#logger.info(\"intercepted click on <a> tag\", anchor);\n\n const href = anchor.getAttribute(\"href\")!;\n const preserveQuery = anchor.getAttribute(\"data-router-preserve-query\");\n\n this.go(href, {\n preserveQuery: parsePreserveQueryAttribute(preserveQuery),\n });\n }),\n );\n this.#logger.info(\"will intercept clicks on <a> tags within parent element:\", parent);\n\n this.#isMounted = true;\n\n // Mount initial route.\n await this.#updateRoute();\n\n return this.#rootLayer.node;\n }\n\n async [UNMOUNT]() {\n for (const callback of this.#cleanup) {\n callback();\n }\n this.#cleanup.length = 0;\n }\n\n /**\n * Navigate backward. Pass a number of steps to hit the back button that many times.\n */\n back(steps = 1) {\n window.history.go(-steps);\n }\n\n /**\n * Navigate forward. Pass a number of steps to hit the forward button that many times.\n */\n forward(steps = 1) {\n window.history.go(steps);\n }\n\n /**\n * Navigates to another route.\n *\n * @example\n * router.go(\"/login\"); // navigate to `/login`\n * router.go[\"/users\", 215], { replace: true }); // replace current history entry with `/users/215`\n */\n go(path: Stringable | Stringable[], options: NavigateOptions = {}) {\n let joined: string;\n\n if (Array.isArray(path)) {\n joined = joinPath(path);\n } else {\n joined = path.toString();\n }\n\n joined = resolvePath(window.location.pathname, joined);\n\n if (options.replace) {\n this.#replace(joined, options);\n } else {\n this.#push(joined, options);\n }\n }\n\n /**\n * Updates query params, keeping existing ones and applying new ones. Removes the query param if value is set to `null`.\n */\n updateQuery(values: Record<string, Stringable | null>) {\n const match = untracked(this.#match)!;\n const query = { ...this.$query() };\n\n for (const key in values) {\n const value = values[key];\n if (value === null) {\n delete query[key];\n } else {\n query[key] = value.toString();\n }\n }\n\n let queryParts: string[] = [];\n\n for (const key in query) {\n queryParts.push(`${key}=${query[key]}`);\n }\n const queryString = queryParts.length > 0 ? \"?\" + queryParts.join(\"&\") : \"\";\n\n this.#match.set({ ...match, query });\n\n window.history.replaceState(null, \"\", this.#hash ? \"/#\" + match.path + queryString : match.path + queryString);\n }\n\n #push(href: string, options: NavigateOptions) {\n this.#logger.info(\"(push)\", href);\n\n window.history.pushState(null, \"\", this.#hash ? \"/#\" + href : href);\n this.#updateRoute(href, options);\n }\n\n #replace(href: string, options: NavigateOptions) {\n this.#logger.info(\"(replace)\", href);\n\n window.history.replaceState(null, \"\", this.#hash ? \"/#\" + href : href);\n this.#updateRoute(href, options);\n }\n\n #getCurrentURL(): URL {\n if (this.#hash) {\n return new URL(window.location.hash.slice(1), window.location.origin);\n } else {\n return new URL(window.location.pathname, window.location.origin);\n }\n }\n\n /**\n * Run when the location changes. Diffs and mounts new routes and updates\n * the $path, $route, $params and $query states accordingly.\n */\n async #updateRoute(href?: string | undefined, options: NavigateOptions = {}) {\n const logger = this.#logger;\n const url = href ? new URL(href, window.location.origin) : this.#getCurrentURL();\n\n const { match, journey, state } = await this.#resolveRoute(url);\n\n for (let i = 0; i < journey.length; i++) {\n const step = journey[i];\n const tag = `(update: step ${i + 1} of ${journey.length})`;\n\n switch (step.kind) {\n case \"match\":\n logger?.info(`${tag} 📍 ${step.message}`);\n break;\n case \"redirect\":\n logger?.info(`${tag} ↩️ ${step.message}`);\n break;\n case \"miss\":\n logger?.info(`${tag} 💀 ${step.message}`);\n break;\n default:\n break;\n }\n }\n\n if (!match) {\n // Only crash if routing has been configured.\n if (this.#isMounted) {\n throw logger.crash(new NoRouteError(`Failed to match route '${url.pathname}'`));\n }\n return;\n }\n\n // Merge query params.\n let query = match.query;\n let queryParts: string[] = [];\n\n if (options.preserveQuery === true) {\n query = Object.assign({}, this.$query(), match.query);\n } else if (isArray(options.preserveQuery)) {\n const preserved: Record<string, any> = {};\n const current = this.$query();\n for (const key in current) {\n if (options.preserveQuery.includes(key)) {\n preserved[key] = current[key];\n }\n }\n query = Object.assign({}, preserved, match.query);\n }\n\n for (const key in query) {\n queryParts.push(`${key}=${query[key]}`);\n }\n const queryString = queryParts.length > 0 ? \"?\" + queryParts.join(\"&\") : \"\";\n\n // Update the URL if matched path differs from navigator path.\n // This happens if route resolution involved redirects.\n if (match.path !== location.pathname || location.search !== queryString) {\n window.history.replaceState(null, \"\", this.#hash ? \"/#\" + match.path + queryString : match.path + queryString);\n }\n\n // Run in batch so all new layers are mounted simultaneously with match signal change.\n // This avoids the old route effects receiving new signal values just before they unmount.\n batch(() => {\n const oldPattern = untracked(this.$pattern);\n\n this.#match.set({ ...match, query });\n\n if (match.pattern === oldPattern) {\n // If pattern has not changed, update state on current layers.\n for (const layer of this.#activeLayers) {\n const stateEntries = state.get(layer.id);\n if (stateEntries) {\n layer.context.setState(stateEntries);\n }\n }\n return;\n }\n\n const layers = match.meta.layers!;\n logger.info(\"mounting\", match);\n\n // Diff and update route layers.\n for (let i = 0; i < layers.length; i++) {\n const matchedLayer = layers[i];\n const activeLayer = this.#activeLayers[i];\n\n if (activeLayer?.id !== matchedLayer.id) {\n // Discard all previously active layers starting at this depth.\n this.#activeLayers = this.#activeLayers.slice(0, i);\n activeLayer?.node.unmount();\n\n const parentLayer = this.#activeLayers.at(-1) ?? this.#rootLayer;\n\n // Create a $slot and element for this layer.\n const $slot = writable<MarkupNode>();\n const node = new ViewNode(parentLayer.context, matchedLayer.view, {\n children: m(MarkupType.Dynamic, { source: $slot }),\n });\n\n // Set state for new layer.\n const stateEntries = state.get(matchedLayer.id);\n if (stateEntries) {\n node.context.setState(stateEntries);\n }\n\n // TODO: Handle route suspense. Route views should be able to suspend route mounting until they have loaded their data.\n\n // const routeLoader = {\n // next() {},\n // error(err: Error) {},\n // };\n // node.context.setState(\"ROUTE_LOADER\", routeLoader);\n // TODO: Views will look for a ROUTE_LOADER on their own context and call next() on it if they find it.\n // This will complete the mounting of the route.\n\n // Add new layer to activeLayers.\n this.#activeLayers.push({\n id: matchedLayer.id,\n node,\n context: node.context,\n $slot: $slot,\n });\n\n // Slot this layer into parent.\n parentLayer.$slot.set(node);\n } else {\n // Update state for layers that are still active.\n const stateEntries = state.get(activeLayer.id);\n if (stateEntries) {\n activeLayer.context.setState(stateEntries);\n }\n }\n }\n });\n\n return { match, journey };\n }\n\n /**\n * Takes a URL and finds a match, following redirects.\n */\n async #resolveRoute(\n url: URL,\n journey: JourneyStep[] = [],\n state = new Map<number, [any, any][]>(),\n ): Promise<{\n match: RouteMatch<RouteMeta> | null;\n journey: JourneyStep[];\n state: Map<number, [any, any][]>; // map of layerId to state entries\n }> {\n return new Promise((resolve, reject) => {\n const match = matchRoutes(this.#routes, url.pathname);\n\n if (!match) {\n return resolve({\n match: null,\n journey: [...journey, { kind: \"miss\", message: `no match for '${url.pathname}'` }],\n state,\n });\n }\n\n let redirect = match.meta.redirect;\n\n const finalize = async () => {\n if (redirect != null) {\n let path: string;\n\n if (isString(redirect)) {\n path = replaceParams(redirect, match.params);\n } else if (isFunction(redirect)) {\n const redirectContext: RouteRedirectContext = {\n path: match.path,\n pattern: match.pattern,\n params: match.params,\n query: match.query,\n data: match.meta.data ?? {},\n };\n path = await redirect(redirectContext);\n if (!isString(path)) {\n return reject(new Error(`Redirect function must return a path to redirect to.`));\n }\n if (!path.startsWith(\"/\")) {\n // Not absolute. Resolve against matched path.\n path = resolvePath(match.path, path);\n }\n } else {\n return reject(new TypeError(`Redirect must either be a path string or a function.`));\n }\n\n resolve(\n this.#resolveRoute(new URL(path, window.location.origin), [\n ...journey,\n { kind: \"redirect\", message: `redirecting '${match.path}' -> '${path}'` },\n ]),\n );\n } else {\n resolve({ match, journey: [...journey, { kind: \"match\", message: `matched route '${match.path}'` }], state });\n }\n };\n\n if (match.meta.beforeMatch?.length) {\n const callbacks = match.meta.beforeMatch;\n let i = -1;\n const next = () => {\n i++;\n if (i === callbacks.length) {\n // Mount route\n finalize();\n } else {\n // Next callback\n let finalized = false;\n const result = callbacks[i].fn({\n path: match.path,\n pattern: match.pattern,\n params: match.params,\n query: match.query,\n data: match.meta.data ?? {},\n\n setState: (...args: any[]) => {\n const id = callbacks[i].layerId;\n const entries: [any, any][] = [];\n\n if (args.length === 1 && isArrayOf(isArray, args[0])) {\n entries.push(...(args[0] as [any, any][]));\n } else if (args.length === 2) {\n entries.push([args[0], args[1]]);\n } else {\n throw new Error(\"Invalid arguments.\");\n }\n\n const current = state.get(id);\n if (!current) {\n state.set(id, entries);\n } else {\n entries.push(...entries);\n }\n },\n\n redirect: (path) => {\n redirect = path;\n finalized = true;\n finalize();\n },\n });\n if (!finalized) {\n if (result instanceof Promise) {\n result.then(next);\n } else {\n next();\n }\n }\n }\n };\n\n next();\n\n // TODO: Show warning after timeout if next hasn't been called?\n } else {\n finalize();\n }\n });\n }\n\n /**\n * Parses a route definition object into a set of matchable routes.\n *\n * @param route - Route config object.\n * @param layers - Array of parent layers. Passed when this function calls itself on nested routes.\n */\n #prepareRoute(route: Route, parents: Route[] = [], layers: RouteLayer[] = []) {\n if (!isObject(route) || !isString(route.path)) {\n throw new TypeError(`Route configs must be objects with a 'path' string property. Got: ${route}`);\n }\n\n if (route.redirect && route.routes) {\n throw new Error(`Route cannot have both a 'redirect' and nested 'routes'.`);\n } else if (route.redirect && route.view) {\n throw new Error(`Route cannot have both a 'redirect' and a 'view'.`);\n } else if (!route.view && !route.routes && !route.redirect) {\n throw new Error(`Route must have a 'view', a 'redirect', or a set of nested 'routes'.`);\n }\n\n let parts: string[] = [];\n\n for (const parent of parents) {\n parts.push(...splitPath(parent.path));\n }\n\n parts.push(...splitPath(route.path));\n\n // Remove trailing wildcard for joining with nested routes.\n if (parts[parts.length - 1] === \"*\") {\n parts.pop();\n }\n\n const routes: RouteConfig[] = [];\n\n if (route.redirect) {\n let redirect = route.redirect;\n\n if (isString(redirect)) {\n redirect = resolvePath(joinPath(parts), redirect);\n\n if (!redirect.startsWith(\"/\")) {\n redirect = \"/\" + redirect;\n }\n }\n\n const config: RouteConfig = {\n pattern: \"/\" + joinPath([...parts, ...splitPath(route.path)]),\n meta: {\n redirect,\n },\n };\n routes.push(config);\n\n return routes;\n }\n\n let view: View<any> = (props: any) => props.children;\n\n if (isFunction(route.view)) {\n view = route.view;\n } else if (route.view) {\n throw new TypeError(`Route '${route.path}' expected a view function or undefined. Got: ${route.view}`);\n }\n\n const layer: RouteLayer = { id: this.#nextLayerId++, view };\n\n // Parse nested routes if they exist.\n if (route.routes) {\n for (const subroute of route.routes) {\n routes.push(...this.#prepareRoute(subroute, [...parents, route], [...layers, layer]));\n }\n } else {\n const config: RouteConfig = {\n pattern: parents.length ? joinPath([...parents.map((p) => p.path), route.path]) : route.path,\n meta: {\n pattern: route.path,\n layers: [...layers, layer],\n // Store the layer ID with each beforeMatch so we can correlate which context needs to get any state that is set.\n beforeMatch: parents\n .flatMap((parent, i) => (parent.beforeMatch ? { fn: parent.beforeMatch, layerId: layers[i].id } : null))\n .concat(route.beforeMatch ? { fn: route.beforeMatch, layerId: layer.id } : null)\n .filter((x) => x != null),\n },\n };\n if (route.data) {\n const parent = parents.at(-1);\n if (parent) {\n config.meta.data = { ...parent.data, ...route.data };\n } else {\n config.meta.data = route.data;\n }\n }\n routes.push(config);\n }\n\n return routes;\n }\n}\n\nfunction assertValidRedirects(routes: ParsedRoute<RouteMeta>[]) {\n // Test redirects to make sure all possible redirect targets actually exist.\n for (const route of routes) {\n if (route.meta.redirect) {\n let redirectPath: string;\n\n if (isFunction(route.meta.redirect)) {\n // throw new Error(`Redirect functions are not yet supported.`);\n // Just allow, though it could fail later. Best not to call the function and cause potential side effects.\n } else if (isString(route.meta.redirect)) {\n redirectPath = route.meta.redirect;\n\n const match = matchRoutes(routes, redirectPath, {\n willMatch(r) {\n return r !== route;\n },\n });\n\n if (!match) {\n throw new Error(`Found a redirect to an undefined URL. From '${route.pattern}' to '${route.meta.redirect}'`);\n }\n } else {\n throw new TypeError(`Expected a string or redirect function. Got: ${route.meta.redirect}`);\n }\n }\n }\n}\n\n/**\n * Parses the data-router-preserve-query attribute from a link.\n */\nfunction parsePreserveQueryAttribute(value: null | string | boolean): boolean | string[] {\n if (value === null) {\n return false;\n } else if (value === true || value === false) {\n return value;\n } else if (typeof value === \"string\") {\n value = value.trim();\n if (value === \"\" || value === \"true\") {\n return true;\n } else if (value === \"false\") {\n return false;\n }\n\n return value\n .split(\",\")\n .map((k) => k.trim())\n .filter((k) => k.length > 0);\n } else {\n throw new Error(`Invalid type for data-router-preserve-query attribute: ${typeof value} (value: ${value})`);\n }\n}\n\nclass NoRouteError extends Error {}\n","import { getCurrentContext } from \"../core/signals\";\nimport { type Router, ROUTER } from \"./router\";\n\nexport function useRouter() {\n const context = getCurrentContext();\n if (!context) throw new Error(`Hooks can only be called in the body of a View, Store or Mixin.`);\n const router = context.getState<Router | null>(ROUTER, { fallback: null });\n if (!router) throw new Error(`useRoute can only be called within an app that uses a router.`);\n return router;\n}\n\ntype RouteController = {\n /**\n * Call when the route is ready to mount.\n */\n next: () => void;\n /**\n * Call when navigation/transition needs to be cancelled.\n */\n cancel: (error: Error) => void;\n};\n\ntype RoutePreloadFn = (controller: RouteController) => any;\n\nfunction useRoutePreload(preload: RoutePreloadFn) {\n // TODO: Suspend route mounting until controller.next() is called by `preload`.\n}\n\n// Used unless a preload function is supplied by the user.\nconst defaultPreload: RoutePreloadFn = (ctrl) => ctrl.next();\n\ntype RouteTransitionOptions = {\n in?: (controller: RouteController) => any;\n out?: (controller: RouteController) => any;\n};\n\nfunction useRouteTransitions(options: RouteTransitionOptions) {\n // Starts after preload ends.\n // TODO: On transition in; mount this route, but suspend previous route's unmount until controller.next() is called.\n // TODO: On transition out; mount next route, but suspend this route's unmount until controller.next() is called.\n}\n\n// Merge route transition options with these default options.\nconst defaultTransitionOptions: RouteTransitionOptions = {\n in: (ctrl) => ctrl.next(),\n out: (ctrl) => ctrl.next(),\n};\n\n// useRoutePreload(async ({ next }) => {\n// await nextValueOf($botInfo, { where: (value) => value != null });\n// next();\n// });\n\n// useRouteTransitions({\n// in: ({ next }) => {\n// // animate(\"#whatever\", onComplete: next);\n// next();\n// },\n// out: ({ next }) => {\n// next();\n// },\n// });\n","import { Router, type RouterOptions } from \"./router.js\";\n\nexport function createRouter(options: RouterOptions): Router {\n return new Router(options);\n}\n\nexport { useRouter } from \"./hooks.js\";\n"],"names":["splitPath","path","assertString","f","joinPath","parts","assertArrayOf","part","isFunction","x","joined","_a","p","resolvePath","base","resolved","i","parseQueryParams","query","entries","entry","matchRoutes","routes","url","options","route","fragments","matched","frag","params","sortRoutes","withoutParams","withNumericParams","withParams","wildcard","bySizeDesc","a","b","patternToFragments","pattern","safeExternalLink","protocolLink","catchLinks","root","callback","_window","traverse","node","handler","e","anchor","replaceParams","key","value","ROUTER","MOUNT","UNMOUNT","Router","__privateAdd","_Router_instances","_logger","createLogger","_nextLayerId","_activeLayers","_routes","_isMounted","_rootLayer","_hash","_cleanup","_match","writable","__publicField","memo","match","__privateGet","deepEqual","shallowEqual","assertObject","__privateSet","__privateMethod","prepareRoute_fn","assertValidRedirects","parent","context","$slot","__privateWrapper","DynamicNode","onPopState","updateRoute_fn","href","preserveQuery","parsePreserveQueryAttribute","steps","replace_fn","push_fn","values","untracked","queryParts","queryString","getCurrentURL_fn","logger","journey","state","resolveRoute_fn","step","tag","NoRouteError","isArray","preserved","current","batch","oldPattern","layer","stateEntries","layers","matchedLayer","activeLayer","parentLayer","ViewNode","m","MarkupType","resolve","reject","redirect","finalize","isString","redirectContext","callbacks","next","finalized","result","args","id","isArrayOf","parents","isObject","config","view","props","subroute","redirectPath","r","k","useRouter","getCurrentContext","router","createRouter"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,24 +1,20 @@
1
- import { g as m } from "./signals-DbDmN2gr.js";
2
- import { $ as q, b as S, d as _, e as $, c as B, m as W, f as z, s as A, a as G, u as K, w as P } from "./signals-DbDmN2gr.js";
3
- import { R as g, D as w, m as n, w as y, C as s, L as c, V as f } from "./markup-DeZDwQ9F.js";
4
- import { M as H, a as J, c as Q, p as X, r as Y, b as Z, u as p } from "./markup-DeZDwQ9F.js";
5
- import { r as ae } from "./ref-BD79iqlg.js";
6
- import { R as N, M as b, U as x } from "./router-C35XmU3k.js";
7
- import { a as L } from "./typeChecking-CbltMOUt.js";
8
- import { o as M } from "./logger-B7RBYtzP.js";
9
- import { c as ne, s as re, a as se } from "./logger-B7RBYtzP.js";
10
- const k = (e) => e;
11
- function E(e, t) {
12
- return new g(t, e.each, e.key ?? k, e.children);
13
- }
14
- function F(e, t) {
15
- return new w(t, () => {
16
- let a = !0;
17
- return e.when != null && e.unless != null ? a = m(e.when) && !m(e.unless) : e.when != null ? a = m(e.when) : e.unless != null && (a = !m(e.unless)), a ? e.children : e.fallback;
18
- });
19
- }
20
- function U(e) {
21
- return n("div", {
1
+ var E = (e) => {
2
+ throw TypeError(e);
3
+ };
4
+ var N = (e, t, r) => t.has(e) || E("Cannot " + r);
5
+ var n = (e, t, r) => (N(e, t, "read from private field"), r ? r.call(e) : t.get(e)), i = (e, t, r) => t.has(e) ? E("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(e) : t.set(e, r), s = (e, t, r, w) => (N(e, t, "write to private field"), w ? w.call(e, r) : t.set(e, r), r), k = (e, t, r) => (N(e, t, "access private method"), r);
6
+ import { R as U, c as v, M as R, a as C, U as O } from "./index-BEDDzyd9.js";
7
+ import { t as S, i as T } from "./typeChecking-_dGK_0uR.js";
8
+ import { m as l, w as D, C as m, V as M, L as g, R as F, D as q, M as P, a as $ } from "./markup-DjDexAN5.js";
9
+ import { b as ee, c as te, p as re, r as ne, d as ae, u as se } from "./markup-DjDexAN5.js";
10
+ import { o as V } from "./logger-CmXtRdEI.js";
11
+ import { c as oe, s as le, a as ce } from "./logger-CmXtRdEI.js";
12
+ import { F as p } from "./fragment-BahD_BJA.js";
13
+ import { g as y } from "./signals-CkfFHd0d.js";
14
+ import { $ as ue, b as me, d as fe, e as de, c as we, m as ge, f as ye, s as be, a as Ne, u as xe, w as Ee } from "./signals-CkfFHd0d.js";
15
+ import { r as Me } from "./ref-BD79iqlg.js";
16
+ function I(e) {
17
+ return l("div", {
22
18
  style: {
23
19
  backgroundColor: "#880000",
24
20
  color: "#fff",
@@ -28,17 +24,17 @@ function U(e) {
28
24
  fontSize: "20px"
29
25
  },
30
26
  children: [
31
- n("h1", { style: { marginBottom: "0.5rem" }, children: "The app has crashed" }),
32
- n("p", {
27
+ l("h1", { style: { marginBottom: "0.5rem" }, children: "The app has crashed" }),
28
+ l("p", {
33
29
  style: { marginBottom: "0.25rem" },
34
30
  children: [
35
- n("span", {
31
+ l("span", {
36
32
  style: { fontFamily: "monospace" },
37
33
  children: e.loggerName
38
34
  }),
39
- y(
35
+ D(
40
36
  e.tag,
41
- n("span", {
37
+ l("span", {
42
38
  style: { fontFamily: "monospace", opacity: 0.5 },
43
39
  children: ` [${e.tagName ? `${e.tagName}: ` : ""}${e.tag}]`
44
40
  })
@@ -46,7 +42,7 @@ function U(e) {
46
42
  " says:"
47
43
  ]
48
44
  }),
49
- n("blockquote", {
45
+ l("blockquote", {
50
46
  style: {
51
47
  backgroundColor: "#991111",
52
48
  padding: "0.25em",
@@ -55,7 +51,7 @@ function U(e) {
55
51
  marginBottom: "1rem"
56
52
  },
57
53
  children: [
58
- n("span", {
54
+ l("span", {
59
55
  style: {
60
56
  display: "inline-block",
61
57
  backgroundColor: "red",
@@ -70,53 +66,112 @@ function U(e) {
70
66
  e.error.message
71
67
  ]
72
68
  }),
73
- n("p", { children: "Please see the browser console for details." })
69
+ l("p", { children: "Please see the browser console for details." })
74
70
  ]
75
71
  });
76
72
  }
77
- let l = !1;
78
- async function V(e, t, a) {
79
- if (L(Element, t, "Expected an element or a selector string. Got type: %t, value: %v"), l)
80
- throw new Error("A Dolla app is already mounted.");
81
- let o, i, d = (a == null ? void 0 : a.crashView) ?? U;
82
- const r = (a == null ? void 0 : a.context) ?? new s("App");
83
- M((h) => {
84
- l && u(), new f(r, d, h).mount(t);
85
- }), s.emit(r, c.WILL_MOUNT), e instanceof N ? (i = e, o = await i[b](t, r)) : o = new f(r, e, {}), o.mount(t), l = !0, s.emit(r, c.DID_MOUNT);
86
- async function u() {
87
- l && (s.emit(r, c.WILL_UNMOUNT), o.unmount(!1), i && await i[x](), l = !1, s.emit(r, c.DID_UNMOUNT));
73
+ var h, a, f, o, c, d, u, b, L;
74
+ class x {
75
+ constructor(t) {
76
+ i(this, b);
77
+ i(this, h);
78
+ i(this, a);
79
+ i(this, f);
80
+ i(this, o);
81
+ i(this, c, !1);
82
+ i(this, d, I);
83
+ i(this, u, []);
84
+ s(this, f, t.view ?? p), s(this, o, t.router), s(this, a, t.context ?? new m("App"));
85
+ }
86
+ get context() {
87
+ return n(this, a);
88
+ }
89
+ setCrashView(t) {
90
+ return s(this, d, t), this;
91
+ }
92
+ async mount(t) {
93
+ if (n(this, c)) return Promise.resolve();
94
+ const r = k(this, b, L).call(this, t);
95
+ n(this, u).push(
96
+ V((w) => {
97
+ n(this, c) && this.unmount(), new M(n(this, a), n(this, d), w).mount(r);
98
+ })
99
+ ), m.emit(n(this, a), g.WILL_MOUNT), n(this, o) ? (s(this, h, await n(this, o)[R](r, n(this, a))), n(this, a).setState(C, n(this, o))) : s(this, h, new M(n(this, a), n(this, f), {})), n(this, h).mount(r), s(this, c, !0), m.emit(n(this, a), g.DID_MOUNT);
100
+ }
101
+ async unmount() {
102
+ if (!n(this, c)) return Promise.resolve();
103
+ m.emit(n(this, a), g.WILL_UNMOUNT), s(this, c, !1), n(this, h).unmount(!1), n(this, o) && await n(this, o)[O]();
104
+ for (const t of n(this, u))
105
+ t();
106
+ s(this, u, []), m.emit(n(this, a), g.DID_UNMOUNT);
107
+ }
108
+ }
109
+ h = new WeakMap(), a = new WeakMap(), f = new WeakMap(), o = new WeakMap(), c = new WeakMap(), d = new WeakMap(), u = new WeakMap(), b = new WeakSet(), L = function(t) {
110
+ if (typeof t == "string") {
111
+ const r = document.querySelector(t);
112
+ if (!r)
113
+ throw new Error(`Selector '${t}' did not many any element.`);
114
+ return r;
115
+ } else {
116
+ if (t instanceof Element)
117
+ return t;
118
+ throw new Error("Expected a selector string or DOM element.");
88
119
  }
89
- return u;
120
+ };
121
+ function H(e, t) {
122
+ return e instanceof U ? new x({ ...t, router: e }) : S(e) === "object" ? new x({ ...t, router: v(e) }) : new x({ ...t, view: e });
123
+ }
124
+ const _ = (e) => e;
125
+ function J(e, t) {
126
+ return new F(t, e.each, e.key ?? _, e.children);
127
+ }
128
+ function Q(e, t) {
129
+ return new q(t, () => {
130
+ let r = !0;
131
+ return e.when != null && e.unless != null ? r = y(e.when) && !y(e.unless) : e.when != null ? r = y(e.when) : e.unless != null && (r = !y(e.unless)), r ? e.children : e.fallback;
132
+ });
133
+ }
134
+ function X(e, t) {
135
+ if (T(e.into)) {
136
+ if (document.querySelector(e.into) == null)
137
+ throw t.crash(new Error(`Portal: selector '${e.into}' did not match any element`));
138
+ } else
139
+ e.into;
140
+ return new P($.Portal, {
141
+ parent: e.into,
142
+ content: e.children
143
+ });
90
144
  }
91
145
  export {
92
- q as $,
93
- E as For,
94
- H as Markup,
95
- J as MarkupNode,
96
- F as Show,
97
- S as batch,
98
- Q as createContext,
99
- ne as createLogger,
100
- _ as deepEqual,
101
- $ as effect,
102
- m as get,
103
- B as getEnv,
104
- n as m,
105
- W as memo,
106
- V as mount,
107
- M as onLoggerCrash,
108
- X as portal,
109
- ae as ref,
110
- Y as render,
111
- Z as repeat,
112
- z as setEnv,
113
- re as setLogFilter,
114
- se as setLogLevels,
115
- A as shallowEqual,
116
- G as strictEqual,
117
- p as unless,
118
- K as untracked,
119
- y as when,
120
- P as writable
146
+ ue as $,
147
+ J as For,
148
+ P as Markup,
149
+ ee as MarkupNode,
150
+ X as Portal,
151
+ Q as Show,
152
+ me as batch,
153
+ H as createApp,
154
+ te as createContext,
155
+ oe as createLogger,
156
+ fe as deepEqual,
157
+ de as effect,
158
+ y as get,
159
+ we as getEnv,
160
+ l as m,
161
+ ge as memo,
162
+ V as onLoggerCrash,
163
+ re as portal,
164
+ Me as ref,
165
+ ne as render,
166
+ ae as repeat,
167
+ ye as setEnv,
168
+ le as setLogFilter,
169
+ ce as setLogLevels,
170
+ be as shallowEqual,
171
+ Ne as strictEqual,
172
+ se as unless,
173
+ xe as untracked,
174
+ D as when,
175
+ Ee as writable
121
176
  };
122
177
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/core/views/for.ts","../src/core/views/show.ts","../src/core/views/default-crash-view.ts","../src/core/mount.ts"],"sourcesContent":["import type { Renderable } from \"../../types\";\nimport type { Context } from \"../context\";\nimport { type Key, RepeatNode } from \"../nodes/repeat\";\nimport { type Signal } from \"../signals\";\n\nexport interface ForProps<T> {\n /**\n * An array of items to render.\n */\n each: Signal<T[]>;\n /**\n * A function to extract a unique key that identifies each item.\n * If no `key` function is passed, object identity (===) will be used.\n */\n key?: (item: T, index: number) => Key;\n /**\n * A render function. Takes the item and its index in signal form and returns something to display for each item.\n */\n children: (item: Signal<T>, index: Signal<number>, ctx: Context) => Renderable;\n}\n\nconst defaultKeyFn = (x: any) => x;\n\n/**\n *\n */\nexport function For<T>(props: ForProps<T>, context: Context) {\n return new RepeatNode(context, props.each, props.key ?? defaultKeyFn, props.children);\n}\n","import type { Renderable } from \"../../types\";\nimport type { Context } from \"../context\";\nimport { DynamicNode } from \"../nodes/dynamic\";\nimport { get, type Signal } from \"../signals\";\n\nexport interface ShowProps {\n /**\n * If present, children will be rendered only when this signal holds a truthy value.\n */\n when?: Signal<any>;\n\n /**\n * If present, children will be rendered only when this signal holds a falsy value.\n */\n unless?: Signal<any>;\n\n /**\n * Content to render if conditions permit.\n */\n children: Renderable;\n\n /**\n * Content to render when conditions don't permit `children` to render.\n */\n fallback?: Renderable;\n}\n\n/**\n * Conditionally display children.\n */\nexport function Show(props: ShowProps, context: Context) {\n return new DynamicNode(context, () => {\n let shouldShow = true;\n\n if (props.when != null && props.unless != null) {\n shouldShow = get(props.when) && !get(props.unless);\n } else if (props.when != null) {\n shouldShow = get(props.when);\n } else if (props.unless != null) {\n shouldShow = !get(props.unless);\n }\n\n if (shouldShow) {\n return props.children;\n } else {\n return props.fallback;\n }\n });\n}\n","import { when, m } from \"../markup.js\";\n\n/**\n * Props passed to the crash view when a crash occurs.\n */\nexport interface CrashViewProps {\n /**\n * JavaScript Error object.\n */\n error: Error;\n\n /**\n * A string to identify the logger that reported this error.\n */\n loggerName: string;\n\n /**\n * Unique identifier to pinpoint the specific view that reported the crash.\n */\n tag?: string;\n\n /**\n * Label for the tag.\n */\n tagName?: string;\n}\n\n/**\n * The crash view displayed unless you specify your own.\n */\nexport function DefaultCrashView(props: CrashViewProps) {\n return m(\"div\", {\n style: {\n backgroundColor: \"#880000\",\n color: \"#fff\",\n padding: \"2rem\",\n position: \"fixed\",\n inset: 0,\n fontSize: \"20px\",\n },\n children: [\n m(\"h1\", { style: { marginBottom: \"0.5rem\" }, children: \"The app has crashed\" }),\n m(\"p\", {\n style: { marginBottom: \"0.25rem\" },\n children: [\n m(\"span\", {\n style: { fontFamily: \"monospace\" },\n children: props.loggerName,\n }),\n when(\n props.tag,\n m(\"span\", {\n style: { fontFamily: \"monospace\", opacity: 0.5 },\n children: ` [${props.tagName ? `${props.tagName}: ` : \"\"}${props.tag}]`,\n }),\n ),\n \" says:\",\n ],\n }),\n m(\"blockquote\", {\n style: {\n backgroundColor: \"#991111\",\n padding: \"0.25em\",\n borderRadius: \"6px\",\n fontFamily: \"monospace\",\n marginBottom: \"1rem\",\n },\n children: [\n m(\"span\", {\n style: {\n display: \"inline-block\",\n backgroundColor: \"red\",\n padding: \"0.1em 0.4em\",\n marginRight: \"0.5em\",\n borderRadius: \"4px\",\n fontSize: \"0.9em\",\n fontWeight: \"bold\",\n },\n children: props.error.name,\n }),\n props.error.message,\n ],\n }),\n m(\"p\", { children: \"Please see the browser console for details.\" }),\n ],\n });\n}\n","import { MOUNT, Router, UNMOUNT } from \"../router/router\";\nimport { assertInstanceOf } from \"../typeChecking\";\nimport type { View } from \"../types\";\nimport { Context, LifecycleEvent } from \"./context\";\nimport { type LoggerCrashProps, onLoggerCrash } from \"./logger\";\nimport { type MarkupNode } from \"./markup\";\nimport { ViewNode } from \"./nodes/view\";\nimport { DefaultCrashView } from \"./views/default-crash-view\";\n\nlet isMounted = false;\n\nexport type UnmountFn = () => Promise<void>;\nexport interface MountOptions {\n crashView?: View<LoggerCrashProps>;\n\n /**\n * An existing Context to use as the root, otherwise a new one will be created.\n * Use this to provide top-level stores and state to the whole app.\n */\n context?: Context;\n}\n\nexport async function mount(view: View<{}>, domNode: Element, options?: MountOptions): Promise<UnmountFn>;\nexport async function mount(router: Router, domNode: Element, options?: MountOptions): Promise<UnmountFn>;\n\nexport async function mount(view: any, rootElement: Element, options?: MountOptions): Promise<UnmountFn> {\n assertInstanceOf(Element, rootElement, \"Expected an element or a selector string. Got type: %t, value: %v\");\n\n if (isMounted) {\n throw new Error(`A Dolla app is already mounted.`);\n }\n\n let rootView: MarkupNode;\n let router: Router | undefined;\n let crashView = options?.crashView ?? DefaultCrashView;\n\n const rootContext = options?.context ?? new Context(\"App\");\n\n onLoggerCrash((props) => {\n if (isMounted) {\n unmount();\n }\n\n // Mount the crash page\n new ViewNode(rootContext, crashView, props).mount(rootElement);\n });\n\n Context.emit(rootContext, LifecycleEvent.WILL_MOUNT);\n\n if (view instanceof Router) {\n // Store router reference so we can unmount it with the app.\n router = view;\n rootView = await router[MOUNT](rootElement, rootContext);\n } else {\n rootView = new ViewNode(rootContext, view, {});\n }\n rootView.mount(rootElement);\n isMounted = true;\n\n Context.emit(rootContext, LifecycleEvent.DID_MOUNT);\n\n async function unmount() {\n if (!isMounted) return;\n\n Context.emit(rootContext, LifecycleEvent.WILL_UNMOUNT);\n\n rootView.unmount(false);\n if (router) {\n await router[UNMOUNT]();\n }\n isMounted = false;\n\n Context.emit(rootContext, LifecycleEvent.DID_UNMOUNT);\n }\n\n return unmount;\n}\n"],"names":["defaultKeyFn","x","For","props","context","RepeatNode","Show","DynamicNode","shouldShow","get","DefaultCrashView","m","when","isMounted","mount","view","rootElement","options","assertInstanceOf","rootView","router","crashView","rootContext","Context","onLoggerCrash","unmount","ViewNode","LifecycleEvent","Router","MOUNT","UNMOUNT"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/core/views/default-crash-view.ts","../src/core/app.ts","../src/core/views/for.ts","../src/core/views/show.ts","../src/core/views/portal.ts"],"sourcesContent":["import { when, m } from \"../markup.js\";\n\n/**\n * Props passed to the crash view when a crash occurs.\n */\nexport interface CrashViewProps {\n /**\n * JavaScript Error object.\n */\n error: Error;\n\n /**\n * A string to identify the logger that reported this error.\n */\n loggerName: string;\n\n /**\n * Unique identifier to pinpoint the specific view that reported the crash.\n */\n tag?: string;\n\n /**\n * Label for the tag.\n */\n tagName?: string;\n}\n\n/**\n * The crash view displayed unless you specify your own.\n */\nexport function DefaultCrashView(props: CrashViewProps) {\n return m(\"div\", {\n style: {\n backgroundColor: \"#880000\",\n color: \"#fff\",\n padding: \"2rem\",\n position: \"fixed\",\n inset: 0,\n fontSize: \"20px\",\n },\n children: [\n m(\"h1\", { style: { marginBottom: \"0.5rem\" }, children: \"The app has crashed\" }),\n m(\"p\", {\n style: { marginBottom: \"0.25rem\" },\n children: [\n m(\"span\", {\n style: { fontFamily: \"monospace\" },\n children: props.loggerName,\n }),\n when(\n props.tag,\n m(\"span\", {\n style: { fontFamily: \"monospace\", opacity: 0.5 },\n children: ` [${props.tagName ? `${props.tagName}: ` : \"\"}${props.tag}]`,\n }),\n ),\n \" says:\",\n ],\n }),\n m(\"blockquote\", {\n style: {\n backgroundColor: \"#991111\",\n padding: \"0.25em\",\n borderRadius: \"6px\",\n fontFamily: \"monospace\",\n marginBottom: \"1rem\",\n },\n children: [\n m(\"span\", {\n style: {\n display: \"inline-block\",\n backgroundColor: \"red\",\n padding: \"0.1em 0.4em\",\n marginRight: \"0.5em\",\n borderRadius: \"4px\",\n fontSize: \"0.9em\",\n fontWeight: \"bold\",\n },\n children: props.error.name,\n }),\n props.error.message,\n ],\n }),\n m(\"p\", { children: \"Please see the browser console for details.\" }),\n ],\n });\n}\n","import { createRouter } from \"../router\";\nimport { MOUNT, ROUTER, Router, RouterOptions, UNMOUNT } from \"../router/router\";\nimport { typeOf } from \"../typeChecking\";\nimport { View } from \"../types\";\nimport { Context, LifecycleEvent } from \"./context\";\nimport { LoggerCrashProps, onLoggerCrash } from \"./logger\";\nimport { MarkupNode } from \"./markup\";\nimport { ViewNode } from \"./nodes/view\";\nimport { DefaultCrashView } from \"./views/default-crash-view\";\nimport { Fragment } from \"./views/fragment\";\n\ninterface AppOptions {\n view?: View<{}>;\n router?: Router;\n context?: Context;\n}\n\nclass App {\n #root!: MarkupNode;\n #context: Context;\n #view: View<{}>;\n #router?: Router;\n #mounted = false;\n #crashView: View<LoggerCrashProps> = DefaultCrashView;\n\n #cleanup: (() => void)[] = [];\n\n get context() {\n return this.#context;\n }\n\n constructor(options: AppOptions) {\n this.#view = options.view ?? Fragment;\n this.#router = options.router;\n this.#context = options.context ?? new Context(\"App\");\n }\n\n setCrashView(view: View<LoggerCrashProps>) {\n this.#crashView = view;\n return this;\n }\n\n async mount(element: string | Element): Promise<void> {\n if (this.#mounted) return Promise.resolve();\n\n const parentElement = this.#getElement(element);\n\n this.#cleanup.push(\n onLoggerCrash((props) => {\n if (this.#mounted) {\n this.unmount();\n }\n new ViewNode(this.#context, this.#crashView, props).mount(parentElement);\n }),\n );\n\n Context.emit(this.#context, LifecycleEvent.WILL_MOUNT);\n\n if (this.#router) {\n this.#root = await this.#router[MOUNT](parentElement, this.#context);\n this.#context.setState(ROUTER, this.#router);\n } else {\n this.#root = new ViewNode(this.#context, this.#view, {});\n }\n this.#root.mount(parentElement);\n this.#mounted = true;\n\n Context.emit(this.#context, LifecycleEvent.DID_MOUNT);\n }\n\n async unmount() {\n if (!this.#mounted) return Promise.resolve();\n\n Context.emit(this.#context, LifecycleEvent.WILL_UNMOUNT);\n this.#mounted = false;\n\n this.#root.unmount(false);\n if (this.#router) {\n await this.#router[UNMOUNT]();\n }\n\n for (const callback of this.#cleanup) {\n callback();\n }\n this.#cleanup = [];\n\n Context.emit(this.#context, LifecycleEvent.DID_UNMOUNT);\n }\n\n #getElement(element: string | Element): Element {\n if (typeof element === \"string\") {\n const match = document.querySelector(element);\n if (!match) {\n throw new Error(`Selector '${element}' did not many any element.`);\n }\n return match;\n } else if (element instanceof Element) {\n return element;\n } else {\n throw new Error(\"Expected a selector string or DOM element.\");\n }\n }\n}\n\nexport interface CreateAppOptions {\n context?: Context;\n}\n\nexport function createApp(view: View<{}>, options?: CreateAppOptions): App;\nexport function createApp(routerOptions: RouterOptions, options?: CreateAppOptions): App;\nexport function createApp(router: Router, options?: CreateAppOptions): App;\n\nexport function createApp(entry: View<{}> | RouterOptions | Router, options?: CreateAppOptions) {\n if (entry instanceof Router) {\n return new App({ ...options, router: entry });\n } else if (typeOf(entry) === \"object\") {\n return new App({ ...options, router: createRouter(entry as RouterOptions) });\n } else {\n return new App({ ...options, view: entry as View<{}> });\n }\n}\n","import type { Renderable } from \"../../types\";\nimport type { Context } from \"../context\";\nimport { type Key, RepeatNode } from \"../nodes/repeat\";\nimport { type Signal } from \"../signals\";\n\nexport interface ForProps<T> {\n /**\n * An array of items to render.\n */\n each: Signal<T[]>;\n /**\n * A function to extract a unique key that identifies each item.\n * If no `key` function is passed, object identity (===) will be used.\n */\n key?: (item: T, index: number) => Key;\n /**\n * A render function. Takes the item and its index in signal form and returns something to display for each item.\n */\n children: (item: Signal<T>, index: Signal<number>, ctx: Context) => Renderable;\n}\n\nconst defaultKeyFn = (x: any) => x;\n\n/**\n *\n */\nexport function For<T>(props: ForProps<T>, context: Context) {\n return new RepeatNode(context, props.each, props.key ?? defaultKeyFn, props.children);\n}\n","import type { Renderable } from \"../../types\";\nimport type { Context } from \"../context\";\nimport { DynamicNode } from \"../nodes/dynamic\";\nimport { get, type Signal } from \"../signals\";\n\nexport interface ShowProps {\n /**\n * If present, children will be rendered only when this signal holds a truthy value.\n */\n when?: Signal<any>;\n\n /**\n * If present, children will be rendered only when this signal holds a falsy value.\n */\n unless?: Signal<any>;\n\n /**\n * Content to render if conditions permit.\n */\n children: Renderable;\n\n /**\n * Content to render when conditions don't permit `children` to render.\n */\n fallback?: Renderable;\n}\n\n/**\n * Conditionally display children.\n */\nexport function Show(props: ShowProps, context: Context) {\n return new DynamicNode(context, () => {\n let shouldShow = true;\n\n if (props.when != null && props.unless != null) {\n shouldShow = get(props.when) && !get(props.unless);\n } else if (props.when != null) {\n shouldShow = get(props.when);\n } else if (props.unless != null) {\n shouldShow = !get(props.unless);\n }\n\n if (shouldShow) {\n return props.children;\n } else {\n return props.fallback;\n }\n });\n}\n","import { isString } from \"../../typeChecking\";\nimport type { Renderable } from \"../../types\";\nimport type { Context } from \"../context\";\nimport { Markup, MarkupType } from \"../markup\";\n\nexport interface PortalProps {\n /**\n * The parent element or a selector that will match it.\n */\n into: Element | string;\n\n /**\n * Content to render inside the `into` element.\n */\n children: Renderable;\n}\n\n/**\n * Render content into any element on the page.\n */\nexport function Portal(props: PortalProps, ctx: Context) {\n let parent: Element;\n\n if (isString(props.into)) {\n const match = document.querySelector(props.into);\n if (match == null) {\n throw ctx.crash(new Error(`Portal: selector '${props.into}' did not match any element`));\n }\n parent = match;\n } else {\n parent = props.into;\n }\n\n return new Markup(MarkupType.Portal, {\n parent: props.into,\n content: props.children,\n });\n}\n"],"names":["DefaultCrashView","props","m","when","App","options","__privateAdd","_App_instances","_root","_context","_view","_router","_mounted","_crashView","_cleanup","__privateSet","Fragment","Context","__privateGet","view","element","parentElement","__privateMethod","getElement_fn","onLoggerCrash","ViewNode","LifecycleEvent","MOUNT","ROUTER","UNMOUNT","callback","match","createApp","entry","Router","typeOf","createRouter","defaultKeyFn","x","For","context","RepeatNode","Show","DynamicNode","shouldShow","get","Portal","ctx","isString","Markup","MarkupType"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { M as n } from "./markup-DeZDwQ9F.js";
1
+ import { M as n } from "./markup-DjDexAN5.js";
2
2
  import { F as m } from "./fragment-BahD_BJA.js";
3
3
  function u(e, r, t, o, a, i) {
4
4
  return new n(e, t != null ? { ...r, key: t } : r);
@@ -1,4 +1,4 @@
1
- import { M as u } from "./markup-DeZDwQ9F.js";
1
+ import { M as u } from "./markup-DjDexAN5.js";
2
2
  import { F as m } from "./fragment-BahD_BJA.js";
3
3
  function o(t, n, r) {
4
4
  return new u(t, r != null ? { ...n, key: r } : n);
@@ -1,5 +1,5 @@
1
- import { b as d } from "./typeChecking-CbltMOUt.js";
2
- import { g as w, u as i, c as m, l as o, n as b, p as h } from "./signals-DbDmN2gr.js";
1
+ import { i as d } from "./typeChecking-_dGK_0uR.js";
2
+ import { g as i, u as w, c as m, p as o, q as h, r as b } from "./signals-CkfFHd0d.js";
3
3
  let g = {
4
4
  info: "development",
5
5
  log: "development",
@@ -13,15 +13,15 @@ function $(r) {
13
13
  }
14
14
  function k(r, e) {
15
15
  const c = (e == null ? void 0 : e.console) ?? v(), t = (a) => {
16
- let n = i(r);
16
+ let n = w(r);
17
17
  if (g[a] === !1 || d(g[a]) && g[a] !== m() || !s(n))
18
- return b;
18
+ return h;
19
19
  {
20
20
  let l = `%c${n}`;
21
21
  return e != null && e.tag ? e.tagName ? l += ` %c[${e.tagName}: %c${e.tag}%c]` : l += ` %c[%c${e.tag}%c]` : l += "%c%c%c", c[a].bind(
22
22
  c,
23
23
  l,
24
- `color:${h(l)};font-weight:bold`,
24
+ `color:${b(l)};font-weight:bold`,
25
25
  "color:#777",
26
26
  "color:#aaa",
27
27
  "color:#777"
@@ -46,7 +46,7 @@ function k(r, e) {
46
46
  u = !0;
47
47
  const n = {
48
48
  error: a,
49
- loggerName: w(r),
49
+ loggerName: i(r),
50
50
  tag: e == null ? void 0 : e.tag,
51
51
  tagName: e == null ? void 0 : e.tagName
52
52
  };
@@ -79,4 +79,4 @@ export {
79
79
  $ as o,
80
80
  x as s
81
81
  };
82
- //# sourceMappingURL=logger-B7RBYtzP.js.map
82
+ //# sourceMappingURL=logger-CmXtRdEI.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger-B7RBYtzP.js","sources":["../src/core/logger.ts"],"sourcesContent":["import { isString } from \"../typeChecking.js\";\nimport type { Env } from \"../types.js\";\nimport { createMatcher, noOp, okhash, type MatcherFunction } from \"../utils.js\";\nimport { getEnv } from \"./env.js\";\nimport { get, untracked, type MaybeSignal } from \"./signals.js\";\n\nexport interface LogLevels {\n info: boolean | Env;\n log: boolean | Env;\n warn: boolean | Env;\n error: boolean | Env;\n}\n\nexport interface Logger {\n info(...args: any[]): void;\n log(...args: any[]): void;\n warn(...args: any[]): void;\n error(...args: any[]): void;\n crash(error: Error): Error;\n}\n\nexport interface LoggerOptions {\n /**\n * Tag value to print with logs.\n */\n tag?: string;\n\n /**\n * Label for tag value. Will be printed without a label if not specified.\n */\n tagName?: string;\n\n /**\n * Console object to use for logging (mostly for testing). Uses window.console by default.\n */\n console?: any;\n}\n\nexport interface LoggerCrashProps {\n error: Error;\n loggerName: string;\n tag?: string;\n tagName?: string;\n}\n\nlet levels: LogLevels = {\n info: \"development\",\n log: \"development\",\n warn: \"development\",\n error: true,\n};\nlet match: MatcherFunction = createMatcher(\"*,-dolla.*\");\nlet crashListeners: ((context: LoggerCrashProps) => void)[] = [];\nlet isCrashed = false;\n\n/**\n * Listen for logged crashes.\n */\nexport function onLoggerCrash(listener: (context: LoggerCrashProps) => void) {\n crashListeners.push(listener);\n\n return function cancel() {\n crashListeners.splice(crashListeners.indexOf(listener), 1);\n };\n}\n\nexport function createLogger(name: MaybeSignal<string>, options?: LoggerOptions): Logger {\n const _console = options?.console ?? _getDefaultConsole();\n\n const bind = (method: keyof LogLevels) => {\n let _name = untracked(name);\n if (levels[method] === false || (isString(levels[method]) && levels[method] !== getEnv()) || !match(_name)) {\n return noOp;\n } else {\n let label = `%c${_name}`;\n if (options?.tag) {\n if (options.tagName) {\n label += ` %c[${options.tagName}: %c${options.tag}%c]`;\n } else {\n label += ` %c[%c${options.tag}%c]`;\n }\n } else {\n label += `%c%c%c`;\n }\n return _console[method].bind(\n _console,\n label,\n `color:${okhash(label)};font-weight:bold`,\n `color:#777`,\n `color:#aaa`,\n `color:#777`,\n );\n }\n };\n\n return {\n get info() {\n return bind(\"info\");\n },\n get log() {\n return bind(\"log\");\n },\n get warn() {\n return bind(\"warn\");\n },\n get error() {\n return bind(\"error\");\n },\n crash(error: Error) {\n if (!isCrashed) {\n isCrashed = true;\n const ctx: LoggerCrashProps = {\n error,\n loggerName: get(name),\n tag: options?.tag,\n tagName: options?.tagName,\n };\n\n for (const listener of crashListeners) {\n listener(ctx);\n }\n\n throw error;\n }\n\n return error;\n },\n };\n}\n\nexport function setLogFilter(filter: string | RegExp) {\n match = createMatcher(filter);\n}\n\nexport function setLogLevels(options: Partial<LogLevels>) {\n for (const key in options) {\n const value = options[key as keyof LogLevels];\n if (value) {\n levels[key as keyof LogLevels] = value;\n }\n }\n}\n\nfunction _getDefaultConsole() {\n if (typeof window !== \"undefined\" && window.console) {\n return window.console;\n }\n if (typeof global !== \"undefined\" && global.console) {\n return global.console;\n }\n}\n"],"names":["levels","match","createMatcher","crashListeners","isCrashed","onLoggerCrash","listener","createLogger","name","options","_console","_getDefaultConsole","bind","method","_name","untracked","isString","getEnv","noOp","label","okhash","error","ctx","get","setLogFilter","filter","setLogLevels","key","value"],"mappings":";;AA6CA,IAAIA,IAAoB;AAAA,EACtB,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,OAAO;AACT,GACIC,IAAyBC,EAAc,YAAY,GACnDC,IAA0D,CAAC,GAC3DC,IAAY;AAKT,SAASC,EAAcC,GAA+C;AAC3E,SAAAH,EAAe,KAAKG,CAAQ,GAErB,WAAkB;AACvB,IAAAH,EAAe,OAAOA,EAAe,QAAQG,CAAQ,GAAG,CAAC;AAAA,EAC3D;AACF;AAEgB,SAAAC,EAAaC,GAA2BC,GAAiC;AACjF,QAAAC,KAAWD,KAAA,gBAAAA,EAAS,YAAWE,EAAmB,GAElDC,IAAO,CAACC,MAA4B;AACpC,QAAAC,IAAQC,EAAUP,CAAI;AAC1B,QAAIR,EAAOa,CAAM,MAAM,MAAUG,EAAShB,EAAOa,CAAM,CAAC,KAAKb,EAAOa,CAAM,MAAMI,OAAa,CAAChB,EAAMa,CAAK;AAChG,aAAAI;AACF;AACD,UAAAC,IAAQ,KAAKL,CAAK;AACtB,aAAIL,KAAA,QAAAA,EAAS,MACPA,EAAQ,UACVU,KAAS,OAAOV,EAAQ,OAAO,OAAOA,EAAQ,GAAG,QAExCU,KAAA,SAASV,EAAQ,GAAG,QAGtBU,KAAA,UAEJT,EAASG,CAAM,EAAE;AAAA,QACtBH;AAAA,QACAS;AAAA,QACA,SAASC,EAAOD,CAAK,CAAC;AAAA,QACtB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IAAA;AAAA,EAEJ;AAEO,SAAA;AAAA,IACL,IAAI,OAAO;AACT,aAAOP,EAAK,MAAM;AAAA,IACpB;AAAA,IACA,IAAI,MAAM;AACR,aAAOA,EAAK,KAAK;AAAA,IACnB;AAAA,IACA,IAAI,OAAO;AACT,aAAOA,EAAK,MAAM;AAAA,IACpB;AAAA,IACA,IAAI,QAAQ;AACV,aAAOA,EAAK,OAAO;AAAA,IACrB;AAAA,IACA,MAAMS,GAAc;AAClB,UAAI,CAACjB,GAAW;AACF,QAAAA,IAAA;AACZ,cAAMkB,IAAwB;AAAA,UAC5B,OAAAD;AAAA,UACA,YAAYE,EAAIf,CAAI;AAAA,UACpB,KAAKC,KAAA,gBAAAA,EAAS;AAAA,UACd,SAASA,KAAA,gBAAAA,EAAS;AAAA,QACpB;AAEA,mBAAWH,KAAYH;AACrB,UAAAG,EAASgB,CAAG;AAGR,cAAAD;AAAA,MAAA;AAGD,aAAAA;AAAA,IAAA;AAAA,EAEX;AACF;AAEO,SAASG,EAAaC,GAAyB;AACpD,EAAAxB,IAAQC,EAAcuB,CAAM;AAC9B;AAEO,SAASC,EAAajB,GAA6B;AACxD,aAAWkB,KAAOlB,GAAS;AACnB,UAAAmB,IAAQnB,EAAQkB,CAAsB;AAC5C,IAAIC,MACF5B,EAAO2B,CAAsB,IAAIC;AAAA,EACnC;AAEJ;AAEA,SAASjB,IAAqB;AAC5B,MAAI,OAAO,SAAW,OAAe,OAAO;AAC1C,WAAO,OAAO;AAEhB,MAAI,OAAO,SAAW,OAAe,OAAO;AAC1C,WAAO,OAAO;AAElB;"}
1
+ {"version":3,"file":"logger-CmXtRdEI.js","sources":["../src/core/logger.ts"],"sourcesContent":["import { isString } from \"../typeChecking.js\";\nimport type { Env } from \"../types.js\";\nimport { createMatcher, noOp, okhash, type MatcherFunction } from \"../utils.js\";\nimport { getEnv } from \"./env.js\";\nimport { get, untracked, type MaybeSignal } from \"./signals.js\";\n\nexport interface LogLevels {\n info: boolean | Env;\n log: boolean | Env;\n warn: boolean | Env;\n error: boolean | Env;\n}\n\nexport interface Logger {\n info(...args: any[]): void;\n log(...args: any[]): void;\n warn(...args: any[]): void;\n error(...args: any[]): void;\n crash(error: Error): Error;\n}\n\nexport interface LoggerOptions {\n /**\n * Tag value to print with logs.\n */\n tag?: string;\n\n /**\n * Label for tag value. Will be printed without a label if not specified.\n */\n tagName?: string;\n\n /**\n * Console object to use for logging (mostly for testing). Uses window.console by default.\n */\n console?: any;\n}\n\nexport interface LoggerCrashProps {\n error: Error;\n loggerName: string;\n tag?: string;\n tagName?: string;\n}\n\nlet levels: LogLevels = {\n info: \"development\",\n log: \"development\",\n warn: \"development\",\n error: true,\n};\nlet match: MatcherFunction = createMatcher(\"*,-dolla.*\");\nlet crashListeners: ((context: LoggerCrashProps) => void)[] = [];\nlet isCrashed = false;\n\n/**\n * Listen for logged crashes.\n */\nexport function onLoggerCrash(listener: (context: LoggerCrashProps) => void) {\n crashListeners.push(listener);\n\n return function cancel() {\n crashListeners.splice(crashListeners.indexOf(listener), 1);\n };\n}\n\nexport function createLogger(name: MaybeSignal<string>, options?: LoggerOptions): Logger {\n const _console = options?.console ?? _getDefaultConsole();\n\n const bind = (method: keyof LogLevels) => {\n let _name = untracked(name);\n if (levels[method] === false || (isString(levels[method]) && levels[method] !== getEnv()) || !match(_name)) {\n return noOp;\n } else {\n let label = `%c${_name}`;\n if (options?.tag) {\n if (options.tagName) {\n label += ` %c[${options.tagName}: %c${options.tag}%c]`;\n } else {\n label += ` %c[%c${options.tag}%c]`;\n }\n } else {\n label += `%c%c%c`;\n }\n return _console[method].bind(\n _console,\n label,\n `color:${okhash(label)};font-weight:bold`,\n `color:#777`,\n `color:#aaa`,\n `color:#777`,\n );\n }\n };\n\n return {\n get info() {\n return bind(\"info\");\n },\n get log() {\n return bind(\"log\");\n },\n get warn() {\n return bind(\"warn\");\n },\n get error() {\n return bind(\"error\");\n },\n crash(error: Error) {\n if (!isCrashed) {\n isCrashed = true;\n const ctx: LoggerCrashProps = {\n error,\n loggerName: get(name),\n tag: options?.tag,\n tagName: options?.tagName,\n };\n\n for (const listener of crashListeners) {\n listener(ctx);\n }\n\n throw error;\n }\n\n return error;\n },\n };\n}\n\nexport function setLogFilter(filter: string | RegExp) {\n match = createMatcher(filter);\n}\n\nexport function setLogLevels(options: Partial<LogLevels>) {\n for (const key in options) {\n const value = options[key as keyof LogLevels];\n if (value) {\n levels[key as keyof LogLevels] = value;\n }\n }\n}\n\nfunction _getDefaultConsole() {\n if (typeof window !== \"undefined\" && window.console) {\n return window.console;\n }\n if (typeof global !== \"undefined\" && global.console) {\n return global.console;\n }\n}\n"],"names":["levels","match","createMatcher","crashListeners","isCrashed","onLoggerCrash","listener","createLogger","name","options","_console","_getDefaultConsole","bind","method","_name","untracked","isString","getEnv","noOp","label","okhash","error","ctx","get","setLogFilter","filter","setLogLevels","key","value"],"mappings":";;AA6CA,IAAIA,IAAoB;AAAA,EACtB,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,OAAO;AACT,GACIC,IAAyBC,EAAc,YAAY,GACnDC,IAA0D,CAAC,GAC3DC,IAAY;AAKT,SAASC,EAAcC,GAA+C;AAC3E,SAAAH,EAAe,KAAKG,CAAQ,GAErB,WAAkB;AACvB,IAAAH,EAAe,OAAOA,EAAe,QAAQG,CAAQ,GAAG,CAAC;AAAA,EAC3D;AACF;AAEgB,SAAAC,EAAaC,GAA2BC,GAAiC;AACjF,QAAAC,KAAWD,KAAA,gBAAAA,EAAS,YAAWE,EAAmB,GAElDC,IAAO,CAACC,MAA4B;AACpC,QAAAC,IAAQC,EAAUP,CAAI;AAC1B,QAAIR,EAAOa,CAAM,MAAM,MAAUG,EAAShB,EAAOa,CAAM,CAAC,KAAKb,EAAOa,CAAM,MAAMI,OAAa,CAAChB,EAAMa,CAAK;AAChG,aAAAI;AACF;AACD,UAAAC,IAAQ,KAAKL,CAAK;AACtB,aAAIL,KAAA,QAAAA,EAAS,MACPA,EAAQ,UACVU,KAAS,OAAOV,EAAQ,OAAO,OAAOA,EAAQ,GAAG,QAExCU,KAAA,SAASV,EAAQ,GAAG,QAGtBU,KAAA,UAEJT,EAASG,CAAM,EAAE;AAAA,QACtBH;AAAA,QACAS;AAAA,QACA,SAASC,EAAOD,CAAK,CAAC;AAAA,QACtB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IAAA;AAAA,EAEJ;AAEO,SAAA;AAAA,IACL,IAAI,OAAO;AACT,aAAOP,EAAK,MAAM;AAAA,IACpB;AAAA,IACA,IAAI,MAAM;AACR,aAAOA,EAAK,KAAK;AAAA,IACnB;AAAA,IACA,IAAI,OAAO;AACT,aAAOA,EAAK,MAAM;AAAA,IACpB;AAAA,IACA,IAAI,QAAQ;AACV,aAAOA,EAAK,OAAO;AAAA,IACrB;AAAA,IACA,MAAMS,GAAc;AAClB,UAAI,CAACjB,GAAW;AACF,QAAAA,IAAA;AACZ,cAAMkB,IAAwB;AAAA,UAC5B,OAAAD;AAAA,UACA,YAAYE,EAAIf,CAAI;AAAA,UACpB,KAAKC,KAAA,gBAAAA,EAAS;AAAA,UACd,SAASA,KAAA,gBAAAA,EAAS;AAAA,QACpB;AAEA,mBAAWH,KAAYH;AACrB,UAAAG,EAASgB,CAAG;AAGR,cAAAD;AAAA,MAAA;AAGD,aAAAA;AAAA,IAAA;AAAA,EAEX;AACF;AAEO,SAASG,EAAaC,GAAyB;AACpD,EAAAxB,IAAQC,EAAcuB,CAAM;AAC9B;AAEO,SAASC,EAAajB,GAA6B;AACxD,aAAWkB,KAAOlB,GAAS;AACnB,UAAAmB,IAAQnB,EAAQkB,CAAsB;AAC5C,IAAIC,MACF5B,EAAO2B,CAAsB,IAAIC;AAAA,EACnC;AAEJ;AAEA,SAASjB,IAAqB;AAC5B,MAAI,OAAO,SAAW,OAAe,OAAO;AAC1C,WAAO,OAAO;AAEhB,MAAI,OAAO,SAAW,OAAe,OAAO;AAC1C,WAAO,OAAO;AAElB;"}