defuss-morph 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +369 -0
- package/dist/all.js +1312 -0
- package/dist/all.js.map +17 -0
- package/dist/all.min.js +2 -0
- package/dist/all.min.js.map +1 -0
- package/dist/index.cjs +1242 -0
- package/dist/index.d.ts +233 -0
- package/dist/index.mjs +1204 -0
- package/dist/stats.json +22 -0
- package/package.json +89 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lean structural types for the defuss morph engine.
|
|
3
|
+
*
|
|
4
|
+
* These are intentionally minimal (no JSX namespace, no store/ref machinery).
|
|
5
|
+
* defuss's richer types are structurally assignable to these.
|
|
6
|
+
*/
|
|
7
|
+
type Globals = Performance & Window & typeof globalThis;
|
|
8
|
+
type DefussKey = string | number;
|
|
9
|
+
type MountHandler<T extends Element = Element> = (element: T) => void;
|
|
10
|
+
type UnmountHandler<T extends Element = Element> = (element: T) => void;
|
|
11
|
+
/**
|
|
12
|
+
* Minimal ref shape: the morph engine only ever assigns `current`.
|
|
13
|
+
* defuss's full `Ref` interface is structurally assignable to this.
|
|
14
|
+
*/
|
|
15
|
+
interface RefLike {
|
|
16
|
+
current?: any;
|
|
17
|
+
orphan?: boolean;
|
|
18
|
+
}
|
|
19
|
+
interface VNodeAttributes {
|
|
20
|
+
ref?: RefLike;
|
|
21
|
+
key?: DefussKey;
|
|
22
|
+
onMount?: MountHandler<any>;
|
|
23
|
+
onUnmount?: UnmountHandler<any>;
|
|
24
|
+
[attributeName: string]: any;
|
|
25
|
+
}
|
|
26
|
+
type VNodeType = string | Function | any;
|
|
27
|
+
interface VNode<A = VNodeAttributes> {
|
|
28
|
+
type?: VNodeType;
|
|
29
|
+
attributes?: A;
|
|
30
|
+
children?: VNodeChildren;
|
|
31
|
+
sourceInfo?: unknown;
|
|
32
|
+
/** Original props passed to a function component (set by jsx runtime for SSG hydration). */
|
|
33
|
+
componentProps?: Record<string, any>;
|
|
34
|
+
}
|
|
35
|
+
type VNodeChild = VNode<any> | object | string | number | boolean | null | undefined;
|
|
36
|
+
type VNodeChildren = VNodeChild[];
|
|
37
|
+
/**
|
|
38
|
+
* Anything the morph engine accepts as new content.
|
|
39
|
+
*/
|
|
40
|
+
type RenderInput = VNode | object | string | number | boolean | null | undefined | RenderInput[];
|
|
41
|
+
interface DomAbstractionImpl {
|
|
42
|
+
hasElNamespace(domElement: Element | Document): boolean;
|
|
43
|
+
hasSvgNamespace(parentElement: Element | Document, type: string): boolean;
|
|
44
|
+
createElementOrElements(virtualNode: RenderInput, parentDomElement?: Element | Document): Array<Element | Text | undefined> | Element | Text | undefined;
|
|
45
|
+
createElement(virtualNode: RenderInput, parentDomElement?: Element | Document): Element | undefined;
|
|
46
|
+
createTextNode(text: string, parentDomElement?: Element | Document): Text;
|
|
47
|
+
createChildElements(virtualChildren: VNodeChildren, parentDomElement?: Element | Document): Array<Element | Text | undefined>;
|
|
48
|
+
setAttribute(name: string, value: any, domElement: Element): void;
|
|
49
|
+
setAttributes(virtualNode: VNode<VNodeAttributes>, domElement: Element): void;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type TransitionType = "fade" | "slide-left" | "slide-right" | "shake" | "none";
|
|
53
|
+
interface TransitionStyles {
|
|
54
|
+
enter: Record<string, string>;
|
|
55
|
+
enterActive: Record<string, string>;
|
|
56
|
+
exit: Record<string, string>;
|
|
57
|
+
exitActive: Record<string, string>;
|
|
58
|
+
}
|
|
59
|
+
type TransitionsEasing = "linear" | "ease" | "ease-in" | "ease-out" | "ease-in-out" | "step-start" | "step-end";
|
|
60
|
+
interface TransitionConfig {
|
|
61
|
+
type?: TransitionType;
|
|
62
|
+
styles?: TransitionStyles;
|
|
63
|
+
duration?: number;
|
|
64
|
+
easing?: TransitionsEasing | string;
|
|
65
|
+
delay?: number;
|
|
66
|
+
target?: "parent" | "self";
|
|
67
|
+
}
|
|
68
|
+
declare const getTransitionStyles: (type: TransitionType, duration: number, easing?: string) => TransitionStyles;
|
|
69
|
+
declare const applyStyles: (el: HTMLElement, styles: Record<string, string | number>) => void;
|
|
70
|
+
declare const DEFAULT_TRANSITION_CONFIG: TransitionConfig;
|
|
71
|
+
declare const performTransition: (element: HTMLElement, updateCallback: () => Promise<void>, config?: TransitionConfig) => Promise<void>;
|
|
72
|
+
|
|
73
|
+
declare const queueCallback: <T extends any[]>(cb: (...args: T) => void) => (...args: T) => void;
|
|
74
|
+
|
|
75
|
+
type DelegatedPhase = "bubble" | "capture";
|
|
76
|
+
interface DelegatedEventOptions {
|
|
77
|
+
capture?: boolean;
|
|
78
|
+
/** If true, allows multiple handlers per element+type (Dequery mode) */
|
|
79
|
+
multi?: boolean;
|
|
80
|
+
}
|
|
81
|
+
interface ParsedEventProp {
|
|
82
|
+
eventType: string;
|
|
83
|
+
capture: boolean;
|
|
84
|
+
}
|
|
85
|
+
/** non-bubbling events best handled via capture */
|
|
86
|
+
declare const CAPTURE_ONLY_EVENTS: Set<string>;
|
|
87
|
+
declare const parseEventPropName: (propName: string) => ParsedEventProp | null;
|
|
88
|
+
declare const registerDelegatedEvent: (element: HTMLElement, eventType: string, handler: EventListener, options?: DelegatedEventOptions) => void;
|
|
89
|
+
declare const removeDelegatedEvent: (target: EventTarget, eventType: string, handler?: EventListener, _options?: DelegatedEventOptions) => void;
|
|
90
|
+
declare const clearDelegatedEvents: (target: EventTarget) => void;
|
|
91
|
+
/**
|
|
92
|
+
* Clear delegated events for an element and all its descendants.
|
|
93
|
+
* Used by empty() to prevent event handler leaks when removing subtrees.
|
|
94
|
+
*/
|
|
95
|
+
declare const clearDelegatedEventsDeep: (root: HTMLElement) => void;
|
|
96
|
+
/**
|
|
97
|
+
* Get all event types currently registered on an element.
|
|
98
|
+
* Used to detect which events need to be removed when vnode props change.
|
|
99
|
+
*/
|
|
100
|
+
declare const getRegisteredEventTypes: (element: HTMLElement) => Set<string>;
|
|
101
|
+
/**
|
|
102
|
+
* Get all event keys with phases currently registered on an element.
|
|
103
|
+
* Returns keys like "click:bubble", "click:capture" for precise phase-aware removal.
|
|
104
|
+
*/
|
|
105
|
+
declare const getRegisteredEventKeys: (element: HTMLElement) => Set<string>;
|
|
106
|
+
/**
|
|
107
|
+
* Remove delegated event handler for a specific phase only.
|
|
108
|
+
* Used by patchElementInPlace to precisely remove stale handlers when vnode changes from
|
|
109
|
+
* onClick + onClickCapture → onClickCapture only.
|
|
110
|
+
*/
|
|
111
|
+
declare const removeDelegatedEventByKey: (element: HTMLElement, eventType: string, phase: "bubble" | "capture") => void;
|
|
112
|
+
|
|
113
|
+
declare const CLASS_ATTRIBUTE_NAME = "class";
|
|
114
|
+
declare const XLINK_ATTRIBUTE_NAME = "xlink";
|
|
115
|
+
declare const XMLNS_ATTRIBUTE_NAME = "xmlns";
|
|
116
|
+
declare const REF_ATTRIBUTE_NAME = "ref";
|
|
117
|
+
declare const DANGEROUSLY_SET_INNER_HTML_ATTRIBUTE = "dangerouslySetInnerHTML";
|
|
118
|
+
declare const nsMap: {
|
|
119
|
+
xmlns: string;
|
|
120
|
+
xlink: string;
|
|
121
|
+
svg: string;
|
|
122
|
+
};
|
|
123
|
+
declare const observeUnmount: (domNode: Node, onUnmount: () => void) => void;
|
|
124
|
+
/** lifecycle event attachment has been implemented separately, because it is also required to run when partially updating the DOM */
|
|
125
|
+
declare const handleLifecycleEventsForOnMount: (newEl: HTMLElement) => void;
|
|
126
|
+
declare const getRenderer: (document: Document) => DomAbstractionImpl;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Compares two DOM nodes for equality with performance optimizations.
|
|
130
|
+
* 1. Checks for reference equality.
|
|
131
|
+
* 2. Compares node types.
|
|
132
|
+
* 3. For Element nodes, compares tag names and attributes.
|
|
133
|
+
* 4. For Text nodes, compares text content.
|
|
134
|
+
*/
|
|
135
|
+
declare const areDomNodesEqual: (oldNode: Node, newNode: Node) => boolean;
|
|
136
|
+
/********************************************************
|
|
137
|
+
* 1) Define a "valid" child type & utilities
|
|
138
|
+
********************************************************/
|
|
139
|
+
type ValidChild = string | number | boolean | null | undefined | VNode<VNodeAttributes>;
|
|
140
|
+
/**
|
|
141
|
+
* How top-level children are reconciled:
|
|
142
|
+
* - `"replace"` (default): full reconciliation — unmentioned nodes are removed.
|
|
143
|
+
* - `"diff"`: partial updates — only patch items addressed by `key`/`id` are
|
|
144
|
+
* applied (attributes merge, new items append, unmentioned nodes untouched).
|
|
145
|
+
*/
|
|
146
|
+
type MorphMode = "replace" | "diff";
|
|
147
|
+
/**
|
|
148
|
+
* Resolve the render globals from an element's own document when not given
|
|
149
|
+
* explicitly (isomorphic: browser window, happy-dom window, multi-document).
|
|
150
|
+
*/
|
|
151
|
+
declare const resolveGlobals: (el?: Element, globals?: Globals) => Globals;
|
|
152
|
+
/**
|
|
153
|
+
* Guarded entry point for DOM morphing.
|
|
154
|
+
*
|
|
155
|
+
* If the target element (or an ancestor) is already being morphed,
|
|
156
|
+
* the render is queued (latest-wins) and replayed after the active
|
|
157
|
+
* morph finishes. Morphs on unrelated subtrees proceed immediately
|
|
158
|
+
* without blocking - conflict-free parallel rendering.
|
|
159
|
+
*
|
|
160
|
+
* `globals` is optional: it is derived from `parentElement.ownerDocument`
|
|
161
|
+
* when omitted.
|
|
162
|
+
*
|
|
163
|
+
* `mode` defaults to `"replace"` (full reconciliation). Pass `"diff"` for
|
|
164
|
+
* partial updates: only `key`/`id`-addressed patch items are applied
|
|
165
|
+
* (attributes merged, new keyed items appended, unmentioned nodes untouched).
|
|
166
|
+
*/
|
|
167
|
+
declare function updateDomWithVdom(parentElement: Element, newVDOM: RenderInput, globals?: Globals, mode?: MorphMode): void;
|
|
168
|
+
/**
|
|
169
|
+
* Directly blow away all children in `parentElement` and create new DOM
|
|
170
|
+
* from `newVDOM`. This never skips or leaves behind stale nodes,
|
|
171
|
+
* at the cost of losing partial update performance.
|
|
172
|
+
*
|
|
173
|
+
* `globals` is optional: it is derived from `parentElement.ownerDocument`
|
|
174
|
+
* when omitted.
|
|
175
|
+
*/
|
|
176
|
+
declare function replaceDomWithVdom(parentElement: Element, newVDOM: RenderInput, globals?: Globals): void;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Marks VNodes derived from existing DOM (HTML strings / DOM nodes).
|
|
180
|
+
* Such VNodes cannot declare event handlers, so the morph engine must
|
|
181
|
+
* preserve delegated handlers already attached to surviving elements
|
|
182
|
+
* (same rationale as uncontrolled form-state preservation).
|
|
183
|
+
*/
|
|
184
|
+
declare const FROM_DOM_MARKER: unique symbol;
|
|
185
|
+
declare function parseDOM(input: string, type: DOMParserSupportedType, Parser: typeof DOMParser): Document;
|
|
186
|
+
declare function isSVG(input: string, Parser: typeof DOMParser): boolean;
|
|
187
|
+
declare function isHTML(input: string, Parser: typeof DOMParser): boolean;
|
|
188
|
+
declare const isMarkup: (input: string, Parser: typeof DOMParser) => boolean;
|
|
189
|
+
declare function renderMarkup(markup: string, Parser: typeof DOMParser, doc?: Document): ChildNode[];
|
|
190
|
+
declare function getMimeType(input: string, Parser: typeof DOMParser): DOMParserSupportedType;
|
|
191
|
+
/**
|
|
192
|
+
* Converts a DOM node to a VNode structure for use with updateDomWithVdom.
|
|
193
|
+
* This allows us to leverage the sophisticated partial update system even for Node inputs.
|
|
194
|
+
*/
|
|
195
|
+
declare function domNodeToVNode(node: Node): VNode<VNodeAttributes> | string;
|
|
196
|
+
/**
|
|
197
|
+
* Converts an HTML string to VNode structure for use with updateDomWithVdom.
|
|
198
|
+
* This allows markup strings to benefit from the intelligent partial update system.
|
|
199
|
+
*/
|
|
200
|
+
declare function htmlStringToVNodes(html: string, Parser: typeof DOMParser): Array<VNode<VNodeAttributes> | string>;
|
|
201
|
+
|
|
202
|
+
interface MorphOptions {
|
|
203
|
+
/**
|
|
204
|
+
* Optional transition to apply around the morph.
|
|
205
|
+
* When set (and `type !== "none"`), `morph()` returns a `Promise`
|
|
206
|
+
* that resolves once the transition completed.
|
|
207
|
+
*/
|
|
208
|
+
transition?: TransitionConfig;
|
|
209
|
+
/**
|
|
210
|
+
* Partial updates: apply only the given change-set instead of reconciling
|
|
211
|
+
* the full child list. Every top-level item must be an element with a
|
|
212
|
+
* `key` (preferred) or `id` — matched nodes are patched with attributes
|
|
213
|
+
* *merged* (undeclared attributes and children stay untouched), unmatched
|
|
214
|
+
* items are appended. Unmentioned siblings keep identity, order and state;
|
|
215
|
+
* diff mode never removes and never moves, so addressing is unambiguous.
|
|
216
|
+
*
|
|
217
|
+
* Plain-text input and key-less items throw (they cannot be addressed).
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* ```ts
|
|
221
|
+
* // update one row, append another — everything else is not re-sent:
|
|
222
|
+
* morph(list, `
|
|
223
|
+
* <li key="b">B (updated)</li>
|
|
224
|
+
* <li key="c">C (new)</li>
|
|
225
|
+
* `, { diff: true });
|
|
226
|
+
* ```
|
|
227
|
+
*/
|
|
228
|
+
diff?: boolean;
|
|
229
|
+
}
|
|
230
|
+
declare const morph: (el: Element, newContent: RenderInput, options?: MorphOptions) => void | Promise<void>;
|
|
231
|
+
|
|
232
|
+
export { CAPTURE_ONLY_EVENTS, CLASS_ATTRIBUTE_NAME, DANGEROUSLY_SET_INNER_HTML_ATTRIBUTE, DEFAULT_TRANSITION_CONFIG, FROM_DOM_MARKER, REF_ATTRIBUTE_NAME, XLINK_ATTRIBUTE_NAME, XMLNS_ATTRIBUTE_NAME, applyStyles, areDomNodesEqual, clearDelegatedEvents, clearDelegatedEventsDeep, domNodeToVNode, getMimeType, getRegisteredEventKeys, getRegisteredEventTypes, getRenderer, getTransitionStyles, handleLifecycleEventsForOnMount, htmlStringToVNodes, isHTML, isMarkup, isSVG, morph, nsMap, observeUnmount, parseDOM, parseEventPropName, performTransition, queueCallback, registerDelegatedEvent, removeDelegatedEvent, removeDelegatedEventByKey, renderMarkup, replaceDomWithVdom, resolveGlobals, updateDomWithVdom };
|
|
233
|
+
export type { DefussKey, DelegatedEventOptions, DelegatedPhase, DomAbstractionImpl, Globals, MorphMode, MorphOptions, MountHandler, ParsedEventProp, RefLike, RenderInput, TransitionConfig, TransitionStyles, TransitionType, TransitionsEasing, UnmountHandler, VNode, VNodeAttributes, VNodeChild, VNodeChildren, VNodeType, ValidChild };
|