remix 3.0.0-rc.4 → 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/INDEX.md +6 -21
- package/README.md +1 -1
- package/dist/component/dev/refresh.d.ts +2 -0
- package/dist/component/dev/refresh.d.ts.map +1 -0
- package/dist/{ui → component}/dev/refresh.js +1 -1
- package/dist/component/jsx-dev-runtime.d.ts +2 -0
- package/dist/component/jsx-dev-runtime.d.ts.map +1 -0
- package/dist/{ui → component}/jsx-dev-runtime.js +1 -1
- package/dist/component/jsx-runtime.d.ts +2 -0
- package/dist/component/jsx-runtime.d.ts.map +1 -0
- package/dist/{ui → component}/jsx-runtime.js +1 -1
- package/dist/component/server.d.ts +2 -0
- package/dist/component/server.d.ts.map +1 -0
- package/dist/{ui → component}/server.js +1 -1
- package/dist/component/test.d.ts +2 -0
- package/dist/component/test.d.ts.map +1 -0
- package/dist/{ui → component}/test.js +1 -1
- package/dist/component-hmr/assets.d.ts +2 -0
- package/dist/component-hmr/assets.d.ts.map +1 -0
- package/dist/{ui-hmr.js → component-hmr/assets.js} +1 -1
- package/dist/component-hmr/node.d.ts +3 -0
- package/dist/component-hmr/node.d.ts.map +1 -0
- package/dist/{ui-hmr → component-hmr}/node.js +1 -1
- package/dist/component-hmr/runtime/browser.d.ts +2 -0
- package/dist/component-hmr/runtime/browser.d.ts.map +1 -0
- package/dist/{ui-hmr → component-hmr}/runtime/browser.js +1 -1
- package/dist/component-hmr/runtime/server.d.ts +2 -0
- package/dist/component-hmr/runtime/server.d.ts.map +1 -0
- package/dist/{ui-hmr → component-hmr}/runtime/server.js +1 -1
- package/dist/component-hmr.d.ts +2 -0
- package/dist/component-hmr.d.ts.map +1 -0
- package/dist/{ui-hmr/assets.js → component-hmr.js} +1 -1
- package/dist/component.d.ts +2 -0
- package/dist/component.d.ts.map +1 -0
- package/dist/{ui/anchor.js → component.js} +1 -1
- package/guides/01-start-here.md +20 -20
- package/guides/02-routing-and-controllers.md +1 -1
- package/guides/03-request-handling.md +1 -1
- package/guides/04-rendering-ui.md +41 -307
- package/guides/05-interactivity.md +42 -37
- package/guides/06-streaming-ui-with-frames.md +28 -70
- package/guides/07-animation.md +41 -35
- package/guides/08-data-and-validation.md +423 -27
- package/guides/09-forms-and-mutations.md +250 -25
- package/guides/13-testing.md +10 -10
- package/guides/14-cli-and-tooling.md +2 -2
- package/package.json +96 -180
- package/src/assets/README.md +12 -12
- package/src/cli/README.md +3 -3
- package/src/{ui → component}/README.md +31 -75
- package/src/{ui → component}/dev/refresh.ts +1 -1
- package/src/{ui → component}/jsx-dev-runtime.ts +1 -1
- package/src/{ui → component}/jsx-runtime.ts +1 -1
- package/src/{ui → component}/server/README.md +8 -8
- package/src/{ui → component}/server.ts +1 -1
- package/src/{ui → component}/test/README.md +6 -6
- package/src/{ui → component}/test.ts +1 -1
- package/src/{ui-hmr → component-hmr}/README.md +13 -13
- package/src/{ui-hmr → component-hmr}/assets.ts +1 -1
- package/src/{ui-hmr → component-hmr}/node.ts +1 -1
- package/src/{ui-hmr → component-hmr}/runtime/browser.ts +1 -1
- package/src/{ui-hmr → component-hmr}/runtime/server.ts +1 -1
- package/{dist/ui/accordion.js → src/component-hmr.ts} +1 -1
- package/{dist/ui/tabs.js → src/component.ts} +1 -1
- package/src/data-table/README.md +2 -1
- package/src/multiple-import-maps-polyfill/README.md +3 -3
- package/src/node-hmr/README.md +6 -6
- package/src/render-middleware/README.md +5 -5
- package/src/spa/README.md +4 -4
- package/src/test/README.md +4 -4
- package/dist/ui/accordion/primitives.d.ts +0 -2
- package/dist/ui/accordion/primitives.d.ts.map +0 -1
- package/dist/ui/accordion/primitives.js +0 -2
- package/dist/ui/accordion.d.ts +0 -2
- package/dist/ui/accordion.d.ts.map +0 -1
- package/dist/ui/anchor.d.ts +0 -2
- package/dist/ui/anchor.d.ts.map +0 -1
- package/dist/ui/animation.d.ts +0 -2
- package/dist/ui/animation.d.ts.map +0 -1
- package/dist/ui/animation.js +0 -2
- package/dist/ui/breadcrumbs.d.ts +0 -2
- package/dist/ui/breadcrumbs.d.ts.map +0 -1
- package/dist/ui/breadcrumbs.js +0 -2
- package/dist/ui/button.d.ts +0 -3
- package/dist/ui/button.d.ts.map +0 -1
- package/dist/ui/button.js +0 -3
- package/dist/ui/checkbox.d.ts +0 -3
- package/dist/ui/checkbox.d.ts.map +0 -1
- package/dist/ui/checkbox.js +0 -3
- package/dist/ui/combobox/primitives.d.ts +0 -2
- package/dist/ui/combobox/primitives.d.ts.map +0 -1
- package/dist/ui/combobox/primitives.js +0 -2
- package/dist/ui/combobox.d.ts +0 -2
- package/dist/ui/combobox.d.ts.map +0 -1
- package/dist/ui/combobox.js +0 -2
- package/dist/ui/dev/refresh.d.ts +0 -2
- package/dist/ui/dev/refresh.d.ts.map +0 -1
- package/dist/ui/input.d.ts +0 -3
- package/dist/ui/input.d.ts.map +0 -1
- package/dist/ui/input.js +0 -3
- package/dist/ui/jsx-dev-runtime.d.ts +0 -2
- package/dist/ui/jsx-dev-runtime.d.ts.map +0 -1
- package/dist/ui/jsx-runtime.d.ts +0 -2
- package/dist/ui/jsx-runtime.d.ts.map +0 -1
- package/dist/ui/listbox.d.ts +0 -2
- package/dist/ui/listbox.d.ts.map +0 -1
- package/dist/ui/listbox.js +0 -2
- package/dist/ui/menu/primitives.d.ts +0 -2
- package/dist/ui/menu/primitives.d.ts.map +0 -1
- package/dist/ui/menu/primitives.js +0 -2
- package/dist/ui/menu.d.ts +0 -2
- package/dist/ui/menu.d.ts.map +0 -1
- package/dist/ui/menu.js +0 -2
- package/dist/ui/popover.d.ts +0 -2
- package/dist/ui/popover.d.ts.map +0 -1
- package/dist/ui/popover.js +0 -2
- package/dist/ui/radio.d.ts +0 -3
- package/dist/ui/radio.d.ts.map +0 -1
- package/dist/ui/radio.js +0 -3
- package/dist/ui/select/primitives.d.ts +0 -2
- package/dist/ui/select/primitives.d.ts.map +0 -1
- package/dist/ui/select/primitives.js +0 -2
- package/dist/ui/select.d.ts +0 -2
- package/dist/ui/select.d.ts.map +0 -1
- package/dist/ui/select.js +0 -2
- package/dist/ui/server.d.ts +0 -2
- package/dist/ui/server.d.ts.map +0 -1
- package/dist/ui/tabs/primitives.d.ts +0 -2
- package/dist/ui/tabs/primitives.d.ts.map +0 -1
- package/dist/ui/tabs/primitives.js +0 -2
- package/dist/ui/tabs.d.ts +0 -2
- package/dist/ui/tabs.d.ts.map +0 -1
- package/dist/ui/test.d.ts +0 -2
- package/dist/ui/test.d.ts.map +0 -1
- package/dist/ui/toggle/primitives.d.ts +0 -2
- package/dist/ui/toggle/primitives.d.ts.map +0 -1
- package/dist/ui/toggle/primitives.js +0 -2
- package/dist/ui/toggle.d.ts +0 -3
- package/dist/ui/toggle.d.ts.map +0 -1
- package/dist/ui/toggle.js +0 -3
- package/dist/ui-hmr/assets.d.ts +0 -2
- package/dist/ui-hmr/assets.d.ts.map +0 -1
- package/dist/ui-hmr/node.d.ts +0 -3
- package/dist/ui-hmr/node.d.ts.map +0 -1
- package/dist/ui-hmr/runtime/browser.d.ts +0 -2
- package/dist/ui-hmr/runtime/browser.d.ts.map +0 -1
- package/dist/ui-hmr/runtime/server.d.ts +0 -2
- package/dist/ui-hmr/runtime/server.d.ts.map +0 -1
- package/dist/ui-hmr.d.ts +0 -2
- package/dist/ui-hmr.d.ts.map +0 -1
- package/dist/ui.d.ts +0 -2
- package/dist/ui.d.ts.map +0 -1
- package/dist/ui.js +0 -2
- package/src/ui/accordion/README.md +0 -202
- package/src/ui/accordion/primitives.ts +0 -2
- package/src/ui/accordion.ts +0 -2
- package/src/ui/anchor/README.md +0 -196
- package/src/ui/anchor.ts +0 -2
- package/src/ui/animation/README.md +0 -318
- package/src/ui/animation.ts +0 -2
- package/src/ui/breadcrumbs/README.md +0 -55
- package/src/ui/breadcrumbs.ts +0 -2
- package/src/ui/button/README.md +0 -44
- package/src/ui/button.ts +0 -3
- package/src/ui/checkbox/README.md +0 -59
- package/src/ui/checkbox.ts +0 -3
- package/src/ui/combobox/README.md +0 -194
- package/src/ui/combobox/primitives.ts +0 -2
- package/src/ui/combobox.ts +0 -2
- package/src/ui/input/README.md +0 -52
- package/src/ui/input.ts +0 -3
- package/src/ui/listbox/README.md +0 -83
- package/src/ui/listbox.ts +0 -2
- package/src/ui/menu/README.md +0 -161
- package/src/ui/menu/primitives.ts +0 -2
- package/src/ui/menu.ts +0 -2
- package/src/ui/popover/README.md +0 -103
- package/src/ui/popover.ts +0 -2
- package/src/ui/radio/README.md +0 -53
- package/src/ui/radio.ts +0 -3
- package/src/ui/select/README.md +0 -117
- package/src/ui/select/primitives.ts +0 -2
- package/src/ui/select.ts +0 -2
- package/src/ui/tabs/README.md +0 -141
- package/src/ui/tabs/primitives.ts +0 -2
- package/src/ui/tabs.ts +0 -2
- package/src/ui/toggle/README.md +0 -56
- package/src/ui/toggle/primitives.ts +0 -2
- package/src/ui/toggle.ts +0 -3
- package/src/ui-hmr.ts +0 -2
- package/src/ui.ts +0 -2
|
@@ -68,8 +68,8 @@ export default createController(routes.albums, {
|
|
|
68
68
|
Now the page can render that route with `Frame`:
|
|
69
69
|
|
|
70
70
|
```tsx filename=app/actions/albums/show-page.tsx
|
|
71
|
-
import { Frame } from "remix/
|
|
72
|
-
import type { Handle } from "remix/
|
|
71
|
+
import { Frame } from "remix/component";
|
|
72
|
+
import type { Handle } from "remix/component";
|
|
73
73
|
|
|
74
74
|
import { routes } from "../../routes.ts";
|
|
75
75
|
import { Document } from "../document.tsx";
|
|
@@ -148,7 +148,7 @@ response type. Normal HTML actions should use the standard `render()` middleware
|
|
|
148
148
|
continue, such as an email preview or a small embedded fragment:
|
|
149
149
|
|
|
150
150
|
```tsx
|
|
151
|
-
import { renderToString } from "remix/
|
|
151
|
+
import { renderToString } from "remix/component/server";
|
|
152
152
|
|
|
153
153
|
// After loading recommendations:
|
|
154
154
|
let html = await renderToString(<AlbumRecommendations albums={recommendations} />);
|
|
@@ -160,62 +160,19 @@ frames with fallbacks arrive after the initial HTML.
|
|
|
160
160
|
## Resolve frames in the browser
|
|
161
161
|
|
|
162
162
|
A blocking frame resolves before the browser receives the page. A frame with a fallback may still
|
|
163
|
-
be pending, and any frame can reload later.
|
|
164
|
-
|
|
163
|
+
be pending, and any frame can reload later. The `run()` call in `app/actions/public/entry.ts` already
|
|
164
|
+
provides a default browser resolver, so these requests need no additional configuration.
|
|
165
165
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
166
|
+
The default resolver fetches same-origin HTML, follows redirects, preserves form submission methods
|
|
167
|
+
and encoding, and cancels requests when a frame is removed or its request is superseded. It also
|
|
168
|
+
keeps the redirect destination available so navigation can update the browser URL after a form saves.
|
|
169
169
|
|
|
170
|
-
|
|
170
|
+
If your app needs different request or response handling, you can provide your own `resolveFrame`
|
|
171
|
+
function in the `run()` options. The [`remix/component` API overview](../src/component/README.md)
|
|
172
|
+
covers the callback's arguments and return values.
|
|
171
173
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
async resolveFrame(src, options) {
|
|
176
|
-
let headers = new Headers({ Accept: "text/html", "X-Remix-Frame": "true" });
|
|
177
|
-
if (options?.target) headers.set("X-Remix-Target", options.target);
|
|
178
|
-
|
|
179
|
-
let response = await fetch(src, {
|
|
180
|
-
body: getRequestBody(options),
|
|
181
|
-
credentials: "same-origin",
|
|
182
|
-
headers,
|
|
183
|
-
method: options?.method,
|
|
184
|
-
mode: "same-origin",
|
|
185
|
-
signal: options?.signal,
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
if (!response.ok) {
|
|
189
|
-
throw new Error(`Frame request failed with status ${response.status}`);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
return response.body ?? response.text();
|
|
193
|
-
},
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
function getRequestBody(options?: ResolveFrameOptions): BodyInit | undefined {
|
|
197
|
-
let formData = options?.formData;
|
|
198
|
-
if (!formData) return;
|
|
199
|
-
if (options.encType !== "application/x-www-form-urlencoded") return formData;
|
|
200
|
-
|
|
201
|
-
let body = new URLSearchParams();
|
|
202
|
-
for (let [name, value] of formData) {
|
|
203
|
-
body.append(name, typeof value === "string" ? value : value.name);
|
|
204
|
-
}
|
|
205
|
-
return body;
|
|
206
|
-
}
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
The default resolver only makes same-origin requests, including redirects. This custom resolver
|
|
210
|
-
keeps that restriction with `mode: "same-origin"`; omit it only when the application explicitly
|
|
211
|
-
trusts a cross-origin source. Remix does not sanitize returned HTML before reconciling it into the
|
|
212
|
-
current document, and same-origin user-generated HTML is not implicitly safe. Sanitize untrusted
|
|
213
|
-
content before returning it.
|
|
214
|
-
|
|
215
|
-
Pass `options.signal` to `fetch()` instead of letting a removed or superseded frame request
|
|
216
|
-
continue. GET forms already include their values in `src`. For non-GET forms, the resolver receives
|
|
217
|
-
the browser's `FormData`, method, and encoding. This example preserves URL-encoded and multipart
|
|
218
|
-
form bodies; the resolver remains the place to apply other encoding or `_method` conventions.
|
|
174
|
+
Remix does not sanitize returned HTML before reconciling it into the current document, and
|
|
175
|
+
same-origin user-generated HTML is not implicitly safe. Sanitize untrusted content before returning it.
|
|
219
176
|
|
|
220
177
|
## Name and reload frames {#frames-and-partial-server-rendered-ui}
|
|
221
178
|
|
|
@@ -245,9 +202,8 @@ setup state and receive current server props.
|
|
|
245
202
|
|
|
246
203
|
## Navigate a frame with a form
|
|
247
204
|
|
|
248
|
-
Once `run(
|
|
249
|
-
|
|
250
|
-
handler:
|
|
205
|
+
Once `run()` starts, an eligible same-origin form follows the same frame navigation path as a link.
|
|
206
|
+
This GET form reloads the recommendations frame without a client entry or submit handler:
|
|
251
207
|
|
|
252
208
|
```tsx
|
|
253
209
|
<form
|
|
@@ -265,11 +221,12 @@ frame, `data-rmx-src` can provide a different request URL for that named frame,
|
|
|
265
221
|
`data-rmx-reset-scroll="false"` preserves the current scroll position, and `data-rmx-document` opts out of
|
|
266
222
|
interception. `data-rmx-history="push|replace"` controls how the navigation updates history.
|
|
267
223
|
|
|
268
|
-
GET controls are already encoded in the destination URL. For non-GET forms,
|
|
269
|
-
|
|
270
|
-
receives a frame request, while keeping its normal document response or redirect for
|
|
271
|
-
submissions. Non-GET submissions to the current URL replace that history entry; GET
|
|
272
|
-
submissions to a different URL push one. The `data-rmx-history` attribute overrides
|
|
224
|
+
GET controls are already encoded in the destination URL. For non-GET forms, the default resolver
|
|
225
|
+
sends the form's body with its method and encoding. The action should return HTML for the targeted
|
|
226
|
+
frame when it receives a frame request, while keeping its normal document response or redirect for
|
|
227
|
+
unenhanced submissions. Non-GET submissions to the current URL replace that history entry; GET
|
|
228
|
+
submissions and submissions to a different URL push one. The `data-rmx-history` attribute overrides
|
|
229
|
+
those defaults.
|
|
273
230
|
|
|
274
231
|
## Coordinate a mutation and a separate frame reload {#coordinating-forms-fetches-frame-reloads-and-navigation}
|
|
275
232
|
|
|
@@ -277,7 +234,7 @@ Start with a form whose action works without browser JavaScript. A client entry
|
|
|
277
234
|
same submission, send its `FormData`, and reload a different route after the action succeeds:
|
|
278
235
|
|
|
279
236
|
```tsx
|
|
280
|
-
import { on } from "remix/
|
|
237
|
+
import { on } from "remix/component";
|
|
281
238
|
|
|
282
239
|
// Inside a client-entry component's render function:
|
|
283
240
|
<form
|
|
@@ -308,7 +265,7 @@ import { on } from "remix/ui";
|
|
|
308
265
|
|
|
309
266
|
This custom handler is useful because the mutation response and recommendations frame are two
|
|
310
267
|
different requests. When the form action itself returns the HTML that belongs in the target frame,
|
|
311
|
-
prefer `data-rmx-target` and let the runtime submit it
|
|
268
|
+
prefer `data-rmx-target` and let the runtime submit it.
|
|
312
269
|
|
|
313
270
|
The handler above keeps the mutation in its existing action and the recommendations HTML in its
|
|
314
271
|
existing `GET` action. The browser component coordinates the two requests without duplicating either
|
|
@@ -345,15 +302,16 @@ Add `data-rmx-history="replace"` when it should replace the current history entr
|
|
|
345
302
|
|
|
346
303
|
## Handle failures and cancellation
|
|
347
304
|
|
|
348
|
-
The server renderer's `onError` and the browser app's `error` event are reporting hooks. The
|
|
349
|
-
|
|
350
|
-
|
|
305
|
+
The server renderer's `onError` and the browser app's `error` event are reporting hooks. The default
|
|
306
|
+
browser resolver renders HTML validation responses such as `400`, but reports server errors (`500`
|
|
307
|
+
and above) and non-HTML error responses through the browser app's `error` event.
|
|
351
308
|
|
|
352
309
|
If a deferred frame fails after its fallback has been sent, the server cannot replace the whole page
|
|
353
310
|
with a new error response. Keep the fallback useful, report the error, and let the surrounding page
|
|
354
311
|
continue when that is safe.
|
|
355
312
|
|
|
356
|
-
Pass `request.signal` through server frame work
|
|
313
|
+
Pass `request.signal` through server frame work. The default browser resolver forwards its cancellation
|
|
314
|
+
signal to `fetch()`; a custom resolver should do the same.
|
|
357
315
|
[Errors and Cancellation](/errors-and-cancellation/) covers reporting policy, while
|
|
358
316
|
[Production](/production/) covers disconnects, compression, and other deployment concerns.
|
|
359
317
|
|
package/guides/07-animation.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Animation
|
|
3
|
-
description: The CSS-first animation model and Remix
|
|
3
|
+
description: The CSS-first animation model and Remix component helpers for motion that respects rendering state.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
## CSS-first visual states {#css-first-visual-states}
|
|
@@ -8,8 +8,8 @@ description: The CSS-first animation model and Remix UI helpers for motion that
|
|
|
8
8
|
Start with CSS when the browser already owns the state. Hover, focus, active, checked, open, selected, and reduced-motion states do not need JavaScript state unless your render output also depends on them.
|
|
9
9
|
|
|
10
10
|
```tsx filename=app/ui/pressable-card.tsx
|
|
11
|
-
import { css } from "remix/
|
|
12
|
-
import type { Handle, RemixNode } from "remix/
|
|
11
|
+
import { css } from "remix/component";
|
|
12
|
+
import type { Handle, RemixNode } from "remix/component";
|
|
13
13
|
|
|
14
14
|
export function PressableCard(handle: Handle<{ children: RemixNode }>) {
|
|
15
15
|
return () => (
|
|
@@ -42,10 +42,16 @@ const cardStyle = css({
|
|
|
42
42
|
|
|
43
43
|
Use Remix animation helpers when the motion depends on rendering state: a node enters, a node exits, a keyed item moves, or an event needs an interruptible animation.
|
|
44
44
|
|
|
45
|
+
The animation helpers are provided by `@remix-run/ui`. This package is currently unstable and versioned independently. It is not available through the `remix` package, so install it separately:
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
npm i remix @remix-run/ui
|
|
49
|
+
```
|
|
50
|
+
|
|
45
51
|
```tsx
|
|
46
|
-
import { createMixin, css, on } from "remix/
|
|
47
|
-
import type { Handle } from "remix/
|
|
48
|
-
import { spring } from "remix/ui/animation";
|
|
52
|
+
import { createMixin, css, on } from "remix/component";
|
|
53
|
+
import type { Handle } from "remix/component";
|
|
54
|
+
import { spring } from "@remix-run/ui/animation";
|
|
49
55
|
|
|
50
56
|
export function PressStateDemo(handle: Handle) {
|
|
51
57
|
let pressed = false;
|
|
@@ -123,9 +129,9 @@ const pressableStyles = css({
|
|
|
123
129
|
`animateEntrance(...)` runs when a host node is inserted. `animateExit(...)` lets a removed node stay in the DOM until its exit animation finishes.
|
|
124
130
|
|
|
125
131
|
```tsx filename=app/ui/public/notice.tsx
|
|
126
|
-
import { clientEntry, css, on } from "remix/
|
|
127
|
-
import { animateEntrance, animateExit, spring } from "remix/ui/animation";
|
|
128
|
-
import type { Handle } from "remix/
|
|
132
|
+
import { clientEntry, css, on } from "remix/component";
|
|
133
|
+
import { animateEntrance, animateExit, spring } from "@remix-run/ui/animation";
|
|
134
|
+
import type { Handle } from "remix/component";
|
|
129
135
|
|
|
130
136
|
export const Notice = clientEntry(import.meta.url, function Notice(handle: Handle) {
|
|
131
137
|
let visible = true;
|
|
@@ -180,9 +186,9 @@ Keep keys stable when toggling between related elements. A stable key tells Remi
|
|
|
180
186
|
Pass `true` for the default opacity animation or `false` to disable a mixin without changing the surrounding `mix` array. `animateEntrance({ initial: false })` skips the first insertion for a key but still animates later insertions. If the same keyed element returns before its exit finishes, Remix reclaims that DOM node and animates it back toward its rendered styles.
|
|
181
187
|
|
|
182
188
|
```tsx
|
|
183
|
-
import { css, on } from "remix/
|
|
184
|
-
import type { Handle } from "remix/
|
|
185
|
-
import { animateEntrance, animateExit, spring } from "remix/ui/animation";
|
|
189
|
+
import { css, on } from "remix/component";
|
|
190
|
+
import type { Handle } from "remix/component";
|
|
191
|
+
import { animateEntrance, animateExit, spring } from "@remix-run/ui/animation";
|
|
186
192
|
|
|
187
193
|
export function NoticePresenceDemo(handle: Handle) {
|
|
188
194
|
let visible = true;
|
|
@@ -257,9 +263,9 @@ const noticeStyles = css({
|
|
|
257
263
|
`animateLayout(...)` measures a host node before and after a render, then animates the visual delta. This is the right tool for sorted lists, expanding cards, and elements that move because layout changed.
|
|
258
264
|
|
|
259
265
|
```tsx filename=app/ui/public/reorder-list.tsx
|
|
260
|
-
import { clientEntry, css, on } from "remix/
|
|
261
|
-
import { animateLayout, spring } from "remix/ui/animation";
|
|
262
|
-
import type { Handle } from "remix/
|
|
266
|
+
import { clientEntry, css, on } from "remix/component";
|
|
267
|
+
import { animateLayout, spring } from "@remix-run/ui/animation";
|
|
268
|
+
import type { Handle } from "remix/component";
|
|
263
269
|
|
|
264
270
|
const initialItems = ["Design", "Build", "Review"];
|
|
265
271
|
|
|
@@ -309,9 +315,9 @@ const itemStyle = css({
|
|
|
309
315
|
Layout animation includes size projection by default. Pass `size: false` when only position should animate and scaling the element's contents would look wrong.
|
|
310
316
|
|
|
311
317
|
```tsx
|
|
312
|
-
import { css } from "remix/
|
|
313
|
-
import type { Handle } from "remix/
|
|
314
|
-
import { animateLayout, spring } from "remix/ui/animation";
|
|
318
|
+
import { css } from "remix/component";
|
|
319
|
+
import type { Handle } from "remix/component";
|
|
320
|
+
import { animateLayout, spring } from "@remix-run/ui/animation";
|
|
315
321
|
|
|
316
322
|
export function ReorderingDemo(handle: Handle) {
|
|
317
323
|
let order = initialOrder;
|
|
@@ -388,9 +394,9 @@ const itemStyles = css({
|
|
|
388
394
|
`spring()` returns an iterator decorated for CSS transitions and Web Animations. Stringify it in CSS, spread it into animation options, or iterate it for custom JavaScript animation.
|
|
389
395
|
|
|
390
396
|
```tsx filename=app/ui/public/bouncy-switch.tsx
|
|
391
|
-
import { clientEntry, css, on } from "remix/
|
|
392
|
-
import { spring } from "remix/ui/animation";
|
|
393
|
-
import type { Handle } from "remix/
|
|
397
|
+
import { clientEntry, css, on } from "remix/component";
|
|
398
|
+
import { spring } from "@remix-run/ui/animation";
|
|
399
|
+
import type { Handle } from "remix/component";
|
|
394
400
|
|
|
395
401
|
export const BouncySwitch = clientEntry(import.meta.url, function BouncySwitch(handle: Handle) {
|
|
396
402
|
let enabled = true;
|
|
@@ -439,7 +445,7 @@ const thumbStyle = css({
|
|
|
439
445
|
Use `tween(...)` when you need a time-based value loop rather than CSS or WAAPI timing.
|
|
440
446
|
|
|
441
447
|
```ts filename=app/ui/public/count-up.ts
|
|
442
|
-
import { easings, tween } from "remix/ui/animation";
|
|
448
|
+
import { easings, tween } from "@remix-run/ui/animation";
|
|
443
449
|
|
|
444
450
|
export function countUp(from: number, to: number, onValue: (value: number) => void) {
|
|
445
451
|
let animation = tween({ from, to, duration: 300, curve: easings.easeOut });
|
|
@@ -461,10 +467,10 @@ export function countUp(from: number, to: number, onValue: (value: number) => vo
|
|
|
461
467
|
Prefer CSS transitions and animation mixins for ordinary UI. Use `tween` for canvas, custom counters, or values that are not CSS properties.
|
|
462
468
|
|
|
463
469
|
```tsx
|
|
464
|
-
import { css, on, ref } from "remix/
|
|
465
|
-
import type { Handle } from "remix/
|
|
466
|
-
import { spring } from "remix/ui/animation";
|
|
467
|
-
import type { SpringPreset } from "remix/ui/animation";
|
|
470
|
+
import { css, on, ref } from "remix/component";
|
|
471
|
+
import type { Handle } from "remix/component";
|
|
472
|
+
import { spring } from "@remix-run/ui/animation";
|
|
473
|
+
import type { SpringPreset } from "@remix-run/ui/animation";
|
|
468
474
|
|
|
469
475
|
import { dragVelocityEvents } from "./gallery/drag-release.ts";
|
|
470
476
|
|
|
@@ -681,9 +687,9 @@ const hintStyle = css({
|
|
|
681
687
|
```
|
|
682
688
|
|
|
683
689
|
```tsx
|
|
684
|
-
import { css, on } from "remix/
|
|
685
|
-
import type { Handle } from "remix/
|
|
686
|
-
import { spring } from "remix/ui/animation";
|
|
690
|
+
import { css, on } from "remix/component";
|
|
691
|
+
import type { Handle } from "remix/component";
|
|
692
|
+
import { spring } from "@remix-run/ui/animation";
|
|
687
693
|
|
|
688
694
|
export function BouncySwitchDemo(handle: Handle) {
|
|
689
695
|
let isOn = true;
|
|
@@ -738,7 +744,7 @@ const thumbStyles = css({
|
|
|
738
744
|
The UI package also keeps a gallery of smaller motion experiments. Keep this kind of broad demo in a bounded frame so it does not take over the surrounding guide page.
|
|
739
745
|
|
|
740
746
|
```tsx
|
|
741
|
-
import { css, on, type Handle, type RemixNode } from "remix/
|
|
747
|
+
import { css, on, type Handle, type RemixNode } from "remix/component";
|
|
742
748
|
import { DefaultAnimate } from "./gallery/default-animate.tsx";
|
|
743
749
|
import { EnterAnimation } from "./gallery/enter.tsx";
|
|
744
750
|
import { ExitAnimation } from "./gallery/exit.tsx";
|
|
@@ -937,9 +943,9 @@ Event handlers receive abort signals, and animation mixins cancel or replace in-
|
|
|
937
943
|
For custom imperative animations, keep the current animation in setup scope and cancel it before starting the next one:
|
|
938
944
|
|
|
939
945
|
```tsx filename=app/ui/public/ripple-button.tsx
|
|
940
|
-
import { clientEntry, css, on, ref } from "remix/
|
|
941
|
-
import { spring } from "remix/ui/animation";
|
|
942
|
-
import type { Handle } from "remix/
|
|
946
|
+
import { clientEntry, css, on, ref } from "remix/component";
|
|
947
|
+
import { spring } from "@remix-run/ui/animation";
|
|
948
|
+
import type { Handle } from "remix/component";
|
|
943
949
|
|
|
944
950
|
export const RippleButton = clientEntry(import.meta.url, function RippleButton(_handle: Handle) {
|
|
945
951
|
let node: HTMLButtonElement;
|
|
@@ -984,8 +990,8 @@ CSS transitions are also interruptible: changing the target value while a transi
|
|
|
984
990
|
Respect `prefers-reduced-motion` at the CSS boundary first. It works before JavaScript loads, applies to server-rendered frames, and covers static transitions.
|
|
985
991
|
|
|
986
992
|
```tsx filename=app/ui/motion-safe-panel.tsx
|
|
987
|
-
import { css } from "remix/
|
|
988
|
-
import type { Handle, RemixNode } from "remix/
|
|
993
|
+
import { css } from "remix/component";
|
|
994
|
+
import type { Handle, RemixNode } from "remix/component";
|
|
989
995
|
|
|
990
996
|
export function MotionSafePanel(handle: Handle<{ children: RemixNode }>) {
|
|
991
997
|
return () => <section mix={panelStyle}>{handle.props.children}</section>;
|