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
|
@@ -1,318 +0,0 @@
|
|
|
1
|
-
# animation
|
|
2
|
-
|
|
3
|
-
`animation` provides small primitives for entrance, exit, layout, spring, and tween animation. Use these helpers with Remix UI mixins, CSS transitions, the Web Animations API, and imperative `requestAnimationFrame` loops.
|
|
4
|
-
|
|
5
|
-
## Usage
|
|
6
|
-
|
|
7
|
-
```tsx
|
|
8
|
-
import { animateEntrance, animateExit, animateLayout, spring } from 'remix/ui/animation'
|
|
9
|
-
|
|
10
|
-
let panelTransition = spring.transition(['opacity', 'transform'], 'snappy')
|
|
11
|
-
|
|
12
|
-
function Panel() {
|
|
13
|
-
return () => (
|
|
14
|
-
<div
|
|
15
|
-
style={{ transition: panelTransition }}
|
|
16
|
-
mix={[
|
|
17
|
-
animateEntrance({ opacity: 0, duration: 120 }),
|
|
18
|
-
animateExit({ opacity: 0, duration: 120 }),
|
|
19
|
-
animateLayout(),
|
|
20
|
-
]}
|
|
21
|
-
>
|
|
22
|
-
Saved filters
|
|
23
|
-
</div>
|
|
24
|
-
)
|
|
25
|
-
}
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Entrance And Exit
|
|
29
|
-
|
|
30
|
-
`animateEntrance` animates an element from the provided keyframe into its natural styles when the element is inserted.
|
|
31
|
-
|
|
32
|
-
```tsx
|
|
33
|
-
import { animateEntrance, spring } from 'remix/ui/animation'
|
|
34
|
-
|
|
35
|
-
function Toast() {
|
|
36
|
-
return () => (
|
|
37
|
-
<div
|
|
38
|
-
mix={[
|
|
39
|
-
animateEntrance({
|
|
40
|
-
opacity: 0,
|
|
41
|
-
transform: 'translateY(8px)',
|
|
42
|
-
...spring('snappy'),
|
|
43
|
-
}),
|
|
44
|
-
]}
|
|
45
|
-
>
|
|
46
|
-
Saved
|
|
47
|
-
</div>
|
|
48
|
-
)
|
|
49
|
-
}
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
`animateExit` keeps a removed keyed element in the DOM long enough to animate from its natural styles to the provided keyframe.
|
|
53
|
-
|
|
54
|
-
```tsx
|
|
55
|
-
import type { Handle } from 'remix/ui'
|
|
56
|
-
import { animateExit } from 'remix/ui/animation'
|
|
57
|
-
|
|
58
|
-
function Item(handle: Handle<{ id: string; label: string }>) {
|
|
59
|
-
return () => (
|
|
60
|
-
<li
|
|
61
|
-
key={handle.props.id}
|
|
62
|
-
mix={[
|
|
63
|
-
animateExit({
|
|
64
|
-
opacity: 0,
|
|
65
|
-
transform: 'scale(0.96)',
|
|
66
|
-
duration: 120,
|
|
67
|
-
easing: 'ease-in',
|
|
68
|
-
}),
|
|
69
|
-
]}
|
|
70
|
-
>
|
|
71
|
-
{handle.props.label}
|
|
72
|
-
</li>
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
Passing `true` uses the default opacity animation. Passing `false`, `null`, or `undefined` disables the animation.
|
|
78
|
-
|
|
79
|
-
```tsx
|
|
80
|
-
<div mix={[animateEntrance(true), animateExit(false)]} />
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
Animation configs combine WAAPI timing options with style properties for the animated keyframe.
|
|
84
|
-
|
|
85
|
-
```ts
|
|
86
|
-
type AnimateMixinConfig = {
|
|
87
|
-
duration: number
|
|
88
|
-
easing?: string
|
|
89
|
-
delay?: number
|
|
90
|
-
composite?: CompositeOperation
|
|
91
|
-
initial?: boolean
|
|
92
|
-
[property: string]: unknown
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
Pass `initial: false` to skip only the first keyed entrance for an element within a parent. Later insertions for the same key can still animate.
|
|
97
|
-
|
|
98
|
-
```tsx
|
|
99
|
-
<div key={id} mix={[animateEntrance({ opacity: 0, duration: 150, initial: false })]} />
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
Exit animations can reclaim a removed keyed node if the same keyed element is rendered again before the exit finishes. The reclaimed node retargets toward its natural styles instead of simply reversing the exit animation.
|
|
103
|
-
|
|
104
|
-
For custom teardown, `createMixin` exposes `event.persistNode(callback)` in its `beforeRemove` event. It keeps the host in the DOM until the callback settles and supplies an abort signal for cancellation when a keyed node is reclaimed. See [Deferring removal](https://github.com/remix-run/remix/blob/main/packages/ui/docs/mixins.md#deferring-removal-with-persistnode) for a complete example and lifecycle ordering.
|
|
105
|
-
|
|
106
|
-
## Layout Animation
|
|
107
|
-
|
|
108
|
-
`animateLayout` animates layout changes with a FLIP-style transform projection. Use it on elements whose position or size can change between renders.
|
|
109
|
-
|
|
110
|
-
```tsx
|
|
111
|
-
import type { Handle } from 'remix/ui'
|
|
112
|
-
import { animateLayout, spring } from 'remix/ui/animation'
|
|
113
|
-
|
|
114
|
-
function Card(handle: Handle<{ expanded: boolean }>) {
|
|
115
|
-
return () => (
|
|
116
|
-
<section
|
|
117
|
-
class={handle.props.expanded ? 'card expanded' : 'card'}
|
|
118
|
-
mix={[
|
|
119
|
-
animateLayout({
|
|
120
|
-
...spring('smooth'),
|
|
121
|
-
}),
|
|
122
|
-
]}
|
|
123
|
-
>
|
|
124
|
-
Details
|
|
125
|
-
</section>
|
|
126
|
-
)
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
Pass `size: false` when the element should animate position only and avoid scale projection.
|
|
131
|
-
|
|
132
|
-
```tsx
|
|
133
|
-
<div mix={[animateLayout({ duration: 180, easing: 'ease-out', size: false })]} />
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
Passing `true` or no argument enables the default layout animation. Passing `false`, `null`, or `undefined` disables it. Layout animation skips work when geometry does not change, keeps in-flight animations running when their target geometry has not changed, and continues from the current visual transform when a new layout change interrupts an active animation.
|
|
137
|
-
|
|
138
|
-
## Spring
|
|
139
|
-
|
|
140
|
-
`spring` returns a decorated iterator. It can be iterated for JavaScript animation, spread into Web Animations API options, or stringified for CSS transition syntax.
|
|
141
|
-
|
|
142
|
-
```tsx
|
|
143
|
-
import { spring } from 'remix/ui/animation'
|
|
144
|
-
|
|
145
|
-
spring('bouncy')
|
|
146
|
-
spring('snappy')
|
|
147
|
-
spring('smooth')
|
|
148
|
-
spring({ duration: 400, bounce: 0.3 })
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
```ts
|
|
152
|
-
interface SpringIterator extends IterableIterator<number> {
|
|
153
|
-
duration: number
|
|
154
|
-
easing: string
|
|
155
|
-
toString(): string
|
|
156
|
-
}
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
Use `spring.transition` to build CSS transition entries.
|
|
160
|
-
|
|
161
|
-
```tsx
|
|
162
|
-
let transition = spring.transition(['opacity', 'transform'], 'bouncy')
|
|
163
|
-
|
|
164
|
-
function Button() {
|
|
165
|
-
return () => <button style={{ transition }}>Save</button>
|
|
166
|
-
}
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
Spread a spring into animation mixin or WAAPI options.
|
|
170
|
-
|
|
171
|
-
```tsx
|
|
172
|
-
<div
|
|
173
|
-
mix={[
|
|
174
|
-
animateEntrance({
|
|
175
|
-
opacity: 0,
|
|
176
|
-
transform: 'scale(0.92)',
|
|
177
|
-
...spring('bouncy'),
|
|
178
|
-
}),
|
|
179
|
-
]}
|
|
180
|
-
/>
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
```ts
|
|
184
|
-
element.animate(
|
|
185
|
-
[
|
|
186
|
-
{ opacity: 0, transform: 'scale(0.92)' },
|
|
187
|
-
{ opacity: 1, transform: 'scale(1)' },
|
|
188
|
-
],
|
|
189
|
-
{ ...spring('snappy') },
|
|
190
|
-
)
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
Use the iterator values as progress from `0` to `1` for imperative animation.
|
|
194
|
-
|
|
195
|
-
```ts
|
|
196
|
-
let from = 0
|
|
197
|
-
let to = 200
|
|
198
|
-
|
|
199
|
-
for (let progress of spring('bouncy')) {
|
|
200
|
-
let x = from + (to - from) * progress
|
|
201
|
-
element.style.transform = `translateX(${x}px)`
|
|
202
|
-
await nextFrame()
|
|
203
|
-
}
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
The built-in presets are:
|
|
207
|
-
|
|
208
|
-
| Preset | Bounce | Duration | Character |
|
|
209
|
-
| -------- | ------ | -------- | ------------------------ |
|
|
210
|
-
| `smooth` | -0.3 | 400ms | Overdamped, no overshoot |
|
|
211
|
-
| `snappy` | 0 | 200ms | Quick, no overshoot |
|
|
212
|
-
| `bouncy` | 0.3 | 400ms | Underdamped bounce |
|
|
213
|
-
|
|
214
|
-
Override preset duration or velocity with the second argument.
|
|
215
|
-
|
|
216
|
-
```ts
|
|
217
|
-
spring('bouncy', { duration: 300 })
|
|
218
|
-
spring('snappy', { velocity: 2 })
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
Use explicit options when you need full control.
|
|
222
|
-
|
|
223
|
-
```ts
|
|
224
|
-
spring({
|
|
225
|
-
duration: 500,
|
|
226
|
-
bounce: 0.35,
|
|
227
|
-
velocity: 0,
|
|
228
|
-
})
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
## Tween
|
|
232
|
-
|
|
233
|
-
`tween` creates a generator that interpolates a numeric value over time with a cubic-bezier curve. Call `next()` once to initialize the generator, then pass `requestAnimationFrame` timestamps into `next(timestamp)`.
|
|
234
|
-
|
|
235
|
-
```ts
|
|
236
|
-
import { easings, tween } from 'remix/ui/animation'
|
|
237
|
-
|
|
238
|
-
let animation = tween({
|
|
239
|
-
from: 0,
|
|
240
|
-
to: 100,
|
|
241
|
-
duration: 300,
|
|
242
|
-
curve: easings.easeOut,
|
|
243
|
-
})
|
|
244
|
-
|
|
245
|
-
animation.next()
|
|
246
|
-
|
|
247
|
-
function tick(timestamp: number) {
|
|
248
|
-
let { value, done } = animation.next(timestamp)
|
|
249
|
-
element.style.transform = `translateX(${value}px)`
|
|
250
|
-
if (!done) requestAnimationFrame(tick)
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
requestAnimationFrame(tick)
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
Animate multiple values with separate tweens.
|
|
257
|
-
|
|
258
|
-
```ts
|
|
259
|
-
let xAnimation = tween({ from: 0, to: 100, duration: 500, curve: easings.easeOut })
|
|
260
|
-
let scaleAnimation = tween({ from: 1, to: 1.2, duration: 500, curve: easings.easeOut })
|
|
261
|
-
|
|
262
|
-
xAnimation.next()
|
|
263
|
-
scaleAnimation.next()
|
|
264
|
-
|
|
265
|
-
function tick(timestamp: number) {
|
|
266
|
-
let x = xAnimation.next(timestamp)
|
|
267
|
-
let scale = scaleAnimation.next(timestamp)
|
|
268
|
-
|
|
269
|
-
element.style.transform = `translateX(${x.value}px) scale(${scale.value})`
|
|
270
|
-
|
|
271
|
-
if (!x.done || !scale.done) {
|
|
272
|
-
requestAnimationFrame(tick)
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
The built-in easing presets are cubic-bezier control points matching common CSS timing functions.
|
|
278
|
-
|
|
279
|
-
```ts
|
|
280
|
-
easings.linear
|
|
281
|
-
easings.ease
|
|
282
|
-
easings.easeIn
|
|
283
|
-
easings.easeOut
|
|
284
|
-
easings.easeInOut
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
Custom curves use the same control points as CSS `cubic-bezier(x1, y1, x2, y2)`.
|
|
288
|
-
|
|
289
|
-
```ts
|
|
290
|
-
let animation = tween({
|
|
291
|
-
from: 0,
|
|
292
|
-
to: 100,
|
|
293
|
-
duration: 500,
|
|
294
|
-
curve: { x1: 0.68, y1: -0.55, x2: 0.265, y2: 1.55 },
|
|
295
|
-
})
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
## API
|
|
299
|
-
|
|
300
|
-
- `animateEntrance(config?)`: mixin that animates an element when it enters the DOM.
|
|
301
|
-
- `animateExit(config?)`: mixin that persists a removed keyed element long enough to run its exit animation.
|
|
302
|
-
- `animateLayout(config?)`: mixin that animates layout changes by comparing geometry between renders.
|
|
303
|
-
- `spring(preset?, overrides?)`: creates a `SpringIterator` from a named preset.
|
|
304
|
-
- `spring(options?)`: creates a `SpringIterator` from explicit spring options.
|
|
305
|
-
- `spring.transition(property, presetOrOptions?, overrides?)`: builds one or more CSS transition entries from a spring.
|
|
306
|
-
- `spring.presets`: named `smooth`, `snappy`, and `bouncy` spring defaults.
|
|
307
|
-
- `tween(options)`: generator that interpolates numeric values over time with a cubic-bezier curve.
|
|
308
|
-
- `easings`: common cubic-bezier presets for `tween`.
|
|
309
|
-
- `SpringIterator`, `SpringPreset`, `SpringOptions`, `TweenOptions`, and `BezierCurve`: public TypeScript types for spring and tween configuration.
|
|
310
|
-
|
|
311
|
-
## Behavior Notes
|
|
312
|
-
|
|
313
|
-
- Animation mixin style properties are copied into WAAPI keyframes; `duration`, `easing`, `delay`, `composite`, and `initial` are treated as options.
|
|
314
|
-
- `animateEntrance({ initial: false })` only skips the first keyed entrance tracked for the parent node.
|
|
315
|
-
- `animateExit` needs keyed elements when removed nodes may be reclaimed or persisted across list updates.
|
|
316
|
-
- `animateLayout({ size: false })` animates translation without scale projection.
|
|
317
|
-
- `spring()` yields progress values from `0` to `1`; its `duration` and `easing` properties are enumerable so `{ ...spring() }` works with WAAPI options.
|
|
318
|
-
- `tween(...)` yields the initial value first; advance the generator with frame timestamps via `next(timestamp)` and read `done` to detect completion.
|
package/src/ui/animation.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# breadcrumbs
|
|
2
|
-
|
|
3
|
-
`Breadcrumbs` renders semantic breadcrumb navigation from a list of items. Use it when the page needs a compact path back through parent sections.
|
|
4
|
-
|
|
5
|
-
## Component Usage
|
|
6
|
-
|
|
7
|
-
```tsx
|
|
8
|
-
import { Breadcrumbs } from 'remix/ui/breadcrumbs'
|
|
9
|
-
|
|
10
|
-
export function ProjectBreadcrumbs() {
|
|
11
|
-
return (
|
|
12
|
-
<Breadcrumbs
|
|
13
|
-
items={[
|
|
14
|
-
{ href: '/', label: 'Home' },
|
|
15
|
-
{ href: '/projects', label: 'Projects' },
|
|
16
|
-
{ label: 'Roadmap' },
|
|
17
|
-
]}
|
|
18
|
-
/>
|
|
19
|
-
)
|
|
20
|
-
}
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Mark an earlier item as current when the page belongs to a parent section but the final crumb is still useful context. The current item always renders as text with `aria-current="page"`.
|
|
24
|
-
|
|
25
|
-
```tsx
|
|
26
|
-
<Breadcrumbs
|
|
27
|
-
items={[
|
|
28
|
-
{ href: '/', label: 'Home' },
|
|
29
|
-
{ current: true, href: '/components', label: 'Components' },
|
|
30
|
-
{ label: 'Breadcrumbs' },
|
|
31
|
-
]}
|
|
32
|
-
/>
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
Pass `separator` to replace the default chevron icon.
|
|
36
|
-
|
|
37
|
-
```tsx
|
|
38
|
-
<Breadcrumbs items={[{ href: '/', label: 'Home' }, { label: 'Breadcrumbs' }]} separator="/" />
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## `remix/ui/breadcrumbs`
|
|
42
|
-
|
|
43
|
-
- `Breadcrumbs`: component that renders a `<nav>` with an ordered list of breadcrumb items.
|
|
44
|
-
- `BreadcrumbItem`: item shape with `label`, optional `href`, and optional `current`.
|
|
45
|
-
- `BreadcrumbsProps`: nav props plus required `items` and optional `separator`.
|
|
46
|
-
|
|
47
|
-
## Behavior Notes
|
|
48
|
-
|
|
49
|
-
- The default `aria-label` is `"Breadcrumb"` unless an `aria-label` prop is provided.
|
|
50
|
-
- Breadcrumb items render inside an ordered list.
|
|
51
|
-
- The last item is treated as current when no item has `current: true`.
|
|
52
|
-
- An explicit current item wins over the last-item default.
|
|
53
|
-
- Current items render as text with `aria-current="page"`, even when they include `href`.
|
|
54
|
-
- Non-current items with `href` render as links; non-current items without `href` render as text.
|
|
55
|
-
- The default separator is a chevron icon. Separators render between items and are hidden from assistive technology.
|
package/src/ui/breadcrumbs.ts
DELETED
package/src/ui/button/README.md
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# button
|
|
2
|
-
|
|
3
|
-
`button` is a style mixin for pill-shaped action controls. It owns only button-like visual styling and the default `type="button"` behavior for native `<button>` hosts.
|
|
4
|
-
|
|
5
|
-
## Primitive Usage
|
|
6
|
-
|
|
7
|
-
```tsx
|
|
8
|
-
import button from 'remix/ui/button'
|
|
9
|
-
|
|
10
|
-
function Actions() {
|
|
11
|
-
return () => (
|
|
12
|
-
<div>
|
|
13
|
-
<button mix={button()}>Edit order</button>
|
|
14
|
-
<button mix={button({ size: 'lg', tone: 'primary' })}>Add product</button>
|
|
15
|
-
<button mix={button({ tone: 'ghost' })}>Cancel</button>
|
|
16
|
-
</div>
|
|
17
|
-
)
|
|
18
|
-
}
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
Compose app-owned styles around the primitive when a control needs local layout or state styling:
|
|
22
|
-
|
|
23
|
-
```tsx
|
|
24
|
-
import button from 'remix/ui/button'
|
|
25
|
-
import { toolbarButtonStyle } from './toolbar.styles'
|
|
26
|
-
|
|
27
|
-
function ToolbarAction() {
|
|
28
|
-
return () => <button mix={[toolbarButtonStyle, button({ tone: 'ghost' })]}>Archive</button>
|
|
29
|
-
}
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## `remix/ui/button`
|
|
33
|
-
|
|
34
|
-
- `button(options)`: style mixin for native buttons or button-like hosts.
|
|
35
|
-
- `ButtonOptions`: accepts `size` and `tone`.
|
|
36
|
-
- `ButtonSize`: `'md'` or `'lg'`. Defaults to `'md'`.
|
|
37
|
-
- `ButtonTone`: `'neutral'`, `'primary'`, or `'ghost'`. Defaults to `'neutral'`.
|
|
38
|
-
|
|
39
|
-
## Behavior Notes
|
|
40
|
-
|
|
41
|
-
- `button()` returns a mixin descriptor, so it composes with other mixins in the host element's `mix` prop.
|
|
42
|
-
- Native `<button>` hosts receive `type="button"` unless an explicit `type` is provided.
|
|
43
|
-
- Non-button hosts receive styling only.
|
|
44
|
-
- Disabled hosts use the shared disabled treatment through `disabled` or `aria-disabled="true"`.
|
package/src/ui/button.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# checkbox
|
|
2
|
-
|
|
3
|
-
`checkbox` is a style mixin for native checkbox inputs. It only owns checkbox visuals, an optional visual state, and the default `type="checkbox"` behavior for native `<input>` hosts.
|
|
4
|
-
|
|
5
|
-
## Usage
|
|
6
|
-
|
|
7
|
-
```tsx
|
|
8
|
-
import checkbox from 'remix/ui/checkbox'
|
|
9
|
-
|
|
10
|
-
function VisibilityToggle() {
|
|
11
|
-
return () => (
|
|
12
|
-
<label>
|
|
13
|
-
<input defaultChecked mix={checkbox()} name="visibility" value="archived" />
|
|
14
|
-
Show archived items
|
|
15
|
-
</label>
|
|
16
|
-
)
|
|
17
|
-
}
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
Use `size: 'lg'` when the surrounding UI needs a larger visual control:
|
|
21
|
-
|
|
22
|
-
```tsx
|
|
23
|
-
<input mix={checkbox({ size: 'lg' })} />
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
For mixed state, app code owns the checkbox state and the native `indeterminate` property:
|
|
27
|
-
|
|
28
|
-
```tsx
|
|
29
|
-
import checkbox from 'remix/ui/checkbox'
|
|
30
|
-
|
|
31
|
-
function PermissionParent() {
|
|
32
|
-
let state: 'checked' | 'mixed' | 'unchecked' = 'mixed'
|
|
33
|
-
|
|
34
|
-
return () => (
|
|
35
|
-
<input
|
|
36
|
-
checked={state === 'checked'}
|
|
37
|
-
indeterminate={state === 'mixed'}
|
|
38
|
-
mix={checkbox({ state })}
|
|
39
|
-
/>
|
|
40
|
-
)
|
|
41
|
-
}
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## `remix/ui/checkbox`
|
|
45
|
-
|
|
46
|
-
- `checkbox(options)`: style mixin for native checkbox inputs or checkbox-like hosts.
|
|
47
|
-
- `CheckboxOptions`: accepts `size` and `state`.
|
|
48
|
-
- `CheckboxSize`: `'md'` or `'lg'`. Defaults to `'md'`.
|
|
49
|
-
- `CheckboxState`: `'checked'`, `'mixed'`, or `'unchecked'`.
|
|
50
|
-
|
|
51
|
-
## Behavior Notes
|
|
52
|
-
|
|
53
|
-
- `checkbox()` returns a mixin descriptor, so it composes with other mixins in the host element's `mix` prop.
|
|
54
|
-
- Native `<input>` hosts receive `type="checkbox"` unless an explicit `type` is provided.
|
|
55
|
-
- Native input state is browser-owned through `checked`, `defaultChecked`, and user interaction.
|
|
56
|
-
- The optional `state` option adds `aria-checked` and `data-state` for app-owned mixed state or custom hosts.
|
|
57
|
-
- Checked styles apply through `:checked`, `aria-checked="true"`, or `data-state="checked"`.
|
|
58
|
-
- Mixed styles apply through `:indeterminate`, `indeterminate`, `aria-checked="mixed"`, or `data-state="mixed"`.
|
|
59
|
-
- Disabled hosts use the shared disabled treatment through `disabled` or `aria-disabled="true"`.
|
package/src/ui/checkbox.ts
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
# combobox
|
|
2
|
-
|
|
3
|
-
`Combobox` is the input-first popup value picker for `remix/ui/combobox`.
|
|
4
|
-
|
|
5
|
-
Use it when the user should type draft text, filter a popup list, and still commit one stable form value. If you just need a button-triggered picker, use `Select` instead.
|
|
6
|
-
|
|
7
|
-
## Component Usage
|
|
8
|
-
|
|
9
|
-
```tsx
|
|
10
|
-
import { css, type Handle } from 'remix/ui'
|
|
11
|
-
import { Combobox, ComboboxOption } from 'remix/ui/combobox'
|
|
12
|
-
import { onComboboxChange } from 'remix/ui/combobox/primitives'
|
|
13
|
-
|
|
14
|
-
let airports = [
|
|
15
|
-
{
|
|
16
|
-
label: 'Los Angeles International',
|
|
17
|
-
searchValue: ['lax', 'los angeles', 'los angeles international'],
|
|
18
|
-
value: 'LAX',
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
label: 'John F. Kennedy International',
|
|
22
|
-
searchValue: ['jfk', 'new york', 'john f. kennedy international'],
|
|
23
|
-
value: 'JFK',
|
|
24
|
-
},
|
|
25
|
-
] as const
|
|
26
|
-
|
|
27
|
-
export default function AirportField(handle: Handle) {
|
|
28
|
-
let value: string | null = null
|
|
29
|
-
|
|
30
|
-
return () => (
|
|
31
|
-
<div mix={root}>
|
|
32
|
-
<Combobox
|
|
33
|
-
inputId="airport"
|
|
34
|
-
mix={onComboboxChange((event) => {
|
|
35
|
-
value = event.value
|
|
36
|
-
void handle.update()
|
|
37
|
-
})}
|
|
38
|
-
name="airport"
|
|
39
|
-
placeholder="Search airports or codes"
|
|
40
|
-
>
|
|
41
|
-
{airports.map((airport) => (
|
|
42
|
-
<ComboboxOption
|
|
43
|
-
key={airport.value}
|
|
44
|
-
label={airport.label}
|
|
45
|
-
searchValue={airport.searchValue}
|
|
46
|
-
value={airport.value}
|
|
47
|
-
/>
|
|
48
|
-
))}
|
|
49
|
-
</Combobox>
|
|
50
|
-
|
|
51
|
-
<p>{`value=${value ?? 'null'}`}</p>
|
|
52
|
-
</div>
|
|
53
|
-
)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
let root = css({
|
|
57
|
-
display: 'grid',
|
|
58
|
-
gap: '8px',
|
|
59
|
-
})
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
## Primitive Usage
|
|
63
|
-
|
|
64
|
-
Use the lower-level primitives when app code owns the input, popover, list, and option markup:
|
|
65
|
-
|
|
66
|
-
```tsx
|
|
67
|
-
import * as combobox from 'remix/ui/combobox/primitives'
|
|
68
|
-
import { inputStyle, listStyle, optionStyle, popoverStyle } from './combobox.styles'
|
|
69
|
-
|
|
70
|
-
let frameworks = [
|
|
71
|
-
{ label: 'Remix', searchValue: ['remix', 'rmx'], value: 'remix' },
|
|
72
|
-
{ label: 'React Router', value: 'react-router' },
|
|
73
|
-
]
|
|
74
|
-
|
|
75
|
-
export function PrimitiveCombobox() {
|
|
76
|
-
return (
|
|
77
|
-
<combobox.Context name="framework">
|
|
78
|
-
<input mix={[inputStyle, combobox.input()]} placeholder="Search frameworks" />
|
|
79
|
-
<div mix={[popoverStyle, combobox.popover()]}>
|
|
80
|
-
<div mix={[listStyle, combobox.list()]}>
|
|
81
|
-
{frameworks.map((option) => (
|
|
82
|
-
<div key={option.value} mix={[optionStyle, combobox.option(option)]}>
|
|
83
|
-
{option.label}
|
|
84
|
-
</div>
|
|
85
|
-
))}
|
|
86
|
-
</div>
|
|
87
|
-
</div>
|
|
88
|
-
<input mix={combobox.hiddenInput()} />
|
|
89
|
-
</combobox.Context>
|
|
90
|
-
)
|
|
91
|
-
}
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
## `remix/ui/combobox`
|
|
95
|
-
|
|
96
|
-
### `Combobox`
|
|
97
|
-
|
|
98
|
-
The convenience component.
|
|
99
|
-
|
|
100
|
-
- Renders the text input, popover surface, listbox root, and hidden form input.
|
|
101
|
-
- Dispatches a bubbled custom event that `onComboboxChange(...)` listens for when the committed value changes.
|
|
102
|
-
- Accepts `children`, `defaultValue`, `disabled`, `inputId`, `name`, `placeholder`, and root `div` props.
|
|
103
|
-
|
|
104
|
-
### `ComboboxOption`
|
|
105
|
-
|
|
106
|
-
The default option row for `Combobox`.
|
|
107
|
-
|
|
108
|
-
- Uses the shared listbox option visuals.
|
|
109
|
-
- Accepts `label`, `value`, optional `searchValue`, and optional `disabled`.
|
|
110
|
-
- Renders `children` when provided, otherwise renders `label`.
|
|
111
|
-
- `searchValue` can be a string or string array for aliases like airport codes, abbreviations, or alternate labels.
|
|
112
|
-
|
|
113
|
-
### Style and Prop Exports
|
|
114
|
-
|
|
115
|
-
- `inputStyle`: default combobox input style.
|
|
116
|
-
- `popoverStyle`: default combobox popover behavior style.
|
|
117
|
-
- `ComboboxProps` and `ComboboxOptionProps`: public TypeScript props for the composed APIs.
|
|
118
|
-
|
|
119
|
-
## `remix/ui/combobox/primitives`
|
|
120
|
-
|
|
121
|
-
### `onComboboxChange(...)`
|
|
122
|
-
|
|
123
|
-
The listener mixin from `remix/ui/combobox/primitives` for bubbled committed-value changes.
|
|
124
|
-
|
|
125
|
-
The event object includes:
|
|
126
|
-
|
|
127
|
-
- `event.value`: the committed value or `null`
|
|
128
|
-
- `event.label`: the committed option label or `null`
|
|
129
|
-
- `event.optionId`: the generated option id or `null`
|
|
130
|
-
- `ComboboxChangeEvent`: the event class dispatched for committed value changes.
|
|
131
|
-
|
|
132
|
-
### `combobox.Context`
|
|
133
|
-
|
|
134
|
-
The lower-level coordinator from `remix/ui/combobox/primitives` for custom combobox composition.
|
|
135
|
-
|
|
136
|
-
It wraps the shared `popover` and `listbox` contexts and owns the draft text, committed value, popup state, and selection timing.
|
|
137
|
-
|
|
138
|
-
### `combobox.input()`
|
|
139
|
-
|
|
140
|
-
Turns the host input into the combobox input.
|
|
141
|
-
|
|
142
|
-
- Keeps focus on the input during list navigation and pointer selection.
|
|
143
|
-
- Wires `role="combobox"`, `aria-expanded`, `aria-controls`, and `aria-activedescendant`.
|
|
144
|
-
- Opens from typing, click, and arrow-key navigation.
|
|
145
|
-
|
|
146
|
-
### `combobox.popover()`
|
|
147
|
-
|
|
148
|
-
Turns the host into the combobox popover surface.
|
|
149
|
-
|
|
150
|
-
- Uses the shared popover primitive.
|
|
151
|
-
- Keeps anchor clicks inside the session so the input stays interactive while open.
|
|
152
|
-
- Applies the combobox open/close reason contract used by `popoverStyle`.
|
|
153
|
-
|
|
154
|
-
### `combobox.list()`
|
|
155
|
-
|
|
156
|
-
Turns the host into the popup listbox root and applies the generated list id.
|
|
157
|
-
|
|
158
|
-
### `combobox.option(options)`
|
|
159
|
-
|
|
160
|
-
Registers one option with the combobox and listbox layers.
|
|
161
|
-
|
|
162
|
-
- Accepts `label`, `value`, optional `searchValue`, and optional `disabled`.
|
|
163
|
-
- Hides non-matching options from the current draft filter.
|
|
164
|
-
- Prevents pointer selection from blurring the input before the click commits.
|
|
165
|
-
|
|
166
|
-
### `combobox.hiddenInput()`
|
|
167
|
-
|
|
168
|
-
Mirrors the committed value into a hidden input for forms.
|
|
169
|
-
|
|
170
|
-
Apply it to an `<input type="hidden" />` inside the same `combobox.Context`.
|
|
171
|
-
|
|
172
|
-
### Primitive Types
|
|
173
|
-
|
|
174
|
-
- `ComboboxOpenStrategy`: initial active-option strategy when the popup opens.
|
|
175
|
-
- `ComboboxHandle`: imperative ref for reading or updating the combobox value and draft label.
|
|
176
|
-
- `ComboboxContextProps`, `ComboboxProps`, `ComboboxOptionOptions`, and `ComboboxOptionProps`: primitive prop and option types for custom composition.
|
|
177
|
-
|
|
178
|
-
## Behavior Notes
|
|
179
|
-
|
|
180
|
-
- Typing opens the popup in hint mode when there are matches.
|
|
181
|
-
- If typing leaves no matches, the popup closes immediately without the navigation fade-out.
|
|
182
|
-
- Selecting from the list flashes the option, then closes the popup and finally commits the visible input label.
|
|
183
|
-
- Typing clears the committed value immediately; the hidden form value becomes empty until the user commits again.
|
|
184
|
-
- Blur commits an exact `label` or `searchValue` match. A non-matching blur clears the draft text and committed value.
|
|
185
|
-
- `Escape` keeps exact-match draft text but clears non-matching draft text and selection.
|
|
186
|
-
- Disabled options can stay visible in filtered results, but they are skipped by keyboard navigation and selection.
|
|
187
|
-
|
|
188
|
-
## When To Use Something Else
|
|
189
|
-
|
|
190
|
-
Use `Select` when you want the ordinary button-triggered single-select control.
|
|
191
|
-
|
|
192
|
-
Use `listbox` when you need listbox semantics without an editable text input.
|
|
193
|
-
|
|
194
|
-
Use `popover` directly for custom floating panels that are not value-picking controls.
|
package/src/ui/combobox.ts
DELETED