react-x11 1.2.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +330 -81
- package/package.json +132 -14
- package/src/ClickToComponent.js +9 -2
- package/src/DevToolsIntegration.js +440 -32
- package/src/Reconciler.js +463 -165
- package/src/a11y.js +1299 -0
- package/src/acceleratorhooks.js +86 -0
- package/src/accelerators.js +128 -0
- package/src/activate.js +168 -0
- package/src/anchor.js +360 -0
- package/src/appcontext.js +161 -0
- package/src/appearance.js +748 -0
- package/src/appearancehooks.js +96 -0
- package/src/apphooks.js +73 -0
- package/src/application.js +748 -0
- package/src/atspi.js +1953 -0
- package/src/bus.js +545 -0
- package/src/bushooks.js +136 -0
- package/src/clientmessage.js +140 -0
- package/src/clipboard.js +121 -0
- package/src/components/Button.js +148 -33
- package/src/components/Checkbox.js +66 -32
- package/src/components/Dialog.js +96 -29
- package/src/components/FileDialog.js +491 -0
- package/src/components/Icon.js +329 -0
- package/src/components/Menu.js +797 -133
- package/src/components/PasswordInput.js +434 -0
- package/src/components/ProgressBar.js +91 -12
- package/src/components/Radio.js +78 -35
- package/src/components/Select.js +255 -65
- package/src/components/Slider.js +102 -41
- package/src/components/SplitPane.js +206 -0
- package/src/components/Switch.js +100 -22
- package/src/components/Table.js +529 -0
- package/src/components/Tabs.js +211 -0
- package/src/components/Tooltip.js +528 -54
- package/src/components/anchor.js +154 -107
- package/src/components/change.js +34 -0
- package/src/components/dnd.js +103 -0
- package/src/components/index.js +16 -3
- package/src/components/keys.js +17 -20
- package/src/components/scribble.js +247 -0
- package/src/components/theme.js +350 -42
- package/src/components/typeahead.js +12 -2
- package/src/compose.js +868 -0
- package/src/compositing.js +224 -0
- package/src/dbusmenu.js +384 -0
- package/src/debug.d.ts +63 -0
- package/src/debug.js +642 -0
- package/src/decorations.js +486 -0
- package/src/desktopsettings.js +209 -0
- package/src/desktopsettingshooks.js +62 -0
- package/src/dnd.js +1725 -0
- package/src/editmenu.js +272 -0
- package/src/errors.js +98 -0
- package/src/events.js +1406 -162
- package/src/extensions.js +45 -0
- package/src/filedialog.js +375 -0
- package/src/filedialoghooks.js +132 -0
- package/src/fonthooks.js +64 -0
- package/src/fonts.js +301 -0
- package/src/foreignnodes.js +519 -0
- package/src/frame/child.js +33 -0
- package/src/frame/childmain.js +274 -0
- package/src/frame/env.js +140 -0
- package/src/frame/index.js +444 -0
- package/src/frame/lifecycle.js +67 -0
- package/src/frame/protocol.js +179 -0
- package/src/frames.js +73 -0
- package/src/glbackend.js +114 -0
- package/src/glnodes.js +125 -67
- package/src/globalmenu.js +683 -0
- package/src/host.d.ts +88 -0
- package/src/host.js +42 -0
- package/src/idle.js +490 -0
- package/src/idlehooks.js +100 -0
- package/src/imagesource.js +349 -0
- package/src/index.d.ts +475 -0
- package/src/index.js +83 -9
- package/src/inputtime.js +206 -0
- package/src/jsx-dev-runtime.d.ts +21 -0
- package/src/jsx-dev-runtime.js +2 -0
- package/src/jsx-runtime.d.ts +39 -0
- package/src/jsx-runtime.js +6 -0
- package/src/keyboard.js +256 -0
- package/src/keyboardstate.js +278 -0
- package/src/keyboardstatehooks.js +58 -0
- package/src/keysyms.d.ts +149 -0
- package/src/keysyms.js +270 -0
- package/src/locale.js +170 -0
- package/src/localehooks.js +47 -0
- package/src/menuitem.js +223 -0
- package/src/node.d.ts +597 -0
- package/src/node.js +44 -0
- package/src/nodes.js +9546 -690
- package/src/ntk.d.ts +44 -0
- package/src/ntk.js +25 -0
- package/src/paintcache.js +366 -0
- package/src/palette.js +380 -0
- package/src/pastestate.js +66 -0
- package/src/portal.js +461 -0
- package/src/priority.js +26 -0
- package/src/refresh/index.d.ts +40 -0
- package/src/refresh/index.js +122 -0
- package/src/refresh/loader.d.ts +37 -0
- package/src/refresh/loader.js +401 -0
- package/src/refresh/register.d.ts +5 -0
- package/src/refresh/register.js +13 -0
- package/src/registry.js +232 -0
- package/src/scale.js +626 -0
- package/src/scalehooks.js +27 -0
- package/src/screencolor.js +640 -0
- package/src/screencolorhooks.js +101 -0
- package/src/screens.js +754 -0
- package/src/screenshooks.js +137 -0
- package/src/startup.js +302 -0
- package/src/style.d.ts +126 -0
- package/src/style.js +33 -0
- package/src/styles.js +1482 -6
- package/src/svgnodes.js +306 -0
- package/src/testing/a11y.js +484 -0
- package/src/testing/components.js +414 -0
- package/src/testing/events.js +407 -0
- package/src/testing/harness.js +455 -0
- package/src/testing/index.d.ts +558 -0
- package/src/testing/index.js +85 -0
- package/src/testing/mock-app.js +463 -0
- package/src/testing/pixels.js +152 -0
- package/src/testing/queries.js +224 -0
- package/src/textrange.js +83 -0
- package/src/textselection.js +439 -0
- package/src/trace-registry.js +63 -0
- package/src/transfer.js +93 -0
- package/src/types/appearance.d.ts +84 -0
- package/src/types/application.d.ts +173 -0
- package/src/types/components.d.ts +820 -0
- package/src/types/dbus.d.ts +177 -0
- package/src/types/elements.d.ts +897 -0
- package/src/types/events.d.ts +549 -0
- package/src/types/filedialog.d.ts +260 -0
- package/src/types/fonts.d.ts +124 -0
- package/src/types/frame.d.ts +146 -0
- package/src/types/globalmenu.d.ts +42 -0
- package/src/types/nodes.d.ts +199 -0
- package/src/types/screencolor.d.ts +84 -0
- package/src/types/style.d.ts +434 -0
- package/src/types/system.d.ts +287 -0
- package/src/windowid.js +151 -0
- package/src/windowstate.js +393 -0
- package/src/xsettings.js +336 -0
- package/src/yoga.d.ts +55 -0
- package/src/yoga.js +135 -0
- package/src/components/Canvas3D.js +0 -28
- package/src/geometry3d.js +0 -223
- package/src/pointer3d.js +0 -158
- package/src/raycast3d.js +0 -146
- package/src/richnodes.js +0 -436
- package/src/scene3d.js +0 -683
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
// Widget components built purely on the host primitives — no reconciler
|
|
2
|
+
// support needed. Plain createElement (no JSX) so the library stays
|
|
3
|
+
// build-step-free for consumers.
|
|
4
|
+
|
|
5
|
+
import React, { useRef, useState } from 'react';
|
|
6
|
+
import { createStyles } from '../styles.js';
|
|
7
|
+
import { labelContent, useDirection, useTheme } from './theme.js';
|
|
8
|
+
import { XK_DOWN, XK_END, XK_HOME, XK_LEFT, XK_RIGHT, XK_UP } from './keys.js';
|
|
9
|
+
|
|
10
|
+
const h = React.createElement;
|
|
11
|
+
|
|
12
|
+
const INDICATOR = 2;
|
|
13
|
+
|
|
14
|
+
const s = createStyles({
|
|
15
|
+
root: { flexGrow: 1, minHeight: 0 },
|
|
16
|
+
strip: { flexShrink: 0, gap: 2 },
|
|
17
|
+
tab: {
|
|
18
|
+
paddingTop: 6,
|
|
19
|
+
paddingBottom: 6,
|
|
20
|
+
paddingLeft: 12,
|
|
21
|
+
paddingRight: 12,
|
|
22
|
+
flexDirection: 'row',
|
|
23
|
+
alignItems: 'center',
|
|
24
|
+
gap: 6,
|
|
25
|
+
cursor: 'pointer',
|
|
26
|
+
transition: { backgroundColor: 100 },
|
|
27
|
+
},
|
|
28
|
+
// the selected marker is a box rather than a border: borders are
|
|
29
|
+
// all-edges here, and this has to sit on one side
|
|
30
|
+
indicator: { position: 'absolute', transition: { backgroundColor: 100 } },
|
|
31
|
+
panel: { flexGrow: 1, minHeight: 0, minWidth: 0 },
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* <Tabs items value onChange orientation/> — one visible panel at a time,
|
|
36
|
+
* switched by a strip of tabs.
|
|
37
|
+
*
|
|
38
|
+
* <Tabs items={[{ id: 'a', label: 'A', content: <box/> }]} />
|
|
39
|
+
*
|
|
40
|
+
* Each item is `{ id, label, content, disabled }`. `content` may be a node,
|
|
41
|
+
* or a function called only while that tab is selected — which is how to
|
|
42
|
+
* avoid building a panel nobody is looking at.
|
|
43
|
+
*
|
|
44
|
+
* Controlled with `value` + `onChange`, uncontrolled otherwise. The strip is
|
|
45
|
+
* a single tab stop: Left/Right (Up/Down when vertical) move and wrap,
|
|
46
|
+
* Home/End jump to the ends, and disabled tabs are skipped. Arrows select as
|
|
47
|
+
* they move, the way a desktop notebook behaves; pass `manual` to move focus
|
|
48
|
+
* only and commit with Enter or Space, which is what you want when a panel
|
|
49
|
+
* is expensive to build.
|
|
50
|
+
*/
|
|
51
|
+
export function Tabs({
|
|
52
|
+
items = [],
|
|
53
|
+
value,
|
|
54
|
+
defaultValue,
|
|
55
|
+
onChange,
|
|
56
|
+
orientation = 'horizontal',
|
|
57
|
+
manual = false,
|
|
58
|
+
style,
|
|
59
|
+
...boxProps
|
|
60
|
+
}) {
|
|
61
|
+
const theme = useTheme();
|
|
62
|
+
const rtl = useDirection() === 'rtl';
|
|
63
|
+
const firstEnabled = items.find((item) => !item.disabled)?.id;
|
|
64
|
+
const [uncontrolled, setUncontrolled] = useState(
|
|
65
|
+
defaultValue ?? firstEnabled,
|
|
66
|
+
);
|
|
67
|
+
const [focusedId, setFocusedId] = useState(null);
|
|
68
|
+
const selected = value ?? uncontrolled;
|
|
69
|
+
const vertical = orientation === 'vertical';
|
|
70
|
+
const tabRefs = useRef(new Map());
|
|
71
|
+
|
|
72
|
+
const select = (id) => {
|
|
73
|
+
if (id == null || id === selected) return;
|
|
74
|
+
if (value === undefined) setUncontrolled(id);
|
|
75
|
+
onChange?.(id);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/** The next enabled tab `delta` steps away, wrapping. */
|
|
79
|
+
const step = (from, delta) => {
|
|
80
|
+
const n = items.length;
|
|
81
|
+
if (n === 0) return null;
|
|
82
|
+
for (let i = 1; i <= n; i++) {
|
|
83
|
+
const item = items[(((from + delta * i) % n) + n) % n];
|
|
84
|
+
if (item && !item.disabled) return item;
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const goTo = (item) => {
|
|
90
|
+
if (!item) return;
|
|
91
|
+
tabRefs.current.get(item.id)?.focus?.();
|
|
92
|
+
if (!manual) select(item.id);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const onKeyDown = (ev) => {
|
|
96
|
+
// The arrows are visual, the list is logical: in a mirrored horizontal
|
|
97
|
+
// strip the *next* tab is the one to the left. A vertical strip never
|
|
98
|
+
// mirrors — Up is Up.
|
|
99
|
+
const swap = !vertical && rtl;
|
|
100
|
+
const back = vertical ? XK_UP : swap ? XK_RIGHT : XK_LEFT;
|
|
101
|
+
const forward = vertical ? XK_DOWN : swap ? XK_LEFT : XK_RIGHT;
|
|
102
|
+
const current = items.findIndex(
|
|
103
|
+
(item) => item.id === (focusedId ?? selected),
|
|
104
|
+
);
|
|
105
|
+
switch (ev.keysym) {
|
|
106
|
+
case back:
|
|
107
|
+
goTo(step(current === -1 ? 0 : current, -1));
|
|
108
|
+
return;
|
|
109
|
+
case forward:
|
|
110
|
+
goTo(step(current === -1 ? 0 : current, 1));
|
|
111
|
+
return;
|
|
112
|
+
case XK_HOME:
|
|
113
|
+
goTo(items.find((item) => !item.disabled));
|
|
114
|
+
return;
|
|
115
|
+
case XK_END:
|
|
116
|
+
goTo([...items].reverse().find((item) => !item.disabled));
|
|
117
|
+
return;
|
|
118
|
+
default:
|
|
119
|
+
}
|
|
120
|
+
// Space and Enter are not here: in manual mode, where focus and
|
|
121
|
+
// selection differ, committing the focused tab is exactly the click
|
|
122
|
+
// that tab's own `onClick` is, and core makes those keys that click
|
|
123
|
+
// (issue #329). In automatic mode the tab is already selected and the
|
|
124
|
+
// click is a no-op.
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const active = items.find((item) => item.id === selected);
|
|
128
|
+
const content =
|
|
129
|
+
typeof active?.content === 'function' ? active.content() : active?.content;
|
|
130
|
+
|
|
131
|
+
// A vertical strip's indicator rides the edge the rows *begin* at, so it
|
|
132
|
+
// is a logical inset; a horizontal one spans the tab and sits underneath
|
|
133
|
+
// it, where both edges are named and neither is a side.
|
|
134
|
+
const indicatorStyle = vertical
|
|
135
|
+
? { top: 0, bottom: 0, start: 0, width: INDICATOR }
|
|
136
|
+
: { left: 0, right: 0, bottom: 0, height: INDICATOR };
|
|
137
|
+
|
|
138
|
+
return h(
|
|
139
|
+
'box',
|
|
140
|
+
{
|
|
141
|
+
theme,
|
|
142
|
+
...boxProps,
|
|
143
|
+
style: [s.root, { flexDirection: vertical ? 'row' : 'column' }, style],
|
|
144
|
+
},
|
|
145
|
+
h(
|
|
146
|
+
'box',
|
|
147
|
+
{
|
|
148
|
+
role: 'tablist',
|
|
149
|
+
'aria-orientation': orientation,
|
|
150
|
+
style: [s.strip, { flexDirection: vertical ? 'column' : 'row' }],
|
|
151
|
+
onKeyDown,
|
|
152
|
+
},
|
|
153
|
+
items.map((item) =>
|
|
154
|
+
h(
|
|
155
|
+
'box',
|
|
156
|
+
{
|
|
157
|
+
key: item.id,
|
|
158
|
+
role: 'tab',
|
|
159
|
+
'aria-selected': item.id === selected,
|
|
160
|
+
ref: (node) => {
|
|
161
|
+
if (node) tabRefs.current.set(item.id, node);
|
|
162
|
+
else tabRefs.current.delete(item.id);
|
|
163
|
+
},
|
|
164
|
+
focusable: !item.disabled,
|
|
165
|
+
tabIndex: item.id === selected ? 0 : -1,
|
|
166
|
+
disabled: item.disabled,
|
|
167
|
+
onFocus: () => setFocusedId(item.id),
|
|
168
|
+
onClick: () => !item.disabled && select(item.id),
|
|
169
|
+
style: [
|
|
170
|
+
s.tab,
|
|
171
|
+
{
|
|
172
|
+
backgroundColor:
|
|
173
|
+
item.id === selected ? theme.surfaceHover : 'transparent',
|
|
174
|
+
},
|
|
175
|
+
// the panel only swaps on the release, so the press is what
|
|
176
|
+
// says the tab heard the click — and it has to outrank the
|
|
177
|
+
// selected tab's own fill, or pressing the selected tab is
|
|
178
|
+
// the one press in the strip that does nothing visible
|
|
179
|
+
!item.disabled && {
|
|
180
|
+
':hover': { backgroundColor: theme.surfaceHover },
|
|
181
|
+
':active': { backgroundColor: theme.surfaceActive },
|
|
182
|
+
},
|
|
183
|
+
],
|
|
184
|
+
},
|
|
185
|
+
labelContent(item.label, {
|
|
186
|
+
color: item.disabled
|
|
187
|
+
? theme.textMuted
|
|
188
|
+
: item.id === selected
|
|
189
|
+
? theme.text
|
|
190
|
+
: theme.textMuted,
|
|
191
|
+
}),
|
|
192
|
+
h('box', {
|
|
193
|
+
style: [
|
|
194
|
+
s.indicator,
|
|
195
|
+
indicatorStyle,
|
|
196
|
+
{
|
|
197
|
+
backgroundColor:
|
|
198
|
+
item.id === selected
|
|
199
|
+
? theme.accent
|
|
200
|
+
: item.id === focusedId
|
|
201
|
+
? theme.borderFocus
|
|
202
|
+
: 'transparent',
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
}),
|
|
206
|
+
),
|
|
207
|
+
),
|
|
208
|
+
),
|
|
209
|
+
h('box', { role: 'tabpanel', style: s.panel }, content ?? null),
|
|
210
|
+
);
|
|
211
|
+
}
|