@react5/dom-jsx 0.1.6 → 0.1.8
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 +51 -1
- package/dist/index.js +1 -1
- package/dist/jsx-runtime.d.ts +10 -3
- package/dist/jsx-runtime.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -56,10 +56,14 @@ type instead, call the component directly or call `jsx(Modal, null)` /
|
|
|
56
56
|
|
|
57
57
|
Intrinsic JSX tags become DOM elements. `class` sets `className`, `style` accepts a style object, DOM properties are assigned when available, boolean attributes use presence semantics, and `onClick`-style function props become event listeners. Text, nested nodes, arrays, fragments, and function components are supported; `null`, `undefined`, and boolean children are ignored.
|
|
58
58
|
|
|
59
|
+
Compound event props require camel casing, such as `onMouseEnter`, `onMouseLeave`,
|
|
60
|
+
`onFocusIn`, `onFocusOut`, `onKeyDown`, and `onAnimationEnd`.
|
|
61
|
+
Handlers receive the DOM event with `currentTarget` typed as the element.
|
|
62
|
+
|
|
59
63
|
The public entry points are:
|
|
60
64
|
|
|
61
65
|
```ts
|
|
62
|
-
import { createRef, createContext, useContext, jsx, jsxs, Fragment } from '@react5/dom-jsx'
|
|
66
|
+
import { createRef, createContext, useContext, onCleanup, onDispose, dispose, jsx, jsxs, Fragment } from '@react5/dom-jsx'
|
|
63
67
|
import { jsx, jsxs, jsxDEV, Fragment } from '@react5/dom-jsx/jsx-dev-runtime'
|
|
64
68
|
```
|
|
65
69
|
|
|
@@ -116,6 +120,52 @@ progress. Call it synchronously in a component body and keep the result.
|
|
|
116
120
|
Called later, for example from an event handler or a `setTimeout`, it
|
|
117
121
|
returns the context's default value.
|
|
118
122
|
|
|
123
|
+
### Cleanup
|
|
124
|
+
|
|
125
|
+
Release subscriptions, timers, and other resources when content is discarded.
|
|
126
|
+
Register cleanups with `onCleanup` in a component body, or with
|
|
127
|
+
`onDispose(node, fn)` anywhere else:
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
import { dispose, onCleanup, onDispose } from '@react5/dom-jsx'
|
|
131
|
+
|
|
132
|
+
function Clock() {
|
|
133
|
+
const el = <time /> as HTMLTimeElement
|
|
134
|
+
const id = setInterval(() => { el.textContent = new Date().toLocaleTimeString() }, 1000)
|
|
135
|
+
onCleanup(() => clearInterval(id))
|
|
136
|
+
return el
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const node = <Clock />
|
|
140
|
+
onDispose(node, () => console.log('disposed'))
|
|
141
|
+
|
|
142
|
+
// Later, where content is swapped:
|
|
143
|
+
old.replaceWith(next)
|
|
144
|
+
dispose(old)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The DOM gives no synchronous signal when a node is removed, so `dispose` must
|
|
148
|
+
be called explicitly. It runs the cleanups of the node and of every node inside
|
|
149
|
+
it, descendants first, each node's cleanups in reverse registration order.
|
|
150
|
+
Disposal follows the DOM tree, so components passed as children are covered
|
|
151
|
+
even though they render before their parent. Each cleanup runs at most once;
|
|
152
|
+
if some throw, the rest still run and the error (or an `AggregateError`) is
|
|
153
|
+
rethrown afterwards.
|
|
154
|
+
|
|
155
|
+
A component's cleanups are attached to the node it returns. When it returns a
|
|
156
|
+
fragment, they are attached to the fragment's top-level children and run once
|
|
157
|
+
all of them are disposed, so dispose every one of them, or a common ancestor.
|
|
158
|
+
An empty fragment gets an empty comment node to carry its cleanups.
|
|
159
|
+
|
|
160
|
+
If a component throws while rendering, the cleanups it already registered run
|
|
161
|
+
immediately. So do those of components it rendered and of JSX passed to it in
|
|
162
|
+
props, unless those nodes are already in the document.
|
|
163
|
+
|
|
164
|
+
`onCleanup` throws when called outside a component render, e.g. from an event
|
|
165
|
+
handler or after an `await`; use `onDispose(node, fn)` there. Moving a node
|
|
166
|
+
never disposes it. A node that is discarded without `dispose` keeps its
|
|
167
|
+
cleanups until it is garbage-collected, and they never run.
|
|
168
|
+
|
|
119
169
|
## Development
|
|
120
170
|
|
|
121
171
|
```sh
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Fragment as r,createContext as m,createRef as o,
|
|
1
|
+
import{Fragment as r,createContext as m,createRef as o,dispose as t,jsx as e,jsxs as i,onCleanup as j,onDispose as p,useContext as s}from"./jsx-runtime.js";export{r as Fragment,m as createContext,o as createRef,t as dispose,e as jsx,i as jsxs,j as onCleanup,p as onDispose,s as useContext};
|
package/dist/jsx-runtime.d.ts
CHANGED
|
@@ -6,12 +6,16 @@ export type Component<P = Props, R extends Node = Node> = (props: P) => R;
|
|
|
6
6
|
export type DOMEventHandler<T extends EventTarget, E extends Event> = (event: E & {
|
|
7
7
|
currentTarget: T;
|
|
8
8
|
}) => void;
|
|
9
|
+
type CompoundEventName = 'AnimationCancel' | 'AnimationEnd' | 'AnimationIteration' | 'AnimationStart' | 'AuxClick' | 'BeforeInput' | 'BeforeMatch' | 'BeforeToggle' | 'CanPlay' | 'CanPlayThrough' | 'CompositionEnd' | 'CompositionStart' | 'CompositionUpdate' | 'ContextLost' | 'ContextMenu' | 'ContextRestored' | 'CueChange' | 'DblClick' | 'DragEnd' | 'DragEnter' | 'DragLeave' | 'DragOver' | 'DragStart' | 'DurationChange' | 'FocusIn' | 'FocusOut' | 'FormData' | 'FullscreenChange' | 'FullscreenError' | 'GotPointerCapture' | 'LostPointerCapture' | 'KeyDown' | 'KeyPress' | 'KeyUp' | 'LoadedData' | 'LoadedMetadata' | 'LoadStart' | 'MouseDown' | 'MouseEnter' | 'MouseLeave' | 'MouseMove' | 'MouseOut' | 'MouseOver' | 'MouseUp' | 'PointerCancel' | 'PointerDown' | 'PointerEnter' | 'PointerLeave' | 'PointerMove' | 'PointerOut' | 'PointerOver' | 'PointerRawUpdate' | 'PointerUp' | 'RateChange' | 'ScrollEnd' | 'SecurityPolicyViolation' | 'SelectionChange' | 'SelectStart' | 'SlotChange' | 'TimeUpdate' | 'TouchCancel' | 'TouchEnd' | 'TouchMove' | 'TouchStart' | 'TransitionCancel' | 'TransitionEnd' | 'TransitionRun' | 'TransitionStart' | 'VolumeChange' | 'WaitingForKey' | 'WebkitAnimationEnd' | 'WebkitAnimationIteration' | 'WebkitAnimationStart' | 'WebkitTransitionEnd';
|
|
10
|
+
type CompoundEventNames = {
|
|
11
|
+
[K in CompoundEventName as Lowercase<K>]: K;
|
|
12
|
+
};
|
|
13
|
+
type EventPropName<K extends string> = K extends keyof CompoundEventNames ? `on${CompoundEventNames[K]}` : `on${Capitalize<K>}`;
|
|
9
14
|
type MappedEventProps<T extends HTMLElement> = {
|
|
10
|
-
[K in keyof HTMLElementEventMap as
|
|
15
|
+
[K in keyof HTMLElementEventMap as EventPropName<K & string>]?: DOMEventHandler<T, HTMLElementEventMap[K]>;
|
|
11
16
|
};
|
|
12
|
-
export type EventProps<T extends HTMLElement> = Omit<MappedEventProps<T>, 'onInput'
|
|
17
|
+
export type EventProps<T extends HTMLElement> = Omit<MappedEventProps<T>, 'onInput'> & {
|
|
13
18
|
onInput?: DOMEventHandler<T, InputEvent>;
|
|
14
|
-
onDblClick?: DOMEventHandler<T, MouseEvent>;
|
|
15
19
|
};
|
|
16
20
|
export type Ref<T> = {
|
|
17
21
|
current: T | null;
|
|
@@ -34,6 +38,9 @@ export type Context<T> = {
|
|
|
34
38
|
};
|
|
35
39
|
export declare function createContext<T>(defaultValue: T): Context<T>;
|
|
36
40
|
export declare function useContext<T>(context: Context<T>): T;
|
|
41
|
+
export declare function onDispose(node: Node, fn: () => void): void;
|
|
42
|
+
export declare function onCleanup(fn: () => void): void;
|
|
43
|
+
export declare function dispose(node: Node): void;
|
|
37
44
|
export declare namespace JSX {
|
|
38
45
|
type Element = Node & {
|
|
39
46
|
api?: Record<string, any>;
|
package/dist/jsx-runtime.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function e(){return{current:null}}var t=/* @__PURE__ */new WeakMap;function n(e){const n=[],
|
|
1
|
+
function e(){return{current:null}}var t=/* @__PURE__ */new WeakMap;function n(e){const n=[],o={Provider({value:e,children:t}){if("function"!=typeof t)throw new TypeError("Context Provider expects a single function child: {() => ...}");n.push(e);try{const e=t();if(e instanceof Node)return e;const n=document.createDocumentFragment();return m(n,e),n}finally{n.pop()}}};return t.set(o,{defaultValue:e,stack:n}),o}function o(e){const n=t.get(e);if(!n)throw new TypeError("useContext expects a context created by createContext");const{defaultValue:o,stack:r}=n;return r.length>0?r[r.length-1]:o}var r=/* @__PURE__ */new WeakMap,c=[];function s(e,t){const n=r.get(e);n?n.push(t):r.set(e,[t])}function i(e,t){s(e,()=>t())}function f(e){const t=c[c.length-1];if(!t)throw new Error("onCleanup must be called while a component is rendering; use onDispose(node, fn) instead");t.cleanups.push(e)}function u(e){const t=[];if(l(e,t),1===t.length)throw t[0];if(t.length>1)throw new AggregateError(t,"Multiple cleanups failed during dispose")}function l(e,t){for(const r of Array.from(e.childNodes))l(r,t);const n=r.get(e);if(n){r.delete(e);for(let e=n.length-1;e>=0;e--)try{n[e](t)}catch(o){t.push(o)}}}function a(e,t){for(let o=e.length-1;o>=0;o--)try{e[o]()}catch(n){t.push(n)}}function d(e,t){if(e instanceof Node)t.push(e);else if(Array.isArray(e))for(const n of e)d(n,t)}function p(e,t){const n={cleanups:[],rendered:[]};let o;c.push(n);try{o=e(t)}catch(f){throw c.pop(),function(e,t){const n=[],o=[...e.rendered];for(const r of Object.values(t))d(r,o);for(const r of o)r.isConnected||l(r,n);a(e.cleanups,n)}(n,t),f}c.pop();let r=[o];if(o instanceof DocumentFragment&&(!o.firstChild&&n.cleanups.length>0&&o.appendChild(document.createComment("")),r=Array.from(o.childNodes)),n.cleanups.length>0)if(1===r.length)for(const c of n.cleanups)i(r[0],c);else{let e=r.length;for(const t of r)s(t,t=>{0===--e&&a(n.cleanups,t)})}return c[c.length-1]?.rendered.push(...r),o}function h(e,t,n){return function(e,t){const n=t??{};if("function"==typeof e)return p(e,n);const o=document.createElement(e);for(const[c,s]of Object.entries(n))if("children"!==c&&"ref"!==c)if(c.startsWith("on")&&"function"==typeof s)o.addEventListener(c.slice(2).toLowerCase(),s);else if("class"!==c){if("style"===c&&s&&"object"==typeof s)Object.assign(o.style,s);else if(null!=s)if(c.includes("-"))o.setAttribute(c,String(s));else{if(c in o){if(!1===s)continue;try{o[c]=s;continue}catch{}}o.setAttribute(c,!0===s?"":String(s))}}else o.className=String(s??"");m(o,n.children);const r=n.ref;"function"==typeof r?r(o):r&&(r.current=o);return o}(e,t)}var g=h;function y(e){const t=document.createDocumentFragment();return m(t,e.children),t}function m(e,t){if(Array.isArray(t))for(const n of t)m(e,n);else t instanceof Node?e.appendChild(t):null!=t&&!1!==t&&!0!==t&&e.appendChild(document.createTextNode(String(t)))}export{y as Fragment,n as createContext,e as createRef,u as dispose,h as jsx,g as jsxs,f as onCleanup,i as onDispose,o as useContext};
|