@remix-run/ui 0.7.0 → 0.9.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 +90 -14
- package/dist/animation/demos/drag-release.js +5 -7
- package/dist/animation/demos/drag-release.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime/component.d.ts +9 -4
- package/dist/runtime/component.js +38 -9
- package/dist/runtime/component.js.map +1 -1
- package/dist/runtime/core/mix.d.ts +21 -0
- package/dist/runtime/core/mix.js +128 -0
- package/dist/runtime/core/mix.js.map +1 -0
- package/dist/runtime/diff-dom.js +15 -16
- package/dist/runtime/diff-dom.js.map +1 -1
- package/dist/runtime/document-reload.d.ts +2 -0
- package/dist/runtime/document-reload.js +14 -0
- package/dist/runtime/document-reload.js.map +1 -0
- package/dist/runtime/dom.d.ts +21 -11
- package/dist/runtime/event-types.d.ts +14 -0
- package/dist/runtime/event-types.js +2 -0
- package/dist/runtime/event-types.js.map +1 -0
- package/dist/runtime/frame-resolution.js +8 -0
- package/dist/runtime/frame-resolution.js.map +1 -1
- package/dist/runtime/frame.d.ts +24 -6
- package/dist/runtime/frame.js +187 -60
- package/dist/runtime/frame.js.map +1 -1
- package/dist/runtime/import-map-manager.d.ts +8 -0
- package/dist/runtime/import-map-manager.js +295 -0
- package/dist/runtime/import-map-manager.js.map +1 -0
- package/dist/runtime/mixins/link-mixin.js +4 -4
- package/dist/runtime/mixins/link-mixin.js.map +1 -1
- package/dist/runtime/mixins/mixin.d.ts +9 -4
- package/dist/runtime/mixins/mixin.js +18 -132
- package/dist/runtime/mixins/mixin.js.map +1 -1
- package/dist/runtime/mixins/on-mixin.d.ts +1 -1
- package/dist/runtime/module-preloader.d.ts +2 -1
- package/dist/runtime/module-preloader.js +6 -5
- package/dist/runtime/module-preloader.js.map +1 -1
- package/dist/runtime/navigation.js +211 -34
- package/dist/runtime/navigation.js.map +1 -1
- package/dist/runtime/reconcile.js +18 -3
- package/dist/runtime/reconcile.js.map +1 -1
- package/dist/runtime/run.d.ts +3 -0
- package/dist/runtime/run.js +8 -4
- package/dist/runtime/run.js.map +1 -1
- package/dist/runtime/scheduler.js +37 -11
- package/dist/runtime/scheduler.js.map +1 -1
- package/dist/runtime/spa-response.d.ts +30 -0
- package/dist/runtime/spa-response.js +47 -0
- package/dist/runtime/spa-response.js.map +1 -0
- package/dist/runtime/to-vnode.js +1 -1
- package/dist/runtime/to-vnode.js.map +1 -1
- package/dist/runtime/typed-event-target.d.ts +0 -4
- package/dist/runtime/typed-event-target.js.map +1 -1
- package/dist/server/stream.d.ts +25 -2
- package/dist/server/stream.js +382 -171
- package/dist/server/stream.js.map +1 -1
- package/dist/style/stylesheet.js +2 -2
- package/dist/style/stylesheet.js.map +1 -1
- package/package.json +1 -1
- package/src/animation/demos/drag-release.ts +5 -7
- package/src/index.ts +2 -2
- package/src/runtime/component.ts +52 -14
- package/src/runtime/core/mix.ts +157 -0
- package/src/runtime/demos/readme.demo.tsx +7 -17
- package/src/runtime/diff-dom.ts +13 -15
- package/src/runtime/document-reload.ts +14 -0
- package/src/runtime/dom.ts +21 -11
- package/src/runtime/event-types.ts +27 -0
- package/src/runtime/frame-resolution.ts +9 -0
- package/src/runtime/frame.ts +216 -65
- package/src/runtime/import-map-manager.ts +369 -0
- package/src/runtime/mixins/link-mixin.ts +4 -4
- package/src/runtime/mixins/mixin.ts +44 -149
- package/src/runtime/mixins/on-mixin.ts +1 -1
- package/src/runtime/module-preloader.ts +9 -6
- package/src/runtime/navigation.ts +257 -42
- package/src/runtime/reconcile.ts +20 -4
- package/src/runtime/run.ts +13 -4
- package/src/runtime/scheduler.ts +53 -13
- package/src/runtime/spa-response.ts +56 -0
- package/src/runtime/to-vnode.ts +1 -1
- package/src/runtime/typed-event-target.ts +1 -6
- package/src/server/README.md +25 -5
- package/src/server/stream.ts +506 -202
- package/src/style/stylesheet.ts +3 -3
- package/src/test/utils.ts +1 -6
- package/dist/runtime/event-listeners.d.ts +0 -50
- package/dist/runtime/event-listeners.js +0 -31
- package/dist/runtime/event-listeners.js.map +0 -1
- package/src/runtime/event-listeners.ts +0 -171
package/README.md
CHANGED
|
@@ -79,10 +79,9 @@ function Actions() {
|
|
|
79
79
|
}
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
##
|
|
82
|
+
## Client Entry Loading
|
|
83
83
|
|
|
84
|
-
`run()`
|
|
85
|
-
fetches the frame source:
|
|
84
|
+
`run()` hydrates client entries by calling `loadModule` for each component module:
|
|
86
85
|
|
|
87
86
|
```tsx
|
|
88
87
|
import { run } from 'remix/ui'
|
|
@@ -97,6 +96,47 @@ let app = run({
|
|
|
97
96
|
await app.ready()
|
|
98
97
|
```
|
|
99
98
|
|
|
99
|
+
Client entries introduced after the initial document may depend on import maps added at runtime.
|
|
100
|
+
When targeting browsers without native support for multiple import maps, use
|
|
101
|
+
`remix/multiple-import-maps-polyfill` to load these modules and process their preloads:
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
import {
|
|
105
|
+
detectMultipleImportMapSupport,
|
|
106
|
+
importModule,
|
|
107
|
+
preloadShim,
|
|
108
|
+
} from 'remix/multiple-import-maps-polyfill'
|
|
109
|
+
|
|
110
|
+
let app = run({
|
|
111
|
+
async loadModule(moduleUrl, exportName) {
|
|
112
|
+
let module = await importModule(moduleUrl)
|
|
113
|
+
let Component = module[exportName]
|
|
114
|
+
if (typeof Component !== 'function') {
|
|
115
|
+
throw new Error(`Unknown component: ${moduleUrl}#${exportName}`)
|
|
116
|
+
}
|
|
117
|
+
return Component
|
|
118
|
+
},
|
|
119
|
+
async processClientEntryPreloads(preloads) {
|
|
120
|
+
if (await detectMultipleImportMapSupport()) return preloads
|
|
121
|
+
|
|
122
|
+
preloadShim(preloads)
|
|
123
|
+
return []
|
|
124
|
+
},
|
|
125
|
+
})
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Frame Navigation
|
|
129
|
+
|
|
130
|
+
The same runtime represents the current document as `app.frames.top` and intercepts eligible
|
|
131
|
+
same-origin links and forms through the browser's Navigation API. Those navigations fetch HTML with
|
|
132
|
+
the frame resolver and update the existing document in place instead of loading a new document.
|
|
133
|
+
This soft-navigation behavior applies even when the page only uses `clientEntry()` and does not
|
|
134
|
+
render an explicit `<Frame>`.
|
|
135
|
+
|
|
136
|
+
Frame navigation requires both `window.navigation` and `NavigateEvent.sourceElement`. Browsers
|
|
137
|
+
missing either capability use document navigation for links, forms, and `navigate()`. Hydration and
|
|
138
|
+
explicit frame reloads still work.
|
|
139
|
+
|
|
100
140
|
The default resolver is equivalent to:
|
|
101
141
|
|
|
102
142
|
```js
|
|
@@ -108,7 +148,8 @@ async function resolveFrame(src, options) {
|
|
|
108
148
|
signal: options?.signal,
|
|
109
149
|
})
|
|
110
150
|
|
|
111
|
-
|
|
151
|
+
let isHtml = response.headers.get('Content-Type')?.toLowerCase().includes('text/html')
|
|
152
|
+
if (response.status >= 500 || (response.status >= 300 && !isHtml)) {
|
|
112
153
|
throw new Error(`Failed to resolve frame: ${response.status} ${response.statusText}`.trimEnd())
|
|
113
154
|
}
|
|
114
155
|
|
|
@@ -149,13 +190,20 @@ CRLF-delimited text, and `multipart/form-data` submissions use `FormData`. Pass
|
|
|
149
190
|
`resolveFrame` when the server requires additional headers, another body encoding, or a different
|
|
150
191
|
response policy.
|
|
151
192
|
|
|
152
|
-
Add `rmx-document` to a link or form to leave
|
|
193
|
+
Add `data-rmx-document` to a link or form to leave that navigation to the browser. To keep all links
|
|
194
|
+
and forms as document navigations while still hydrating client entries and using explicit frames,
|
|
195
|
+
register a listener before calling `run()`:
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
window.navigation?.addEventListener('navigate', (e) => e.stopImmediatePropagation())
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
This prevents Remix from intercepting Navigation API events. Explicit frame reloads such as
|
|
202
|
+
`handle.frame.reload()` continue to use the frame resolver.
|
|
153
203
|
|
|
154
|
-
The default resolver
|
|
155
|
-
A custom `resolveFrame` may return a `Response` with any status when it wants Remix UI to render the
|
|
156
|
-
response body.
|
|
204
|
+
The default resolver accepts `2xx` responses and `3xx` or `4xx` responses whose `Content-Type` includes `text/html`, ignoring case. It rejects other `3xx` or `4xx` responses and all `5xx` responses with an error containing their status and status text. A custom `resolveFrame` may return a `Response` with any status when it wants Remix UI to render the response body.
|
|
157
205
|
|
|
158
|
-
Forms remain ordinary HTML forms before the runtime starts. Add `rmx-target` to reload a named frame, or `rmx-document` to require a full-document submission:
|
|
206
|
+
Forms remain ordinary HTML forms before the runtime starts. Add `data-rmx-target` to reload a named frame, or `data-rmx-document` to require a full-document submission:
|
|
159
207
|
|
|
160
208
|
```tsx
|
|
161
209
|
import { Frame } from 'remix/ui'
|
|
@@ -164,7 +212,7 @@ function AccountPage() {
|
|
|
164
212
|
return () => (
|
|
165
213
|
<>
|
|
166
214
|
<Frame name="account" src="/account/edit" />
|
|
167
|
-
<form action="/account/edit" method="post" rmx-target="account">
|
|
215
|
+
<form action="/account/edit" method="post" data-rmx-target="account">
|
|
168
216
|
<label for="display-name">Display name</label>
|
|
169
217
|
<input id="display-name" name="displayName" required />
|
|
170
218
|
<button type="submit">Save</button>
|
|
@@ -176,19 +224,47 @@ function AccountPage() {
|
|
|
176
224
|
|
|
177
225
|
Native constraint validation and submitter overrides still apply. GET form values arrive in `src`; non-GET forms provide `formData`, `method`, and `encType` to the resolver. See [Frames](https://github.com/remix-run/remix/blob/main/packages/ui/docs/frames.md#form-navigation) for targeting, history behavior, request encoding, opt-outs, and server response guidance.
|
|
178
226
|
|
|
179
|
-
Use `rmx-history="push|replace"` on an enhanced anchor or form to control how the navigation updates history. This can override the automatic replacement used for non-GET form submissions to the current URL.
|
|
227
|
+
Use `data-rmx-history="push|replace"` on an enhanced anchor or form to control how the navigation updates history. This can override the automatic replacement used for non-GET form submissions to the current URL.
|
|
228
|
+
|
|
229
|
+
## Single-page Applications
|
|
230
|
+
|
|
231
|
+
Use `render` and `run` from `remix/spa` when every route runs in the browser and returns a Remix UI
|
|
232
|
+
tree instead of an HTTP response body. The render middleware keeps the router's standard `Request`
|
|
233
|
+
to `Response` contract while associating the response with a node for the top frame to render:
|
|
234
|
+
|
|
235
|
+
```tsx
|
|
236
|
+
import { createRouter } from 'remix/router'
|
|
237
|
+
import { render, run } from 'remix/spa'
|
|
238
|
+
|
|
239
|
+
let router = createRouter({ middleware: [render()] })
|
|
240
|
+
|
|
241
|
+
router.get('/', ({ render }) => render(<h1>Home</h1>))
|
|
242
|
+
router.get('/about', ({ render }) => render(<h1>About</h1>))
|
|
243
|
+
|
|
244
|
+
function LoadingPage() {
|
|
245
|
+
return () => <p role="status">Loading…</p>
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
let app = run(router, { fallback: <LoadingPage /> })
|
|
249
|
+
await app.ready()
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
The optional `fallback` is a live Remix node displayed while the initial route loads.
|
|
253
|
+
`app.ready()` resolves after the initial URL has replaced it with the routed node. The runtime then
|
|
254
|
+
reuses frame navigation for same-origin links, forms, history traversal, redirects, cancellation,
|
|
255
|
+
and `rmx-target`.
|
|
180
256
|
|
|
181
257
|
## Preserving Client-Owned DOM
|
|
182
258
|
|
|
183
|
-
Use `rmx-preserve-dom` on the smallest element whose live DOM should belong to client code after initial render, such as a custom element or third-party widget:
|
|
259
|
+
Use `data-rmx-preserve-dom` on the smallest element whose live DOM should belong to client code after initial render, such as a custom element or third-party widget:
|
|
184
260
|
|
|
185
261
|
```tsx
|
|
186
|
-
<pagefind-ui data-key="search" rmx-preserve-dom>
|
|
262
|
+
<pagefind-ui data-rmx-key="search" data-rmx-preserve-dom>
|
|
187
263
|
<button type="button">Search</button>
|
|
188
264
|
</pagefind-ui>
|
|
189
265
|
```
|
|
190
266
|
|
|
191
|
-
Remix UI still renders the element's children during SSR and still hydrates any initial client entries inside it. On later frame reloads, matched `rmx-preserve-dom` elements keep their current attributes and children instead of accepting incoming DOM updates. See [Preserving client-owned DOM](https://github.com/remix-run/remix/blob/main/packages/ui/docs/frames.md#preserving-client-owned-dom) for guidance and caveats.
|
|
267
|
+
Remix UI still renders the element's children during SSR and still hydrates any initial client entries inside it. On later frame reloads, matched `data-rmx-preserve-dom` elements keep their current attributes and children instead of accepting incoming DOM updates. See [Preserving client-owned DOM](https://github.com/remix-run/remix/blob/main/packages/ui/docs/frames.md#preserving-client-owned-dom) for guidance and caveats.
|
|
192
268
|
|
|
193
269
|
## Cascade Layers
|
|
194
270
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createMixin } from '@remix-run/ui';
|
|
2
2
|
export const dragVelocityReleaseEventType = 'rmx:drag-velocity-release';
|
|
3
3
|
export class DragVelocityEvent extends Event {
|
|
4
4
|
clientX;
|
|
@@ -82,12 +82,10 @@ const baseDragVelocityEvents = createMixin((handle) => {
|
|
|
82
82
|
};
|
|
83
83
|
handle.addEventListener('insert', (event) => {
|
|
84
84
|
target = event.node;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
pointercancel: onPointerCancel,
|
|
90
|
-
});
|
|
85
|
+
target.addEventListener('pointerdown', onPointerDown, { signal: handle.signal });
|
|
86
|
+
target.addEventListener('pointermove', onPointerMove, { signal: handle.signal });
|
|
87
|
+
target.addEventListener('pointerup', onPointerUp, { signal: handle.signal });
|
|
88
|
+
target.addEventListener('pointercancel', onPointerCancel, { signal: handle.signal });
|
|
91
89
|
});
|
|
92
90
|
});
|
|
93
91
|
export const dragVelocityEvents = Object.assign(baseDragVelocityEvents, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drag-release.js","sourceRoot":"","sources":["../../../src/animation/demos/drag-release.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"drag-release.js","sourceRoot":"","sources":["../../../src/animation/demos/drag-release.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,14 +9,14 @@ export type { SerializablePrimitive, SerializableObject, SerializableArray, Seri
|
|
|
9
9
|
export { Fragment, Frame } from './runtime/component.ts';
|
|
10
10
|
export type { Task, Handle, Context, FrameHandleEventMap, FrameContent, FrameHandle, FrameProps, } from './runtime/component.ts';
|
|
11
11
|
export type { LoadModule, ResolveFrame, ResolveFrameOptions } from './runtime/frame.ts';
|
|
12
|
+
export { spaResponse } from './runtime/spa-response.ts';
|
|
12
13
|
export { createElement } from './runtime/create-element.ts';
|
|
13
14
|
export type { ElementType, ElementProps, RemixElement, Renderable, RemixNode, Props, } from './runtime/jsx.ts';
|
|
14
15
|
export type { HostProps, LayoutAnimationConfig } from './runtime/dom.ts';
|
|
15
16
|
export { createMixin } from './runtime/mixins/mixin.ts';
|
|
16
17
|
export type { MixinDescriptor, MixinFactory, MixinHandle, MixinType, MixInput, MixValue, } from './runtime/mixins/mixin.ts';
|
|
17
18
|
export { TypedEventTarget } from './runtime/typed-event-target.ts';
|
|
18
|
-
export {
|
|
19
|
-
export type { Dispatched } from './runtime/event-listeners.ts';
|
|
19
|
+
export type { Dispatched } from './runtime/event-types.ts';
|
|
20
20
|
export { on } from './runtime/mixins/on-mixin.ts';
|
|
21
21
|
export { link } from './runtime/mixins/link-mixin.ts';
|
|
22
22
|
export { ref } from './runtime/mixins/ref-mixin.ts';
|
package/dist/index.js
CHANGED
|
@@ -6,11 +6,11 @@ export { createRoot, createRangeRoot, createScheduler } from './runtime/vdom.js'
|
|
|
6
6
|
export { clientEntry } from './runtime/client-entries.js';
|
|
7
7
|
// -- Components --
|
|
8
8
|
export { Fragment, Frame } from './runtime/component.js';
|
|
9
|
+
export { spaResponse } from './runtime/spa-response.js';
|
|
9
10
|
// -- Elements/JSX/Props --
|
|
10
11
|
export { createElement } from './runtime/create-element.js';
|
|
11
12
|
export { createMixin } from './runtime/mixins/mixin.js';
|
|
12
13
|
export { TypedEventTarget } from './runtime/typed-event-target.js';
|
|
13
|
-
export { addEventListeners } from './runtime/event-listeners.js';
|
|
14
14
|
export { on } from './runtime/mixins/on-mixin.js';
|
|
15
15
|
export { link } from './runtime/mixins/link-mixin.js';
|
|
16
16
|
export { ref } from './runtime/mixins/ref-mixin.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wDAAwD;AAExD,cAAc;AACd,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAItC,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAQhF,uBAAuB;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAUzD,mBAAmB;AACnB,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wDAAwD;AAExD,cAAc;AACd,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAItC,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAQhF,uBAAuB;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAUzD,mBAAmB;AACnB,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AAWxD,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAEvD,2BAA2B;AAC3B,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAU3D,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AASvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AAElE,OAAO,EAAE,EAAE,EAAE,MAAM,8BAA8B,CAAA;AACjD,OAAO,EAAE,IAAI,EAAE,MAAM,gCAAgC,CAAA;AACrD,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AAEnD,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAA;AACvD,OAAO,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAA;AAG1C,mBAAmB;AACnB,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA"}
|
|
@@ -26,10 +26,14 @@ export interface Handle<Props = Record<string, never>, ContextValue = NoContext>
|
|
|
26
26
|
context: Context<ContextValue>;
|
|
27
27
|
/**
|
|
28
28
|
* Schedules an update for the component to render again. Returns a promise
|
|
29
|
-
* that resolves with an AbortSignal after the update completes.
|
|
30
|
-
*
|
|
29
|
+
* that resolves with an AbortSignal after the update completes. Call this
|
|
30
|
+
* from an event handler, queued task, or other work that runs after the
|
|
31
|
+
* component commits. The signal is aborted when the component re-renders or
|
|
32
|
+
* is removed. Calling this during setup warns and skips the extra render;
|
|
33
|
+
* the promise resolves after the initial commit.
|
|
31
34
|
*
|
|
32
35
|
* @returns A promise that resolves with an AbortSignal after the update
|
|
36
|
+
* @throws If called during rendering or before the initial commit outside setup
|
|
33
37
|
*/
|
|
34
38
|
update(): Promise<AbortSignal>;
|
|
35
39
|
/**
|
|
@@ -121,8 +125,9 @@ export type FrameContent = ReadableStream<Uint8Array> | string | RemixNode;
|
|
|
121
125
|
* Value returned by a browser frame resolver.
|
|
122
126
|
*
|
|
123
127
|
* Response bodies are rendered as frame content regardless of status. The default browser resolver
|
|
124
|
-
*
|
|
125
|
-
*
|
|
128
|
+
* accepts 2xx responses and 3xx or 4xx HTML responses. It rejects other 3xx or 4xx responses and all
|
|
129
|
+
* 5xx responses. When `fetch()` followed a redirect, the response's final URL updates the frame source
|
|
130
|
+
* and browser URL for a top-frame navigation.
|
|
126
131
|
*/
|
|
127
132
|
export type FrameResolution = FrameContent | Response;
|
|
128
133
|
/**
|
|
@@ -18,6 +18,7 @@ class ComponentRuntime {
|
|
|
18
18
|
#renderController;
|
|
19
19
|
#renderFn;
|
|
20
20
|
#removed = false;
|
|
21
|
+
#phase = 'idle';
|
|
21
22
|
// The schedule target is stored as fields (updated each render) rather than
|
|
22
23
|
// a closure so re-renders don't allocate a new function per component.
|
|
23
24
|
#updateQueue;
|
|
@@ -49,7 +50,14 @@ class ComponentRuntime {
|
|
|
49
50
|
let renderFn = this.#renderFn;
|
|
50
51
|
if (renderFn === undefined) {
|
|
51
52
|
let initialize = this.#config.type;
|
|
52
|
-
let result
|
|
53
|
+
let result;
|
|
54
|
+
this.#phase = 'setup';
|
|
55
|
+
try {
|
|
56
|
+
result = initialize(this.#handle);
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
this.#phase = 'idle';
|
|
60
|
+
}
|
|
53
61
|
if (!isRenderFn(result)) {
|
|
54
62
|
let name = this.#config.type.name || 'Anonymous';
|
|
55
63
|
throw new Error(`${name} must return a render function, received ${typeof result}`);
|
|
@@ -57,7 +65,15 @@ class ComponentRuntime {
|
|
|
57
65
|
renderFn = result;
|
|
58
66
|
this.#renderFn = renderFn;
|
|
59
67
|
}
|
|
60
|
-
|
|
68
|
+
let element;
|
|
69
|
+
this.#phase = 'render';
|
|
70
|
+
try {
|
|
71
|
+
element = renderFn();
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
this.#phase = 'idle';
|
|
75
|
+
}
|
|
76
|
+
return [element, this.#dequeueTasks()];
|
|
61
77
|
};
|
|
62
78
|
remove = () => {
|
|
63
79
|
if (this.#removed)
|
|
@@ -87,14 +103,27 @@ class ComponentRuntime {
|
|
|
87
103
|
return {
|
|
88
104
|
id: this.#config.id,
|
|
89
105
|
props: this.#props,
|
|
90
|
-
update: () =>
|
|
91
|
-
if (component.#removed)
|
|
92
|
-
resolve(AbortSignal.abort());
|
|
93
|
-
|
|
106
|
+
update: () => {
|
|
107
|
+
if (component.#removed)
|
|
108
|
+
return Promise.resolve(AbortSignal.abort());
|
|
109
|
+
let name = component.#config.type.name || 'Anonymous';
|
|
110
|
+
if (component.#phase === 'setup') {
|
|
111
|
+
console.warn(`Ignored handle.update() while ${name} is running its setup function. The initial render includes setup changes.`);
|
|
112
|
+
return new Promise((resolve) => {
|
|
113
|
+
this.#tasks.push((signal) => resolve(signal));
|
|
114
|
+
});
|
|
94
115
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
116
|
+
if (component.#phase !== 'idle') {
|
|
117
|
+
throw new Error(`Cannot call handle.update() while ${name} is running its ${component.#phase} function. Call it from an event handler or handle.queueTask() instead.`);
|
|
118
|
+
}
|
|
119
|
+
if (component.#updateQueue === undefined) {
|
|
120
|
+
throw new Error(`Cannot call handle.update() before ${name}'s initial render commits. Call it from an event handler or handle.queueTask() instead.`);
|
|
121
|
+
}
|
|
122
|
+
return new Promise((resolve) => {
|
|
123
|
+
this.#tasks.push((signal) => resolve(signal));
|
|
124
|
+
this.#scheduleUpdate();
|
|
125
|
+
});
|
|
126
|
+
},
|
|
98
127
|
queueTask: (task) => {
|
|
99
128
|
this.#tasks.push(task);
|
|
100
129
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component.js","sourceRoot":"","sources":["../../src/runtime/component.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;
|
|
1
|
+
{"version":3,"file":"component.js","sourceRoot":"","sources":["../../src/runtime/component.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ElementProps } from '../jsx.ts';
|
|
2
|
+
interface MixDescriptor {
|
|
3
|
+
type: (...args: any[]) => unknown;
|
|
4
|
+
args: readonly unknown[];
|
|
5
|
+
}
|
|
6
|
+
type MixDescriptorRunner = (descriptor: MixDescriptor, index: number, mixinProps: ElementProps) => unknown;
|
|
7
|
+
/**
|
|
8
|
+
* Composes an element's `mix` descriptors into its final props.
|
|
9
|
+
*
|
|
10
|
+
* @param hostType Host element tag name the mixins are composed for.
|
|
11
|
+
* @param props Original element props, including `mix`.
|
|
12
|
+
* @param runDescriptor Runs each mixin using the caller's state and error handling.
|
|
13
|
+
* @returns The composed props.
|
|
14
|
+
*/
|
|
15
|
+
export declare function composeMixedProps(hostType: string, props: ElementProps, runDescriptor: MixDescriptorRunner): ElementProps;
|
|
16
|
+
export declare function resolveMixDescriptors(props: ElementProps): MixDescriptor[];
|
|
17
|
+
export declare function isMixinDescriptor(value: unknown): value is MixDescriptor;
|
|
18
|
+
export declare function isMixinElementFunction(value: unknown): value is ((...args: unknown[]) => unknown) & {
|
|
19
|
+
__rmxMixinElementType: string;
|
|
20
|
+
};
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// Stop mixins that return themselves from expanding forever.
|
|
2
|
+
const MAX_MIX_DESCRIPTORS = 1024;
|
|
3
|
+
/**
|
|
4
|
+
* Composes an element's `mix` descriptors into its final props.
|
|
5
|
+
*
|
|
6
|
+
* @param hostType Host element tag name the mixins are composed for.
|
|
7
|
+
* @param props Original element props, including `mix`.
|
|
8
|
+
* @param runDescriptor Runs each mixin using the caller's state and error handling.
|
|
9
|
+
* @returns The composed props.
|
|
10
|
+
*/
|
|
11
|
+
export function composeMixedProps(hostType, props, runDescriptor) {
|
|
12
|
+
let descriptors = resolveMixDescriptors(props);
|
|
13
|
+
let composedProps = withoutMix(props);
|
|
14
|
+
let mixinProps = withoutMixinTreeProps(composedProps);
|
|
15
|
+
for (let index = 0; index < descriptors.length && index < MAX_MIX_DESCRIPTORS; index++) {
|
|
16
|
+
let result = runDescriptor(descriptors[index], index, mixinProps);
|
|
17
|
+
if (!result)
|
|
18
|
+
continue;
|
|
19
|
+
if (isMixinElementFunction(result))
|
|
20
|
+
continue;
|
|
21
|
+
let returnedDescriptors = resolveReturnedMixDescriptors(result);
|
|
22
|
+
if (returnedDescriptors) {
|
|
23
|
+
for (let returned of returnedDescriptors)
|
|
24
|
+
descriptors.push(returned);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (!isRemixElementResult(result)) {
|
|
28
|
+
console.error(new Error('mixins must return a remix element'));
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
let resultType = typeof result.type === 'string'
|
|
32
|
+
? result.type
|
|
33
|
+
: isMixinElementFunction(result.type)
|
|
34
|
+
? result.type.__rmxMixinElementType
|
|
35
|
+
: null;
|
|
36
|
+
if (resultType !== hostType) {
|
|
37
|
+
console.error(new Error('mixins must return an element with the same host type'));
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
let nextProps = sanitizeReturnedMixinProps(result.props);
|
|
41
|
+
for (let nested of resolveMixDescriptors(nextProps))
|
|
42
|
+
descriptors.push(nested);
|
|
43
|
+
composedProps = { ...composedProps, ...withoutMix(nextProps) };
|
|
44
|
+
mixinProps = withoutMixinTreeProps(composedProps);
|
|
45
|
+
}
|
|
46
|
+
let nextMix = props.mix;
|
|
47
|
+
return {
|
|
48
|
+
...composedProps,
|
|
49
|
+
...(nextMix === undefined ? {} : { mix: nextMix }),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
// JSX creation flattens nested mix arrays before composition.
|
|
53
|
+
export function resolveMixDescriptors(props) {
|
|
54
|
+
let mix = props.mix;
|
|
55
|
+
if (!mix)
|
|
56
|
+
return [];
|
|
57
|
+
if (Array.isArray(mix)) {
|
|
58
|
+
if (mix.length === 0)
|
|
59
|
+
return [];
|
|
60
|
+
return mix.filter(Boolean);
|
|
61
|
+
}
|
|
62
|
+
return [mix];
|
|
63
|
+
}
|
|
64
|
+
function withoutMix(props) {
|
|
65
|
+
if (!('mix' in props))
|
|
66
|
+
return props;
|
|
67
|
+
let output = { ...props };
|
|
68
|
+
delete output.mix;
|
|
69
|
+
return output;
|
|
70
|
+
}
|
|
71
|
+
function withoutMixinTreeProps(props) {
|
|
72
|
+
if (!('children' in props) && !('innerHTML' in props))
|
|
73
|
+
return props;
|
|
74
|
+
let output = { ...props };
|
|
75
|
+
delete output.children;
|
|
76
|
+
delete output.innerHTML;
|
|
77
|
+
return output;
|
|
78
|
+
}
|
|
79
|
+
function sanitizeReturnedMixinProps(props) {
|
|
80
|
+
if (!('children' in props) && !('innerHTML' in props))
|
|
81
|
+
return props;
|
|
82
|
+
console.error(new Error('mixins must not return children or innerHTML'));
|
|
83
|
+
return withoutMixinTreeProps(props);
|
|
84
|
+
}
|
|
85
|
+
export function isMixinDescriptor(value) {
|
|
86
|
+
if (!value || typeof value !== 'object' || isRemixElementResult(value)) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
let descriptor = value;
|
|
90
|
+
return typeof descriptor.type === 'function' && Array.isArray(descriptor.args);
|
|
91
|
+
}
|
|
92
|
+
export function isMixinElementFunction(value) {
|
|
93
|
+
if (typeof value !== 'function')
|
|
94
|
+
return false;
|
|
95
|
+
return '__rmxMixinElementType' in value;
|
|
96
|
+
}
|
|
97
|
+
// The composition loop checks the returned element's host type separately.
|
|
98
|
+
function isRemixElementResult(value) {
|
|
99
|
+
if (!value || typeof value !== 'object')
|
|
100
|
+
return false;
|
|
101
|
+
return value.$rmx === true;
|
|
102
|
+
}
|
|
103
|
+
function resolveReturnedMixDescriptors(value) {
|
|
104
|
+
let descriptors = [];
|
|
105
|
+
if (!collectReturnedMixDescriptors(value, descriptors)) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
return descriptors;
|
|
109
|
+
}
|
|
110
|
+
function collectReturnedMixDescriptors(value, output) {
|
|
111
|
+
if (!value) {
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
if (Array.isArray(value)) {
|
|
115
|
+
for (let item of value) {
|
|
116
|
+
if (!collectReturnedMixDescriptors(item, output)) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
if (!isMixinDescriptor(value)) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
output.push(value);
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=mix.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mix.js","sourceRoot":"","sources":["../../../src/runtime/core/mix.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime/diff-dom.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { invariant } from './invariant.js';
|
|
2
2
|
import { disposeClientEntryBoundary, getClientEntryBoundaryOwner } from './client-entry-boundary.js';
|
|
3
|
-
const REMIX_PRESERVE_DOM_ATTRIBUTE = 'rmx-preserve-dom';
|
|
3
|
+
const REMIX_PRESERVE_DOM_ATTRIBUTE = 'data-rmx-preserve-dom';
|
|
4
4
|
export function diffNodes(curr, next, context) {
|
|
5
5
|
let parent = curr[0]?.parentNode ?? context.regionParent ?? null;
|
|
6
6
|
invariant(parent, 'Parent node not found');
|
|
@@ -44,10 +44,15 @@ function diffNode(current, next, context) {
|
|
|
44
44
|
if (nextMarkerData.status === 'resolved') {
|
|
45
45
|
let nextEnd = findFrameEndMarker(next);
|
|
46
46
|
let nextContent = collectFrameContentFragment(current.ownerDocument, next, nextEnd);
|
|
47
|
-
|
|
47
|
+
let render = frame.renderMarkerContent({ ...nextMarkerData, id: getFrameId(next) }, nextContent, {
|
|
48
48
|
data: context.data,
|
|
49
49
|
signal: context.signal,
|
|
50
|
+
reconciliationTracker: context.reconciliationTracker,
|
|
50
51
|
});
|
|
52
|
+
if (context.reconciliationTracker)
|
|
53
|
+
context.reconciliationTracker.waitFor(render);
|
|
54
|
+
else
|
|
55
|
+
void render;
|
|
51
56
|
return nextEnd;
|
|
52
57
|
}
|
|
53
58
|
if (frame.isDisplayingResolvedContent()) {
|
|
@@ -179,21 +184,15 @@ function isPopoverOpen(element) {
|
|
|
179
184
|
}
|
|
180
185
|
}
|
|
181
186
|
function diffElementChildren(current, next, context) {
|
|
182
|
-
let
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
if (
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
if (!context.isActiveModulePreload(node))
|
|
189
|
-
currentChildren.push(node);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
else {
|
|
193
|
-
currentChildren = Array.from(current.childNodes);
|
|
187
|
+
let shouldPreserveHeadNode = context.shouldPreserveHeadNode;
|
|
188
|
+
let preservedHeadNodes = [];
|
|
189
|
+
let currentChildren = Array.from(current.childNodes);
|
|
190
|
+
if (current === current.ownerDocument.head && shouldPreserveHeadNode) {
|
|
191
|
+
preservedHeadNodes = currentChildren.filter(shouldPreserveHeadNode);
|
|
192
|
+
currentChildren = currentChildren.filter((node) => !shouldPreserveHeadNode(node));
|
|
194
193
|
}
|
|
195
194
|
let nextChildren = Array.from(next.childNodes);
|
|
196
|
-
diffSiblingUnits(currentChildren, nextChildren, current, null, context);
|
|
195
|
+
diffSiblingUnits(currentChildren, nextChildren, current, preservedHeadNodes[0] ?? null, context);
|
|
197
196
|
}
|
|
198
197
|
function diffSiblingUnits(currentNodes, nextNodes, parent, regionTailRef, context) {
|
|
199
198
|
let currentUnits = parseSiblingUnits(currentNodes);
|
|
@@ -346,7 +345,7 @@ function parseSiblingUnits(nodes) {
|
|
|
346
345
|
function getSiblingUnitKey(unit) {
|
|
347
346
|
if (unit.kind !== 'node' || !isElement(unit.node))
|
|
348
347
|
return;
|
|
349
|
-
return unit.node.getAttribute('data-key') ?? undefined;
|
|
348
|
+
return unit.node.getAttribute('data-rmx-key') ?? undefined;
|
|
350
349
|
}
|
|
351
350
|
function siblingUnitsComparable(current, next) {
|
|
352
351
|
if (current.kind !== next.kind)
|