react-x11 2.52.0 → 2.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -10
- package/docs/README.md +160 -314
- package/docs/accessibility.md +176 -229
- package/docs/appearance.md +77 -176
- package/docs/click-to-component.md +18 -51
- package/docs/clipboard.md +40 -59
- package/docs/components.md +518 -1036
- package/docs/dbus.md +61 -133
- package/docs/debugging.md +152 -245
- package/docs/desktop-calendar.md +51 -88
- package/docs/desktop.md +222 -347
- package/docs/devtools.md +50 -167
- package/docs/drag-and-drop.md +126 -204
- package/docs/ecosystem/animation.md +91 -125
- package/docs/ecosystem/data-fetching.md +38 -53
- package/docs/ecosystem/dev-tooling.md +159 -202
- package/docs/ecosystem/forms.md +61 -97
- package/docs/ecosystem/headless.md +64 -89
- package/docs/ecosystem/i18n.md +18 -21
- package/docs/ecosystem/icons.md +93 -126
- package/docs/ecosystem/layout.md +42 -52
- package/docs/ecosystem/routing.md +18 -29
- package/docs/ecosystem/state.md +71 -88
- package/docs/ecosystem/testing.md +131 -157
- package/docs/ecosystem/theming.md +119 -165
- package/docs/ecosystem.md +145 -179
- package/docs/elements.md +1091 -1774
- package/docs/embedding.md +83 -132
- package/docs/events.md +412 -695
- package/docs/extending.md +784 -1326
- package/docs/eyedropper.md +63 -122
- package/docs/filedialog.md +71 -107
- package/docs/frame.md +195 -339
- package/docs/gl.md +65 -62
- package/docs/globalmenu.md +63 -146
- package/docs/macos.md +531 -3234
- package/docs/notifications.md +33 -47
- package/docs/packaging.md +166 -309
- package/docs/permissions.md +9 -14
- package/docs/react-features.md +81 -106
- package/docs/remote.md +32 -76
- package/docs/scale.md +72 -186
- package/docs/styling.md +329 -547
- package/docs/system.md +200 -280
- package/docs/testing.md +63 -83
- package/docs/typescript.md +6 -48
- package/docs/uri-schemes.md +67 -107
- package/docs/wayland-backend.md +200 -459
- package/docs/windows-integrations.md +75 -131
- package/docs/windows.md +343 -1367
- package/package.json +3 -2
- package/src/Reconciler.js +2 -2
- package/src/a11y.js +1 -1
- package/src/backend/context2d.js +3 -3
- package/src/bootstrap.js +1 -1
- package/src/cocoa/app.js +6 -6
- package/src/cocoa/bezels.js +1 -1
- package/src/cocoa/fonts.js +1 -1
- package/src/cocoa/globalmenu.js +1 -1
- package/src/cocoa/keymap.js +1 -1
- package/src/cocoa/panewindow.js +1 -1
- package/src/cocoa/player.js +1 -1
- package/src/cocoa/presenter.js +2 -2
- package/src/cocoa/promotion.js +1 -1
- package/src/cocoa/relaunch.js +1 -1
- package/src/cocoa/threaded.js +1 -1
- package/src/cocoa/video.js +1 -1
- package/src/cocoa/window.js +4 -4
- package/src/components/Menu.js +7 -2
- package/src/components/Switch.js +1 -1
- package/src/components/native.js +1 -1
- package/src/dnd.js +2 -2
- package/src/glnodes.js +1 -1
- package/src/grid.js +1 -1
- package/src/layouts.js +1 -1
- package/src/nodes/animation.js +1 -1
- package/src/nodes/invalidate.js +1 -1
- package/src/nodes/layouthost.js +1 -1
- package/src/nodes/video.js +19 -8
- package/src/nodes/window/droptarget.js +1 -1
- package/src/pacing.js +1 -1
- package/src/refresh/index.js +2 -1
- package/src/types/video.d.ts +5 -2
- package/src/videobackend.js +28 -0
- package/src/videoframes.js +29 -16
- package/src/wayland/app.js +27 -0
- package/src/wayland/video.js +376 -0
- package/src/win32/a11y.js +1 -1
- package/src/win32/app.js +2 -2
- package/src/win32/fonts.js +1 -1
- package/src/win32/glarea.js +4 -4
- package/src/win32/overlay.js +1 -1
- package/src/win32/panewindow.js +3 -3
- package/src/win32/shell.js +1 -1
- package/src/win32/window.js +2 -2
- package/src/windowid.js +1 -1
- package/src/xvideo.js +189 -0
- package/docs/architecture/accessibility.md +0 -470
- package/docs/architecture/animation.md +0 -707
- package/docs/architecture/container-queries.md +0 -525
- package/docs/architecture/custom-layout.md +0 -334
- package/docs/architecture/drag-and-drop.md +0 -941
- package/docs/architecture/element-layer-contents.md +0 -622
- package/docs/architecture/frame-pacing.md +0 -255
- package/docs/architecture/grid-layout.md +0 -358
- package/docs/architecture/protocol-efficiency.md +0 -357
- package/docs/architecture/video.md +0 -1149
- package/docs/architecture/windowed-regions.md +0 -854
- package/docs/glx.md +0 -137
- package/docs/wayland.md +0 -545
- package/docs/windows-embedding.md +0 -271
- package/docs/windows-gl.md +0 -221
package/docs/ecosystem/forms.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# Forms and validation
|
|
2
2
|
|
|
3
|
-
There is no `<form>` element
|
|
3
|
+
There is no `<form>` element, so nothing submits itself — wire
|
|
4
4
|
`handleSubmit` to a `Button`'s `onPress` or to `<textinput onSubmit>`.
|
|
5
5
|
|
|
6
|
-
Everything else follows from **one signature**. Every value control
|
|
7
|
-
|
|
8
|
-
`
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
Everything else follows from **one signature**. Every value control — the
|
|
7
|
+
host elements `<textinput>` and `<textarea>`, and the widgets `Checkbox`,
|
|
8
|
+
`Switch`, `RadioGroup`, `Select` and `Slider` — calls `onChange(ev)` with a
|
|
9
|
+
change event carrying `ev.value`, `ev.target.value`, `ev.target.name` and,
|
|
10
|
+
for a checkbox, `ev.target.checked`. That is the shape DOM form libraries
|
|
11
|
+
read, so a library's handler goes straight in, with no per-widget bridge:
|
|
12
12
|
|
|
13
13
|
```jsx
|
|
14
14
|
<textinput name="host" value={f.values.host} onChange={f.handleChange} />
|
|
@@ -16,9 +16,6 @@ every DOM form library reads, so a library's handler goes straight in:
|
|
|
16
16
|
<Select name="size" value={f.values.size} options={sizes} onChange={f.handleChange} />
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
No adapter, no per-widget bridge, nothing to remember about which control
|
|
20
|
-
you are wiring.
|
|
21
|
-
|
|
22
19
|
| library | how it goes in |
|
|
23
20
|
| ---------------------- | --------------------------------------------------------- |
|
|
24
21
|
| `react-hook-form` | `{...register('host')}`, or `<Controller>` for a widget |
|
|
@@ -26,43 +23,36 @@ you are wiring.
|
|
|
26
23
|
| `downshift` | `getInputProps()` spread onto a `<textinput>` |
|
|
27
24
|
| `@tanstack/react-form` | `onChange={(ev) => field.handleChange(ev.value)}` — below |
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
renderer rather than by reading its documentation: react-hook-form@7.84.0,
|
|
26
|
+
Each row was run headless against the renderer: react-hook-form@7.84.0,
|
|
31
27
|
formik@2.4.9, downshift@9.4.0, @tanstack/react-form@1.33.2.
|
|
32
28
|
|
|
33
29
|
**The one thing to know**: a library whose field contract is
|
|
34
|
-
value-in/value-out — TanStack Form
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
value-in/value-out — TanStack Form here — needs the value taken off the
|
|
31
|
+
event; a bare `onChange={field.handleChange}` stores the _event object_ as
|
|
32
|
+
the field value with no error.
|
|
37
33
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
and keep their plain callbacks
|
|
34
|
+
A control that takes a `name` is a form field and reports an event. `Tabs`,
|
|
35
|
+
`Table` and the menus are not, and keep their plain callbacks
|
|
41
36
|
([components](../components.md#the-change-event-and-name)).
|
|
42
37
|
|
|
43
38
|
## TanStack Form {#tanstack-form}
|
|
44
39
|
|
|
45
40
|
**Out of the box.** @tanstack/react-form@1.33.2 (form-core 1.33.2).
|
|
46
41
|
|
|
47
|
-
A headless
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
value
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
a **value, not an event**. react-x11's controls fire an event, so each field
|
|
54
|
-
takes the value off it:
|
|
42
|
+
A headless form state manager: field values, dirty and touched tracking,
|
|
43
|
+
sync and async validation (Standard Schema, so zod/valibot/arktype plug in
|
|
44
|
+
directly), and submission. The field contract is `field.state.value` +
|
|
45
|
+
`field.handleChange(value)` — a **value, not an event** — so each field
|
|
46
|
+
takes the value off the control's event, the same expression a DOM app
|
|
47
|
+
writes, for a `<textinput>` and a `Checkbox` alike:
|
|
55
48
|
|
|
56
49
|
```jsx
|
|
57
50
|
onChange={(ev) => field.handleChange(ev.value)}
|
|
58
51
|
```
|
|
59
52
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
Watch for the bare form: `onChange={field.handleChange}` stores the event
|
|
64
|
-
object as the field's value — no error, no warning, and validation sees an
|
|
65
|
-
object where it expected a string.
|
|
53
|
+
The bare `onChange={field.handleChange}` stores the event object as the
|
|
54
|
+
field's value — no error, no warning, and validation sees an object where it
|
|
55
|
+
expected a string.
|
|
66
56
|
|
|
67
57
|
```jsx
|
|
68
58
|
import React from 'react';
|
|
@@ -101,25 +91,19 @@ function ConnectForm({ connect }) {
|
|
|
101
91
|
}
|
|
102
92
|
```
|
|
103
93
|
|
|
104
|
-
-
|
|
105
|
-
|
|
106
|
-
key handler.
|
|
107
|
-
- The **widgets** are the exception: `Checkbox`, `Switch`, `RadioGroup`,
|
|
108
|
-
`Select` and `Slider` still pass the next value first, so
|
|
109
|
-
`onChange={field.handleChange}` is right there and needs no unwrap. Only
|
|
110
|
-
the host elements `<textinput>`/`<textarea>` changed.
|
|
94
|
+
- There is no submit-on-Enter for free. Wire `form.handleSubmit()` to a
|
|
95
|
+
button's `onPress` and/or a window-level Enter key handler.
|
|
111
96
|
- Validation errors from a zod schema are error _objects_
|
|
112
|
-
(`errors[0].message`)
|
|
113
|
-
|
|
114
|
-
- The
|
|
115
|
-
|
|
97
|
+
(`errors[0].message`); a plain string validator returns strings. A
|
|
98
|
+
`<text>` child must be a string, so render `.message`.
|
|
99
|
+
- The SSR and Next helpers live under subpaths; the root import pulls in no
|
|
100
|
+
react-dom.
|
|
116
101
|
|
|
117
102
|
## zod {#zod}
|
|
118
103
|
|
|
119
104
|
**Out of the box.** zod@4.4.3.
|
|
120
105
|
|
|
121
|
-
|
|
122
|
-
renderer-specific — the interesting part is only where it plugs in:
|
|
106
|
+
Schema validation, pure computation. Where it plugs in:
|
|
123
107
|
|
|
124
108
|
- **TanStack Form** — pass a schema straight into a field's
|
|
125
109
|
`validators: { onChange: z.string().min(3, 'too short') }`. Zod 4
|
|
@@ -157,49 +141,39 @@ function Settings({ raw }) {
|
|
|
157
141
|
|
|
158
142
|
- Zod 4 field errors surface as issue objects; render `issue.message`, not
|
|
159
143
|
the issue itself.
|
|
160
|
-
- `valibot` and `arktype` are equally viable (also Standard Schema).
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
no bundle.
|
|
144
|
+
- `valibot` and `arktype` are equally viable (also Standard Schema).
|
|
145
|
+
- Bundle-size arguments from the web do not apply — an X11 app ships no
|
|
146
|
+
bundle.
|
|
164
147
|
|
|
165
148
|
## React Hook Form {#react-hook-form}
|
|
166
149
|
|
|
167
150
|
**Out of the box, both APIs.** react-hook-form@7.84.0 with
|
|
168
151
|
@hookform/resolvers@5.5.7.
|
|
169
152
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
works:
|
|
153
|
+
`register()` returns DOM-shaped props (`{name, ref, onChange(e),
|
|
154
|
+
onBlur(e)}`) and reads `e.target.value` off the event, which is what
|
|
155
|
+
`<textinput>` provides, so the spread works:
|
|
174
156
|
|
|
175
157
|
```jsx
|
|
176
158
|
const { register, handleSubmit } = useForm({ defaultValues: { host: '' } });
|
|
177
159
|
<textinput {...register('host')} />;
|
|
178
160
|
```
|
|
179
161
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
`
|
|
183
|
-
|
|
184
|
-
`
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
`
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
which it never does here. `setValue()` is not gated that way and does write
|
|
196
|
-
through. If you need `reset()` to clear the display, make the field
|
|
197
|
-
controlled — `<Controller>`, below — or assign `ref.current.value = ''`
|
|
198
|
-
yourself.
|
|
199
|
-
|
|
200
|
-
`<Controller>` / `useController` still works, unchanged, and is the better
|
|
201
|
-
choice when you want the field controlled. `field.onChange` accepts either a
|
|
202
|
-
plain value or an event, so both of these are fine:
|
|
162
|
+
The `ref` RHF attaches lands on a node whose `value` is writable (RHF
|
|
163
|
+
assigns `ref.value = ''` while registering). Through `register()`, typing
|
|
164
|
+
updates `getValues()`, `handleSubmit` receives the values,
|
|
165
|
+
`setValue(name, v)` writes through the ref so the field redraws, and
|
|
166
|
+
`setFocus(name)` calls the node's `.focus()`.
|
|
167
|
+
|
|
168
|
+
**`reset()` updates form state but does not clear an uncontrolled field's
|
|
169
|
+
text.** RHF writes values back through refs on reset only when its `isWeb`
|
|
170
|
+
probe (`typeof window !== 'undefined' && window.HTMLElement && document`)
|
|
171
|
+
passes, which it never does here; `setValue()` is not gated. To have
|
|
172
|
+
`reset()` clear the display, make the field controlled with `<Controller>`,
|
|
173
|
+
or assign `ref.current.value = ''` yourself.
|
|
174
|
+
|
|
175
|
+
`<Controller>` / `useController` is the choice for a controlled field.
|
|
176
|
+
`field.onChange` accepts a plain value or an event, so both are fine:
|
|
203
177
|
|
|
204
178
|
```jsx
|
|
205
179
|
onChange={(ev) => field.onChange(ev.target.value)} // explicit
|
|
@@ -246,11 +220,9 @@ function ConnectForm({ connect }) {
|
|
|
246
220
|
}
|
|
247
221
|
```
|
|
248
222
|
|
|
249
|
-
- A `Controller` field
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
- `setFocus(name)` works: it calls `.focus()` on whatever the ref holds, and
|
|
253
|
-
a `<textinput>` node has one.
|
|
223
|
+
- A `Controller` field re-renders its subtree on every keystroke;
|
|
224
|
+
`register()` does not — the same performance argument RHF makes on the
|
|
225
|
+
web.
|
|
254
226
|
- `handleSubmit` returns a function. Call it: `handleSubmit(fn)` in an
|
|
255
227
|
`onPress` is the curried form, and there is no submit event to pass.
|
|
256
228
|
|
|
@@ -258,12 +230,7 @@ function ConnectForm({ connect }) {
|
|
|
258
230
|
|
|
259
231
|
**Out of the box.** formik@2.4.9.
|
|
260
232
|
|
|
261
|
-
|
|
262
|
-
it failed _silently_: `handleChange` treats a string argument as its curried
|
|
263
|
-
field-name form, returns a handler, and never touches state — so spreading
|
|
264
|
-
`getFieldProps` onto a `<textinput>` left `values` at its initial object and
|
|
265
|
-
`touched` empty, with nothing logged. That is fixed by the event, not by an
|
|
266
|
-
adapter. All three of Formik's field styles now work:
|
|
233
|
+
All three of Formik's field styles work:
|
|
267
234
|
|
|
268
235
|
```jsx
|
|
269
236
|
import { Formik, Field, useFormik } from 'formik';
|
|
@@ -286,10 +253,7 @@ import { Formik, Field, useFormik } from 'formik';
|
|
|
286
253
|
```
|
|
287
254
|
|
|
288
255
|
`handleChange` reads `target.name` to decide which field to write, so the
|
|
289
|
-
`name` prop is
|
|
290
|
-
event carries it for.
|
|
291
|
-
|
|
292
|
-
The widgets need no bridge — same handler, same signature:
|
|
256
|
+
`name` prop is required in all of these. The widgets take the same handler:
|
|
293
257
|
|
|
294
258
|
```jsx
|
|
295
259
|
<Checkbox
|
|
@@ -301,13 +265,13 @@ The widgets need no bridge — same handler, same signature:
|
|
|
301
265
|
</Checkbox>
|
|
302
266
|
```
|
|
303
267
|
|
|
304
|
-
`ev.target` is `{ type: 'checkbox', name, value, checked }`, which is
|
|
305
|
-
|
|
306
|
-
take `checked` rather than `value`.
|
|
268
|
+
`ev.target` is `{ type: 'checkbox', name, value, checked }`, which is what
|
|
269
|
+
`handleChange` destructures — `type` is how it knows to take `checked`.
|
|
307
270
|
|
|
308
271
|
- `<Formik>`'s render-prop form and `useFormik` both work; there is no
|
|
309
272
|
`<form>` element, so call `submitForm()` (or `handleSubmit()`) yourself
|
|
310
273
|
from a `Button` or from `<textinput onSubmit>`.
|
|
311
|
-
- Passing a non-event object
|
|
312
|
-
|
|
313
|
-
undefined (reading 'type')` rather
|
|
274
|
+
- Passing `handleChange` a non-event object — a hand-rolled fake event with
|
|
275
|
+
no `target` — throws
|
|
276
|
+
`TypeError: Cannot read properties of undefined (reading 'type')` rather
|
|
277
|
+
than no-opping. Pass the real event.
|
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
# Headless components
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
UI, the Radix primitives and downshift all fail, the last one silently until
|
|
12
|
-
the first keystroke.
|
|
13
|
-
|
|
14
|
-
For finished widgets, react-x11 ships its own: `Button`, `Checkbox`,
|
|
3
|
+
A library that returns DOM prop bags — `useButton()` and the like — is
|
|
4
|
+
DOM-coupled with the rendering deferred, not headless in a sense that helps
|
|
5
|
+
here. The two packages below own state and collections, return plain values,
|
|
6
|
+
and never touch a ref. Headless UI and the Radix primitives render DOM hosts
|
|
7
|
+
and fail ([register](../ecosystem.md#what-does-not-work)); downshift's
|
|
8
|
+
`getInputProps()` works on a `<textinput>` ([forms](forms.md)).
|
|
9
|
+
|
|
10
|
+
For finished widgets react-x11 ships its own: `Button`, `Checkbox`,
|
|
15
11
|
`Radio`/`RadioGroup`, `Switch`, `ProgressBar`, `Select`, `Slider`, `Tooltip`,
|
|
16
|
-
`Dialog`, `MenuBar`/`ContextMenu`, `Tabs`, `Table`, `SplitPane
|
|
12
|
+
`Dialog`, `MenuBar`/`ContextMenu`, `Tabs`, `Table`, `SplitPane` — see
|
|
17
13
|
[components](../components.md).
|
|
18
14
|
|
|
19
15
|
## react-stately {#react-stately}
|
|
@@ -25,13 +21,9 @@ The state-machine half of React Aria: `useListState`, `useTreeState`,
|
|
|
25
21
|
`useComboBoxState`, `useMenuTriggerState`, `useNumberFieldState` and about
|
|
26
22
|
thirty-five more, plus the `Item`/`Section` collection API. Each hook owns
|
|
27
23
|
selection, disabled-key traversal, expansion and typeahead-ready collections
|
|
28
|
-
— everything
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
There is no seam to bridge: the hooks take props, return state, and never
|
|
32
|
-
touch a ref. A scan of the shipped `dist/` finds no runtime reference to
|
|
33
|
-
`document`, `window` or `getBoundingClientRect` in any hook, and its
|
|
34
|
-
dependencies (`@internationalized/*`, `@react-types/shared`,
|
|
24
|
+
— everything but rendering and event binding, which react-x11 supplies. No
|
|
25
|
+
hook references `document`, `window` or `getBoundingClientRect` at runtime,
|
|
26
|
+
and the dependencies (`@internationalized/*`, `@react-types/shared`,
|
|
35
27
|
`use-sync-external-store`) are DOM-free.
|
|
36
28
|
|
|
37
29
|
```jsx
|
|
@@ -76,21 +68,18 @@ function Picker() {
|
|
|
76
68
|
}
|
|
77
69
|
```
|
|
78
70
|
|
|
79
|
-
- **Only `react-stately` is portable.** `react-aria` (
|
|
80
|
-
|
|
81
|
-
follow Adobe's docs into `useListBox` or `useButton
|
|
82
|
-
|
|
83
|
-
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
- Drag-and-drop hooks (`useDraggableCollectionState`) hold state fine, but
|
|
92
|
-
everything that would _feed_ them events is DOM-side. Expect to write the
|
|
93
|
-
event plumbing.
|
|
71
|
+
- **Only `react-stately` is portable.** `react-aria` (hooks that produce DOM
|
|
72
|
+
props and bind DOM events) and `react-aria-components` are not — do not
|
|
73
|
+
follow Adobe's docs into `useListBox` or `useButton`.
|
|
74
|
+
- Since 3.48 the old `@react-stately/*` packages are bundled in, with
|
|
75
|
+
per-hook subpath exports (`react-stately/useListState`) for lean imports.
|
|
76
|
+
- The collection API wants `<Item>`/`<Section>` elements, or `items` plus a
|
|
77
|
+
render function — ceremonious for a three-entry menu.
|
|
78
|
+
- `useAsyncList` carries fetch-based loading state — fine under Node, the
|
|
79
|
+
one hook with I/O opinions.
|
|
80
|
+
- Drag-and-drop hooks (`useDraggableCollectionState`) hold state, but
|
|
81
|
+
everything that would _feed_ them events is DOM-side; write the event
|
|
82
|
+
plumbing yourself.
|
|
94
83
|
|
|
95
84
|
## `@tanstack/react-table` {#tanstack-table}
|
|
96
85
|
|
|
@@ -98,21 +87,16 @@ function Picker() {
|
|
|
98
87
|
react-store 0.11.1).
|
|
99
88
|
|
|
100
89
|
A headless table engine: column defs, row models, sorting, filtering,
|
|
101
|
-
grouping, pagination, column sizing, visibility and pinning
|
|
102
|
-
plus derived row models.
|
|
103
|
-
`getRowModel().rows` to
|
|
104
|
-
|
|
105
|
-
v9
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
bullets below. `column.getToggleSortingHandler()` still goes straight onto a
|
|
112
|
-
header `onClick`.
|
|
113
|
-
|
|
114
|
-
v9's API is modular where v8's was monolithic: features and row models are
|
|
115
|
-
registered up front through `tableFeatures`, and the hook is `useTable`.
|
|
90
|
+
grouping, pagination, column sizing, visibility and pinning, as pure state
|
|
91
|
+
plus derived row models. You map `getHeaderGroups()` and
|
|
92
|
+
`getRowModel().rows` to react-x11 elements.
|
|
93
|
+
|
|
94
|
+
v9's "adapters" are per framework, not per renderer: `@tanstack/react-table`
|
|
95
|
+
_is_ the React adapter, so there is nothing to write, and it never touches
|
|
96
|
+
`react-dom` or `document` at runtime (but see the react-dom and `flexRender`
|
|
97
|
+
bullets). `column.getToggleSortingHandler()` goes straight onto a header
|
|
98
|
+
`onClick`. Features and row models are registered up front through
|
|
99
|
+
`tableFeatures`, and the hook is `useTable`.
|
|
116
100
|
|
|
117
101
|
```jsx
|
|
118
102
|
import React from 'react';
|
|
@@ -173,47 +157,38 @@ function Servers({ data }) {
|
|
|
173
157
|
}
|
|
174
158
|
```
|
|
175
159
|
|
|
176
|
-
Sorting is uncontrolled here — the table's
|
|
177
|
-
|
|
178
|
-
`state`/`onSortingChange`
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
`<box style={{ flexDirection: 'row' }}>` rows: TanStack owns the data logic,
|
|
183
|
-
react-x11 owns painting.
|
|
160
|
+
Sorting is uncontrolled here — the table's store holds it, and the header
|
|
161
|
+
click re-renders through the adapter's subscription. Pass
|
|
162
|
+
`state`/`onSortingChange` to control it, or a selector as `useTable`'s
|
|
163
|
+
second argument to subscribe a component to only some slices. Render into
|
|
164
|
+
the built-in `Table` component or raw `<box style={{ flexDirection: 'row' }}>`
|
|
165
|
+
rows.
|
|
184
166
|
|
|
185
167
|
- **`coreRowModel` is opt-in, and forgetting it fails silently.** Without
|
|
186
|
-
`coreRowModel: createCoreRowModel()` in `tableFeatures`,
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
it yourself.
|
|
168
|
+
`coreRowModel: createCoreRowModel()` in `tableFeatures`, headers render
|
|
169
|
+
and `getRowModel().rows` is `[]`, with no error. The official examples get
|
|
170
|
+
it from framework presets; register it yourself.
|
|
190
171
|
- **npm installs a `react-dom` you must not keep.** `@tanstack/react-store`
|
|
191
|
-
declares a `react-dom` _peer_
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
-
|
|
206
|
-
mouse or touch events with `clientX`, and now fall back to a
|
|
207
|
-
`document`-listener drag loop (injectable as `_contextDocument`). Simpler
|
|
208
|
-
to ignore the helper: write your own drag handling off
|
|
209
|
-
`onMouseDown`/`onMouseMove` — react-x11 events carry `x`/`y` — and call
|
|
172
|
+
declares a `react-dom` _peer_, which npm 7+ auto-installs. The shipped
|
|
173
|
+
code never imports it (test 2 finds one `"button"`, in a doc comment, and
|
|
174
|
+
the table works with `node_modules/react-dom` deleted), but a resident
|
|
175
|
+
react-dom is the [silent-failures](../ecosystem.md#silent-failures)
|
|
176
|
+
hazard. Install with `--legacy-peer-deps`, or delete it so
|
|
177
|
+
`npm ls react-dom` stays empty.
|
|
178
|
+
- **`flexRender` returns a React element even for a plain string cell** (v8
|
|
179
|
+
returned the string). Inside `<text>` it paints identically, but a test or
|
|
180
|
+
a11y walk reading a `<text>` node's `children` prop sees an element
|
|
181
|
+
object; read the rendered chunks. A `cell` that returns DOM elements
|
|
182
|
+
throws the unknown-element error; return strings or react-x11 elements.
|
|
183
|
+
- Column _resizing_ helpers (`header.getResizeHandler`) expect DOM mouse or
|
|
184
|
+
touch events with `clientX` and fall back to a `document`-listener drag
|
|
185
|
+
loop (injectable as `_contextDocument`). Simpler: handle the drag off
|
|
186
|
+
`onMouseDown`/`onMouseMove` (react-x11 events carry `x`/`y`) and call
|
|
210
187
|
`table.setColumnSizing` (needs `columnSizingFeature` registered).
|
|
211
|
-
- `useTable` probes `typeof window` to pick `useLayoutEffect
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
-
|
|
216
|
-
[layout](layout.md#tanstack-virtual). TanStack Table will happily hand you
|
|
217
|
-
10,000 row objects and let the renderer drown.
|
|
188
|
+
- `useTable` probes `typeof window` to pick `useLayoutEffect` and gets
|
|
189
|
+
`useEffect` under Node — a harmless test-3 hit (timing, not a feature
|
|
190
|
+
gate).
|
|
191
|
+
- For thousands of rows, pair it with a
|
|
192
|
+
[virtualizer](layout.md#tanstack-virtual).
|
|
218
193
|
- State updates driven from outside a React event land one frame later than
|
|
219
|
-
the call,
|
|
194
|
+
the call, as with any react-x11 update.
|
package/docs/ecosystem/i18n.md
CHANGED
|
@@ -4,16 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
**Out of the box.** i18next@26.3.6, react-i18next@17.0.11.
|
|
6
6
|
|
|
7
|
-
i18next
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
The core has no DOM in it and react-i18next renders whatever elements you
|
|
13
|
-
hand it, so the whole stack runs unmodified: interpolation, count-based
|
|
14
|
-
plurals, `<Trans>`, and `i18n.changeLanguage('de')` re-rendering the mounted
|
|
15
|
-
tree in place. Node ships full ICU, so `Intl.NumberFormat` and
|
|
16
|
-
`Intl.DateTimeFormat` formatting work too.
|
|
7
|
+
i18next (resources, interpolation, plurals, namespaces, backends) with
|
|
8
|
+
react-i18next's `useTranslation`, `<Trans>` and provider-driven re-render
|
|
9
|
+
runs unmodified: interpolation, count-based plurals, `<Trans>`, and
|
|
10
|
+
`i18n.changeLanguage('de')` re-rendering the mounted tree in place. Node
|
|
11
|
+
ships full ICU, so `Intl.NumberFormat` and `Intl.DateTimeFormat` work too.
|
|
17
12
|
|
|
18
13
|
Two react-x11-specific rules:
|
|
19
14
|
|
|
@@ -72,18 +67,20 @@ function Status() {
|
|
|
72
67
|
// i18n.changeLanguage('de') re-renders live
|
|
73
68
|
```
|
|
74
69
|
|
|
75
|
-
|
|
76
|
-
|
|
70
|
+
To load translations from disk use `i18next-fs-backend`;
|
|
71
|
+
`i18next-http-backend` also works, since Node has `fetch`.
|
|
77
72
|
|
|
78
73
|
## What is missing below the string
|
|
79
74
|
|
|
80
|
-
|
|
81
|
-
|
|
75
|
+
React-x11 gaps rather than i18next ones, and they matter more than the
|
|
76
|
+
library choice:
|
|
82
77
|
|
|
83
|
-
- **
|
|
84
|
-
in the renderer ([events.md](../events.md#composition)), but
|
|
85
|
-
XIM/IBus
|
|
86
|
-
can be _displayed_ but not
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
78
|
+
- **No input method on X11 or Cocoa.** Dead keys and the Compose key are
|
|
79
|
+
handled in the renderer ([events.md](../events.md#composition)), but
|
|
80
|
+
there is no XIM/IBus/Fcitx client on X11 and no `NSTextInputClient` on
|
|
81
|
+
Cocoa, so a language that needs one — CJK — can be _displayed_ but not
|
|
82
|
+
typed there. The Wayland and Windows backends drive the system input
|
|
83
|
+
method.
|
|
84
|
+
- `<Trans>` with `<strong>`/`<em>`-style numbered tags is fine as long as
|
|
85
|
+
every referenced component is a `<text>` span. An accidental DOM tag fails
|
|
86
|
+
loudly at render.
|