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.
Files changed (158) hide show
  1. package/README.md +330 -81
  2. package/package.json +132 -14
  3. package/src/ClickToComponent.js +9 -2
  4. package/src/DevToolsIntegration.js +440 -32
  5. package/src/Reconciler.js +463 -165
  6. package/src/a11y.js +1299 -0
  7. package/src/acceleratorhooks.js +86 -0
  8. package/src/accelerators.js +128 -0
  9. package/src/activate.js +168 -0
  10. package/src/anchor.js +360 -0
  11. package/src/appcontext.js +161 -0
  12. package/src/appearance.js +748 -0
  13. package/src/appearancehooks.js +96 -0
  14. package/src/apphooks.js +73 -0
  15. package/src/application.js +748 -0
  16. package/src/atspi.js +1953 -0
  17. package/src/bus.js +545 -0
  18. package/src/bushooks.js +136 -0
  19. package/src/clientmessage.js +140 -0
  20. package/src/clipboard.js +121 -0
  21. package/src/components/Button.js +148 -33
  22. package/src/components/Checkbox.js +66 -32
  23. package/src/components/Dialog.js +96 -29
  24. package/src/components/FileDialog.js +491 -0
  25. package/src/components/Icon.js +329 -0
  26. package/src/components/Menu.js +797 -133
  27. package/src/components/PasswordInput.js +434 -0
  28. package/src/components/ProgressBar.js +91 -12
  29. package/src/components/Radio.js +78 -35
  30. package/src/components/Select.js +255 -65
  31. package/src/components/Slider.js +102 -41
  32. package/src/components/SplitPane.js +206 -0
  33. package/src/components/Switch.js +100 -22
  34. package/src/components/Table.js +529 -0
  35. package/src/components/Tabs.js +211 -0
  36. package/src/components/Tooltip.js +528 -54
  37. package/src/components/anchor.js +154 -107
  38. package/src/components/change.js +34 -0
  39. package/src/components/dnd.js +103 -0
  40. package/src/components/index.js +16 -3
  41. package/src/components/keys.js +17 -20
  42. package/src/components/scribble.js +247 -0
  43. package/src/components/theme.js +350 -42
  44. package/src/components/typeahead.js +12 -2
  45. package/src/compose.js +868 -0
  46. package/src/compositing.js +224 -0
  47. package/src/dbusmenu.js +384 -0
  48. package/src/debug.d.ts +63 -0
  49. package/src/debug.js +642 -0
  50. package/src/decorations.js +486 -0
  51. package/src/desktopsettings.js +209 -0
  52. package/src/desktopsettingshooks.js +62 -0
  53. package/src/dnd.js +1725 -0
  54. package/src/editmenu.js +272 -0
  55. package/src/errors.js +98 -0
  56. package/src/events.js +1406 -162
  57. package/src/extensions.js +45 -0
  58. package/src/filedialog.js +375 -0
  59. package/src/filedialoghooks.js +132 -0
  60. package/src/fonthooks.js +64 -0
  61. package/src/fonts.js +301 -0
  62. package/src/foreignnodes.js +519 -0
  63. package/src/frame/child.js +33 -0
  64. package/src/frame/childmain.js +274 -0
  65. package/src/frame/env.js +140 -0
  66. package/src/frame/index.js +444 -0
  67. package/src/frame/lifecycle.js +67 -0
  68. package/src/frame/protocol.js +179 -0
  69. package/src/frames.js +73 -0
  70. package/src/glbackend.js +114 -0
  71. package/src/glnodes.js +125 -67
  72. package/src/globalmenu.js +683 -0
  73. package/src/host.d.ts +88 -0
  74. package/src/host.js +42 -0
  75. package/src/idle.js +490 -0
  76. package/src/idlehooks.js +100 -0
  77. package/src/imagesource.js +349 -0
  78. package/src/index.d.ts +475 -0
  79. package/src/index.js +83 -9
  80. package/src/inputtime.js +206 -0
  81. package/src/jsx-dev-runtime.d.ts +21 -0
  82. package/src/jsx-dev-runtime.js +2 -0
  83. package/src/jsx-runtime.d.ts +39 -0
  84. package/src/jsx-runtime.js +6 -0
  85. package/src/keyboard.js +256 -0
  86. package/src/keyboardstate.js +278 -0
  87. package/src/keyboardstatehooks.js +58 -0
  88. package/src/keysyms.d.ts +149 -0
  89. package/src/keysyms.js +270 -0
  90. package/src/locale.js +170 -0
  91. package/src/localehooks.js +47 -0
  92. package/src/menuitem.js +223 -0
  93. package/src/node.d.ts +597 -0
  94. package/src/node.js +44 -0
  95. package/src/nodes.js +9546 -690
  96. package/src/ntk.d.ts +44 -0
  97. package/src/ntk.js +25 -0
  98. package/src/paintcache.js +366 -0
  99. package/src/palette.js +380 -0
  100. package/src/pastestate.js +66 -0
  101. package/src/portal.js +461 -0
  102. package/src/priority.js +26 -0
  103. package/src/refresh/index.d.ts +40 -0
  104. package/src/refresh/index.js +122 -0
  105. package/src/refresh/loader.d.ts +37 -0
  106. package/src/refresh/loader.js +401 -0
  107. package/src/refresh/register.d.ts +5 -0
  108. package/src/refresh/register.js +13 -0
  109. package/src/registry.js +232 -0
  110. package/src/scale.js +626 -0
  111. package/src/scalehooks.js +27 -0
  112. package/src/screencolor.js +640 -0
  113. package/src/screencolorhooks.js +101 -0
  114. package/src/screens.js +754 -0
  115. package/src/screenshooks.js +137 -0
  116. package/src/startup.js +302 -0
  117. package/src/style.d.ts +126 -0
  118. package/src/style.js +33 -0
  119. package/src/styles.js +1482 -6
  120. package/src/svgnodes.js +306 -0
  121. package/src/testing/a11y.js +484 -0
  122. package/src/testing/components.js +414 -0
  123. package/src/testing/events.js +407 -0
  124. package/src/testing/harness.js +455 -0
  125. package/src/testing/index.d.ts +558 -0
  126. package/src/testing/index.js +85 -0
  127. package/src/testing/mock-app.js +463 -0
  128. package/src/testing/pixels.js +152 -0
  129. package/src/testing/queries.js +224 -0
  130. package/src/textrange.js +83 -0
  131. package/src/textselection.js +439 -0
  132. package/src/trace-registry.js +63 -0
  133. package/src/transfer.js +93 -0
  134. package/src/types/appearance.d.ts +84 -0
  135. package/src/types/application.d.ts +173 -0
  136. package/src/types/components.d.ts +820 -0
  137. package/src/types/dbus.d.ts +177 -0
  138. package/src/types/elements.d.ts +897 -0
  139. package/src/types/events.d.ts +549 -0
  140. package/src/types/filedialog.d.ts +260 -0
  141. package/src/types/fonts.d.ts +124 -0
  142. package/src/types/frame.d.ts +146 -0
  143. package/src/types/globalmenu.d.ts +42 -0
  144. package/src/types/nodes.d.ts +199 -0
  145. package/src/types/screencolor.d.ts +84 -0
  146. package/src/types/style.d.ts +434 -0
  147. package/src/types/system.d.ts +287 -0
  148. package/src/windowid.js +151 -0
  149. package/src/windowstate.js +393 -0
  150. package/src/xsettings.js +336 -0
  151. package/src/yoga.d.ts +55 -0
  152. package/src/yoga.js +135 -0
  153. package/src/components/Canvas3D.js +0 -28
  154. package/src/geometry3d.js +0 -223
  155. package/src/pointer3d.js +0 -158
  156. package/src/raycast3d.js +0 -146
  157. package/src/richnodes.js +0 -436
  158. 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
+ }