@manyducks.co/dolla 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +133 -284
- package/dist/core/context.d.ts +22 -146
- package/dist/core/debug.d.ts +19 -0
- package/dist/core/index.d.ts +15 -16
- package/dist/core/markup/helpers.d.ts +34 -0
- package/dist/core/markup/html.d.ts +3 -0
- package/dist/core/{nodes → markup/nodes}/dom.d.ts +5 -4
- package/dist/core/markup/nodes/dynamic.d.ts +16 -0
- package/dist/core/markup/nodes/element.d.ts +14 -0
- package/dist/core/markup/nodes/portal.d.ts +15 -0
- package/dist/core/markup/nodes/repeat.d.ts +21 -0
- package/dist/core/markup/nodes/view.d.ts +17 -0
- package/dist/core/markup/scheduler.d.ts +1 -0
- package/dist/core/markup/types.d.ts +62 -0
- package/dist/core/markup/utils.d.ts +22 -0
- package/dist/core/ref.d.ts +6 -12
- package/dist/core/root.d.ts +36 -0
- package/dist/core/signals.d.ts +46 -76
- package/dist/core/symbols.d.ts +2 -0
- package/dist/core-BLkJ-xuh.js +242 -0
- package/dist/core-BLkJ-xuh.js.map +1 -0
- package/dist/http/index.d.ts +21 -33
- package/dist/http.js +89 -149
- package/dist/http.js.map +1 -1
- package/dist/index.js +4 -174
- package/dist/jsx-dev-runtime.d.ts +4 -3
- package/dist/jsx-dev-runtime.js +12 -9
- package/dist/jsx-dev-runtime.js.map +1 -1
- package/dist/jsx-runtime.d.ts +5 -4
- package/dist/jsx-runtime.js +17 -12
- package/dist/jsx-runtime.js.map +1 -1
- package/dist/router/index.d.ts +4 -3
- package/dist/router/router.d.ts +19 -162
- package/dist/router/store.d.ts +12 -0
- package/dist/router/types.d.ts +152 -0
- package/dist/router/utils.d.ts +99 -0
- package/dist/router/utils.test.d.ts +1 -0
- package/dist/router.js +428 -5
- package/dist/router.js.map +1 -1
- package/dist/signals-CMJPGr_M.js +354 -0
- package/dist/signals-CMJPGr_M.js.map +1 -0
- package/dist/translate/index.d.ts +82 -0
- package/dist/translate.js +125 -0
- package/dist/translate.js.map +1 -0
- package/dist/types.d.ts +21 -39
- package/dist/utils.d.ts +41 -29
- package/dist/utils.test.d.ts +1 -0
- package/dist/view-cBN-hn_T.js +360 -0
- package/dist/view-cBN-hn_T.js.map +1 -0
- package/dist/virtual/index.d.ts +1 -0
- package/dist/virtual/list.d.ts +53 -0
- package/package.json +19 -16
- package/dist/core/app.d.ts +0 -24
- package/dist/core/env.d.ts +0 -3
- package/dist/core/hooks.d.ts +0 -70
- package/dist/core/logger.d.ts +0 -42
- package/dist/core/logger.test.d.ts +0 -0
- package/dist/core/markup.d.ts +0 -82
- package/dist/core/markup.test.d.ts +0 -0
- package/dist/core/nodes/_markup.d.ts +0 -36
- package/dist/core/nodes/dynamic.d.ts +0 -22
- package/dist/core/nodes/element.d.ts +0 -27
- package/dist/core/nodes/portal.d.ts +0 -18
- package/dist/core/nodes/repeat.d.ts +0 -27
- package/dist/core/nodes/view.d.ts +0 -25
- package/dist/core/views/default-crash-view.d.ts +0 -25
- package/dist/core/views/for.d.ts +0 -21
- package/dist/core/views/fragment.d.ts +0 -7
- package/dist/core/views/portal.d.ts +0 -16
- package/dist/core/views/show.d.ts +0 -25
- package/dist/fragment-BahD_BJA.js +0 -7
- package/dist/fragment-BahD_BJA.js.map +0 -1
- package/dist/i18n/index.d.ts +0 -134
- package/dist/i18n.js +0 -309
- package/dist/i18n.js.map +0 -1
- package/dist/index-DRJlxs-Q.js +0 -535
- package/dist/index-DRJlxs-Q.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/logger-Aqi9m1CF.js +0 -565
- package/dist/logger-Aqi9m1CF.js.map +0 -1
- package/dist/markup-8jNhoqDe.js +0 -1089
- package/dist/markup-8jNhoqDe.js.map +0 -1
- package/dist/router/hooks.d.ts +0 -2
- package/dist/router/router.utils.d.ts +0 -93
- package/dist/typeChecking-5kmX0ulW.js +0 -65
- package/dist/typeChecking-5kmX0ulW.js.map +0 -1
- package/dist/typeChecking.d.ts +0 -95
- package/docs/buildless.md +0 -132
- package/docs/components.md +0 -238
- package/docs/hooks.md +0 -356
- package/docs/http.md +0 -178
- package/docs/i18n.md +0 -220
- package/docs/index.md +0 -10
- package/docs/markup.md +0 -136
- package/docs/mixins.md +0 -176
- package/docs/ref.md +0 -77
- package/docs/router.md +0 -281
- package/docs/setup.md +0 -137
- package/docs/signals.md +0 -262
- package/docs/stores.md +0 -113
- package/docs/views.md +0 -356
- package/notes/atomic.md +0 -452
- package/notes/elimination.md +0 -33
- package/notes/observable.md +0 -180
- package/notes/scratch.md +0 -565
- package/notes/splitting.md +0 -5
- package/notes/views.md +0 -195
- package/vite.config.js +0 -22
- /package/dist/core/{hooks.test.d.ts → markup/html.test.d.ts} +0 -0
- /package/dist/core/{ref.test.d.ts → markup/utils.test.d.ts} +0 -0
- /package/dist/router/{router.utils.test.d.ts → matcher.test.d.ts} +0 -0
- /package/dist/{typeChecking.test.d.ts → router/router.test.d.ts} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-cBN-hn_T.js","names":["#root","#context","#slot","#root","#unsubscribe","#update","#cleanup","#children","#props","#context","#ownContext","#root","#applyProps","#childNodes","#refCleanup","#unsubscribers","#applyStyles","#applyClasses","#attach","#props","#view","#node"],"sources":["../src/core/context.ts","../src/core/markup/types.ts","../src/core/markup/nodes/dom.ts","../src/core/markup/scheduler.ts","../src/core/markup/nodes/dynamic.ts","../src/core/symbols.ts","../src/core/markup/nodes/element.ts","../src/core/markup/utils.ts","../src/core/markup/nodes/view.ts"],"sourcesContent":["import type { Store } from \"../types.js\";\nimport { assert } from \"../utils.js\";\nimport { createEffect } from \"./signals.js\";\n\nexport type LifecycleListener = () => any;\n\ntype ContextState = {\n isMounted: boolean;\n};\n\nexport type ComponentState = ContextState & {\n name: string;\n};\n\nexport type Context<T = Record<string | symbol, any>> = ContextState & T;\n\n/*===================================*\\\n|| Context ||\n\\*===================================*/\n\nconst MOUNT_LISTENERS = Symbol(\"Context.mountListeners\");\nconst CLEANUP_LISTENERS = Symbol(\"Context.cleanupListeners\");\n\nexport function createContext(parent?: Context): Context {\n return Object.assign(Object.create(parent ?? null), { isMounted: false });\n}\n\nexport function mountContext(context: Context) {\n if (context.isMounted) return;\n context.isMounted = true;\n _callListeners(context, MOUNT_LISTENERS);\n}\n\nexport function unmountContext(context: Context) {\n if (!context.isMounted) return;\n context.isMounted = false;\n _callListeners(context, CLEANUP_LISTENERS);\n}\n\nfunction _callListeners(context: Context, key: symbol) {\n if (!Object.hasOwn(context, key)) return;\n for (const callback of context[key]) callback();\n context[key].length = 0;\n}\n\n/*===================================*\\\n|| Lifecycle Hooks ||\n\\*===================================*/\n\nexport function onMount(context: Context, fn: LifecycleListener) {\n if (!Object.hasOwn(context, MOUNT_LISTENERS)) context[MOUNT_LISTENERS] = [fn];\n else context[MOUNT_LISTENERS].push(fn);\n}\n\nexport function onCleanup(context: Context, fn: LifecycleListener) {\n if (!Object.hasOwn(context, CLEANUP_LISTENERS)) context[CLEANUP_LISTENERS] = [fn];\n else context[CLEANUP_LISTENERS].push(fn);\n}\n\nexport function onEffect(context: Context, fn: () => void) {\n if (context.isMounted) {\n onCleanup(context, createEffect(fn));\n } else {\n onMount(context, () => {\n onCleanup(context, createEffect(fn));\n });\n }\n}\n\n/*===================================*\\\n|| Stores ||\n\\*===================================*/\n\nexport const STORE_ID = Symbol(\"Dolla.StoreId\");\n\nexport function addStore<Props, Returns>(\n context: Context,\n store: Store<Props, Returns> & { [STORE_ID]?: symbol },\n ...args: undefined extends Props ? [props?: Props] : [props: Props]\n) {\n // Tag the store function with a unique symbol if it doesn't have one.\n store[STORE_ID] ??= Symbol(store.name);\n\n assert(!Object.hasOwn(context, store[STORE_ID]), \"Store was already provided on this context.\");\n\n // Give the store its own context bound to this lifecycle.\n const storeContext = createContext(context) as Context<ComponentState>;\n onMount(context, () => mountContext(storeContext));\n onCleanup(context, () => unmountContext(storeContext));\n storeContext.name = store.name;\n\n return (context[store[STORE_ID]!] = store.call(storeContext, args[0] as Props, storeContext));\n}\n\nexport function getStore<Returns>(context: Context, store: Store<any, Returns> & { [STORE_ID]?: symbol }): Returns {\n const id = store[STORE_ID];\n const result = id ? context[id] : undefined;\n assert(result != null, `Store '${store.name}' is not provided by this context.`);\n return result;\n}\n","import type { IntrinsicElements, View } from \"../../types.js\";\nimport { Context } from \"../index.js\";\n\n/**\n * Determines the type of the `props` object for any kind of Markup type.\n */\nexport type PropsOf<T extends string | View<any> | (new (...args: any[]) => MarkupNode)> =\n T extends View<infer P>\n ? P\n : T extends new (...args: infer Args) => MarkupNode\n ? { args: Args extends [Context, ...infer Rest] ? Rest : [] }\n : T extends keyof IntrinsicElements\n ? IntrinsicElements[T]\n : any;\n\nexport const IS_MARKUP = Symbol();\nexport const IS_MARKUP_NODE = Symbol();\nexport const IS_MARKUP_NODE_CLASS = Symbol();\n\n/**\n * A set of basic metadata that can be constructed into a `MarkupNode`.\n */\nexport interface Markup<\n Type extends string | View<any> | (new (...args: any[]) => MarkupNode) =\n | string\n | View<any>\n | (new (...args: any[]) => MarkupNode),\n> {\n [IS_MARKUP]: true;\n type: Type;\n props: PropsOf<Type>;\n}\n\nexport interface MountTarget {\n insertBefore(node: Node, child: Node | null): any;\n moveBefore?: (node: Node, child: Node | null) => any;\n appendChild(node: Node): any;\n}\n\n/**\n * A node that can be mounted by the Markup layout engine. Can be extended to create new custom node types.\n *\n * A `MarkupNode` instance can be passed anywhere a `Renderable` is required.\n */\nexport abstract class MarkupNode {\n static [IS_MARKUP_NODE_CLASS] = true;\n\n get [IS_MARKUP_NODE]() {\n return true;\n }\n\n /**\n * Returns a single DOM node to represent this MarkupNode's position in the DOM.\n * Usually the parent element, but it can be an empty Text node used as a marker.\n *\n * It only needs to be defined while the node is mounted, so it can be created in the `mount` function.\n */\n abstract getRoot(): Node | undefined;\n\n /**\n * Returns true while this node is mounted.\n */\n abstract isMounted(): boolean;\n\n /**\n * Mount this node to a `parent` element.\n * If passed, this node will be mounted as the next sibling of `after`.\n */\n abstract mount(parent: MountTarget, after?: Node): void;\n\n /**\n * Unmount this MarkupNode from its parent element.\n *\n * The `skipDOM` option can be passed as an optimization when unmounting a parent node.\n * A value of `true` indicates that no DOM operations need to happen because the parent is already being unmounted.\n *\n * @param skipDOM - No DOM updates will be performed when true. Lifecycle methods will be called regardless.\n */\n abstract unmount(skipDOM?: boolean): void;\n\n /**\n * Moves a node without unmounting and remounting (if the browser supports Element.moveBefore).\n */\n abstract move(parent: MountTarget, after?: Node): void;\n}\n","import { Context } from \"../../context.js\";\nimport { MarkupNode, type MountTarget } from \"../types.js\";\nimport { addChild, moveAfter } from \"../utils.js\";\n\n/**\n * A lightweight MarkupNode wrapper for a plain DOM node.\n */\nexport class DOMNode extends MarkupNode {\n #root: Node;\n\n constructor(_context: Context, node: Node) {\n super();\n this.#root = node;\n }\n\n override getRoot() {\n return this.#root;\n }\n\n override isMounted() {\n return this.#root.parentNode != null;\n }\n\n override mount(parent: MountTarget, after?: Node) {\n addChild(parent, this.#root, after);\n }\n\n override unmount(skipDOM = false) {\n if (skipDOM) return;\n this.#root.parentNode?.removeChild(this.#root);\n }\n\n override move(parent: Element, after?: Node) {\n moveAfter(parent, this.#root, after);\n }\n}\n","const pendingUpdates = new Set<() => void>();\nlet isScheduled = false;\n\nfunction flushUpdates() {\n for (const update of pendingUpdates) update();\n pendingUpdates.clear();\n isScheduled = false;\n}\n\nexport function scheduleUpdate(updateFn: () => void) {\n updateFn();\n\n // pendingUpdates.add(updateFn);\n // if (!isScheduled) {\n // isScheduled = true;\n // queueMicrotask(flushUpdates);\n // }\n}\n","import type { Context } from \"../../context.js\";\nimport { subscribe, type Getter } from \"../../signals.js\";\nimport { scheduleUpdate } from \"../scheduler.js\";\nimport { MarkupNode, MountTarget } from \"../types.js\";\nimport { addChild, createTextNode, toMarkupNodes } from \"../utils.js\";\nimport { DOMNode } from \"./dom.js\";\n\n/**\n * Renders any kind of content; markup, signals, DOM nodes, etc.\n * If it can be rendered by Dolla then Dynamic will do it.\n */\n\nexport class DynamicNode extends MarkupNode {\n #root = createTextNode(\"\");\n #children: MarkupNode[] = [];\n #context: Context;\n #slot: Getter<any>;\n #unsubscribe?: () => void;\n\n constructor(context: Context, slot: Getter<any>) {\n super();\n this.#context = context;\n this.#slot = slot;\n }\n\n override getRoot() {\n return this.#root;\n }\n\n override isMounted() {\n return this.#root.parentNode != null;\n }\n\n override mount(parent: MountTarget, after?: Node) {\n if (!this.isMounted()) {\n addChild(parent, this.#root, after);\n this.#unsubscribe = subscribe(this.#slot, (content) => {\n scheduleUpdate(() => {\n this.#update(content);\n });\n });\n }\n }\n\n override unmount(skipDOM = false) {\n this.#unsubscribe?.();\n\n if (this.isMounted()) {\n if (!skipDOM) {\n this.#root.parentNode?.removeChild(this.#root);\n }\n this.#cleanup(skipDOM);\n }\n }\n\n override move(parent: MountTarget, after?: Node) {\n let referenceNode: Node | null = after?.nextSibling ?? null;\n\n if (parent.moveBefore) {\n try {\n parent.moveBefore(this.#root, referenceNode);\n referenceNode = this.#root.nextSibling;\n\n for (let i = 0; i < this.#children.length; i++) {\n const childRoot = this.#children[i].getRoot();\n if (childRoot) {\n (parent as any).moveBefore(childRoot, referenceNode);\n }\n }\n return;\n } catch {\n // Fallthrough to standard insertBefore\n }\n }\n\n // Standard DOM fallback (moves root AND children)\n parent.insertBefore(this.#root, referenceNode);\n referenceNode = this.#root.nextSibling;\n\n for (let i = 0; i < this.#children.length; i++) {\n this.#children[i].move(parent, this.#children[i - 1]?.getRoot() ?? this.#root);\n }\n }\n\n #cleanup(skipDOM: boolean) {\n for (let i = 0; i < this.#children.length; i++) {\n this.#children[i].unmount(skipDOM);\n }\n this.#children.length = 0;\n }\n\n #update(content: any) {\n if (!this.isMounted()) return;\n\n // Fast-path for primitive text updates\n const isPrimitive = typeof content === \"string\" || typeof content === \"number\";\n if (isPrimitive && this.#children.length === 1) {\n const child = this.#children[0];\n if (child instanceof DOMNode) {\n const domNode = child.getRoot();\n if (domNode && domNode.nodeType === Node.TEXT_NODE) {\n domNode.nodeValue = String(content);\n return;\n }\n }\n }\n\n this.#cleanup(false);\n\n if (content == null || content === false) return;\n\n const nodes = toMarkupNodes(this.#context, content);\n\n const parent = this.#root.parentElement!;\n let referenceNode: Node = this.#root;\n\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i];\n node.mount(parent, referenceNode);\n this.#children.push(node);\n\n const nextRoot = node.getRoot();\n if (nextRoot) referenceNode = nextRoot;\n }\n }\n}\n","export const PARENT_ELEMENT = Symbol(\"parentElement\");\nexport const DEBUG = Symbol(\"debug\");\n","import { isArray, isFunction, isNumber, isObject, isString, omit } from \"../../../utils.js\";\nimport { Context, createContext, mountContext, unmountContext } from \"../../context.js\";\nimport { Ref } from \"../../ref.js\";\nimport { type Getter, subscribe } from \"../../signals.js\";\nimport { DEBUG } from \"../../symbols.js\";\nimport { scheduleUpdate } from \"../scheduler.js\";\nimport { MarkupNode, MountTarget } from \"../types.js\";\nimport { addChild, addListener, toMarkupNodes } from \"../utils.js\";\nimport { VIEW, ViewNode } from \"./view.js\";\n\nconst IS_SVG = Symbol(\"isSVG\");\n\n// Properties in this list will not be processed by applyProps because they are already handled elsewhere.\nconst ignoredProps = [\"ref\", \"children\"];\n\n/**\n * Renders an HTML or SVG element.\n */\nexport class ElementNode extends MarkupNode {\n #root: HTMLElement | SVGElement;\n\n readonly #props: Record<string, any>;\n\n #context: Context;\n #ownContext = false;\n #childNodes: MarkupNode[] = [];\n #unsubscribers = new Set<() => void>();\n\n #refCleanup?: () => void;\n\n constructor(context: Context, tag: string, props: Record<string, any>) {\n super();\n\n this.#props = props;\n this.#context = context;\n\n if (tag === \"svg\") {\n // This and all nested views will be created as SVG elements.\n this.#context = createContext(context);\n this.#context[IS_SVG] = true;\n this.#ownContext = true;\n } else if (this.#context[IS_SVG] && tag === \"foreignObject\") {\n // No longer in SVG.\n this.#context = createContext(context);\n this.#context[IS_SVG] = false;\n this.#ownContext = false;\n }\n\n // Create node with the appropriate constructor.\n if (this.#context[IS_SVG]) {\n this.#root = document.createElementNS(\"http://www.w3.org/2000/svg\", tag);\n } else {\n this.#root = document.createElement(tag);\n }\n\n // Add view name as a data attribute debug mode.\n if (this.#context[DEBUG]) {\n const view = this.#context[VIEW] as ViewNode<any>;\n if (view) {\n this.#root.dataset.view = view.context.name;\n }\n }\n }\n\n override getRoot() {\n return this.#root;\n }\n\n override isMounted() {\n return this.#root.parentNode != null;\n }\n\n override mount(parent: MountTarget, after?: Node) {\n const wasMounted = this.isMounted();\n\n if (!wasMounted) {\n this.#applyProps(this.#root, omit(ignoredProps, this.#props));\n\n if (this.#props.children) {\n this.#childNodes = toMarkupNodes(this.#context, this.#props.children);\n for (const child of this.#childNodes) {\n child.mount(this.#root);\n }\n }\n }\n\n const targetSibling = after?.nextSibling ?? null;\n if (this.#root.parentNode !== parent || this.#root.nextSibling !== targetSibling) {\n addChild(parent, this.#root, targetSibling);\n }\n\n if (!wasMounted) {\n if (isFunction<Ref<any>>(this.#props.ref)) {\n const result = this.#props.ref(this.#root);\n if (isFunction(result)) {\n this.#refCleanup = result;\n }\n }\n\n if (this.#ownContext) mountContext(this.#context);\n }\n }\n\n override unmount(skipDOM = false) {\n if (!skipDOM && this.#root.parentNode) {\n this.#root.parentNode.removeChild(this.#root);\n }\n\n for (const child of this.#childNodes) {\n child.unmount(true); // Skip DOM removal for children\n }\n\n // Clear reactivity\n this.#unsubscribers.forEach((unsubscribe) => unsubscribe());\n this.#unsubscribers.clear();\n\n if (this.#ownContext) unmountContext(this.#context);\n\n // Clear ref\n if (this.#refCleanup) {\n this.#refCleanup();\n this.#refCleanup = undefined;\n }\n\n // Release memory\n this.#childNodes.length = 0;\n }\n\n override move(parent: MountTarget, after?: Node) {\n if (parent.moveBefore) {\n try {\n parent.moveBefore(this.#root, after?.nextSibling ?? null);\n return;\n } catch {}\n }\n this.mount(parent, after);\n }\n\n #attach<T>(value: Getter<T> | T, callback: (value: T) => void) {\n if (isFunction<Getter<T>>(value)) {\n this.#unsubscribers.add(\n subscribe(value, (current) => {\n scheduleUpdate(() => callback(current));\n }),\n );\n } else {\n // No need to schedule since DOM node is not connected yet.\n callback(value);\n }\n }\n\n #applyProps(element: any, props: Record<string, unknown>) {\n for (const key in props) {\n const value = props[key];\n\n if (key === \"style\") {\n this.#applyStyles(element, value);\n } else if (key === \"class\" || key === \"className\") {\n this.#applyClasses(element, value);\n } else if (key === \"for\") {\n this.#attach(value, (current) => {\n element.htmlFor = current;\n });\n } else if (key[0] === \".\" || key.startsWith(\"prop:\")) {\n // Keys starting with `.` or `prop:` are set as props.\n\n const _key = key.substring(5);\n this.#attach(value, (current) => {\n element[_key] = current;\n });\n } else if (key[0] === \":\" || key.startsWith(\"attr:\")) {\n // Keys starting with `:` or `attr:` are set as attributes.\n\n const _key = key.substring(5).toLowerCase();\n this.#attach(value, (current) => {\n setAttribute(element, _key, current);\n });\n } else if (key[0] === \"@\" && isFunction(value)) {\n // Anything that's a function starting with `@` is an event listener.\n\n const eventName = key.substring(1);\n this.#unsubscribers.add(addListener(element, eventName, value));\n } else if (key.startsWith(\"on\") && isFunction(value)) {\n // Anything that's a function starting with `on` is an event listener.\n\n const eventName = key.toLowerCase().slice(2);\n this.#unsubscribers.add(addListener(element, eventName, value));\n } else if (key in element && !this.#context[IS_SVG]) {\n // Set as property if the element has one.\n\n if (typeof element[key] === \"boolean\") {\n this.#attach(value, (current) => {\n const isTrue = Boolean(current);\n element[key] = isTrue;\n setAttribute(element, key, isTrue);\n });\n } else {\n this.#attach(value, (current) => {\n element[key] = current;\n });\n }\n } else {\n // Fall back to attributes.\n\n this.#attach(value, (current) => {\n setAttribute(element, key, current);\n });\n }\n }\n }\n\n #applyStyles(element: HTMLElement | SVGElement, styles: unknown) {\n const localUnsubs = new Set<() => void>();\n\n const apply = (current: unknown) => {\n localUnsubs.forEach((unsub) => {\n unsub();\n this.#unsubscribers.delete(unsub);\n });\n localUnsubs.clear();\n element.style.cssText = \"\";\n\n const mapped = getStyleMap(current);\n for (const [name, { value, priority }] of Object.entries(mapped)) {\n if (isFunction(value)) {\n const unsub = subscribe(value, (v) => {\n if (v) element.style.setProperty(name, asPixelsIfNumber(v), priority);\n else element.style.removeProperty(name);\n });\n this.#unsubscribers.add(unsub);\n localUnsubs.add(unsub);\n } else if (value != null) {\n element.style.setProperty(name, asPixelsIfNumber(value), priority);\n }\n }\n };\n\n if (isFunction(styles)) {\n this.#unsubscribers.add(subscribe(styles, apply));\n } else {\n apply(styles);\n }\n }\n\n #applyClasses(element: HTMLElement | SVGElement, classes: unknown) {\n const localUnsubs = new Set<() => void>();\n\n const apply = (current: unknown) => {\n // Clean up nested subscriptions if the top-level signal emits a new object\n localUnsubs.forEach((unsub) => {\n unsub();\n this.#unsubscribers.delete(unsub);\n });\n localUnsubs.clear();\n setAttribute(element, \"class\", null);\n\n const mapped = getClassMap(current);\n for (const [name, value] of Object.entries(mapped)) {\n if (name === \"undefined\") continue;\n\n if (isFunction(value)) {\n const unsub = subscribe(value, (isActive) => element.classList.toggle(name, !!isActive));\n this.#unsubscribers.add(unsub);\n localUnsubs.add(unsub);\n } else if (value) {\n element.classList.add(name);\n }\n }\n };\n\n if (isFunction(classes)) {\n this.#unsubscribers.add(subscribe(classes, apply));\n } else {\n apply(classes);\n }\n }\n}\n\n/**\n * Parse classes into a single object. Classes can be passed as a string, an object with class keys can boolean values, or an array with a mix of both.\n */\nfunction getClassMap(classes: unknown): Record<string, unknown> {\n if (isString(classes)) return Object.fromEntries(classes.split(\" \").map((c) => [c, true]));\n if (isArray(classes)) return Object.assign({}, ...classes.filter(Boolean).map(getClassMap));\n if (isObject(classes)) return classes as Record<string, unknown>;\n return {};\n}\n\n/**\n * Parse styles into a single object.\n */\nfunction getStyleMap(styles: unknown): Record<string, { value: unknown; priority?: string }> {\n if (isString(styles)) {\n return Object.fromEntries(\n styles\n .split(\";\")\n .filter((s) => s.trim())\n .map((line) => {\n const [key, val] = line.split(\":\");\n return [\n camelToKebab(key.trim()),\n {\n value: val.replace(\"!important\", \"\").trim(),\n priority: val.includes(\"!important\") ? \"important\" : \"\",\n },\n ];\n }),\n );\n }\n if (isArray(styles)) return Object.assign({}, ...styles.filter(Boolean).map(getStyleMap));\n if (isObject(styles)) {\n return Object.fromEntries(\n Object.entries(styles).map(([k, v]) => [k.startsWith(\"--\") ? k : camelToKebab(k), { value: v }]),\n );\n }\n return {};\n}\n\n/**\n * Converts a camelCase string to kebab-case.\n */\nfunction camelToKebab(value: string): string {\n return value.replace(/[A-Z]+(?![a-z])|[A-Z]/g, ($, ofs) => (ofs ? \"-\" : \"\") + $.toLowerCase());\n}\n\nfunction asPixelsIfNumber(value: any): string {\n if (isNumber(value)) {\n return `${value}px`;\n } else {\n return value;\n }\n}\n\nfunction setAttribute(element: Element, name: string, value: any) {\n if (value) {\n element.setAttribute(name, String(value));\n } else {\n element.removeAttribute(name);\n }\n}\n","import type { Renderable, View } from \"../../types.js\";\nimport { isArray, isFunction, isNumber, isString } from \"../../utils.js\";\nimport { Context, createContext } from \"../context.js\";\nimport { DOMNode } from \"./nodes/dom.js\";\nimport { DynamicNode } from \"./nodes/dynamic.js\";\nimport { ElementNode } from \"./nodes/element.js\";\nimport { ViewNode } from \"./nodes/view.js\";\nimport { IS_MARKUP, IS_MARKUP_NODE, IS_MARKUP_NODE_CLASS, Markup, MarkupNode, MountTarget, PropsOf } from \"./types.js\";\n\nexport function createMarkup<Type extends string | View<any> | (new (...args: any[]) => MarkupNode)>(\n type: Type,\n props: PropsOf<Type>,\n): Markup<Type> {\n return {\n [IS_MARKUP]: true,\n type,\n props,\n };\n}\n\nexport function isMarkup<T extends string | View<any> | (new (...args: any[]) => MarkupNode)>(\n value: any,\n): value is Markup<T> {\n return value && value[IS_MARKUP];\n}\n\nexport function isMarkupNode(value: any): value is MarkupNode {\n return value && value[IS_MARKUP_NODE];\n}\n\nexport function isMarkupNodeClass(value: any): value is new (...args: any[]) => MarkupNode {\n return value && value[IS_MARKUP_NODE_CLASS];\n}\n\n/**\n * Takes any `Renderable` value and returns a `MarkupNode` that will display it.\n */\nexport function render(content: Renderable, context = createContext()): MarkupNode {\n const nodes = toMarkupNodes(context, content);\n if (nodes.length === 1) {\n return nodes[0]; // if it's just one item return it\n }\n // otherwise wrap it in something that can display multiple nodes\n return new DynamicNode(context, () => nodes);\n}\n\n/**\n * Convert basically anything into an array of `MarkupNode`\n */\nexport function toMarkupNodes(context: Context, ...content: any[]): MarkupNode[] {\n const nodes: MarkupNode[] = [];\n\n // Internal processor to avoid intermediate array allocations\n function process(item: any) {\n if (item == null || item === false) return;\n\n if (isArray(item)) {\n for (let i = 0; i < item.length; i++) {\n process(item[i]);\n }\n } else if (isString(item) || isNumber(item)) {\n nodes.push(new DOMNode(context, createTextNode(String(item))));\n } else if (isMarkup(item)) {\n const { type, props } = item;\n\n if (isMarkupNodeClass(type)) {\n nodes.push(new type(context, ...props.args));\n } else if (isFunction(type)) {\n nodes.push(new ViewNode(context, type as View<any>, props));\n } else if (isString(type)) {\n nodes.push(new ElementNode(context, type, props));\n }\n } else if (isMarkupNode(item)) {\n nodes.push(item);\n } else if (item instanceof Node) {\n nodes.push(new DOMNode(context, item));\n } else if (isFunction(item)) {\n nodes.push(new DynamicNode(context, item));\n }\n }\n\n for (let i = 0; i < content.length; i++) {\n process(content[i]);\n }\n\n return nodes;\n}\n\nexport function addChild(parent: MountTarget, node: Node, after?: Node | null) {\n if (after) {\n parent.insertBefore(node, after?.nextSibling);\n } else {\n parent.appendChild(node);\n }\n}\n\nexport function createTextNode(text: string) {\n return document.createTextNode(text);\n}\n\n/**\n * Moves an element using `moveBefore` if the browser supports it, otherwise falls back to `insertBefore`.\n */\nexport function moveAfter(parent: MountTarget, node: Node, after?: Node | null) {\n const before = after?.nextSibling ?? null;\n if (parent.moveBefore) {\n try {\n parent.moveBefore(node, before);\n return;\n } catch {}\n }\n parent.insertBefore(node, before);\n}\n\nexport function addListener<T extends Event>(target: EventTarget, event: string, listener: (event: T) => any) {\n target.addEventListener(event, listener as any);\n return () => target.removeEventListener(event, listener as any);\n}\n","import type { View } from \"../../../types.js\";\nimport { ComponentState, Context, createContext, mountContext, unmountContext } from \"../../context.js\";\nimport { peek } from \"../../signals.js\";\nimport { MarkupNode } from \"../types.js\";\nimport { createTextNode, render } from \"../utils.js\";\nimport { DOMNode } from \"./dom.js\";\n\nexport const VIEW = Symbol.for(\"ViewNode\");\n\n/**\n * Renders a View.\n */\nexport class ViewNode<P> extends MarkupNode {\n readonly #props: P;\n readonly #view: View<P>;\n #node?: MarkupNode;\n\n readonly context: Context<ComponentState & Record<string | symbol, any>>;\n\n constructor(context: Context, view: View<P>, props: P) {\n super();\n this.context = createContext(context) as Context<ComponentState>;\n this.context[VIEW] = this;\n this.context.name = view.name;\n this.#props = props;\n this.#view = view;\n }\n\n getRoot() {\n return this.#node?.getRoot();\n }\n\n isMounted() {\n return this.context.isMounted;\n }\n\n mount(parent: Element, after?: Node) {\n const wasMounted = this.isMounted();\n\n if (!wasMounted) {\n const viewContent = peek(() => this.#view.call(this.context, this.#props, this.context));\n\n if (viewContent != null && viewContent !== false) {\n this.#node = render(viewContent, this.context);\n } else {\n this.#node = new DOMNode(this.context, createTextNode(\"\"));\n }\n }\n\n this.#node!.mount(parent, after);\n\n if (!wasMounted) mountContext(this.context);\n }\n\n unmount(skipDOM = false) {\n this.#node?.unmount(skipDOM);\n unmountContext(this.context);\n }\n\n move(parent: Element, after?: Node) {\n this.#node?.move(parent, after);\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createVirtualList } from "./list";
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type Getter } from "../core/signals.js";
|
|
2
|
+
import { View } from "../types.js";
|
|
3
|
+
export interface VirtualListAPI<T> {
|
|
4
|
+
scrollToBottom: (smooth?: boolean) => void;
|
|
5
|
+
scrollToTop: (smooth?: boolean) => void;
|
|
6
|
+
scrollToIndex: (index: number, options?: {
|
|
7
|
+
smooth?: boolean;
|
|
8
|
+
align?: "start" | "center" | "end";
|
|
9
|
+
}) => void;
|
|
10
|
+
scrollToItem: (item: T, options?: {
|
|
11
|
+
smooth?: boolean;
|
|
12
|
+
align?: "start" | "center" | "end";
|
|
13
|
+
}) => void;
|
|
14
|
+
isAtBottom: Getter<boolean>;
|
|
15
|
+
}
|
|
16
|
+
export interface VirtualListContext {
|
|
17
|
+
isEntering: Getter<boolean>;
|
|
18
|
+
}
|
|
19
|
+
export interface VirtualListOptions<T> {
|
|
20
|
+
items: Getter<T[]>;
|
|
21
|
+
/** A stable identifier for each item, crucial for detecting changes accurately */
|
|
22
|
+
keyFn: (item: T) => string | number;
|
|
23
|
+
bottomUp?: boolean;
|
|
24
|
+
enterAnimationMs?: number;
|
|
25
|
+
/** Configuration for the virtual pool */
|
|
26
|
+
estimatedItemHeight?: number;
|
|
27
|
+
poolSize?: number;
|
|
28
|
+
/** Infinite scroll callbacks */
|
|
29
|
+
onTopReached?: () => void;
|
|
30
|
+
onBottomReached?: () => void;
|
|
31
|
+
threshold?: number;
|
|
32
|
+
render: (item: Getter<T>, index: Getter<number>, context: VirtualListContext) => any;
|
|
33
|
+
renderEmpty?: () => any;
|
|
34
|
+
isSticky?: (item: T) => boolean;
|
|
35
|
+
renderSticky?: (item: Getter<T>) => any;
|
|
36
|
+
}
|
|
37
|
+
export declare function createVirtualList<T>(props: VirtualListOptions<T>): [View, VirtualListAPI<T>];
|
|
38
|
+
export declare function createOffsetEngine(defaultAssumption: number): {
|
|
39
|
+
averageHeight: Getter<number>;
|
|
40
|
+
getTotalHeight: (totalItems: number) => number;
|
|
41
|
+
getOffset: (index: number, avg: number) => number;
|
|
42
|
+
findIndexAtScroll: (scrollPos: number, totalItems: number, avg: number) => number;
|
|
43
|
+
findSticky: (scrollPos: number, indices: number[], avg: number) => {
|
|
44
|
+
activeIdx: number;
|
|
45
|
+
nextIdx: number;
|
|
46
|
+
};
|
|
47
|
+
updateHeights: (entries: {
|
|
48
|
+
index: number;
|
|
49
|
+
height: number;
|
|
50
|
+
}[], avg: number) => boolean;
|
|
51
|
+
clearCache: () => void;
|
|
52
|
+
getItemHeight: (index: number) => number | undefined;
|
|
53
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@manyducks.co/dolla",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "A fast, batteries-included JavaScript framework with a React-
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "A fast, batteries-included JavaScript framework with a React-inspired API and the power of signals.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/core/index.d.ts",
|
|
7
7
|
"type": "module",
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"web app",
|
|
22
22
|
"front end framework",
|
|
23
23
|
"functional",
|
|
24
|
-
"reactive state"
|
|
24
|
+
"reactive state",
|
|
25
|
+
"signals"
|
|
25
26
|
],
|
|
26
27
|
"author": "tony@manyducks.co",
|
|
27
28
|
"license": "MIT",
|
|
@@ -34,14 +35,14 @@
|
|
|
34
35
|
"import": "./dist/router.js",
|
|
35
36
|
"types": "./dist/router/index.d.ts"
|
|
36
37
|
},
|
|
38
|
+
"./translate": {
|
|
39
|
+
"import": "./dist/translate.js",
|
|
40
|
+
"types": "./dist/translate/index.d.ts"
|
|
41
|
+
},
|
|
37
42
|
"./http": {
|
|
38
43
|
"import": "./dist/http.js",
|
|
39
44
|
"types": "./dist/http/index.d.ts"
|
|
40
45
|
},
|
|
41
|
-
"./i18n": {
|
|
42
|
-
"import": "./dist/i18n.js",
|
|
43
|
-
"types": "./dist/i18n/index.d.ts"
|
|
44
|
-
},
|
|
45
46
|
"./jsx-runtime": {
|
|
46
47
|
"import": "./dist/jsx-runtime.js",
|
|
47
48
|
"types": "./jsx-runtime.d.ts"
|
|
@@ -51,15 +52,17 @@
|
|
|
51
52
|
"types": "./jsx-dev-runtime.d.ts"
|
|
52
53
|
}
|
|
53
54
|
},
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
|
|
55
|
+
"files": [
|
|
56
|
+
"dist",
|
|
57
|
+
"*.d.ts"
|
|
58
|
+
],
|
|
57
59
|
"devDependencies": {
|
|
58
|
-
"@types/node": "^
|
|
59
|
-
"csstype": "^3.
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
60
|
+
"@types/node": "^25.6.0",
|
|
61
|
+
"csstype": "^3.2.3",
|
|
62
|
+
"jsdom": "^29.0.2",
|
|
63
|
+
"prettier": "^3.8.3",
|
|
64
|
+
"typescript": "^6.0.3",
|
|
65
|
+
"vite": "^8.0.10",
|
|
66
|
+
"vitest": "^4.1.5"
|
|
64
67
|
}
|
|
65
68
|
}
|
package/dist/core/app.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Router, RouterOptions } from "../router/router";
|
|
2
|
-
import { View } from "../types";
|
|
3
|
-
import { Context } from "./context";
|
|
4
|
-
import { LoggerCrashProps } from "./logger";
|
|
5
|
-
interface AppOptions {
|
|
6
|
-
view?: View<{}>;
|
|
7
|
-
router?: Router;
|
|
8
|
-
context?: Context;
|
|
9
|
-
}
|
|
10
|
-
declare class App {
|
|
11
|
-
#private;
|
|
12
|
-
get context(): Context;
|
|
13
|
-
constructor(options: AppOptions);
|
|
14
|
-
setCrashView(view: View<LoggerCrashProps>): this;
|
|
15
|
-
mount(element: string | Element): Promise<void>;
|
|
16
|
-
unmount(): Promise<void>;
|
|
17
|
-
}
|
|
18
|
-
export interface CreateAppOptions {
|
|
19
|
-
context?: Context;
|
|
20
|
-
}
|
|
21
|
-
export declare function createApp(view: View<{}>, options?: CreateAppOptions): App;
|
|
22
|
-
export declare function createApp(routerOptions: RouterOptions, options?: CreateAppOptions): App;
|
|
23
|
-
export declare function createApp(router: Router, options?: CreateAppOptions): App;
|
|
24
|
-
export {};
|
package/dist/core/env.d.ts
DELETED
package/dist/core/hooks.d.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { type Context, type Ref, type Store } from "../core";
|
|
2
|
-
import { type EffectFn, type MaybeSignal, type Setter, type Signal, type SignalOptions } from "../core/signals";
|
|
3
|
-
/**
|
|
4
|
-
* Returns the Context object of the `View`, `Store` or `Mixin` this hook is called in.
|
|
5
|
-
*
|
|
6
|
-
* @param name - If passed, the context will be renamed. Context takes the name of the component function by default.
|
|
7
|
-
*/
|
|
8
|
-
export declare function useContext(name?: MaybeSignal<string>): Context;
|
|
9
|
-
/**
|
|
10
|
-
* Returns the nearest instance of a Store provided to this context.
|
|
11
|
-
*/
|
|
12
|
-
export declare function useStore<T>(store: Store<any, T>): T;
|
|
13
|
-
/**
|
|
14
|
-
* Adds a store to this context and returns the store instance.
|
|
15
|
-
*/
|
|
16
|
-
export declare function useStoreProvider<T, O>(store: Store<O, T>, options?: O): T;
|
|
17
|
-
/**
|
|
18
|
-
* Schedules `callback` to run just after the component is mounted.
|
|
19
|
-
* If `callback` returns a function, that function will run when the context is unmounted.
|
|
20
|
-
*/
|
|
21
|
-
export declare function useMount(callback: () => void | (() => void)): void;
|
|
22
|
-
/**
|
|
23
|
-
* Schedules `callback` to run when the context is unmounted.
|
|
24
|
-
*/
|
|
25
|
-
export declare function useUnmount(callback: () => void): void;
|
|
26
|
-
/**
|
|
27
|
-
* Creates a new read-only Signal. Returns bound Getter and Setter functions.
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* const [$count, setCount] = useSignal(5);
|
|
31
|
-
* $count(); // 5
|
|
32
|
-
* setCount(6);
|
|
33
|
-
* setCount((current) => current + 1);
|
|
34
|
-
* $count(); // 7
|
|
35
|
-
*/
|
|
36
|
-
export declare function useSignal<T>(value: T, options?: SignalOptions<T>): [Signal<T>, Setter<T>];
|
|
37
|
-
export declare function useSignal<T>(value: undefined, options: SignalOptions<T>): [Signal<T | undefined>, Setter<T | undefined>];
|
|
38
|
-
export declare function useSignal<T>(): [Signal<T | undefined>, Setter<T | undefined>];
|
|
39
|
-
export declare function useMemo<T>(compute: (current?: T) => MaybeSignal<T>, deps?: Signal<any>[], options?: SignalOptions<T>): Signal<T>;
|
|
40
|
-
/**
|
|
41
|
-
* Takes the current state and a dispatched action. Returns a new state based on the action.
|
|
42
|
-
* Typically the body of this function will be a large switch statement.
|
|
43
|
-
*/
|
|
44
|
-
export type Reducer<State, Action> = (state: State, action: Action) => State;
|
|
45
|
-
/**
|
|
46
|
-
* Dispatches an action to this reducer, causing the state to update.
|
|
47
|
-
*/
|
|
48
|
-
export type Dispatcher<Action> = (action: Action) => void;
|
|
49
|
-
/**
|
|
50
|
-
*
|
|
51
|
-
*/
|
|
52
|
-
export declare function useReducer<State, Action>(reducer: Reducer<State, Action>, initialState: State): [Signal<State>, Dispatcher<Action>];
|
|
53
|
-
/**
|
|
54
|
-
* Creates an effect bound to the current context.
|
|
55
|
-
* The `fn` is called when the component is mounted, then again each time the dependencies are updated until the component is unmounted.
|
|
56
|
-
*/
|
|
57
|
-
export declare function useEffect(fn: EffectFn, deps?: Signal<any>[]): void;
|
|
58
|
-
/**
|
|
59
|
-
* A hybrid Ref which is both a function ref and a React-style object ref with a `current` property.
|
|
60
|
-
* Both the `current` property and the function syntax access the same value.
|
|
61
|
-
*/
|
|
62
|
-
export interface HybridRef<T> extends Ref<T> {
|
|
63
|
-
current: T;
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Creates a Ref. Useful for getting references to DOM nodes.
|
|
67
|
-
*
|
|
68
|
-
* @deprecated use ref()
|
|
69
|
-
*/
|
|
70
|
-
export declare function useRef<T>(initialValue?: T): HybridRef<T>;
|
package/dist/core/logger.d.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import type { Env } from "../types.js";
|
|
2
|
-
import { type MaybeSignal } from "./signals.js";
|
|
3
|
-
export interface LogLevels {
|
|
4
|
-
info: boolean | Env;
|
|
5
|
-
log: boolean | Env;
|
|
6
|
-
warn: boolean | Env;
|
|
7
|
-
error: boolean | Env;
|
|
8
|
-
}
|
|
9
|
-
export interface Logger {
|
|
10
|
-
info(...args: any[]): void;
|
|
11
|
-
log(...args: any[]): void;
|
|
12
|
-
warn(...args: any[]): void;
|
|
13
|
-
error(...args: any[]): void;
|
|
14
|
-
crash(error: Error): Error;
|
|
15
|
-
}
|
|
16
|
-
export interface LoggerOptions {
|
|
17
|
-
/**
|
|
18
|
-
* Tag value to print with logs.
|
|
19
|
-
*/
|
|
20
|
-
tag?: string;
|
|
21
|
-
/**
|
|
22
|
-
* Label for tag value. Will be printed without a label if not specified.
|
|
23
|
-
*/
|
|
24
|
-
tagName?: string;
|
|
25
|
-
/**
|
|
26
|
-
* Console object to use for logging (mostly for testing). Uses window.console by default.
|
|
27
|
-
*/
|
|
28
|
-
console?: any;
|
|
29
|
-
}
|
|
30
|
-
export interface LoggerCrashProps {
|
|
31
|
-
error: Error;
|
|
32
|
-
loggerName: string;
|
|
33
|
-
tag?: string;
|
|
34
|
-
tagName?: string;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Listen for logged crashes.
|
|
38
|
-
*/
|
|
39
|
-
export declare function onLoggerCrash(listener: (context: LoggerCrashProps) => void): () => void;
|
|
40
|
-
export declare function createLogger(name: MaybeSignal<string>, options?: LoggerOptions): Logger;
|
|
41
|
-
export declare function setLogFilter(filter: string | RegExp): void;
|
|
42
|
-
export declare function setLogLevels(options: Partial<LogLevels>): void;
|
|
File without changes
|
package/dist/core/markup.d.ts
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import type { IntrinsicElements, Renderable, View } from "../types.js";
|
|
2
|
-
import { Context } from "./context.js";
|
|
3
|
-
import { MarkupNode } from "./nodes/_markup.js";
|
|
4
|
-
import { KeyFn, RenderFn } from "./nodes/repeat.js";
|
|
5
|
-
import { type Signal } from "./signals.js";
|
|
6
|
-
export { MarkupNode };
|
|
7
|
-
type PropsOf<V extends string | View<any>> = V extends View<infer U> ? U : any;
|
|
8
|
-
/**
|
|
9
|
-
* `Markup` is a set of metadata that will be constructed into a `MarkupNode`.
|
|
10
|
-
*/
|
|
11
|
-
export declare class Markup<Type extends string | View<any> = string | View<any>> {
|
|
12
|
-
/**
|
|
13
|
-
* In the case of a view, type will be the View function itself. It can also hold an identifier for special nodes like "$cond", "$repeat", etc.
|
|
14
|
-
* DOM nodes can be created by name, such as HTML elements like "div", "ul" or "span", SVG elements like ""
|
|
15
|
-
*/
|
|
16
|
-
type: Type;
|
|
17
|
-
/**
|
|
18
|
-
* Data that will be passed to a new MarkupNode instance when it is constructed.
|
|
19
|
-
* Includes a `children` prop if children were passed.
|
|
20
|
-
*/
|
|
21
|
-
props: PropsOf<Type>;
|
|
22
|
-
constructor(type: Type, props: PropsOf<Type>);
|
|
23
|
-
}
|
|
24
|
-
export declare enum MarkupType {
|
|
25
|
-
DOM = "$dom",
|
|
26
|
-
Dynamic = "$dynamic",
|
|
27
|
-
Portal = "$portal",
|
|
28
|
-
Repeat = "$repeat"
|
|
29
|
-
}
|
|
30
|
-
export interface MarkupNodeProps {
|
|
31
|
-
[MarkupType.DOM]: {
|
|
32
|
-
value: Node;
|
|
33
|
-
};
|
|
34
|
-
[MarkupType.Dynamic]: {
|
|
35
|
-
source: Signal<any>;
|
|
36
|
-
};
|
|
37
|
-
[MarkupType.Portal]: {
|
|
38
|
-
content: Renderable;
|
|
39
|
-
parent: Element;
|
|
40
|
-
};
|
|
41
|
-
[MarkupType.Repeat]: {
|
|
42
|
-
items: Signal<any[]>;
|
|
43
|
-
key: KeyFn<any>;
|
|
44
|
-
render: RenderFn<any>;
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
export interface MarkupCustomElementProps {
|
|
48
|
-
/**
|
|
49
|
-
* Custom element tagName pattern (must include a hyphen).
|
|
50
|
-
*/
|
|
51
|
-
[tag: `${string}-${string}`]: Record<string, any>;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Creates a `Markup` element that defines an HTML element.
|
|
55
|
-
*/
|
|
56
|
-
export declare function createMarkup<T extends keyof IntrinsicElements>(tag: T, attrs: IntrinsicElements[T] & {
|
|
57
|
-
children?: Renderable;
|
|
58
|
-
}): Markup;
|
|
59
|
-
/**
|
|
60
|
-
* Creates a `Markup` element that defines an HTML custom element.
|
|
61
|
-
*/
|
|
62
|
-
export declare function createMarkup<T extends keyof MarkupCustomElementProps>(type: T, props: MarkupCustomElementProps[T]): Markup;
|
|
63
|
-
/**
|
|
64
|
-
* Creates a `Markup` element that defines a `MarkupNode`.
|
|
65
|
-
*/
|
|
66
|
-
export declare function createMarkup<T extends keyof MarkupNodeProps>(type: T, props: MarkupNodeProps[T]): Markup;
|
|
67
|
-
/**
|
|
68
|
-
* Creates a `Markup` element that defines a view.
|
|
69
|
-
*/
|
|
70
|
-
export declare function createMarkup<P extends {}>(type: View<P>, props?: P): Markup;
|
|
71
|
-
/**
|
|
72
|
-
* Creates a `Markup` element that defines a view.
|
|
73
|
-
*/
|
|
74
|
-
export declare function createMarkup<P>(type: View<P>, props: P): Markup;
|
|
75
|
-
/**
|
|
76
|
-
* Takes any `Renderable` value and returns a `MarkupNode` that will display it.
|
|
77
|
-
*/
|
|
78
|
-
export declare function render(content: Renderable, context?: Context): MarkupNode;
|
|
79
|
-
/**
|
|
80
|
-
* Convert basically anything into a set of `MarkupNode`s.
|
|
81
|
-
*/
|
|
82
|
-
export declare function toMarkupNodes(context: Context, ...content: any[]): MarkupNode[];
|
|
File without changes
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A node that can be mounted by the Markup layout engine. Can be extended to create new custom node types.
|
|
3
|
-
*
|
|
4
|
-
* A `MarkupNode` instance can be passed anywhere a `Renderable` is required.
|
|
5
|
-
*/
|
|
6
|
-
export declare abstract class MarkupNode {
|
|
7
|
-
/**
|
|
8
|
-
* Returns a single DOM node to represent this MarkupNode's position in the DOM.
|
|
9
|
-
* Usually the parent element, but it can be an empty Text node used as a marker.
|
|
10
|
-
*
|
|
11
|
-
* It only needs to be defined while the node is mounted, so it can be created in the `mount` function.
|
|
12
|
-
*/
|
|
13
|
-
getRoot(): Node | undefined;
|
|
14
|
-
/**
|
|
15
|
-
* Returns true while this node is mounted.
|
|
16
|
-
*/
|
|
17
|
-
isMounted(): boolean;
|
|
18
|
-
/**
|
|
19
|
-
* Mount this node to a `parent` element.
|
|
20
|
-
* If passed, this node will be mounted as the next sibling of `after`.
|
|
21
|
-
*/
|
|
22
|
-
mount(parent: Element, after?: Node): void;
|
|
23
|
-
/**
|
|
24
|
-
* Unmount this MarkupNode from its parent element.
|
|
25
|
-
*
|
|
26
|
-
* The `skipDOM` option can be passed as an optimization when unmounting a parent node.
|
|
27
|
-
* A value of `true` indicates that no DOM operations need to happen because the parent is already being unmounted.
|
|
28
|
-
*
|
|
29
|
-
* @param skipDOM - No DOM updates will be performed when true. Lifecycle methods will be called regardless.
|
|
30
|
-
*/
|
|
31
|
-
unmount(skipDOM?: boolean): void;
|
|
32
|
-
/**
|
|
33
|
-
* Moves a node without unmounting and remounting (if the browser supports Element.moveBefore).
|
|
34
|
-
*/
|
|
35
|
-
move(parent: Element, after?: Node): void;
|
|
36
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { Context } from "../context.js";
|
|
2
|
-
import { type Signal } from "../signals.js";
|
|
3
|
-
import { MarkupNode } from "./_markup.js";
|
|
4
|
-
/**
|
|
5
|
-
* Renders any kind of content; markup, signals, DOM nodes, etc.
|
|
6
|
-
* If it can be rendered by Dolla then Dynamic will do it.
|
|
7
|
-
*/
|
|
8
|
-
export declare class DynamicNode extends MarkupNode {
|
|
9
|
-
private root;
|
|
10
|
-
private children;
|
|
11
|
-
private context;
|
|
12
|
-
private $slot;
|
|
13
|
-
private unsubscribe?;
|
|
14
|
-
constructor(context: Context, $slot: Signal<any>);
|
|
15
|
-
getRoot(): Text;
|
|
16
|
-
isMounted(): boolean;
|
|
17
|
-
mount(parent: Node, after?: Node): void;
|
|
18
|
-
unmount(skipDOM?: boolean): void;
|
|
19
|
-
move(parent: Element, after?: Node): void;
|
|
20
|
-
private cleanup;
|
|
21
|
-
private update;
|
|
22
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { Context } from "../context.js";
|
|
2
|
-
import { MarkupNode } from "./_markup.js";
|
|
3
|
-
/**
|
|
4
|
-
* Renders an HTML or SVG element.
|
|
5
|
-
*/
|
|
6
|
-
export declare class ElementNode extends MarkupNode {
|
|
7
|
-
private root;
|
|
8
|
-
private id;
|
|
9
|
-
readonly tag: string;
|
|
10
|
-
readonly props: Record<string, any>;
|
|
11
|
-
private context;
|
|
12
|
-
private childNodes;
|
|
13
|
-
private unsubscribers;
|
|
14
|
-
private ref?;
|
|
15
|
-
private canClickAway;
|
|
16
|
-
constructor(context: Context, tag: string, props: Record<string, any>);
|
|
17
|
-
getRoot(): HTMLElement | SVGElement;
|
|
18
|
-
isMounted(): boolean;
|
|
19
|
-
mount(parent: Node, after?: Node): void;
|
|
20
|
-
unmount(skipDOM?: boolean): void;
|
|
21
|
-
move(parent: Element, after?: Node): void;
|
|
22
|
-
private attachProp;
|
|
23
|
-
private getKey;
|
|
24
|
-
private applyProps;
|
|
25
|
-
private applyStyles;
|
|
26
|
-
private applyClasses;
|
|
27
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { Renderable } from "../../types.js";
|
|
2
|
-
import { Context } from "../context.js";
|
|
3
|
-
import { MarkupNode } from "./_markup.js";
|
|
4
|
-
/**
|
|
5
|
-
* Renders content into a specified parent node.
|
|
6
|
-
*/
|
|
7
|
-
export declare class PortalNode extends MarkupNode {
|
|
8
|
-
private context;
|
|
9
|
-
private value;
|
|
10
|
-
private parent;
|
|
11
|
-
private node?;
|
|
12
|
-
constructor(context: Context, value: Renderable, parent: Element);
|
|
13
|
-
getRoot(): Node | undefined;
|
|
14
|
-
isMounted(): boolean;
|
|
15
|
-
mount(_parent: Element, _after?: Node): void;
|
|
16
|
-
unmount(skipDOM?: boolean): void;
|
|
17
|
-
move(_parent: Element, _after?: Node): void;
|
|
18
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type { Renderable } from "../../types.js";
|
|
2
|
-
import type { Context } from "../context.js";
|
|
3
|
-
import { type Signal } from "../signals.js";
|
|
4
|
-
import { MarkupNode } from "./_markup.js";
|
|
5
|
-
export type Key = any;
|
|
6
|
-
export type KeyFn<T> = (item: T, index: number) => Key;
|
|
7
|
-
export type RenderFn<T> = (item: Signal<T>, index: Signal<number>) => Renderable;
|
|
8
|
-
/**
|
|
9
|
-
* Renders a list of items.
|
|
10
|
-
*/
|
|
11
|
-
export declare class RepeatNode<T> extends MarkupNode {
|
|
12
|
-
private root;
|
|
13
|
-
private context;
|
|
14
|
-
private items;
|
|
15
|
-
private key;
|
|
16
|
-
private render;
|
|
17
|
-
private unsubscribe;
|
|
18
|
-
private connectedItems;
|
|
19
|
-
constructor(context: Context, items: Signal<T[]>, key: KeyFn<T>, render: RenderFn<T>);
|
|
20
|
-
getRoot(): Text;
|
|
21
|
-
isMounted(): boolean;
|
|
22
|
-
mount(parent: Element, after?: Node): void;
|
|
23
|
-
unmount(skipDOM?: boolean): void;
|
|
24
|
-
move(parent: Element, after?: Node): void;
|
|
25
|
-
private _cleanup;
|
|
26
|
-
private _update;
|
|
27
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { View } from "../../types.js";
|
|
2
|
-
import { Context } from "../context.js";
|
|
3
|
-
import { MarkupNode } from "./_markup.js";
|
|
4
|
-
export declare const VIEW: unique symbol;
|
|
5
|
-
/**
|
|
6
|
-
* Renders a View.
|
|
7
|
-
*/
|
|
8
|
-
export declare class ViewNode<P> extends MarkupNode {
|
|
9
|
-
readonly id: string;
|
|
10
|
-
readonly props: P;
|
|
11
|
-
readonly context: Context;
|
|
12
|
-
readonly view: View<P>;
|
|
13
|
-
node?: MarkupNode;
|
|
14
|
-
/**
|
|
15
|
-
* @param context - Parent contenxt to link to.
|
|
16
|
-
* @param view - View function to mount.
|
|
17
|
-
* @param props - Props to pass to view function.
|
|
18
|
-
*/
|
|
19
|
-
constructor(context: Context, view: View<P>, props: P);
|
|
20
|
-
getRoot(): Node | undefined;
|
|
21
|
-
isMounted(): boolean;
|
|
22
|
-
mount(parent: Element, after?: Node): void;
|
|
23
|
-
unmount(skipDOM?: boolean): void;
|
|
24
|
-
move(parent: Element, after?: Node): void;
|
|
25
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Props passed to the crash view when a crash occurs.
|
|
3
|
-
*/
|
|
4
|
-
export interface CrashViewProps {
|
|
5
|
-
/**
|
|
6
|
-
* JavaScript Error object.
|
|
7
|
-
*/
|
|
8
|
-
error: Error;
|
|
9
|
-
/**
|
|
10
|
-
* A string to identify the logger that reported this error.
|
|
11
|
-
*/
|
|
12
|
-
loggerName: string;
|
|
13
|
-
/**
|
|
14
|
-
* Unique identifier to pinpoint the specific view that reported the crash.
|
|
15
|
-
*/
|
|
16
|
-
tag?: string;
|
|
17
|
-
/**
|
|
18
|
-
* Label for the tag.
|
|
19
|
-
*/
|
|
20
|
-
tagName?: string;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* The crash view displayed unless you specify your own.
|
|
24
|
-
*/
|
|
25
|
-
export declare function DefaultCrashView(props: CrashViewProps): import("../markup.js").Markup<string | import("../index.js").View<any>>;
|
package/dist/core/views/for.d.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { type Key, RenderFn, RepeatNode } from "../nodes/repeat";
|
|
2
|
-
import { type MaybeSignal } from "../signals";
|
|
3
|
-
export interface ForProps<T> {
|
|
4
|
-
/**
|
|
5
|
-
* An array of items to render.
|
|
6
|
-
*/
|
|
7
|
-
each: MaybeSignal<T[]>;
|
|
8
|
-
/**
|
|
9
|
-
* A function to extract a unique key that identifies each item.
|
|
10
|
-
* If no `key` function is passed, object identity (===) will be used.
|
|
11
|
-
*/
|
|
12
|
-
key?: (item: T, index: number) => Key;
|
|
13
|
-
/**
|
|
14
|
-
* A render function. Takes the item and its index in signal form and returns something to display for each item.
|
|
15
|
-
*/
|
|
16
|
-
children: RenderFn<T>;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
*
|
|
20
|
-
*/
|
|
21
|
-
export declare function For<T>(props: ForProps<T>): RepeatNode<T>;
|