@rust-js/resources 0.0.1
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/builtins/Cargo.toml +20 -0
- package/builtins/build.sh +20 -0
- package/builtins/src/lib.rs +264 -0
- package/package.json +32 -0
- package/react/Cargo.toml +27 -0
- package/react/build.rs +59 -0
- package/react/build.sh +44 -0
- package/react/cfg.js +60 -0
- package/react/src/dom.rs +542 -0
- package/react/src/elements.rs +8556 -0
- package/react/src/event.rs +238 -0
- package/react/src/lib.rs +1065 -0
- package/react/versions.json +2103 -0
- package/rust-toolchain.toml +4 -0
- package/serde/Cargo.lock +107 -0
- package/serde/Cargo.toml +15 -0
- package/serde/src/lib.rs +1 -0
- package/webapi/Cargo.toml +23 -0
- package/webapi/build.sh +32 -0
- package/webapi/src/lib.rs +6822 -0
package/react/src/lib.rs
ADDED
|
@@ -0,0 +1,1065 @@
|
|
|
1
|
+
//! [React](https://react.dev) and React DOM for rust-js (ADRs 0041, 0043). A
|
|
2
|
+
//! component is a function that returns an [`Element`], and elements are
|
|
3
|
+
//! written with `jsx!`, which rust-js prints as the JSX you would write by
|
|
4
|
+
//! hand (ADR 0075):
|
|
5
|
+
//!
|
|
6
|
+
//! ```ignore
|
|
7
|
+
//! use react::{Element, use_state};
|
|
8
|
+
//!
|
|
9
|
+
//! pub fn Counter() -> Element {
|
|
10
|
+
//! let (count, set_count) = use_state(0);
|
|
11
|
+
//! jsx! {
|
|
12
|
+
//! <div className="counter">
|
|
13
|
+
//! <button onClick={move |_| set_count.update(|count| count + 1)}>{"+"}</button>
|
|
14
|
+
//! {count}
|
|
15
|
+
//! </div>
|
|
16
|
+
//! }
|
|
17
|
+
//! }
|
|
18
|
+
//! ```
|
|
19
|
+
//!
|
|
20
|
+
//! ```js
|
|
21
|
+
//! import { useState } from "react";
|
|
22
|
+
//!
|
|
23
|
+
//! export function Counter() {
|
|
24
|
+
//! const [count, setCount] = useState(0);
|
|
25
|
+
//! return <div className="counter">
|
|
26
|
+
//! <button onClick={() => setCount((count) => count + 1 | 0)}>+</button>
|
|
27
|
+
//! {count}
|
|
28
|
+
//! </div>;
|
|
29
|
+
//! }
|
|
30
|
+
//! ```
|
|
31
|
+
//!
|
|
32
|
+
//! Every item here is a binding: rustc checks the types, and the bodies never
|
|
33
|
+
//! run. Generic ones use `#[rust_js::link_name]` (ADR 0039).
|
|
34
|
+
//!
|
|
35
|
+
//! # React versions
|
|
36
|
+
//!
|
|
37
|
+
//! This crate binds React's API as of the latest release, from 18.0 on. What
|
|
38
|
+
//! a later release added is gated by it: `#[cfg(react = "19.2")]` is "React
|
|
39
|
+
//! 19.2 or later". `react/build.sh --react <version>` builds the crate for the
|
|
40
|
+
//! version a project has installed, so using what that version lacks is a
|
|
41
|
+
//! compile error, not a crash in the browser (ADR 0043). `react/versions.json`
|
|
42
|
+
//! records which release first has each export, event and attribute, read
|
|
43
|
+
//! from the releases themselves.
|
|
44
|
+
|
|
45
|
+
// The bodies are never compiled, so they don't use their parameters.
|
|
46
|
+
#![allow(unused_variables)]
|
|
47
|
+
|
|
48
|
+
#[cfg(react = "19.0")]
|
|
49
|
+
use core::future::Future;
|
|
50
|
+
use core::marker::PhantomData;
|
|
51
|
+
use core::ops::Deref;
|
|
52
|
+
use std::thread::LocalKey;
|
|
53
|
+
|
|
54
|
+
use js::{JsError, JsObject, Promise};
|
|
55
|
+
|
|
56
|
+
pub mod dom;
|
|
57
|
+
mod elements;
|
|
58
|
+
pub mod event;
|
|
59
|
+
|
|
60
|
+
#[doc(hidden)]
|
|
61
|
+
pub use elements::html;
|
|
62
|
+
/// The DOM, whose types React's APIs use: `react::webapi::FormData`.
|
|
63
|
+
pub use js;
|
|
64
|
+
pub use webapi;
|
|
65
|
+
|
|
66
|
+
/// A React element: what a component returns, and what goes in children.
|
|
67
|
+
/// Construct it with `jsx! { <Tag ... /> }`.
|
|
68
|
+
#[cfg_attr(rust_js, rust_js::jsx_element)]
|
|
69
|
+
pub struct Element(PhantomData<JsObject>);
|
|
70
|
+
|
|
71
|
+
/// JSX, `jsx! { <h1>{"Hi"}</h1> }`, which rust-js compiles itself (ADR 0040):
|
|
72
|
+
/// to rust-js, the Rust it writes for it, which it gives as `@rust_js ..`; to
|
|
73
|
+
/// a plain rustc, a user's own `cargo check`, an `Element` it doesn't look
|
|
74
|
+
/// inside (ADR 0113). A file with JSX imports it, `use react::jsx;`.
|
|
75
|
+
#[macro_export]
|
|
76
|
+
macro_rules! jsx {
|
|
77
|
+
(@rust_js $($rust:tt)*) => { $($rust)* };
|
|
78
|
+
($($jsx:tt)*) => { $crate::Element::__jsx() };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/// What React renders as a child: elements, text and numbers, and tuples,
|
|
82
|
+
/// `Vec`s and `Option`s of them. A tuple is several children, `("Count is ",
|
|
83
|
+
/// count)`; a `Vec` is a list, whose items each need a [`key`](Element::key);
|
|
84
|
+
/// `None` is nothing. Each is the JS value React expects already, so nothing
|
|
85
|
+
/// converts them.
|
|
86
|
+
pub trait Node {}
|
|
87
|
+
|
|
88
|
+
impl Node for Element {}
|
|
89
|
+
impl Node for &str {}
|
|
90
|
+
impl Node for String {}
|
|
91
|
+
impl Node for () {}
|
|
92
|
+
impl Node for bool {}
|
|
93
|
+
impl<T: Node + ?Sized> Node for &T {}
|
|
94
|
+
impl<T: Node> Node for Option<T> {}
|
|
95
|
+
impl<T: Node> Node for Vec<T> {}
|
|
96
|
+
|
|
97
|
+
macro_rules! numbers {
|
|
98
|
+
($($t:ty),*) => { $(impl Node for $t {} impl Value for $t {})* };
|
|
99
|
+
}
|
|
100
|
+
numbers!(i8, i16, i32, u8, u16, u32, usize, f64);
|
|
101
|
+
|
|
102
|
+
macro_rules! tuples {
|
|
103
|
+
($($name:ident)+) => {
|
|
104
|
+
impl<$($name: Node),+> Node for ($($name,)+) {}
|
|
105
|
+
impl<$($name),+> Deps for ($($name,)+) {}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
tuples!(A);
|
|
109
|
+
tuples!(A B);
|
|
110
|
+
tuples!(A B C);
|
|
111
|
+
tuples!(A B C D);
|
|
112
|
+
tuples!(A B C D E);
|
|
113
|
+
tuples!(A B C D E F);
|
|
114
|
+
tuples!(A B C D E F G);
|
|
115
|
+
tuples!(A B C D E F G H);
|
|
116
|
+
tuples!(A B C D E F G H I);
|
|
117
|
+
tuples!(A B C D E F G H I J);
|
|
118
|
+
tuples!(A B C D E F G H I J K);
|
|
119
|
+
tuples!(A B C D E F G H I J K L);
|
|
120
|
+
|
|
121
|
+
/// What an attribute or style takes: text, a number (which React turns into
|
|
122
|
+
/// text, or pixels in a style), a `bool`, or an `Option` of one, which leaves
|
|
123
|
+
/// it out when `None`.
|
|
124
|
+
pub trait Value {}
|
|
125
|
+
|
|
126
|
+
impl Value for &str {}
|
|
127
|
+
impl Value for String {}
|
|
128
|
+
impl Value for bool {}
|
|
129
|
+
impl<T: Value + ?Sized> Value for &T {}
|
|
130
|
+
impl<T: Value> Value for Option<T> {}
|
|
131
|
+
|
|
132
|
+
/// What a [`key`](Element::key) can be: a string or a number.
|
|
133
|
+
pub trait Key {}
|
|
134
|
+
|
|
135
|
+
impl Key for &str {}
|
|
136
|
+
impl Key for String {}
|
|
137
|
+
impl Key for i32 {}
|
|
138
|
+
impl Key for u32 {}
|
|
139
|
+
impl Key for usize {}
|
|
140
|
+
impl<T: Key + ?Sized> Key for &T {}
|
|
141
|
+
|
|
142
|
+
/// A [`style`](Element::style) object, `{ color: "red", fontSize: 12 }`:
|
|
143
|
+
/// made by `Style::new()`, then CSS properties by name, `.color("red")`.
|
|
144
|
+
pub struct Style(PhantomData<JsObject>);
|
|
145
|
+
|
|
146
|
+
impl Style {
|
|
147
|
+
#[cfg_attr(rust_js, rust_js::link_name = "{}")]
|
|
148
|
+
pub fn new() -> Style {
|
|
149
|
+
unreachable!()
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/// Any property, like a custom one: `.set("--accent", "red")`. The name
|
|
153
|
+
/// is a string literal.
|
|
154
|
+
#[cfg_attr(rust_js, rust_js::link_name = "prop")]
|
|
155
|
+
pub fn set(self, name: &'static str, value: impl Value) -> Style {
|
|
156
|
+
unreachable!()
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/// `{ __html }`, for [`dangerously_set_inner_html`](Element::dangerously_set_inner_html).
|
|
161
|
+
pub struct InnerHtml(PhantomData<JsObject>);
|
|
162
|
+
|
|
163
|
+
#[cfg_attr(rust_js, rust_js::link_name = "{__html}")]
|
|
164
|
+
pub fn inner_html(html: impl Value) -> InnerHtml {
|
|
165
|
+
unreachable!()
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
#[doc(hidden)]
|
|
169
|
+
impl Element {
|
|
170
|
+
/// What `jsx!` is to a plain rustc, which doesn't compile JSX: named so
|
|
171
|
+
/// no prop is, as a prop is a method.
|
|
172
|
+
#[doc(hidden)]
|
|
173
|
+
pub fn __jsx() -> Element {
|
|
174
|
+
unreachable!()
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/// Spread a props struct into this element. Fields keep the JS names of
|
|
178
|
+
/// their Rust struct (including the crate's camel_case setting).
|
|
179
|
+
#[cfg_attr(rust_js, rust_js::link_name = "prop ...")]
|
|
180
|
+
pub fn props<P>(self, props: P) -> Element {
|
|
181
|
+
unreachable!()
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/// Its children: one [`Node`], or several as a tuple.
|
|
185
|
+
#[cfg_attr(rust_js, rust_js::link_name = "prop children")]
|
|
186
|
+
pub fn children(self, children: impl Node) -> Element {
|
|
187
|
+
unreachable!()
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/// Tells React which item of a list this is, across renders.
|
|
191
|
+
#[cfg_attr(rust_js, rust_js::link_name = "prop key")]
|
|
192
|
+
pub fn key(self, key: impl Key) -> Element {
|
|
193
|
+
unreachable!()
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
#[cfg_attr(rust_js, rust_js::link_name = "prop ref")]
|
|
197
|
+
pub fn r#ref<H, M>(self, value: impl RefValue<H, M>) -> Element {
|
|
198
|
+
unreachable!()
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/// Any attribute, by its name in JSX, which must be a string literal:
|
|
202
|
+
/// `.attr("aria-hidden", "true")`, `.attr("data-id", id)`.
|
|
203
|
+
#[cfg_attr(rust_js, rust_js::link_name = "prop")]
|
|
204
|
+
pub fn attr(self, name: &'static str, value: impl Value) -> Element {
|
|
205
|
+
unreachable!()
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/// [`style`](https://react.dev/reference/react-dom/components/common#applying-css-styles):
|
|
209
|
+
/// `.style(Style::new().color("red"))` is `style={{ color: "red" }}`.
|
|
210
|
+
#[cfg_attr(rust_js, rust_js::link_name = "prop style")]
|
|
211
|
+
pub fn style(self, style: Style) -> Element {
|
|
212
|
+
unreachable!()
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/// `dangerouslySetInnerHTML={{ __html }}`: HTML that React doesn't escape.
|
|
216
|
+
#[cfg_attr(rust_js, rust_js::link_name = "prop dangerouslySetInnerHTML")]
|
|
217
|
+
pub fn dangerously_set_inner_html(self, html: InnerHtml) -> Element {
|
|
218
|
+
unreachable!()
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
#[cfg_attr(rust_js, rust_js::link_name = "prop action")]
|
|
222
|
+
pub fn action<M>(self, value: impl FormAction<M>) -> Element {
|
|
223
|
+
unreachable!()
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
#[cfg_attr(rust_js, rust_js::link_name = "prop formAction")]
|
|
227
|
+
pub fn form_action<M>(self, value: impl FormAction<M>) -> Element {
|
|
228
|
+
unreachable!()
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/// A stylesheet's or style's place among others, which React orders and
|
|
232
|
+
/// hoists into `<head>`.
|
|
233
|
+
#[cfg(react = "19.0")]
|
|
234
|
+
#[cfg_attr(rust_js, rust_js::link_name = "prop precedence")]
|
|
235
|
+
pub fn precedence(self, value: impl Value) -> Element {
|
|
236
|
+
unreachable!()
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/// What an action returns: nothing, or, from React 19, a future, which
|
|
241
|
+
/// React awaits while its Transition is pending. `M` only tells them apart.
|
|
242
|
+
pub trait ActionResult<M> {}
|
|
243
|
+
|
|
244
|
+
pub struct SyncAction;
|
|
245
|
+
pub struct AsyncAction;
|
|
246
|
+
|
|
247
|
+
impl ActionResult<SyncAction> for () {}
|
|
248
|
+
#[cfg(react = "19.0")]
|
|
249
|
+
impl<F: Future<Output = ()>> ActionResult<AsyncAction> for F {}
|
|
250
|
+
|
|
251
|
+
/// A JSX ref is a ref object or a callback. React calls a callback on attach
|
|
252
|
+
/// and detach; from React 19, its returned cleanup runs on detach.
|
|
253
|
+
/// The marker only distinguishes types.
|
|
254
|
+
pub trait RefValue<H, M> {}
|
|
255
|
+
#[doc(hidden)]
|
|
256
|
+
pub struct ObjectRef;
|
|
257
|
+
#[doc(hidden)]
|
|
258
|
+
pub struct CallbackRef<C>(PhantomData<C>);
|
|
259
|
+
impl<H> RefValue<H, ObjectRef> for Ref<Option<H>> {}
|
|
260
|
+
impl<H: 'static, C: Cleanup, F: Fn(Option<H>) -> C + 'static> RefValue<H, CallbackRef<C>> for F {}
|
|
261
|
+
|
|
262
|
+
/// A JSX form action is a URL or, on React 19+, a function or action dispatch.
|
|
263
|
+
pub trait FormAction<M> {}
|
|
264
|
+
#[doc(hidden)]
|
|
265
|
+
pub struct UrlAction;
|
|
266
|
+
#[doc(hidden)]
|
|
267
|
+
pub struct FunctionAction<M>(PhantomData<M>);
|
|
268
|
+
#[doc(hidden)]
|
|
269
|
+
pub struct DispatchAction;
|
|
270
|
+
impl<T: Value> FormAction<UrlAction> for T {}
|
|
271
|
+
#[cfg(react = "19.0")]
|
|
272
|
+
impl<M, R: ActionResult<M>, F: Fn(&'static webapi::FormData) -> R + 'static> FormAction<FunctionAction<M>> for F {}
|
|
273
|
+
#[cfg(react = "19.0")]
|
|
274
|
+
impl FormAction<DispatchAction> for Dispatch<&'static webapi::FormData> {}
|
|
275
|
+
|
|
276
|
+
// ── Hooks ───────────────────────────────────────────────────────────────
|
|
277
|
+
//
|
|
278
|
+
// What a hook gives back is borrowed, `&'static T`: React keeps it, and it's
|
|
279
|
+
// read-only, as React's state is (a new value is what renders again). A
|
|
280
|
+
// shared reference is `Copy`, so every handler can `move` it in. In JS it's
|
|
281
|
+
// the value itself. They're at the crate's root, not re-exported from a
|
|
282
|
+
// module, so using one a React version lacks says which version it needs.
|
|
283
|
+
|
|
284
|
+
/// Declares a JS function a hook gives back, `setCount` or `dispatch`: a
|
|
285
|
+
/// `Copy` handle, called with `this()` (ADR 0039).
|
|
286
|
+
macro_rules! handle {
|
|
287
|
+
($(#[doc = $doc:literal])* $name:ident<$t:ident>) => {
|
|
288
|
+
$(#[doc = $doc])*
|
|
289
|
+
pub struct $name<$t>(PhantomData<JsObject>, PhantomData<$t>);
|
|
290
|
+
|
|
291
|
+
impl<$t> Clone for $name<$t> {
|
|
292
|
+
fn clone(&self) -> Self {
|
|
293
|
+
*self
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
impl<$t> Copy for $name<$t> {}
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// ── State ───────────────────────────────────────────────────────────────
|
|
302
|
+
|
|
303
|
+
/// [`useState`](https://react.dev/reference/react/useState): the state, and
|
|
304
|
+
/// what sets it. `let (count, set_count) = use_state(0);` is
|
|
305
|
+
/// `const [count, setCount] = useState(0);`.
|
|
306
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useState")]
|
|
307
|
+
pub fn use_state<T>(initial: T) -> (&'static T, SetState<T>) {
|
|
308
|
+
unreachable!()
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/// `useState(() => initial())`: the first value, computed on the first render only.
|
|
312
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useState")]
|
|
313
|
+
pub fn use_state_with<T>(initial: impl Fn() -> T + 'static) -> (&'static T, SetState<T>) {
|
|
314
|
+
unreachable!()
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
handle! {
|
|
318
|
+
/// What [`use_state`] gives to set the state: React's `setCount`.
|
|
319
|
+
SetState<T>
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
impl<T> SetState<T> {
|
|
323
|
+
/// `setCount(value)`.
|
|
324
|
+
#[cfg_attr(rust_js, rust_js::link_name = "this()")]
|
|
325
|
+
pub fn set(&self, value: T) {
|
|
326
|
+
unreachable!()
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/// `setCount((count) => count + 1)`: a new state from the latest one,
|
|
330
|
+
/// which it only reads.
|
|
331
|
+
#[cfg_attr(rust_js, rust_js::link_name = "this()")]
|
|
332
|
+
pub fn update(&self, f: impl Fn(&T) -> T + 'static) {
|
|
333
|
+
unreachable!()
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/// [`useReducer`](https://react.dev/reference/react/useReducer): the state,
|
|
338
|
+
/// and what sends it actions, which `reducer` turns into the next state.
|
|
339
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useReducer")]
|
|
340
|
+
pub fn use_reducer<S, A>(reducer: impl Fn(&S, A) -> S + 'static, initial: S) -> (&'static S, Dispatch<A>) {
|
|
341
|
+
unreachable!()
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/// `useReducer(reducer, arg, init)`: the first state is `init(arg)`, computed
|
|
345
|
+
/// on the first render only.
|
|
346
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useReducer")]
|
|
347
|
+
pub fn use_reducer_with<S, A, I>(
|
|
348
|
+
reducer: impl Fn(&S, A) -> S + 'static,
|
|
349
|
+
arg: I,
|
|
350
|
+
init: impl Fn(I) -> S + 'static,
|
|
351
|
+
) -> (&'static S, Dispatch<A>) {
|
|
352
|
+
unreachable!()
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
handle! {
|
|
356
|
+
/// What sends an action: React's `dispatch`, from [`use_reducer`] and
|
|
357
|
+
/// [`use_action_state`].
|
|
358
|
+
Dispatch<A>
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
impl<A> Dispatch<A> {
|
|
362
|
+
/// `dispatch(action)`.
|
|
363
|
+
#[cfg_attr(rust_js, rust_js::link_name = "this()")]
|
|
364
|
+
pub fn dispatch(&self, action: A) {
|
|
365
|
+
unreachable!()
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/// [`useActionState`](https://react.dev/reference/react/useActionState): the
|
|
370
|
+
/// state, an action that runs `action` with the previous state and its
|
|
371
|
+
/// payload, and whether one is pending. Give the action to a form with
|
|
372
|
+
/// [`Element::action_dispatch`], or call it in a Transition.
|
|
373
|
+
#[cfg(react = "19.0")]
|
|
374
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useActionState")]
|
|
375
|
+
pub fn use_action_state<S, P>(
|
|
376
|
+
action: impl Fn(&S, P) -> S + 'static,
|
|
377
|
+
initial: S,
|
|
378
|
+
) -> (&'static S, Dispatch<P>, bool) {
|
|
379
|
+
unreachable!()
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/// [`use_action_state`] with an `async` action: the state is what its
|
|
383
|
+
/// future gives, and it's pending until then.
|
|
384
|
+
#[cfg(react = "19.0")]
|
|
385
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useActionState")]
|
|
386
|
+
pub fn use_async_action_state<S, P, F: Future<Output = S>>(
|
|
387
|
+
action: impl Fn(&S, P) -> F + 'static,
|
|
388
|
+
initial: S,
|
|
389
|
+
) -> (&'static S, Dispatch<P>, bool) {
|
|
390
|
+
unreachable!()
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/// [`useOptimistic`](https://react.dev/reference/react/useOptimistic):
|
|
394
|
+
/// `value`, or what [`SetOptimistic`] set while an action is pending.
|
|
395
|
+
#[cfg(react = "19.0")]
|
|
396
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useOptimistic")]
|
|
397
|
+
pub fn use_optimistic<S>(value: S) -> (&'static S, SetOptimistic<S>) {
|
|
398
|
+
unreachable!()
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/// `useOptimistic(value, reducer)`: the optimistic state is `reducer`'s,
|
|
402
|
+
/// from the actions sent to it.
|
|
403
|
+
#[cfg(react = "19.0")]
|
|
404
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useOptimistic")]
|
|
405
|
+
pub fn use_optimistic_with<S, A>(value: S, reducer: impl Fn(&S, A) -> S + 'static) -> (&'static S, Dispatch<A>) {
|
|
406
|
+
unreachable!()
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
handle! {
|
|
410
|
+
/// What [`use_optimistic`] gives to set the optimistic state.
|
|
411
|
+
SetOptimistic<S>
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
#[cfg(react = "19.0")]
|
|
415
|
+
impl<S> SetOptimistic<S> {
|
|
416
|
+
#[cfg_attr(rust_js, rust_js::link_name = "this()")]
|
|
417
|
+
pub fn set(&self, value: S) {
|
|
418
|
+
unreachable!()
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
#[cfg_attr(rust_js, rust_js::link_name = "this()")]
|
|
422
|
+
pub fn update(&self, f: impl Fn(&S) -> S + 'static) {
|
|
423
|
+
unreachable!()
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// ── Context and refs ────────────────────────────────────────────────────
|
|
428
|
+
|
|
429
|
+
/// [`useContext`](https://react.dev/reference/react/useContext): the value of
|
|
430
|
+
/// the nearest provider above, or the context's default.
|
|
431
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useContext")]
|
|
432
|
+
pub fn use_context<T>(context: &'static LocalKey<Context<T>>) -> &'static T {
|
|
433
|
+
unreachable!()
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/// [`useRef`](https://react.dev/reference/react/useRef): a box that keeps its
|
|
437
|
+
/// value across renders, without rendering again when it changes. For a DOM
|
|
438
|
+
/// element, start it with `None` and give it to [`Element::ref`].
|
|
439
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useRef")]
|
|
440
|
+
pub fn use_ref<T>(initial: T) -> Ref<T> {
|
|
441
|
+
unreachable!()
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
handle! {
|
|
445
|
+
/// What [`use_ref`] gives: `{ current }`.
|
|
446
|
+
Ref<T>
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
impl<T> Ref<T> {
|
|
450
|
+
/// `ref.current`.
|
|
451
|
+
#[cfg_attr(rust_js, rust_js::link_name = "get current")]
|
|
452
|
+
pub fn current(&self) -> T {
|
|
453
|
+
unreachable!()
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/// `ref.current = value`.
|
|
457
|
+
#[cfg_attr(rust_js, rust_js::link_name = "set current")]
|
|
458
|
+
pub fn set_current(&self, value: T) {
|
|
459
|
+
unreachable!()
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/// [`useImperativeHandle`](https://react.dev/reference/react/useImperativeHandle):
|
|
464
|
+
/// what a parent's ref to this component gets, made by `create`.
|
|
465
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useImperativeHandle")]
|
|
466
|
+
pub fn use_imperative_handle<H>(r: Ref<Option<H>>, create: impl Fn() -> H + 'static, deps: impl Deps) {
|
|
467
|
+
unreachable!()
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// ── Effects ─────────────────────────────────────────────────────────────
|
|
471
|
+
|
|
472
|
+
/// What an effect's dependencies are: a tuple of values, `(count, name)` for
|
|
473
|
+
/// `[count, name]`, or `()` for `[]`, when it runs once.
|
|
474
|
+
pub trait Deps {}
|
|
475
|
+
|
|
476
|
+
impl Deps for () {}
|
|
477
|
+
impl<T, const N: usize> Deps for [T; N] {}
|
|
478
|
+
|
|
479
|
+
/// What an effect returns: nothing, or a function that cleans it up.
|
|
480
|
+
pub trait Cleanup {}
|
|
481
|
+
|
|
482
|
+
impl Cleanup for () {}
|
|
483
|
+
impl<F: FnOnce() + 'static> Cleanup for F {}
|
|
484
|
+
|
|
485
|
+
/// [`useEffect`](https://react.dev/reference/react/useEffect): run `effect`
|
|
486
|
+
/// after a render in which `deps` changed.
|
|
487
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useEffect")]
|
|
488
|
+
pub fn use_effect<C: Cleanup>(effect: impl Fn() -> C + 'static, deps: impl Deps) {
|
|
489
|
+
unreachable!()
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/// `useEffect(effect)`: after every render.
|
|
493
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useEffect")]
|
|
494
|
+
pub fn use_effect_on_every_render<C: Cleanup>(effect: impl Fn() -> C + 'static) {
|
|
495
|
+
unreachable!()
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/// [`useLayoutEffect`](https://react.dev/reference/react/useLayoutEffect):
|
|
499
|
+
/// [`use_effect`], before the browser paints.
|
|
500
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useLayoutEffect")]
|
|
501
|
+
pub fn use_layout_effect<C: Cleanup>(effect: impl Fn() -> C + 'static, deps: impl Deps) {
|
|
502
|
+
unreachable!()
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/// `useLayoutEffect(effect)`: after every render, before the browser paints.
|
|
506
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useLayoutEffect")]
|
|
507
|
+
pub fn use_layout_effect_on_every_render<C: Cleanup>(effect: impl Fn() -> C + 'static) {
|
|
508
|
+
unreachable!()
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/// [`useInsertionEffect`](https://react.dev/reference/react/useInsertionEffect):
|
|
512
|
+
/// before layout effects, for CSS-in-JS libraries to insert styles.
|
|
513
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useInsertionEffect")]
|
|
514
|
+
pub fn use_insertion_effect<C: Cleanup>(effect: impl Fn() -> C + 'static, deps: impl Deps) {
|
|
515
|
+
unreachable!()
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/// `useInsertionEffect(effect)`: after every render.
|
|
519
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useInsertionEffect")]
|
|
520
|
+
pub fn use_insertion_effect_on_every_render<C: Cleanup>(effect: impl Fn() -> C + 'static) {
|
|
521
|
+
unreachable!()
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/// [`useEffectEvent`](https://react.dev/reference/react/useEffectEvent): `f`,
|
|
525
|
+
/// which an effect can call and always see the latest props and state, without
|
|
526
|
+
/// being one of its dependencies. Call it only from effects.
|
|
527
|
+
#[cfg(react = "19.2")]
|
|
528
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useEffectEvent")]
|
|
529
|
+
pub fn use_effect_event<F: 'static>(f: F) -> &'static F {
|
|
530
|
+
unreachable!()
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// ── Performance ─────────────────────────────────────────────────────────
|
|
534
|
+
|
|
535
|
+
/// [`useMemo`](https://react.dev/reference/react/useMemo): `f`'s value, computed
|
|
536
|
+
/// again only when `deps` change.
|
|
537
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useMemo")]
|
|
538
|
+
pub fn use_memo<T>(f: impl Fn() -> T + 'static, deps: impl Deps) -> &'static T {
|
|
539
|
+
unreachable!()
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/// [`useCallback`](https://react.dev/reference/react/useCallback): the same
|
|
543
|
+
/// function across renders, until `deps` change.
|
|
544
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useCallback")]
|
|
545
|
+
pub fn use_callback<F: 'static>(f: F, deps: impl Deps) -> &'static F {
|
|
546
|
+
unreachable!()
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/// [`useTransition`](https://react.dev/reference/react/useTransition): whether
|
|
550
|
+
/// a Transition is pending, and what starts one.
|
|
551
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useTransition")]
|
|
552
|
+
pub fn use_transition() -> (bool, StartTransition) {
|
|
553
|
+
unreachable!()
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/// What [`use_transition`] gives: React's `startTransition`.
|
|
557
|
+
pub struct StartTransition(PhantomData<JsObject>);
|
|
558
|
+
|
|
559
|
+
impl Clone for StartTransition {
|
|
560
|
+
fn clone(&self) -> Self {
|
|
561
|
+
*self
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
impl Copy for StartTransition {}
|
|
566
|
+
|
|
567
|
+
impl StartTransition {
|
|
568
|
+
/// `startTransition(action)`: the updates in `action` render without
|
|
569
|
+
/// blocking the page. From React 19, `action` can be `async`.
|
|
570
|
+
#[cfg_attr(rust_js, rust_js::link_name = "this()")]
|
|
571
|
+
pub fn start<R: ActionResult<M>, M>(&self, action: impl FnOnce() -> R + 'static) {
|
|
572
|
+
unreachable!()
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/// [`useDeferredValue`](https://react.dev/reference/react/useDeferredValue):
|
|
577
|
+
/// `value`, which lags behind while more urgent updates render.
|
|
578
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useDeferredValue")]
|
|
579
|
+
pub fn use_deferred_value<T>(value: T) -> &'static T {
|
|
580
|
+
unreachable!()
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/// `useDeferredValue(value, initialValue)`: `initial` on the first render.
|
|
584
|
+
#[cfg(react = "19.0")]
|
|
585
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useDeferredValue")]
|
|
586
|
+
pub fn use_deferred_value_with<T>(value: T, initial: T) -> &'static T {
|
|
587
|
+
unreachable!()
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// ── Other ───────────────────────────────────────────────────────────────
|
|
591
|
+
|
|
592
|
+
/// [`useId`](https://react.dev/reference/react/useId): an id unique to this
|
|
593
|
+
/// component, the same on every render, for `id` and `html_for`.
|
|
594
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useId")]
|
|
595
|
+
pub fn use_id() -> String {
|
|
596
|
+
unreachable!()
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/// What [`use_sync_external_store`]'s `subscribe` is given: call it when the
|
|
600
|
+
/// store changes.
|
|
601
|
+
pub struct Notify(PhantomData<JsObject>);
|
|
602
|
+
|
|
603
|
+
impl Clone for Notify {
|
|
604
|
+
fn clone(&self) -> Self {
|
|
605
|
+
*self
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
impl Copy for Notify {}
|
|
610
|
+
|
|
611
|
+
impl Notify {
|
|
612
|
+
#[cfg_attr(rust_js, rust_js::link_name = "this()")]
|
|
613
|
+
pub fn call(&self) {
|
|
614
|
+
unreachable!()
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/// [`useSyncExternalStore`](https://react.dev/reference/react/useSyncExternalStore):
|
|
619
|
+
/// a value from outside React. `subscribe` gets a [`Notify`] to call on each
|
|
620
|
+
/// change, and returns what unsubscribes; `snapshot` reads the value.
|
|
621
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useSyncExternalStore")]
|
|
622
|
+
pub fn use_sync_external_store<T, U: Cleanup>(
|
|
623
|
+
subscribe: impl Fn(Notify) -> U + 'static,
|
|
624
|
+
snapshot: impl Fn() -> T + 'static,
|
|
625
|
+
) -> &'static T {
|
|
626
|
+
unreachable!()
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/// `useSyncExternalStore(subscribe, snapshot, serverSnapshot)`: on the server
|
|
630
|
+
/// and while hydrating, the value is `server_snapshot`'s.
|
|
631
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useSyncExternalStore")]
|
|
632
|
+
pub fn use_sync_external_store_with_server<T, U: Cleanup>(
|
|
633
|
+
subscribe: impl Fn(Notify) -> U + 'static,
|
|
634
|
+
snapshot: impl Fn() -> T + 'static,
|
|
635
|
+
server_snapshot: impl Fn() -> T + 'static,
|
|
636
|
+
) -> &'static T {
|
|
637
|
+
unreachable!()
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/// [`useDebugValue`](https://react.dev/reference/react/useDebugValue): a label
|
|
641
|
+
/// for a custom hook in React DevTools.
|
|
642
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useDebugValue")]
|
|
643
|
+
pub fn use_debug_value<T>(value: T) {
|
|
644
|
+
unreachable!()
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/// `useDebugValue(value, format)`: formatted only when DevTools shows it.
|
|
648
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#useDebugValue")]
|
|
649
|
+
pub fn use_debug_value_with<T>(value: T, format: impl Fn(&T) -> String + 'static) {
|
|
650
|
+
unreachable!()
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// ── Components ──────────────────────────────────────────────────────────
|
|
654
|
+
|
|
655
|
+
/// An element of a component: `component(Counter, CounterProps { initial: 1 })`
|
|
656
|
+
/// is `<Counter initial={1} />`. Its props are a struct, whose `children`
|
|
657
|
+
/// field, if it has one, is the element's children; `()` for a component that
|
|
658
|
+
/// takes none, `component(App, ())`. A component's name starts with an
|
|
659
|
+
/// uppercase letter, as JSX and Fast Refresh need.
|
|
660
|
+
#[cfg_attr(rust_js, rust_js::link_name = "<*>")]
|
|
661
|
+
#[doc(hidden)]
|
|
662
|
+
pub fn component<P, M>(component: impl Component<P, M>, props: P) -> Element {
|
|
663
|
+
unreachable!()
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/// A JSX component: a function from its props to an [`Element`], or
|
|
667
|
+
/// one with no props, or one made by [`memo`], [`lazy`] or [`forward_ref`].
|
|
668
|
+
/// `M` only tells them apart.
|
|
669
|
+
pub trait Component<P, M> {}
|
|
670
|
+
|
|
671
|
+
pub struct NoProps;
|
|
672
|
+
pub struct WithProps;
|
|
673
|
+
|
|
674
|
+
impl<F: Fn() -> Element> Component<(), NoProps> for F {}
|
|
675
|
+
impl<P, F: Fn(P) -> Element> Component<P, WithProps> for F {}
|
|
676
|
+
|
|
677
|
+
/// Children with nothing around them: `<>..</>`.
|
|
678
|
+
#[cfg_attr(rust_js, rust_js::link_name = "<>")]
|
|
679
|
+
#[doc(hidden)]
|
|
680
|
+
pub fn fragment(children: impl Node) -> Element {
|
|
681
|
+
unreachable!()
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/// [`<StrictMode>`](https://react.dev/reference/react/StrictMode).
|
|
685
|
+
#[cfg_attr(rust_js, rust_js::link_name = "<react#StrictMode>")]
|
|
686
|
+
#[doc(hidden)]
|
|
687
|
+
pub fn strict_mode(children: impl Node) -> Element {
|
|
688
|
+
unreachable!()
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
/// Declares a built-in component: `name()` makes its element, whose props
|
|
692
|
+
/// are set by its methods, and `.children(..)` finishes it.
|
|
693
|
+
macro_rules! built_in {
|
|
694
|
+
($(#[doc = $doc:literal])* $(#[cfg($cfg:meta)])? $name:ident = $make:ident $tag:literal { $($(#[doc = $pdoc:literal])* $prop:ident: $ty:ty = $js:literal;)* }) => {
|
|
695
|
+
$(#[doc = $doc])*
|
|
696
|
+
$(#[cfg($cfg)])?
|
|
697
|
+
#[cfg_attr(rust_js, rust_js::jsx_element)]
|
|
698
|
+
#[doc(hidden)]
|
|
699
|
+
pub struct $name(PhantomData<JsObject>);
|
|
700
|
+
|
|
701
|
+
#[doc = concat!("`<", $tag, ">`: set its props, then its children.")]
|
|
702
|
+
$(#[cfg($cfg)])?
|
|
703
|
+
#[cfg_attr(rust_js, rust_js::link_name = concat!("<react#", $tag, ">"))]
|
|
704
|
+
#[doc(hidden)]
|
|
705
|
+
pub fn $make() -> $name {
|
|
706
|
+
unreachable!()
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
$(#[cfg($cfg)])?
|
|
710
|
+
impl Node for $name {}
|
|
711
|
+
|
|
712
|
+
$(#[cfg($cfg)])?
|
|
713
|
+
#[doc(hidden)]
|
|
714
|
+
impl $name {
|
|
715
|
+
#[cfg_attr(rust_js, rust_js::link_name = "prop key")]
|
|
716
|
+
pub fn key(self, value: impl Key) -> $name {
|
|
717
|
+
unreachable!()
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
#[cfg_attr(rust_js, rust_js::link_name = "prop ...")]
|
|
721
|
+
pub fn props<P>(self, value: P) -> $name {
|
|
722
|
+
unreachable!()
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
$(
|
|
726
|
+
$(#[doc = $pdoc])*
|
|
727
|
+
#[cfg_attr(rust_js, rust_js::link_name = concat!("prop ", $js))]
|
|
728
|
+
pub fn $prop(self, value: $ty) -> $name {
|
|
729
|
+
unreachable!()
|
|
730
|
+
}
|
|
731
|
+
)*
|
|
732
|
+
|
|
733
|
+
/// Its children, which finish the element.
|
|
734
|
+
#[cfg_attr(rust_js, rust_js::link_name = "prop children")]
|
|
735
|
+
pub fn children(self, children: impl Node) -> Element {
|
|
736
|
+
unreachable!()
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
built_in! {
|
|
743
|
+
/// [`<Fragment>`](https://react.dev/reference/react/Fragment) with a key,
|
|
744
|
+
/// for a list item of several elements. Without one, [`fragment`] is `<>`.
|
|
745
|
+
Fragment = keyed_fragment "Fragment" {}
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
built_in! {
|
|
749
|
+
/// [`<Suspense>`](https://react.dev/reference/react/Suspense): shows
|
|
750
|
+
/// `fallback` until its children stop suspending.
|
|
751
|
+
Suspense = suspense "Suspense" {
|
|
752
|
+
/// What to show while the children load.
|
|
753
|
+
fallback: impl Node = "fallback";
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
built_in! {
|
|
758
|
+
/// [`<Profiler>`](https://react.dev/reference/react/Profiler): measures
|
|
759
|
+
/// how long its children take to render, in development and profiling builds.
|
|
760
|
+
Profiler = profiler "Profiler" {
|
|
761
|
+
id: impl Value = "id";
|
|
762
|
+
/// Called after each commit: `(id, phase, actual_duration,
|
|
763
|
+
/// base_duration, start_time, commit_time)`, the times in milliseconds.
|
|
764
|
+
on_render: impl Fn(&str, Phase, f64, f64, f64, f64) + 'static = "onRender";
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/// A [`Profiler`]'s render: the first, a later one, or one its effects caused.
|
|
769
|
+
pub enum Phase {
|
|
770
|
+
#[cfg_attr(rust_js, rust_js::name = "mount")]
|
|
771
|
+
Mount,
|
|
772
|
+
#[cfg_attr(rust_js, rust_js::name = "update")]
|
|
773
|
+
Update,
|
|
774
|
+
#[cfg_attr(rust_js, rust_js::name = "nested-update")]
|
|
775
|
+
NestedUpdate,
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
built_in! {
|
|
779
|
+
/// [`<Activity>`](https://react.dev/reference/react/Activity): hides its
|
|
780
|
+
/// children and keeps their state, or shows them.
|
|
781
|
+
#[cfg(react = "19.2")]
|
|
782
|
+
Activity = activity "Activity" {
|
|
783
|
+
mode: ActivityMode = "mode";
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
/// Whether an [`Activity`]'s children show.
|
|
788
|
+
#[cfg(react = "19.2")]
|
|
789
|
+
pub enum ActivityMode {
|
|
790
|
+
#[cfg_attr(rust_js, rust_js::name = "visible")]
|
|
791
|
+
Visible,
|
|
792
|
+
#[cfg_attr(rust_js, rust_js::name = "hidden")]
|
|
793
|
+
Hidden,
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
built_in! {
|
|
797
|
+
/// [`<ViewTransition>`](https://react.dev/reference/react/ViewTransition):
|
|
798
|
+
/// animates its children with the browser's View Transitions when they
|
|
799
|
+
/// change in a Transition. A class prop is `"auto"`, `"none"`, or a CSS
|
|
800
|
+
/// class for the `::view-transition-*` pseudo-elements.
|
|
801
|
+
#[cfg(react = "19.3")]
|
|
802
|
+
ViewTransition = view_transition "ViewTransition" {
|
|
803
|
+
/// Its name, for a shared-element transition between two of them.
|
|
804
|
+
name: impl Value = "name";
|
|
805
|
+
enter: impl Value = "enter";
|
|
806
|
+
exit: impl Value = "exit";
|
|
807
|
+
update: impl Value = "update";
|
|
808
|
+
share: impl Value = "share";
|
|
809
|
+
default: impl Value = "default";
|
|
810
|
+
on_enter: impl Fn(&ViewTransitionInstance, &Vec<String>) + 'static = "onEnter";
|
|
811
|
+
on_exit: impl Fn(&ViewTransitionInstance, &Vec<String>) + 'static = "onExit";
|
|
812
|
+
on_share: impl Fn(&ViewTransitionInstance, &Vec<String>) + 'static = "onShare";
|
|
813
|
+
on_update: impl Fn(&ViewTransitionInstance, &Vec<String>) + 'static = "onUpdate";
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
/// What a [`ViewTransition`]'s event gets: its pseudo-elements, to animate.
|
|
818
|
+
#[cfg(react = "19.3")]
|
|
819
|
+
pub struct ViewTransitionInstance(PhantomData<JsObject>);
|
|
820
|
+
|
|
821
|
+
#[cfg(react = "19.3")]
|
|
822
|
+
impl ViewTransitionInstance {
|
|
823
|
+
#[cfg_attr(rust_js, rust_js::link_name = "get name")]
|
|
824
|
+
pub fn name(&self) -> String {
|
|
825
|
+
unreachable!()
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/// `::view-transition-old`, `new`, `group` and `image-pair`.
|
|
829
|
+
#[cfg_attr(rust_js, rust_js::link_name = "get old")]
|
|
830
|
+
pub fn old(&self) -> &'static webapi::Element {
|
|
831
|
+
unreachable!()
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
#[cfg_attr(rust_js, rust_js::link_name = "get new")]
|
|
835
|
+
pub fn new(&self) -> &'static webapi::Element {
|
|
836
|
+
unreachable!()
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
#[cfg_attr(rust_js, rust_js::link_name = "get group")]
|
|
840
|
+
pub fn group(&self) -> &'static webapi::Element {
|
|
841
|
+
unreachable!()
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
#[cfg_attr(rust_js, rust_js::link_name = "get imagePair")]
|
|
845
|
+
pub fn image_pair(&self) -> &'static webapi::Element {
|
|
846
|
+
unreachable!()
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// ── Context, memo, lazy ─────────────────────────────────────────────────
|
|
851
|
+
//
|
|
852
|
+
// JS makes a context, a memoized or lazy component once, at a module's top
|
|
853
|
+
// level. Rust keeps such a value in a `thread_local!`, which rust-js
|
|
854
|
+
// compiles to just that, a `const` of its module (ADR 0037):
|
|
855
|
+
//
|
|
856
|
+
// thread_local! {
|
|
857
|
+
// static THEME: Context<&'static str> = create_context("light");
|
|
858
|
+
// static FAST_CARD: Memo<CardProps> = memo(Card);
|
|
859
|
+
// }
|
|
860
|
+
//
|
|
861
|
+
// const THEME = createContext("light");
|
|
862
|
+
// const FAST_CARD = memo(Card);
|
|
863
|
+
//
|
|
864
|
+
// Hooks take the key: `use_context(&THEME)`. JSX uses `<FAST_CARD ... />`.
|
|
865
|
+
|
|
866
|
+
/// A [context](https://react.dev/reference/react/createContext): a value that
|
|
867
|
+
/// a component's descendants read with [`use_context`], from the nearest
|
|
868
|
+
/// provider above them, or `default` without one.
|
|
869
|
+
pub struct Context<T>(PhantomData<JsObject>, PhantomData<T>);
|
|
870
|
+
|
|
871
|
+
/// [`createContext`](https://react.dev/reference/react/createContext), in a `thread_local!`.
|
|
872
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#createContext")]
|
|
873
|
+
pub fn create_context<T>(default: T) -> Context<T> {
|
|
874
|
+
unreachable!()
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
/// Props of `<THEME value={value}>{children}</THEME>` on React 19+,
|
|
878
|
+
/// or `<THEME.Provider value={value}>{children}</THEME.Provider>` on React 18+.
|
|
879
|
+
pub struct Provider<T> {
|
|
880
|
+
pub value: T,
|
|
881
|
+
pub children: Element,
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
pub struct ProvidesContext;
|
|
885
|
+
|
|
886
|
+
#[cfg(react = "19.0")]
|
|
887
|
+
impl<T> Component<Provider<T>, ProvidesContext> for &'static LocalKey<Context<T>> {}
|
|
888
|
+
|
|
889
|
+
/// `THEME.Provider`, a context's provider in every React version:
|
|
890
|
+
/// Used by `<THEME.Provider value={value}>{children}</THEME.Provider>`.
|
|
891
|
+
#[cfg_attr(rust_js, rust_js::link_name = "get Provider")]
|
|
892
|
+
#[doc(hidden)]
|
|
893
|
+
pub fn provider<T>(this: &'static LocalKey<Context<T>>) -> ContextProvider<T> {
|
|
894
|
+
unreachable!()
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
pub struct ContextProvider<T>(PhantomData<JsObject>, PhantomData<T>);
|
|
898
|
+
|
|
899
|
+
impl<T> Component<Provider<T>, ProvidesContext> for ContextProvider<T> {}
|
|
900
|
+
|
|
901
|
+
/// A component that [`memo`] made: React skips rendering it again while its
|
|
902
|
+
/// props are the same as last time.
|
|
903
|
+
pub struct Memo<P>(PhantomData<JsObject>, PhantomData<P>);
|
|
904
|
+
|
|
905
|
+
/// [`memo`](https://react.dev/reference/react/memo), in a `thread_local!`.
|
|
906
|
+
/// Props are the same when each field is (`Object.is`).
|
|
907
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#memo")]
|
|
908
|
+
pub fn memo<P, M>(component: impl Component<P, M>) -> Memo<P> {
|
|
909
|
+
unreachable!()
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
/// `memo(component, arePropsEqual)`: the props are the same when `are_equal` says so.
|
|
913
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#memo")]
|
|
914
|
+
pub fn memo_with<P, M>(component: impl Component<P, M>, are_equal: impl Fn(&P, &P) -> bool + 'static) -> Memo<P> {
|
|
915
|
+
unreachable!()
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
pub struct Memoized;
|
|
919
|
+
|
|
920
|
+
impl<P> Component<P, Memoized> for &'static LocalKey<Memo<P>> {}
|
|
921
|
+
|
|
922
|
+
/// A component [`lazy`] loads the first time it renders.
|
|
923
|
+
pub struct Lazy<P>(PhantomData<JsObject>, PhantomData<P>);
|
|
924
|
+
|
|
925
|
+
/// A JS module whose default export is a component taking `P`, as
|
|
926
|
+
/// [`import_module`] loads it.
|
|
927
|
+
pub struct Module<P>(PhantomData<JsObject>, PhantomData<P>);
|
|
928
|
+
|
|
929
|
+
/// [`lazy`](https://react.dev/reference/react/lazy), in a `thread_local!`:
|
|
930
|
+
/// `lazy(|| import_module("./Chart.jsx"))`. It suspends while it loads, so
|
|
931
|
+
/// render it inside `<Suspense fallback={...}>...</Suspense>`.
|
|
932
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#lazy")]
|
|
933
|
+
pub fn lazy<P>(load: impl Fn() -> Promise<Module<P>> + 'static) -> Lazy<P> {
|
|
934
|
+
unreachable!()
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
/// `import(specifier)`: a module, loaded when it's first needed. The
|
|
938
|
+
/// specifier names the JS file, as the bundler sees it.
|
|
939
|
+
#[cfg_attr(rust_js, rust_js::link_name = "import")]
|
|
940
|
+
pub fn import_module<P>(specifier: &'static str) -> Promise<Module<P>> {
|
|
941
|
+
unreachable!()
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
pub struct Loaded;
|
|
945
|
+
|
|
946
|
+
impl<P> Component<P, Loaded> for &'static LocalKey<Lazy<P>> {}
|
|
947
|
+
|
|
948
|
+
/// A component that [`forward_ref`] made: its parent's `ref` reaches it.
|
|
949
|
+
pub struct ForwardRef<P, H>(PhantomData<JsObject>, PhantomData<(P, H)>);
|
|
950
|
+
|
|
951
|
+
/// [`forwardRef`](https://react.dev/reference/react/forwardRef), in a
|
|
952
|
+
/// `thread_local!`: `render` gets the props and the parent's ref. From React
|
|
953
|
+
/// 19 a component can take `ref` as a prop instead.
|
|
954
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#forwardRef")]
|
|
955
|
+
pub fn forward_ref<P, H>(render: impl Fn(P, Ref<Option<H>>) -> Element + 'static) -> ForwardRef<P, H> {
|
|
956
|
+
unreachable!()
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
pub struct Forwarded;
|
|
960
|
+
|
|
961
|
+
impl<P, H> Component<P, Forwarded> for &'static LocalKey<ForwardRef<P, H>> {}
|
|
962
|
+
|
|
963
|
+
/// Check the handle type of a forwarded JSX ref without emitting a runtime call.
|
|
964
|
+
#[doc(hidden)]
|
|
965
|
+
#[cfg_attr(rust_js, rust_js::link_name = "this")]
|
|
966
|
+
pub fn checked_ref<H, M, R: RefValue<H, M>>(this: R) -> R {
|
|
967
|
+
unreachable!()
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
// ── APIs ────────────────────────────────────────────────────────────────
|
|
971
|
+
|
|
972
|
+
/// [`startTransition`](https://react.dev/reference/react/startTransition):
|
|
973
|
+
/// the state updates in `action` render without blocking the page. From
|
|
974
|
+
/// React 19, `action` can be `async`.
|
|
975
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#startTransition")]
|
|
976
|
+
pub fn start_transition<R: ActionResult<M>, M>(action: impl FnOnce() -> R + 'static) {
|
|
977
|
+
unreachable!()
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
/// [`addTransitionType`](https://react.dev/reference/react/addTransitionType):
|
|
981
|
+
/// names what the current Transition is, for [`ViewTransition`]'s classes.
|
|
982
|
+
#[cfg(react = "19.3")]
|
|
983
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#addTransitionType")]
|
|
984
|
+
pub fn add_transition_type(name: &str) {
|
|
985
|
+
unreachable!()
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
/// [`act`](https://react.dev/reference/react/act): in a test, apply every
|
|
989
|
+
/// update `f` causes before it returns. Development builds only.
|
|
990
|
+
#[cfg(react = "18.3")]
|
|
991
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#act")]
|
|
992
|
+
pub fn act<R: ActionResult<M>, M>(f: impl FnOnce() -> R + 'static) -> Promise<()> {
|
|
993
|
+
unreachable!()
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
/// [`cache`](https://react.dev/reference/react/cache): `f`, remembering its
|
|
997
|
+
/// results. For React Server Components only.
|
|
998
|
+
#[cfg(react = "19.0")]
|
|
999
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#cache")]
|
|
1000
|
+
pub fn cache<F: 'static>(f: F) -> F {
|
|
1001
|
+
unreachable!()
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
/// [`cacheSignal`](https://react.dev/reference/react/cacheSignal): aborted
|
|
1005
|
+
/// when the render that [`cache`] belongs to is done. Server Components only;
|
|
1006
|
+
/// `None` elsewhere.
|
|
1007
|
+
#[cfg(react = "19.2")]
|
|
1008
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#cacheSignal")]
|
|
1009
|
+
pub fn cache_signal() -> Option<&'static webapi::AbortSignal> {
|
|
1010
|
+
unreachable!()
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
/// [`captureOwnerStack`](https://react.dev/reference/react/captureOwnerStack):
|
|
1014
|
+
/// which components rendered the current one, in development only.
|
|
1015
|
+
#[cfg(react = "19.1")]
|
|
1016
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#captureOwnerStack")]
|
|
1017
|
+
pub fn capture_owner_stack() -> Option<String> {
|
|
1018
|
+
unreachable!()
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
unsafe extern "Rust" {
|
|
1022
|
+
/// React's version, like `"19.3.0"`.
|
|
1023
|
+
#[link_name = "react#version"]
|
|
1024
|
+
pub safe static VERSION: &'static str;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
/// What [`use_`] reads: a [`Promise`]'s value, a [`Context`]'s, or, for
|
|
1028
|
+
/// [`dom::browser`], nothing.
|
|
1029
|
+
#[cfg(react = "19.0")]
|
|
1030
|
+
pub trait Usable {
|
|
1031
|
+
type Output;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
#[cfg(react = "19.0")]
|
|
1035
|
+
impl<T: 'static> Usable for &Promise<T> {
|
|
1036
|
+
type Output = &'static T;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
#[cfg(react = "19.0")]
|
|
1040
|
+
impl<T: 'static> Usable for &'static LocalKey<Context<T>> {
|
|
1041
|
+
type Output = &'static T;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
/// [`use`](https://react.dev/reference/react/use): a promise's value,
|
|
1045
|
+
/// suspending until it resolves, or a context's. Unlike a hook, it can be
|
|
1046
|
+
/// called in a condition or a loop. `use` is a Rust keyword, hence the name.
|
|
1047
|
+
#[cfg(react = "19.0")]
|
|
1048
|
+
#[cfg_attr(rust_js, rust_js::link_name = "react#use")]
|
|
1049
|
+
pub fn use_<U: Usable>(value: U) -> U::Output {
|
|
1050
|
+
unreachable!()
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
/// What React gives a root's error callbacks with the error: where it happened.
|
|
1054
|
+
pub struct ErrorInfo(PhantomData<JsObject>);
|
|
1055
|
+
|
|
1056
|
+
impl ErrorInfo {
|
|
1057
|
+
/// The components the error went through, as text.
|
|
1058
|
+
#[cfg_attr(rust_js, rust_js::link_name = "get componentStack")]
|
|
1059
|
+
pub fn component_stack(&self) -> Option<String> {
|
|
1060
|
+
unreachable!()
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
/// What React's error callbacks get: whatever was thrown, usually an `Error`.
|
|
1065
|
+
pub type Error = JsError;
|