react-x11 2.52.0 → 2.54.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 +1096 -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/imagedecode-worker.js +32 -0
- package/src/imagedecode.js +140 -2
- 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/ntk.d.ts +12 -0
- 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/icons.md
CHANGED
|
@@ -1,28 +1,27 @@
|
|
|
1
1
|
# Icons
|
|
2
2
|
|
|
3
3
|
react-x11 has a real `<svg>` host, so icons get further than most DOM
|
|
4
|
-
libraries
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
inherit.
|
|
4
|
+
libraries. Two renderer facts shape every entry on this page:
|
|
5
|
+
|
|
6
|
+
1. **ntk's `SvgView`, which rasterizes `<svg>`, ignores presentation
|
|
7
|
+
attributes on the root element.** Inheritance starts from its own
|
|
8
|
+
defaults, so an icon with `fill="none" stroke="currentColor"
|
|
9
|
+
stroke-width="2"` on the root renders as solid black blobs — wrong
|
|
10
|
+
glyphs, not just the wrong colour. Moving those attributes onto an inner
|
|
11
|
+
`<g>`, which does inherit, fixes it.
|
|
13
12
|
2. **Flat style props on `<svg>` throw.** `<svg width={24}>` is
|
|
14
13
|
`react-x11: <svg width=…> is a style property — pass it in style`. Size
|
|
15
14
|
with `style={{ width: 24 }}`; the `viewBox` keeps the aspect ratio.
|
|
16
15
|
|
|
17
16
|
Fact 2 is why `lucide-react`, `@tabler/icons-react` and
|
|
18
|
-
`@phosphor-icons/react` cannot work
|
|
19
|
-
[
|
|
20
|
-
|
|
17
|
+
`@phosphor-icons/react` cannot work
|
|
18
|
+
([register](../ecosystem.md#render-time)); `@heroicons/react` is the
|
|
19
|
+
exception.
|
|
21
20
|
|
|
22
21
|
## The `iconSource` wrapper {#iconsource}
|
|
23
22
|
|
|
24
23
|
Four of the packages below ship whole SVG _strings_ with paint attributes on
|
|
25
|
-
the root. They all need the same twelve lines
|
|
24
|
+
the root. They all need the same twelve lines:
|
|
26
25
|
|
|
27
26
|
```js
|
|
28
27
|
// icon-source.js — re-root an icon's paint attributes onto a <g> so they
|
|
@@ -41,14 +40,11 @@ export function iconSource(svgText, color = '#000') {
|
|
|
41
40
|
}
|
|
42
41
|
```
|
|
43
42
|
|
|
44
|
-
`
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
Cache the wrapped strings per (name, style, colour); parsing per mount is
|
|
51
|
-
avoidable work.
|
|
43
|
+
`currentColor` resolves to the inherited `color`, which defaults to `#000`,
|
|
44
|
+
so the `color` attribute on the `<g>` is what makes recolouring work.
|
|
45
|
+
`svgText.replaceAll('currentColor', color)` alone is _not_ enough: it fixes
|
|
46
|
+
the colour but not the dropped `fill="none"`, so stroke icons still paint as
|
|
47
|
+
filled blobs. Cache the wrapped strings per (name, style, colour).
|
|
52
48
|
|
|
53
49
|
## Iconify {#iconify}
|
|
54
50
|
|
|
@@ -56,14 +52,11 @@ avoidable work.
|
|
|
56
52
|
|
|
57
53
|
Iconify publishes every major icon set as JSON data — `@iconify-json/tabler`,
|
|
58
54
|
`@iconify-json/mdi`, `@iconify-json/ph`, `@iconify-json/lucide`,
|
|
59
|
-
`@iconify-json/heroicons` — plus `@iconify/utils`,
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
needs **no re-rooting adapter**, because `iconToSVG` returns the icon body
|
|
65
|
-
separately from the root attributes, and the paint attributes live inside the
|
|
66
|
-
body rather than on the root.
|
|
55
|
+
`@iconify-json/heroicons` — plus `@iconify/utils`, which looks an icon up and
|
|
56
|
+
builds SVG markup from it. The highest-leverage route: one pipeline, 200,000+
|
|
57
|
+
icons, and the only string-SVG route that needs **no re-rooting adapter**,
|
|
58
|
+
because `iconToSVG` returns the body separately from the root attributes and
|
|
59
|
+
the paint attributes live inside the body.
|
|
67
60
|
|
|
68
61
|
```jsx
|
|
69
62
|
import { getIconData, iconToSVG, iconToHTML, replaceIDs } from '@iconify/utils';
|
|
@@ -86,10 +79,9 @@ function Icon({ name, size = 24, color }) {
|
|
|
86
79
|
// <Icon name="settings" size={16} color="#0891b2" />
|
|
87
80
|
```
|
|
88
81
|
|
|
89
|
-
- `replaceIDs` matters for icons
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
keep.
|
|
82
|
+
- `replaceIDs` matters for icons with gradients or clip paths, whose `id`s
|
|
83
|
+
would collide inside one rasterized document. Harmless across separate
|
|
84
|
+
`<svg>` nodes, but free to keep.
|
|
93
85
|
- Pick per-set packages (`@iconify-json/tabler` is about 5,000 icons in one
|
|
94
86
|
JSON) rather than the monolithic `@iconify/json`, which is all 200,000+ and
|
|
95
87
|
roughly 100 MB.
|
|
@@ -100,11 +92,10 @@ function Icon({ name, size = 24, color }) {
|
|
|
100
92
|
|
|
101
93
|
**Out of the box — size it with `style`.** @heroicons/react@2.2.0.
|
|
102
94
|
|
|
103
|
-
The exception among the `*-react` icon packages
|
|
104
|
-
|
|
105
|
-
attributes, so
|
|
106
|
-
|
|
107
|
-
`@phosphor-icons/react`, all three of which throw.
|
|
95
|
+
The exception among the `*-react` icon packages: its components size
|
|
96
|
+
themselves with a Tailwind class name rather than flat `width`/`height`
|
|
97
|
+
attributes, so the `<svg>` host accepts them. lucide-react,
|
|
98
|
+
`@tabler/icons-react` and `@phosphor-icons/react` all throw.
|
|
108
99
|
|
|
109
100
|
```jsx
|
|
110
101
|
import { BeakerIcon } from '@heroicons/react/24/solid';
|
|
@@ -114,25 +105,20 @@ import { BeakerIcon } from '@heroicons/react/24/solid';
|
|
|
114
105
|
</box>;
|
|
115
106
|
```
|
|
116
107
|
|
|
117
|
-
The
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
There is no recolour channel through the component, so if you need a themed
|
|
122
|
-
icon use the asset package below, or `@iconify-json/heroicons`.
|
|
108
|
+
The renderer ignores the `className`, so pass `style={{ width, height }}`
|
|
109
|
+
yourself — an icon with no size lays out at its natural size or collapses,
|
|
110
|
+
depending on the surrounding flex box. There is no recolour channel; for a
|
|
111
|
+
themed icon use the asset package below, or `@iconify-json/heroicons`.
|
|
123
112
|
|
|
124
113
|
## `lucide` {#lucide}
|
|
125
114
|
|
|
126
115
|
**Adapter, ~10 lines.** lucide@1.28.0.
|
|
127
116
|
|
|
128
|
-
Lucide's core package
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
skips string parsing entirely — each pair becomes a JSX child of `<svg>`,
|
|
134
|
-
which react-x11 serializes through `SvgChildNode` (camelCase to kebab
|
|
135
|
-
attributes) into ntk's `SvgView`.
|
|
117
|
+
Lucide's core package exports every icon as plain data — an array of
|
|
118
|
+
`[tag, attrs]` pairs — alongside the DOM-oriented `createIcons`.
|
|
119
|
+
Tree-shakeable per icon, and the best fit for react-x11: no string parsing,
|
|
120
|
+
each pair becomes a JSX child of `<svg>` (camelCase props serialize as
|
|
121
|
+
kebab-case attributes).
|
|
136
122
|
|
|
137
123
|
```jsx
|
|
138
124
|
import { createElement } from 'react';
|
|
@@ -160,8 +146,7 @@ function Icon({ icon, size = 24, color = '#000', strokeWidth = 2 }) {
|
|
|
160
146
|
// <Icon icon={theme === 'dark' ? Sun : House} color={accent} />
|
|
161
147
|
```
|
|
162
148
|
|
|
163
|
-
|
|
164
|
-
`icon` or `color` in state re-renders the icon.
|
|
149
|
+
Swapping `icon` or `color` in state repaints the icon.
|
|
165
150
|
|
|
166
151
|
- Omitting the `<g>` and putting `stroke`/`fill` on the `<svg>` silently
|
|
167
152
|
renders black filled blobs.
|
|
@@ -175,10 +160,9 @@ Prop changes on SVG children invalidate and repaint correctly — swapping
|
|
|
175
160
|
|
|
176
161
|
**Adapter — the [`iconSource` wrapper](#iconsource).** lucide-static@1.28.0.
|
|
177
162
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
the wrapper.
|
|
163
|
+
Every Lucide icon as a named export holding an SVG markup string: 24×24,
|
|
164
|
+
stroke-based, `stroke="currentColor"` with round caps and joins — all on the
|
|
165
|
+
root element, hence the wrapper.
|
|
182
166
|
|
|
183
167
|
```jsx
|
|
184
168
|
import * as lucide from 'lucide-static';
|
|
@@ -192,25 +176,23 @@ const Icon = ({ name, size = 24, color = '#000' }) => (
|
|
|
192
176
|
// <Icon name="Sun" size={16} color="#eab308" />
|
|
193
177
|
```
|
|
194
178
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
sheet).
|
|
179
|
+
Prefer the `lucide` data package; use this one when you want the markup
|
|
180
|
+
string itself (asset pipelines, a pre-built sheet).
|
|
198
181
|
|
|
199
182
|
## `react-icons` {#react-icons}
|
|
200
183
|
|
|
201
184
|
**Adapter, ~15 lines.** react-icons@5.7.0.
|
|
202
185
|
|
|
203
|
-
The
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
186
|
+
The React icon aggregator — Font Awesome, Material, Lucide, Bootstrap,
|
|
187
|
+
Simple Icons and about fifty more behind one API. Unadapted it throws,
|
|
188
|
+
because `IconBase` always sets `height`/`width` (default `"1em"`) as flat
|
|
189
|
+
props on `<svg>`.
|
|
207
190
|
|
|
208
|
-
The adapter sidesteps `IconBase
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
fact 1 above.
|
|
191
|
+
The adapter sidesteps `IconBase`. An icon component called with empty props
|
|
192
|
+
returns the `IconBase` element, whose props carry `attr` (the set's root
|
|
193
|
+
attributes — `viewBox`, and for stroke sets the paint attributes) and
|
|
194
|
+
`children` (the paths as React elements). Re-rooting `attr` onto an inner
|
|
195
|
+
`<g>` handles fact 1.
|
|
214
196
|
|
|
215
197
|
```jsx
|
|
216
198
|
import { FaHeart } from 'react-icons/fa';
|
|
@@ -239,25 +221,23 @@ function RIcon({ icon: I, size = 24, color = '#000' }) {
|
|
|
239
221
|
// <RIcon icon={LuHouse} color="#2563eb" /> stroke-based
|
|
240
222
|
```
|
|
241
223
|
|
|
242
|
-
- `I({})`
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
which have no such seam.
|
|
224
|
+
- `I({})` relies on each icon being a plain function component wrapping
|
|
225
|
+
`GenIcon` — react-icons' shape since v4, but an internal one. `lucide` and
|
|
226
|
+
the Iconify pipeline have no such seam.
|
|
246
227
|
- `IconContext` (global size/colour config) is bypassed; pass props instead.
|
|
247
|
-
- The `title` prop emits an SVG `<title>` child,
|
|
248
|
-
assistive
|
|
249
|
-
- react-icons
|
|
250
|
-
|
|
228
|
+
- The `title` prop emits an SVG `<title>` child, which reaches no tooltip or
|
|
229
|
+
assistive technology from a rasterized SVG. Omit it.
|
|
230
|
+
- react-icons bundles every set and is heavy on disk; for one style,
|
|
231
|
+
`lucide` or `@iconify-json/<set>` is a much smaller install.
|
|
251
232
|
|
|
252
233
|
## `@tabler/icons` {#tabler-icons}
|
|
253
234
|
|
|
254
235
|
**Adapter — the [`iconSource` wrapper](#iconsource).** @tabler/icons@3.46.0.
|
|
255
236
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
`
|
|
260
|
-
idea as `lucide`'s data exports.
|
|
237
|
+
5,000+ MIT icons as SVG files under `icons/outline/` (stroke-based, 24×24)
|
|
238
|
+
and `icons/filled/`, with an `exports` map that resolves file paths, plus
|
|
239
|
+
`tabler-nodes-outline.json`/`-filled.json` — per-icon node arrays like
|
|
240
|
+
`lucide`'s data exports.
|
|
261
241
|
|
|
262
242
|
```jsx
|
|
263
243
|
import fs from 'node:fs';
|
|
@@ -280,30 +260,25 @@ const Icon = ({ name, style, size = 24, color = '#000' }) => (
|
|
|
280
260
|
// <Icon name="settings" style="filled" size={16} />
|
|
281
261
|
```
|
|
282
262
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
the JSON node arrays.
|
|
263
|
+
**Prefer `@iconify-json/tabler` + `@iconify/utils`**: identical art, no
|
|
264
|
+
adapter. Use this package when you want the files themselves or the JSON
|
|
265
|
+
node arrays.
|
|
287
266
|
|
|
288
|
-
- Outline icons start with a
|
|
289
|
-
fill="none"/>` bounds rect
|
|
290
|
-
Harmless.
|
|
291
|
-
- `@tabler/icons-react` throws.
|
|
292
|
-
[register](../ecosystem.md#render-time).
|
|
267
|
+
- Outline icons start with a
|
|
268
|
+
`<path stroke="none" d="M0 0h24v24H0z" fill="none"/>` bounds rect, which
|
|
269
|
+
paints nothing. Harmless.
|
|
270
|
+
- `@tabler/icons-react` throws ([register](../ecosystem.md#render-time)).
|
|
293
271
|
|
|
294
272
|
## `@phosphor-icons/core` {#phosphor-icons}
|
|
295
273
|
|
|
296
274
|
**Adapter — the [`iconSource` wrapper](#iconsource).**
|
|
297
275
|
@phosphor-icons/core@2.1.1.
|
|
298
276
|
|
|
299
|
-
|
|
300
|
-
`
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
glyphs — the default fill happens to match — so the wrapper is only
|
|
305
|
-
mandatory for colour. The `duotone` weight relies on per-path opacity, which
|
|
306
|
-
survives fine either way.
|
|
277
|
+
Raw SVG files under `assets/<weight>/<name>.svg` for six weights (`thin`,
|
|
278
|
+
`light`, `regular`, `bold`, `fill`, `duotone`), 256×256 viewBox,
|
|
279
|
+
fill-based. Because the default fill matches, the raw file renders legible
|
|
280
|
+
black glyphs; the wrapper is only needed for colour. `duotone`'s per-path
|
|
281
|
+
opacity survives either way.
|
|
307
282
|
|
|
308
283
|
```jsx
|
|
309
284
|
import fs from 'node:fs';
|
|
@@ -331,19 +306,17 @@ const Icon = ({ name, weight, size = 24, color = '#000' }) => (
|
|
|
331
306
|
```
|
|
332
307
|
|
|
333
308
|
- Non-`regular` weights use suffixed filenames
|
|
334
|
-
(`assets/bold/house-bold.svg`); the helper above
|
|
309
|
+
(`assets/bold/house-bold.svg`); the helper above handles it.
|
|
335
310
|
- `@iconify-json/ph` serves the same set with no adapter and no filesystem
|
|
336
311
|
access. Prefer it unless you want the files.
|
|
337
|
-
- `@phosphor-icons/react` throws.
|
|
338
|
-
[register](../ecosystem.md#render-time).
|
|
312
|
+
- `@phosphor-icons/react` throws ([register](../ecosystem.md#render-time)).
|
|
339
313
|
|
|
340
314
|
## `heroicons` (the asset package) {#heroicons-assets}
|
|
341
315
|
|
|
342
316
|
**Adapter — the [`iconSource` wrapper](#iconsource).** heroicons@2.2.0.
|
|
343
317
|
|
|
344
|
-
The Tailwind
|
|
345
|
-
`24/solid/`, `20/solid/` and `16/solid/`.
|
|
346
|
-
package is just the files.
|
|
318
|
+
The Tailwind set as plain SVG files, no JS: `24/outline/*.svg`
|
|
319
|
+
(stroke-based), `24/solid/`, `20/solid/` and `16/solid/`.
|
|
347
320
|
|
|
348
321
|
```jsx
|
|
349
322
|
import fs from 'node:fs';
|
|
@@ -366,22 +339,18 @@ const Icon = ({ name, style, size = 24, color = '#000' }) => (
|
|
|
366
339
|
// <Icon name="home" style="24/solid" color="#0ea5e9" />
|
|
367
340
|
```
|
|
368
341
|
|
|
369
|
-
Use this rather than `@heroicons/react` when you need to recolour
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
**Prefer `@iconify-json/heroicons`** through the [Iconify](#iconify)
|
|
374
|
-
pipeline: it is the same art, with no adapter and no filesystem access. Reach
|
|
375
|
-
for the asset package when you specifically want the files.
|
|
342
|
+
Use this rather than `@heroicons/react` when you need to recolour. There is
|
|
343
|
+
no JS index, so enumerate the directory for a picker. **Prefer
|
|
344
|
+
`@iconify-json/heroicons`** through the [Iconify](#iconify) pipeline — same
|
|
345
|
+
art, no adapter, no filesystem access — unless you want the files.
|
|
376
346
|
|
|
377
347
|
## `feather-icons` {#feather-icons}
|
|
378
348
|
|
|
379
349
|
**Adapter, ~5 lines.** feather-icons@4.29.2.
|
|
380
350
|
|
|
381
|
-
The classic 24×24 stroke set, 287 icons.
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
never applies.
|
|
351
|
+
The classic 24×24 stroke set, 287 icons. `.contents` is the inner SVG
|
|
352
|
+
markup without a root element, so the adapter is a template literal: build
|
|
353
|
+
the root and the `<g>` yourself and fact 1 never applies.
|
|
385
354
|
|
|
386
355
|
```jsx
|
|
387
356
|
import feather from 'feather-icons';
|
|
@@ -399,12 +368,10 @@ const Icon = ({ name, size = 24, color, strokeWidth }) => (
|
|
|
399
368
|
// <Icon name="alert-circle" color="#f59e0b" />
|
|
400
369
|
```
|
|
401
370
|
|
|
402
|
-
- **Prefer Lucide
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
`color` on the root too, where it is equally ignored. Always go through
|
|
409
|
-
`.contents`.
|
|
371
|
+
- **Prefer Lucide**, Feather's actively developed fork with five times the
|
|
372
|
+
coverage and the same look; Feather has had no new icons in years. Use it
|
|
373
|
+
only to match an existing design.
|
|
374
|
+
- `feather.icons.x.toSvg()` into `<svg source>` renders wrong: `toSvg()`
|
|
375
|
+
puts every paint attribute, and `toSvg({ color })`'s `color`, on the root,
|
|
376
|
+
where they are ignored. Always go through `.contents`.
|
|
410
377
|
- `feather.replace()` (the DOM `<i data-feather>` swapper) is browser-only.
|
package/docs/ecosystem/layout.md
CHANGED
|
@@ -1,31 +1,25 @@
|
|
|
1
1
|
# Layout and positioning
|
|
2
2
|
|
|
3
3
|
Layout itself is yoga's job — see [styling](../styling.md). The two packages
|
|
4
|
-
here cover
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Both are the _core_ half of a library whose React wrapper is DOM-bound. That
|
|
9
|
-
is the recurring shape in this section of the ecosystem: the algorithm is
|
|
10
|
-
portable, the wrapper is not, and the core is published separately precisely
|
|
11
|
-
so that non-DOM hosts can use it.
|
|
4
|
+
here cover what yoga does not: placing a popup relative to a trigger across
|
|
5
|
+
screen edges, and rendering a long list without a node per row. Both are the
|
|
6
|
+
_core_ half of a library whose React wrapper is DOM-bound; the core is
|
|
7
|
+
published separately so non-DOM hosts can use it.
|
|
12
8
|
|
|
13
9
|
## `@floating-ui/core` {#floating-ui}
|
|
14
10
|
|
|
15
11
|
**Adapter, ~35 lines (a platform object).** @floating-ui/core@1.8.0.
|
|
16
12
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
`
|
|
20
|
-
|
|
21
|
-
`autoPlacement`, `hide`) with the placement vocabulary every web developer
|
|
22
|
-
already knows.
|
|
13
|
+
Floating UI's positioning engine without DOM code. Hand `computePosition` a
|
|
14
|
+
`platform` object — `getElementRects`, `getDimensions`, `getClippingRect`,
|
|
15
|
+
`isRTL` — and get the full middleware pipeline (`offset`, `flip`, `shift`,
|
|
16
|
+
`size`, `arrow`, `autoPlacement`, `hide`) and its placement vocabulary.
|
|
23
17
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
As in the built-in `anchorRect()`, a drawn node's `node.abs` rect plus the
|
|
19
|
+
window's screen origin is the reference rect in screen coordinates,
|
|
20
|
+
`screenOf(node)` gives the clipping rect, and the popup-to-be is just
|
|
21
|
+
`{width, height}`. The result's `{x, y, placement}` drops straight into
|
|
22
|
+
`<popup x y>`.
|
|
29
23
|
|
|
30
24
|
```jsx
|
|
31
25
|
import { computePosition, offset, flip, shift } from '@floating-ui/core';
|
|
@@ -78,40 +72,37 @@ const { x, y, placement } = await computePosition(
|
|
|
78
72
|
// -> <popup x={x} y={y}> ; placement tells you which side won
|
|
79
73
|
```
|
|
80
74
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
`
|
|
75
|
+
Over `anchorRect` this adds middleware composition (`shift` with padding,
|
|
76
|
+
`size` to clamp long menus, `arrow`) and alignment fallback — `flip` with
|
|
77
|
+
`crossAxis: 'alignment'` switches `bottom-start` to `bottom-end` when that
|
|
78
|
+
fits. `anchorRect`'s `placement`, `align` and `offset` options map 1:1 onto
|
|
79
|
+
`placement` plus the `offset()` middleware.
|
|
86
80
|
|
|
87
|
-
- `computePosition` is async — `await` it,
|
|
81
|
+
- `computePosition` is async — `await` it, though this platform is
|
|
88
82
|
synchronous.
|
|
89
83
|
- `getClippingRect` above is screen 0's full rect, the same single-monitor
|
|
90
|
-
simplification `screenOf
|
|
91
|
-
|
|
92
|
-
- **`@floating-ui/dom` and `@floating-ui/react` are not usable**
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
-
|
|
96
|
-
|
|
97
|
-
the built-in one.
|
|
84
|
+
simplification as `screenOf`. On a dual-head X display, popups clamp to
|
|
85
|
+
the bounding box of both monitors.
|
|
86
|
+
- **`@floating-ui/dom` and `@floating-ui/react` are not usable** (DOM
|
|
87
|
+
platform and DOM interactions). Only `core` and its `@floating-ui/utils`
|
|
88
|
+
dependency belong in an X11 app.
|
|
89
|
+
- Safe-polygon hover lives in `@floating-ui/react`'s DOM-bound `useHover`,
|
|
90
|
+
not in `core`; keep react-x11's built-in one.
|
|
98
91
|
|
|
99
92
|
## `@tanstack/virtual-core` {#tanstack-virtual}
|
|
100
93
|
|
|
101
94
|
**Adapter, ~40 lines.** @tanstack/virtual-core@3.17.7.
|
|
102
95
|
|
|
103
|
-
The
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
constructor options, which is what makes this work.
|
|
96
|
+
The engine behind `useVirtualizer`: from a count, an `estimateSize`, the
|
|
97
|
+
viewport rect and the scroll offset it computes the visible items
|
|
98
|
+
(`getVirtualItems()`), the total size (`getTotalSize()`), and offsets for
|
|
99
|
+
`scrollToIndex`. Every DOM touchpoint is a constructor option.
|
|
108
100
|
|
|
109
101
|
**Do not import `@tanstack/react-virtual`.** Its first line is
|
|
110
|
-
`import { flushSync } from "react-dom"
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
React wrapper adds is the hook below.
|
|
102
|
+
`import { flushSync } from "react-dom"`: without react-dom it fails to
|
|
103
|
+
resolve; _with_ it, it silently flushes into the wrong reconciler
|
|
104
|
+
([silent failures](../ecosystem.md#silent-failures)). The hook below is
|
|
105
|
+
everything the React wrapper adds.
|
|
115
106
|
|
|
116
107
|
Three seams wire to a scrolling `<box>`:
|
|
117
108
|
|
|
@@ -121,9 +112,9 @@ Three seams wire to a scrolling `<box>`:
|
|
|
121
112
|
- `observeElementOffset` → `<box onScroll>` (`scrollY`);
|
|
122
113
|
- `scrollToFn` → `ref.scrollTo(offset)`.
|
|
123
114
|
|
|
124
|
-
|
|
125
|
-
`scrollHeight`/`clientHeight
|
|
126
|
-
|
|
115
|
+
`getScrollElement()` must return something with
|
|
116
|
+
`scrollHeight`/`clientHeight` (virtual-core duck-types Element vs Window
|
|
117
|
+
with `'scrollHeight' in el`); a getter shim over the node's
|
|
127
118
|
`contentHeight`/`abs.height` satisfies it.
|
|
128
119
|
|
|
129
120
|
```jsx
|
|
@@ -207,10 +198,9 @@ function BigList() {
|
|
|
207
198
|
- **First paint shows zero rows.** Layout runs on the frame clock after the
|
|
208
199
|
mount commit, `onViewport` reports a tick later, and the list fills in on
|
|
209
200
|
the next frame. Fine interactively; tests must tick a few times.
|
|
210
|
-
- `estimateSize` is the only measurement
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
`estimateSize: (i) => heights[i]`.
|
|
201
|
+
- `estimateSize` is the only measurement; `measureElement` is built on
|
|
202
|
+
`ResizeObserver` and `getBoundingClientRect`. For variable-height rows
|
|
203
|
+
pass exact sizes: `estimateSize: (i) => heights[i]`.
|
|
214
204
|
- `_didMount`/`_willUpdate` are underscored but are the documented pattern
|
|
215
|
-
for custom
|
|
216
|
-
|
|
205
|
+
for custom adapters — the official React, Vue and Svelte adapters call
|
|
206
|
+
exactly these.
|
|
@@ -1,25 +1,17 @@
|
|
|
1
1
|
# Routing
|
|
2
2
|
|
|
3
|
-
There is no URL bar and no `history` object, so
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
What consistently does not survive is the _link_ element. `<Link>` renders an
|
|
9
|
-
`<a>` host in both routers, and there is no `<a>` here. Navigate imperatively
|
|
10
|
-
from a `<box onClick>` instead; that is two lines and it is all you lose.
|
|
11
|
-
|
|
12
|
-
Also worth saying up front: a desktop app usually wants stack or tab
|
|
13
|
-
navigation semantics rather than URL paths. These libraries give you the
|
|
14
|
-
matching machinery, not a back stack — build that on top if you need it.
|
|
3
|
+
There is no URL bar and no `history` object, so both routers here run on
|
|
4
|
+
their first-party in-memory location. What does not survive is `<Link>`,
|
|
5
|
+
which renders an `<a>` host in both; navigate from a `<box onClick>`
|
|
6
|
+
instead. These libraries give you matching, not a back stack — build stack
|
|
7
|
+
or tab navigation on top if you need it.
|
|
15
8
|
|
|
16
9
|
## wouter {#wouter}
|
|
17
10
|
|
|
18
11
|
**Out of the box — with `wouter/memory-location`.** wouter@3.10.0.
|
|
19
12
|
|
|
20
13
|
A 2 kB router: `<Router>`, `<Route>`, `<Switch>`, `useLocation`, pattern
|
|
21
|
-
params
|
|
22
|
-
non-browser one, so there is no adapter to write.
|
|
14
|
+
params, and a pluggable location hook with a non-browser one shipped.
|
|
23
15
|
|
|
24
16
|
```jsx
|
|
25
17
|
import React from 'react';
|
|
@@ -66,13 +58,12 @@ const App = () => (
|
|
|
66
58
|
- **Always mount the memory hook at the top.** A `<Route>` outside a
|
|
67
59
|
`<Router hook={...}>` falls back to `useBrowserLocation` and crashes
|
|
68
60
|
immediately with `ReferenceError: location is not defined`.
|
|
69
|
-
- **`<Link>` does not work
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
- `useLocation()[1]`
|
|
74
|
-
|
|
75
|
-
single router.
|
|
61
|
+
- **`<Link>` does not work**: it renders an `<a>`. `<Link asChild>` avoids
|
|
62
|
+
the `<a>` but does not navigate, because its click guard checks
|
|
63
|
+
`event.button !== 0` and react-x11's `MouseEvent.button` is the X button
|
|
64
|
+
number, `1` for left.
|
|
65
|
+
- `useLocation()[1]` is the same `navigate` from inside components; the
|
|
66
|
+
module-level one is handier with a single router.
|
|
76
67
|
- `useHashLocation` and `useBrowserLocation` are browser-only. Everything
|
|
77
68
|
else — matching, params, nesting, `useRoute` — is pure.
|
|
78
69
|
- `memoryLocation({ record: true })` keeps a `history` array, which is the
|
|
@@ -85,8 +76,7 @@ react-router 7.18.2.
|
|
|
85
76
|
|
|
86
77
|
The router core — `useRoutes`, `useNavigate`, `useParams`, `useLocation`,
|
|
87
78
|
loaders, actions — is DOM-free. Import from `react-router`, not
|
|
88
|
-
`react-router-dom
|
|
89
|
-
entry points, and the browser entry points are exactly what fails.
|
|
79
|
+
`react-router-dom`, whose browser entry points are what fails.
|
|
90
80
|
|
|
91
81
|
```jsx
|
|
92
82
|
import React from 'react';
|
|
@@ -131,16 +121,15 @@ function About() {
|
|
|
131
121
|
);
|
|
132
122
|
```
|
|
133
123
|
|
|
134
|
-
- **`BrowserRouter` and `HashRouter`
|
|
135
|
-
`
|
|
124
|
+
- **`BrowserRouter` and `HashRouter` fail** — `createBrowserHistory` needs
|
|
125
|
+
`window.history`. The error is
|
|
136
126
|
`react-x11: uncaught error ReferenceError: document is not defined` at
|
|
137
|
-
`getUrlBasedHistory
|
|
138
|
-
|
|
127
|
+
`getUrlBasedHistory`; `render()` does not throw, react-x11 logs it and the
|
|
128
|
+
window count stays 0.
|
|
139
129
|
- **`<Link>`, `<NavLink>` and `<Form>` all render `<a>`/`<form>` hosts** and
|
|
140
130
|
cannot work. Use `useNavigate()` on a `<box onClick>`.
|
|
141
131
|
- A `<Link>` with a bare string child hits the raw-text error before the
|
|
142
132
|
element error: `react-x11: raw text "go" must be wrapped in a <text>
|
|
143
133
|
element`. Both are in the
|
|
144
134
|
[register](../ecosystem.md#render-time).
|
|
145
|
-
-
|
|
146
|
-
dependency by a wide margin.
|
|
135
|
+
- Without loaders and actions, wouter is the much smaller dependency.
|