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,820 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The widget set: plain React over the host primitives, themable through
|
|
3
|
+
* `ThemeProvider`. See docs/components.md.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { ComponentType, ReactNode, Ref, RefObject } from 'react';
|
|
7
|
+
import type { ColorSchemePreference } from './appearance.js';
|
|
8
|
+
import type { Color, StyleProp } from './style.js';
|
|
9
|
+
import type {
|
|
10
|
+
BoxProps,
|
|
11
|
+
CanvasProps,
|
|
12
|
+
DrawInfo,
|
|
13
|
+
GlAreaProps,
|
|
14
|
+
} from './elements.js';
|
|
15
|
+
import type { DrawnNode, Rect } from './nodes.js';
|
|
16
|
+
import type {
|
|
17
|
+
DragEndEvent,
|
|
18
|
+
DragEvent,
|
|
19
|
+
DragSourceEvent,
|
|
20
|
+
DragSourceProps,
|
|
21
|
+
DropAccept,
|
|
22
|
+
DropEvent,
|
|
23
|
+
DropTargetProps,
|
|
24
|
+
KeyboardEvent,
|
|
25
|
+
MouseEvent,
|
|
26
|
+
} from './events.js';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The palette every widget reads. A theme overrides what it cares about and
|
|
30
|
+
* inherits the rest; the shape tokens are what let a theme be more than a
|
|
31
|
+
* recolour.
|
|
32
|
+
*/
|
|
33
|
+
export interface Theme {
|
|
34
|
+
border: string;
|
|
35
|
+
/** The border of a focused control. Named for focus and not for `:active`,
|
|
36
|
+
* which is the pressed state — the `…Active` tokens below. */
|
|
37
|
+
borderFocus: string;
|
|
38
|
+
/** The ground: what the window itself is painted with, under everything. */
|
|
39
|
+
background: string;
|
|
40
|
+
/** What is raised off it — a control's fill, a card, the sheet a menu or a
|
|
41
|
+
* dialog is drawn on. The same colour as `background` in the light palette
|
|
42
|
+
* and a step lighter in the dark one, where a card at the ground's own
|
|
43
|
+
* colour is a card you cannot see. */
|
|
44
|
+
surface: string;
|
|
45
|
+
text: string;
|
|
46
|
+
/** Secondary ink: a placeholder, a caption, a disabled label. */
|
|
47
|
+
textMuted: string;
|
|
48
|
+
hoverBackground: string;
|
|
49
|
+
hoverText: string;
|
|
50
|
+
accent: string;
|
|
51
|
+
accentHover: string;
|
|
52
|
+
/** The letters on an `accent` fill. Derived from it when a palette names
|
|
53
|
+
* the fill and not the ink — the more legible of this palette's own `text`
|
|
54
|
+
* and `background` — so an accent light enough that white disappears on it
|
|
55
|
+
* gets dark letters without being asked. */
|
|
56
|
+
accentText: string;
|
|
57
|
+
surfaceHover: string;
|
|
58
|
+
track: string;
|
|
59
|
+
/** What a screen says with colour: this failed, this worked, look at this,
|
|
60
|
+
* here is a note. Each works as ink as well as fill — 4.5:1 against the
|
|
61
|
+
* palette's own ground — so a validation message and the badge beside it
|
|
62
|
+
* are one token. `…Text` is the letters on the fill, derived by contrast
|
|
63
|
+
* like `accentText`. */
|
|
64
|
+
danger: string;
|
|
65
|
+
dangerHover: string;
|
|
66
|
+
dangerText: string;
|
|
67
|
+
success: string;
|
|
68
|
+
successText: string;
|
|
69
|
+
warning: string;
|
|
70
|
+
warningText: string;
|
|
71
|
+
info: string;
|
|
72
|
+
infoText: string;
|
|
73
|
+
/** The pressed step of each fill family: rest → `…Hover` → `…Active`.
|
|
74
|
+
* A control activates on the release, so this is the only thing it can
|
|
75
|
+
* show while it is being held. `danger` is the only status colour with
|
|
76
|
+
* one: a destructive button is the only status fill anyone presses. */
|
|
77
|
+
accentActive: string;
|
|
78
|
+
surfaceActive: string;
|
|
79
|
+
textMutedActive: string;
|
|
80
|
+
dangerActive: string;
|
|
81
|
+
/** The keyboard focus ring every focusable node under this palette draws
|
|
82
|
+
* on `:focus-visible` — read by the renderer, not by the widgets. */
|
|
83
|
+
focusRing: string;
|
|
84
|
+
focusRingWidth: number;
|
|
85
|
+
focusRingOffset: number;
|
|
86
|
+
radius: number;
|
|
87
|
+
radiusSmall: number;
|
|
88
|
+
/** A floating surface — a menu, a dropdown — which rounds on a wider
|
|
89
|
+
* scale than a control does: half the text size, and derived from
|
|
90
|
+
* `fontSize` for any palette that moves it without naming this. */
|
|
91
|
+
radiusPopup: number;
|
|
92
|
+
/** A row inside one, a step tighter so the highlight reads as a pill on
|
|
93
|
+
* the sheet rather than as a second edge just inside its own. */
|
|
94
|
+
radiusPopupItem: number;
|
|
95
|
+
/** A tooltip bubble — the smallest floating surface there is. */
|
|
96
|
+
radiusTooltip: number;
|
|
97
|
+
borderWidth: number;
|
|
98
|
+
/** The size unstyled text comes out at, and what the popup radii are
|
|
99
|
+
* derived from. */
|
|
100
|
+
fontSize: number;
|
|
101
|
+
/** The UI face, as a CSS-style family list. What a `<text>` that names no
|
|
102
|
+
* `fontFamily` inherits. */
|
|
103
|
+
fontFamily: string;
|
|
104
|
+
/** The face code surfaces use — a `<Code>`, a log pane, a hex dump. Not
|
|
105
|
+
* read by anything unstyled; it is there so `fontFamily: '$monoFamily'`
|
|
106
|
+
* says "this app's mono face" in one place. */
|
|
107
|
+
monoFamily: string;
|
|
108
|
+
/**
|
|
109
|
+
* Which way this app reads. Seeded from the environment's locale, so an app
|
|
110
|
+
* started under an RTL locale is mirrored without being asked; set it to
|
|
111
|
+
* mirror a whole UI from one place — the provider plants the matching
|
|
112
|
+
* `direction` style property in the tree, so the boxes and the widgets
|
|
113
|
+
* follow it together.
|
|
114
|
+
*/
|
|
115
|
+
direction: 'ltr' | 'rtl';
|
|
116
|
+
paddingX: number;
|
|
117
|
+
paddingY: number;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface ThemeProviderProps {
|
|
121
|
+
/**
|
|
122
|
+
* Merges over the scheme in force — the desktop's palette, or an outer
|
|
123
|
+
* provider's. So a partial palette names what this app changes and
|
|
124
|
+
* everything else keeps following the desktop.
|
|
125
|
+
*/
|
|
126
|
+
value?: Partial<Theme>;
|
|
127
|
+
/**
|
|
128
|
+
* A palette layered on only when the scheme in force is dark — for a design
|
|
129
|
+
* whose two schemes are not one recolour of the other. Usually unnecessary:
|
|
130
|
+
* `value` already layers over the desktop's own light or dark palette.
|
|
131
|
+
*/
|
|
132
|
+
dark?: Partial<Theme>;
|
|
133
|
+
/**
|
|
134
|
+
* `'system'` (the default) follows the desktop. `'light'` and `'dark'` pin
|
|
135
|
+
* this subtree, for an app whose own settings own the choice — and pinning
|
|
136
|
+
* is the complete opt-out: nothing under a pinned provider asks the desktop
|
|
137
|
+
* anything.
|
|
138
|
+
*/
|
|
139
|
+
colorScheme?: ColorSchemePreference;
|
|
140
|
+
/**
|
|
141
|
+
* Style for the box the provider renders to carry the palette into the
|
|
142
|
+
* node tree. Defaults to `{ flexGrow: 1 }` — an app-level provider fills
|
|
143
|
+
* its parent. No box is rendered above a `<window>`, which may not sit
|
|
144
|
+
* inside one; the palette goes on the window itself.
|
|
145
|
+
*/
|
|
146
|
+
style?: StyleProp;
|
|
147
|
+
children?: ReactNode;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Themes everything below it, by both routes at once: widgets read the
|
|
152
|
+
* palette through {@link useTheme}, and a `$token` in a style resolves
|
|
153
|
+
* against the `theme` prop the provider plants in the node tree.
|
|
154
|
+
*/
|
|
155
|
+
export const ThemeProvider: ComponentType<ThemeProviderProps>;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* The palette as a bag of tokens, which is what it is at runtime: a theme
|
|
159
|
+
* merges over whatever is above it and a `$name` in a style resolves against
|
|
160
|
+
* the result, so a component that reads tokens by name — a code block asking
|
|
161
|
+
* for `surface`/`text`/`textMuted`, a renderer resolving a palette it was handed
|
|
162
|
+
* — can index it. The named tokens keep their types; anything else is
|
|
163
|
+
* `unknown` and has to be narrowed, which is the honest answer for a name
|
|
164
|
+
* only the caller knows.
|
|
165
|
+
*
|
|
166
|
+
* `<ThemeProvider value>` stays closed (`Partial<Theme>`) on purpose: a typo
|
|
167
|
+
* in a palette is a bug, and there is nowhere else to catch it.
|
|
168
|
+
*/
|
|
169
|
+
export interface ThemeTokens extends Theme {
|
|
170
|
+
readonly [token: string]: unknown;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** The palette in force: merged over the defaults and over any outer
|
|
174
|
+
* provider, and the same object `$token` resolution sees. */
|
|
175
|
+
export function useTheme(): ThemeTokens;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Which way the widgets here read. Yoga mirrors the boxes on its own from the
|
|
179
|
+
* `direction` style property, so this is for what it cannot decide: which way
|
|
180
|
+
* an arrow key steps, which way a glyph points, which side a menu opens on.
|
|
181
|
+
*/
|
|
182
|
+
export function useDirection(): 'ltr' | 'rtl';
|
|
183
|
+
|
|
184
|
+
/** Props a widget passes through to the `<box>` it renders. */
|
|
185
|
+
type WidgetProps = Omit<BoxProps, 'children' | 'style' | 'ref'>;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* What a value widget's `onChange` receives — one signature across the
|
|
189
|
+
* library, so `onChange={formik.handleChange}` wires to a `Checkbox` exactly
|
|
190
|
+
* as it does to a `<textinput>`.
|
|
191
|
+
*
|
|
192
|
+
* The new value is `ev.value`, so `onChange={(ev) => setChecked(ev.value)}`
|
|
193
|
+
* is the plain-React form.
|
|
194
|
+
*
|
|
195
|
+
* `target` is a plain descriptor, not a node: a widget is several nodes and
|
|
196
|
+
* none of them holds its value, so there is nothing honest to point at. Its
|
|
197
|
+
* shape is what formik's `handleChange` and react-hook-form's event reader
|
|
198
|
+
* destructure, `type` included.
|
|
199
|
+
*/
|
|
200
|
+
export interface WidgetChangeEvent<V = unknown> {
|
|
201
|
+
type: 'change';
|
|
202
|
+
target: {
|
|
203
|
+
/** `'checkbox'`, `'radio'`, `'select-one'`, `'range'`. */
|
|
204
|
+
type: string;
|
|
205
|
+
name?: string;
|
|
206
|
+
value: V;
|
|
207
|
+
/** Checkbox and switch only. */
|
|
208
|
+
checked?: boolean;
|
|
209
|
+
};
|
|
210
|
+
currentTarget: WidgetChangeEvent<V>['target'];
|
|
211
|
+
name?: string;
|
|
212
|
+
value: V;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** Widgets that are one form field: they take a `name` and echo it back. */
|
|
216
|
+
interface NamedWidget {
|
|
217
|
+
/**
|
|
218
|
+
* Field name, echoed on the change event as `ev.name` and
|
|
219
|
+
* `ev.target.name`. Nothing in react-x11 reads it — it is there so a form
|
|
220
|
+
* library has somewhere to put one.
|
|
221
|
+
*/
|
|
222
|
+
name?: string;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* The system icon set: the affordance glyphs core's own widgets are drawn
|
|
227
|
+
* with. Affordances only — no nouns; a folder or a save icon belongs to an
|
|
228
|
+
* icon theme. See docs/components.md#system-icons.
|
|
229
|
+
*/
|
|
230
|
+
export type IconName =
|
|
231
|
+
| 'chevronRight'
|
|
232
|
+
| 'chevronLeft'
|
|
233
|
+
| 'chevronDown'
|
|
234
|
+
| 'chevronUp'
|
|
235
|
+
| 'check'
|
|
236
|
+
| 'dash'
|
|
237
|
+
| 'dot'
|
|
238
|
+
| 'close'
|
|
239
|
+
| 'plus'
|
|
240
|
+
| 'moreVertical'
|
|
241
|
+
| 'eye'
|
|
242
|
+
| 'eyeOff';
|
|
243
|
+
|
|
244
|
+
export interface IconProps extends Omit<CanvasProps, 'onDraw' | 'cacheKey'> {
|
|
245
|
+
name: IconName;
|
|
246
|
+
/**
|
|
247
|
+
* The size of the mark, not of a grid it sits in — the ink runs corner to
|
|
248
|
+
* corner, unlike lucide and its descendants. A chevron's arms are at 45°,
|
|
249
|
+
* so it is `size` along the way it points across and half that the other
|
|
250
|
+
* way. Default: a shade under the palette's `fontSize`.
|
|
251
|
+
*/
|
|
252
|
+
size?: number;
|
|
253
|
+
/** Default: the ink of the element around it, and under that the palette's
|
|
254
|
+
* `text` — `color` inherits, so an icon in a row that dims itself dims
|
|
255
|
+
* with it. Pass this only to say something the surrounding text does not. */
|
|
256
|
+
color?: Color;
|
|
257
|
+
style?: StyleProp;
|
|
258
|
+
}
|
|
259
|
+
export const Icon: ComponentType<IconProps>;
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* The drawings themselves, keyed by name — each one an `onDraw` for
|
|
263
|
+
* `<canvas mono>`, for a widget that wants the glyph without the component.
|
|
264
|
+
*/
|
|
265
|
+
export const icons: Readonly<
|
|
266
|
+
Record<IconName, (ctx: any, info: DrawInfo) => void>
|
|
267
|
+
>;
|
|
268
|
+
export const iconNames: readonly IconName[];
|
|
269
|
+
/** The default icon box for a given `fontSize`. */
|
|
270
|
+
export function iconSize(fontSize: number): number;
|
|
271
|
+
|
|
272
|
+
export interface ButtonProps extends WidgetProps {
|
|
273
|
+
children?: ReactNode;
|
|
274
|
+
label?: string;
|
|
275
|
+
onPress?: (ev: MouseEvent<DrawnNode>) => void;
|
|
276
|
+
primary?: boolean;
|
|
277
|
+
/** How much chrome: a fill, a border on nothing, or neither. */
|
|
278
|
+
variant?: 'solid' | 'outline' | 'ghost';
|
|
279
|
+
/** `'small'` is the compact metric for toolbars and inline rows. */
|
|
280
|
+
size?: 'medium' | 'small';
|
|
281
|
+
disabled?: boolean;
|
|
282
|
+
style?: StyleProp;
|
|
283
|
+
}
|
|
284
|
+
export const Button: ComponentType<ButtonProps>;
|
|
285
|
+
|
|
286
|
+
export interface PasswordMaskInfo {
|
|
287
|
+
/** How wide the mask should be — what the field worked out from the
|
|
288
|
+
* length, not the width of the box. */
|
|
289
|
+
width: number;
|
|
290
|
+
height: number;
|
|
291
|
+
/** Seeded from the window and a hash of the value, so it changes on every
|
|
292
|
+
* keystroke and repaints identically in between. */
|
|
293
|
+
seed: number;
|
|
294
|
+
color: Color;
|
|
295
|
+
length: number;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export interface PasswordInputProps extends WidgetProps, NamedWidget {
|
|
299
|
+
value?: string;
|
|
300
|
+
defaultValue?: string;
|
|
301
|
+
onChange?: (ev: WidgetChangeEvent<string>) => void;
|
|
302
|
+
/** Enter. */
|
|
303
|
+
onSubmit?: (value: string) => void;
|
|
304
|
+
placeholder?: string;
|
|
305
|
+
/** Show the reveal eye at all. Default `true`, as GTK's peek icon is. */
|
|
306
|
+
revealable?: boolean;
|
|
307
|
+
/** Drive the reveal yourself — for a toggle the keyboard can reach, the
|
|
308
|
+
* built-in eye being a pointer affordance. */
|
|
309
|
+
revealed?: boolean;
|
|
310
|
+
onRevealChange?: (revealed: boolean) => void;
|
|
311
|
+
/** In code points, not UTF-16 units. */
|
|
312
|
+
maxLength?: number;
|
|
313
|
+
/** Draw the mask instead of the scribble. `ctx` is ntk's canvas-like 2d
|
|
314
|
+
* context, translated to the mask's origin. */
|
|
315
|
+
drawMask?: (ctx: any, info: PasswordMaskInfo) => void;
|
|
316
|
+
disabled?: boolean;
|
|
317
|
+
style?: StyleProp;
|
|
318
|
+
}
|
|
319
|
+
export const PasswordInput: ComponentType<PasswordInputProps>;
|
|
320
|
+
|
|
321
|
+
export interface CheckboxProps extends WidgetProps, NamedWidget {
|
|
322
|
+
children?: ReactNode;
|
|
323
|
+
label?: string;
|
|
324
|
+
checked?: boolean;
|
|
325
|
+
onChange?: (ev: WidgetChangeEvent<boolean>) => void;
|
|
326
|
+
disabled?: boolean;
|
|
327
|
+
style?: StyleProp;
|
|
328
|
+
}
|
|
329
|
+
export const Checkbox: ComponentType<CheckboxProps>;
|
|
330
|
+
|
|
331
|
+
export interface RadioGroupProps<T = unknown> extends WidgetProps, NamedWidget {
|
|
332
|
+
value?: T;
|
|
333
|
+
onChange?: (ev: WidgetChangeEvent<T>) => void;
|
|
334
|
+
children?: ReactNode;
|
|
335
|
+
style?: StyleProp;
|
|
336
|
+
}
|
|
337
|
+
export function RadioGroup<T = unknown>(props: RadioGroupProps<T>): ReactNode;
|
|
338
|
+
|
|
339
|
+
export interface RadioProps<T = unknown> {
|
|
340
|
+
value: T;
|
|
341
|
+
children?: ReactNode;
|
|
342
|
+
label?: string;
|
|
343
|
+
disabled?: boolean;
|
|
344
|
+
}
|
|
345
|
+
export function Radio<T = unknown>(props: RadioProps<T>): ReactNode;
|
|
346
|
+
|
|
347
|
+
export interface SwitchProps extends WidgetProps, NamedWidget {
|
|
348
|
+
checked?: boolean;
|
|
349
|
+
onChange?: (ev: WidgetChangeEvent<boolean>) => void;
|
|
350
|
+
disabled?: boolean;
|
|
351
|
+
style?: StyleProp;
|
|
352
|
+
}
|
|
353
|
+
export const Switch: ComponentType<SwitchProps>;
|
|
354
|
+
|
|
355
|
+
export interface ProgressBarProps extends WidgetProps {
|
|
356
|
+
/** 0 to 1. Ignored when {@link ProgressBarProps.indeterminate} is set. */
|
|
357
|
+
value?: number;
|
|
358
|
+
/**
|
|
359
|
+
* Working, with no idea how far along: a block slides across the track
|
|
360
|
+
* forever and the bar says `aria-busy` with no value. Honours the
|
|
361
|
+
* desktop's reduced-motion setting — see docs/components.md.
|
|
362
|
+
*/
|
|
363
|
+
indeterminate?: boolean;
|
|
364
|
+
color?: Color;
|
|
365
|
+
trackColor?: Color;
|
|
366
|
+
height?: number;
|
|
367
|
+
style?: StyleProp;
|
|
368
|
+
}
|
|
369
|
+
export const ProgressBar: ComponentType<ProgressBarProps>;
|
|
370
|
+
|
|
371
|
+
export interface SliderProps extends WidgetProps, NamedWidget {
|
|
372
|
+
value?: number;
|
|
373
|
+
min?: number;
|
|
374
|
+
max?: number;
|
|
375
|
+
step?: number;
|
|
376
|
+
onChange?: (ev: WidgetChangeEvent<number>) => void;
|
|
377
|
+
disabled?: boolean;
|
|
378
|
+
height?: number;
|
|
379
|
+
style?: StyleProp;
|
|
380
|
+
}
|
|
381
|
+
export const Slider: ComponentType<SliderProps>;
|
|
382
|
+
|
|
383
|
+
export type Placement = 'top' | 'bottom' | 'left' | 'right';
|
|
384
|
+
|
|
385
|
+
export interface TooltipProps extends WidgetProps {
|
|
386
|
+
/**
|
|
387
|
+
* The hint. A string is measured and the popup sized around it; an
|
|
388
|
+
* element **self-sizes too** — the popup is rendered once hidden at its
|
|
389
|
+
* natural size, read back, and placed before it is ever mapped — so a card
|
|
390
|
+
* whose height depends on its content needs no numbers. It gets the
|
|
391
|
+
* bubble to fill and draws its own padding.
|
|
392
|
+
*/
|
|
393
|
+
label: ReactNode;
|
|
394
|
+
children?: ReactNode;
|
|
395
|
+
/**
|
|
396
|
+
* Which side of the trigger to open on. `'auto'` (the default) takes the
|
|
397
|
+
* first side the hint fits on, preferring above; a named side is still a
|
|
398
|
+
* preference rather than a promise, since it flips to its opposite rather
|
|
399
|
+
* than opening off-screen.
|
|
400
|
+
*/
|
|
401
|
+
direction?: Placement | 'auto';
|
|
402
|
+
/** The older name for {@link TooltipProps.direction}; wins where given. */
|
|
403
|
+
placement?: Placement;
|
|
404
|
+
/** ms before it appears (default 500). */
|
|
405
|
+
delay?: number;
|
|
406
|
+
fontSize?: number;
|
|
407
|
+
/**
|
|
408
|
+
* Pin an axis of the bubble exactly. For text they override the measured
|
|
409
|
+
* size; for an element, a pinned axis stays pinned and the other is
|
|
410
|
+
* measured for it — `width={340}` is a fixed column whose height fits the
|
|
411
|
+
* message. Give both and nothing is measured at all.
|
|
412
|
+
*/
|
|
413
|
+
width?: number;
|
|
414
|
+
height?: number;
|
|
415
|
+
/**
|
|
416
|
+
* Cap what an element label may measure out to, on top of the screen's
|
|
417
|
+
* own cap. Inert on an axis pinned by {@link TooltipProps.width} /
|
|
418
|
+
* {@link TooltipProps.height}, and on a text label, which stays one line.
|
|
419
|
+
*/
|
|
420
|
+
maxWidth?: number;
|
|
421
|
+
maxHeight?: number;
|
|
422
|
+
style?: StyleProp;
|
|
423
|
+
}
|
|
424
|
+
export const Tooltip: ComponentType<TooltipProps>;
|
|
425
|
+
|
|
426
|
+
export interface DialogProps extends WidgetProps {
|
|
427
|
+
open?: boolean;
|
|
428
|
+
title?: string;
|
|
429
|
+
children?: ReactNode;
|
|
430
|
+
/**
|
|
431
|
+
* `true` (the default) makes the dialog a **window-manager-managed**
|
|
432
|
+
* window with `WM_TRANSIENT_FOR` pointing at its owner: framed, movable,
|
|
433
|
+
* closable through the WM, out of the taskbar and alt-tab list, and — on a
|
|
434
|
+
* full EWMH window manager — stacked above its owner and iconified with
|
|
435
|
+
* it. A press outside does **not** close it, because a real dialog does
|
|
436
|
+
* not close that way; Escape and the WM close button both call
|
|
437
|
+
* {@link DialogProps.onClose}.
|
|
438
|
+
*
|
|
439
|
+
* `false` is the override-redirect popup 1.x shipped: no frame, not
|
|
440
|
+
* movable, and a press anywhere outside dismisses it (a pointer grab).
|
|
441
|
+
* Right for a transient confirmation on a display with no window manager.
|
|
442
|
+
*/
|
|
443
|
+
managed?: boolean;
|
|
444
|
+
onClose?: () => void;
|
|
445
|
+
actions?: ReactNode;
|
|
446
|
+
width?: number;
|
|
447
|
+
height?: number;
|
|
448
|
+
style?: StyleProp;
|
|
449
|
+
}
|
|
450
|
+
export const Dialog: ComponentType<DialogProps>;
|
|
451
|
+
|
|
452
|
+
/** An option, or a plain value used as both value and label. */
|
|
453
|
+
export type SelectOption<T = unknown> = { value: T; label: string } | T;
|
|
454
|
+
|
|
455
|
+
export interface SelectProps<T = unknown> extends WidgetProps, NamedWidget {
|
|
456
|
+
value?: T;
|
|
457
|
+
options?: readonly SelectOption<T>[];
|
|
458
|
+
onChange?: (ev: WidgetChangeEvent<T>) => void;
|
|
459
|
+
placeholder?: string;
|
|
460
|
+
style?: StyleProp;
|
|
461
|
+
}
|
|
462
|
+
export function Select<T = unknown>(props: SelectProps<T>): ReactNode;
|
|
463
|
+
|
|
464
|
+
/** dbusmenu's `toggle-type`. */
|
|
465
|
+
export type MenuToggleType = 'checkmark' | 'radio';
|
|
466
|
+
|
|
467
|
+
/** dbusmenu's `toggle-state`: off, on, and "on for part of the selection". */
|
|
468
|
+
export type MenuToggleState = 0 | 1 | -1;
|
|
469
|
+
|
|
470
|
+
/** dbusmenu's `disposition` — what kind of attention the item wants. */
|
|
471
|
+
export type MenuDisposition = 'normal' | 'informative' | 'warning' | 'alert';
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* One `aas` shortcut: a list of **alternatives**, each a list of modifier
|
|
475
|
+
* tokens (`Control`, `Alt`, `Shift`, `Super`) ending in the key.
|
|
476
|
+
*
|
|
477
|
+
* ```ts
|
|
478
|
+
* shortcut: [['Control', 'S']]
|
|
479
|
+
* ```
|
|
480
|
+
*
|
|
481
|
+
* The key is named the way GDK names it — `plus`, not `+` — because that is
|
|
482
|
+
* what a panel's importer parses. Menus print the friendly form.
|
|
483
|
+
*/
|
|
484
|
+
export type MenuShortcut = readonly (readonly string[])[];
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* An item in a menu.
|
|
488
|
+
*
|
|
489
|
+
* The vocabulary is `com.canonical.dbusmenu`'s, so the identical array
|
|
490
|
+
* serialises to the desktop's global menu with no translation and there is
|
|
491
|
+
* no second authoring model. See docs/globalmenu.md.
|
|
492
|
+
*/
|
|
493
|
+
export interface MenuItem {
|
|
494
|
+
label?: string;
|
|
495
|
+
/** `'separator'` draws a rule instead of a row. Absent means `'standard'`. */
|
|
496
|
+
type?: 'standard' | 'separator';
|
|
497
|
+
/** Present and non-empty makes this a submenu parent. */
|
|
498
|
+
items?: MenuItem[];
|
|
499
|
+
/** Defaults to `true`; `false` dims the row and makes it inert. */
|
|
500
|
+
enabled?: boolean;
|
|
501
|
+
/** Defaults to `true`; `false` removes the row from the menu entirely. */
|
|
502
|
+
visible?: boolean;
|
|
503
|
+
/**
|
|
504
|
+
* Drawn right-aligned, announced as `aria-keyshortcuts`, sent to the
|
|
505
|
+
* panel — **and bound**: pressing it fires this item's `onSelect` while
|
|
506
|
+
* the menu is mounted, without the menu being opened (#351). `enabled`
|
|
507
|
+
* and `visible` gate the binding with the row. `accelerators={false}` on
|
|
508
|
+
* the menu turns that off for an app with a dispatcher of its own.
|
|
509
|
+
*/
|
|
510
|
+
shortcut?: MenuShortcut;
|
|
511
|
+
/** With `toggleState`, draws a check mark or a radio dot in the gutter. */
|
|
512
|
+
toggleType?: MenuToggleType;
|
|
513
|
+
toggleState?: MenuToggleState;
|
|
514
|
+
/** An icon-theme name, for the desktop's menu. Ignored by the drawn one. */
|
|
515
|
+
iconName?: string;
|
|
516
|
+
/** Raw PNG bytes, for an icon that is not in a theme. */
|
|
517
|
+
iconData?: Uint8Array;
|
|
518
|
+
disposition?: MenuDisposition;
|
|
519
|
+
/**
|
|
520
|
+
* Drawn in the 16px column left of the label — the same column the toggle
|
|
521
|
+
* mark uses, so an item that is both checked and iconned shows the check.
|
|
522
|
+
*
|
|
523
|
+
* **Local only**, and the one deliberate departure from the dbusmenu
|
|
524
|
+
* vocabulary: the desktop cannot call a function, so an item that wants an
|
|
525
|
+
* icon in both menus carries `icon` for ours and `iconName` for the panel's.
|
|
526
|
+
*
|
|
527
|
+
* A string is drawn as text, which is a one-liner but only as good as the
|
|
528
|
+
* font: an exotic glyph is tofu on a machine without it. A **function**
|
|
529
|
+
* is called with the colour the row's label is being drawn in and the
|
|
530
|
+
* size the gutter allows, which is what a `<canvas onDraw>` icon needs —
|
|
531
|
+
* it has to pick a stroke colour, and nothing else can tell it whether
|
|
532
|
+
* its row is highlighted, disabled or at rest. An element renders as-is.
|
|
533
|
+
*/
|
|
534
|
+
icon?:
|
|
535
|
+
| string
|
|
536
|
+
| number
|
|
537
|
+
| ReactNode
|
|
538
|
+
| ((state: { color: string; size: number }) => ReactNode);
|
|
539
|
+
/** Identity for React keys and for the exported item's stable integer id. */
|
|
540
|
+
key?: string;
|
|
541
|
+
onSelect?: (item: MenuItem) => void;
|
|
542
|
+
[key: string]: unknown;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
export interface ContextMenuProps extends WidgetProps {
|
|
546
|
+
items?: readonly MenuItem[];
|
|
547
|
+
children?: ReactNode;
|
|
548
|
+
onSelect?: (item: MenuItem) => void;
|
|
549
|
+
/**
|
|
550
|
+
* Honour the items' own `shortcut`s while this menu is mounted. On by
|
|
551
|
+
* default; `false` leaves the chords to an app that dispatches its own.
|
|
552
|
+
*/
|
|
553
|
+
accelerators?: boolean;
|
|
554
|
+
fontSize?: number;
|
|
555
|
+
style?: StyleProp;
|
|
556
|
+
}
|
|
557
|
+
export const ContextMenu: ComponentType<ContextMenuProps>;
|
|
558
|
+
|
|
559
|
+
export interface MenuBarMenu {
|
|
560
|
+
label: string;
|
|
561
|
+
items: MenuItem[];
|
|
562
|
+
visible?: boolean;
|
|
563
|
+
key?: string;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
export interface MenuBarProps extends WidgetProps {
|
|
567
|
+
menus?: readonly MenuBarMenu[];
|
|
568
|
+
onSelect?: (item: MenuItem) => void;
|
|
569
|
+
/**
|
|
570
|
+
* Hand the bar to the desktop's panel where there is one. On by default,
|
|
571
|
+
* and `false` keeps it in the window. See docs/globalmenu.md.
|
|
572
|
+
*/
|
|
573
|
+
globalMenu?: boolean;
|
|
574
|
+
/**
|
|
575
|
+
* Called with `true` when the desktop's panel takes the menu and `false`
|
|
576
|
+
* when it gives it back. The one fact about this an app cannot work out for
|
|
577
|
+
* itself: calling `useGlobalMenu` beside a `MenuBar` would export the menu
|
|
578
|
+
* twice.
|
|
579
|
+
*/
|
|
580
|
+
onGlobalMenuChange?: (exported: boolean) => void;
|
|
581
|
+
/**
|
|
582
|
+
* Honour the items' own `shortcut`s while this bar is mounted — including
|
|
583
|
+
* when the desktop's panel has taken the menu over, since the panel draws
|
|
584
|
+
* the rows but the key is pressed in this window. On by default; `false`
|
|
585
|
+
* leaves the chords to an app that dispatches its own.
|
|
586
|
+
*/
|
|
587
|
+
accelerators?: boolean;
|
|
588
|
+
fontSize?: number;
|
|
589
|
+
style?: StyleProp;
|
|
590
|
+
}
|
|
591
|
+
export const MenuBar: ComponentType<MenuBarProps>;
|
|
592
|
+
|
|
593
|
+
export interface TabItem {
|
|
594
|
+
id: string;
|
|
595
|
+
label: string;
|
|
596
|
+
content?: ReactNode;
|
|
597
|
+
disabled?: boolean;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
export interface TabsProps extends WidgetProps {
|
|
601
|
+
items?: readonly TabItem[];
|
|
602
|
+
value?: string;
|
|
603
|
+
defaultValue?: string;
|
|
604
|
+
onChange?: (id: string) => void;
|
|
605
|
+
orientation?: 'horizontal' | 'vertical';
|
|
606
|
+
/** Arrow keys move the highlight without selecting until Enter/Space. */
|
|
607
|
+
manual?: boolean;
|
|
608
|
+
style?: StyleProp;
|
|
609
|
+
}
|
|
610
|
+
export const Tabs: ComponentType<TabsProps>;
|
|
611
|
+
|
|
612
|
+
export interface TableColumn<Row = any> {
|
|
613
|
+
id: string;
|
|
614
|
+
label?: string;
|
|
615
|
+
width?: number;
|
|
616
|
+
align?: 'left' | 'right' | 'center';
|
|
617
|
+
/** Pull the cell value out of a row; defaults to `row[id]`. */
|
|
618
|
+
value?: (row: Row) => unknown;
|
|
619
|
+
/**
|
|
620
|
+
* Draw the cell yourself. `selected` says the cell is on the selected row —
|
|
621
|
+
* a filled bar — so a colour chosen against the resting background has to
|
|
622
|
+
* give way to `hoverText` there.
|
|
623
|
+
*/
|
|
624
|
+
render?: (
|
|
625
|
+
row: Row,
|
|
626
|
+
context: { selected: boolean; column: TableColumn<Row> },
|
|
627
|
+
) => ReactNode;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
export interface TableSort {
|
|
631
|
+
column: string;
|
|
632
|
+
direction: 'asc' | 'desc';
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
export interface TableProps<Row = any> extends WidgetProps {
|
|
636
|
+
columns?: readonly TableColumn<Row>[];
|
|
637
|
+
rows?: readonly Row[];
|
|
638
|
+
rowHeight?: number;
|
|
639
|
+
sort?: TableSort | null;
|
|
640
|
+
defaultSort?: TableSort | null;
|
|
641
|
+
onSortChange?: (sort: TableSort | null) => void;
|
|
642
|
+
selected?: string | number | null;
|
|
643
|
+
defaultSelected?: string | number | null;
|
|
644
|
+
onSelect?: (id: string | number, row: Row) => void;
|
|
645
|
+
/** Double click, or Enter on the selected row. */
|
|
646
|
+
onActivate?: (id: string | number, row: Row) => void;
|
|
647
|
+
onColumnResize?: (id: string, width: number) => void;
|
|
648
|
+
style?: StyleProp;
|
|
649
|
+
}
|
|
650
|
+
export function Table<Row = any>(props: TableProps<Row>): ReactNode;
|
|
651
|
+
|
|
652
|
+
export interface SplitPaneProps extends WidgetProps {
|
|
653
|
+
direction?: 'row' | 'column';
|
|
654
|
+
size?: number;
|
|
655
|
+
defaultSize?: number;
|
|
656
|
+
/** Minimum size of the first pane. */
|
|
657
|
+
min?: number;
|
|
658
|
+
/** Minimum size of the second. */
|
|
659
|
+
minSecond?: number;
|
|
660
|
+
onResize?: (size: number) => void;
|
|
661
|
+
/** Exactly two children: the two panes. */
|
|
662
|
+
children?: ReactNode;
|
|
663
|
+
style?: StyleProp;
|
|
664
|
+
}
|
|
665
|
+
export const SplitPane: ComponentType<SplitPaneProps>;
|
|
666
|
+
|
|
667
|
+
// --- anchoring helpers -----------------------------------------------------
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* The side a popup is asked for. `'start'`/`'end'` are the **logical** ones
|
|
671
|
+
* and mirror with the anchor's direction, which is what a submenu wants;
|
|
672
|
+
* `'left'`/`'right'` stay physical.
|
|
673
|
+
*/
|
|
674
|
+
export type AnchorPlacement = Placement | 'start' | 'end';
|
|
675
|
+
|
|
676
|
+
export interface AnchorOptions {
|
|
677
|
+
/** Preferred side, flipped at a screen edge (default `'bottom'`). */
|
|
678
|
+
placement?: AnchorPlacement;
|
|
679
|
+
/** Which edges line up on the cross axis (default `'start'`). */
|
|
680
|
+
align?: 'start' | 'center' | 'end';
|
|
681
|
+
/** Gap from the anchor along the placement axis, in px (default 2). */
|
|
682
|
+
offset?: number;
|
|
683
|
+
/**
|
|
684
|
+
* Shift along the *alignment* axis, applied before the popup is clamped
|
|
685
|
+
* into the screen. For lining up what is drawn in a surface rather than
|
|
686
|
+
* the surface itself: a submenu level with the row that opened it has its
|
|
687
|
+
* first item a border and a padding lower, and the eye lines up the items.
|
|
688
|
+
*/
|
|
689
|
+
alignOffset?: number;
|
|
690
|
+
/**
|
|
691
|
+
* Anchor to a rect **inside** the node, in the node's own coordinates:
|
|
692
|
+
* a caret, a table cell, a chart datapoint. Everything reads it — the
|
|
693
|
+
* side that flips, the edge that aligns, the gap `offset` leaves — so a
|
|
694
|
+
* popup at a caret behaves like one at a small widget that happens to be
|
|
695
|
+
* there. `width`/`height` default to 0, so `{x, y}` alone is a point.
|
|
696
|
+
*/
|
|
697
|
+
at?: { x: number; y: number; width?: number; height?: number };
|
|
698
|
+
/** The size of the popup being placed. `width` defaults to the anchor's. */
|
|
699
|
+
width?: number;
|
|
700
|
+
height?: number;
|
|
701
|
+
/** Take the alignment from this node instead — a submenu lines up with
|
|
702
|
+
* the row that opened it while hanging off the menu's outer edge. */
|
|
703
|
+
alignTo?: DrawnNode | null;
|
|
704
|
+
/** Overrides the direction read off the anchoring node. */
|
|
705
|
+
direction?: 'ltr' | 'rtl';
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/** An anchored rect, and the side it actually ended up on. */
|
|
709
|
+
export interface AnchorRect extends Rect {
|
|
710
|
+
placement: Placement;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* Where to put a `<popup>` relative to a node, in screen coordinates,
|
|
715
|
+
* flipped at screen edges. `null` for a node that has not been laid out.
|
|
716
|
+
*/
|
|
717
|
+
export function anchorRect(
|
|
718
|
+
node: DrawnNode | null,
|
|
719
|
+
options?: AnchorOptions,
|
|
720
|
+
): AnchorRect | null;
|
|
721
|
+
|
|
722
|
+
/** Centre a popup of this size on the node's screen. */
|
|
723
|
+
export function centerRect(
|
|
724
|
+
node: DrawnNode,
|
|
725
|
+
size: { width: number; height: number },
|
|
726
|
+
): Rect;
|
|
727
|
+
|
|
728
|
+
/**
|
|
729
|
+
* The area a popup anchored to this node may be placed in: the usable part
|
|
730
|
+
* of the monitor it is on — per-monitor, minus the panels, the same answer
|
|
731
|
+
* `<window width="auto">` is capped by. What a widget sizing its own surface
|
|
732
|
+
* needs (a menu is never wider than the screen it opens on). `null` where
|
|
733
|
+
* there is no display to ask, which includes the headless mock.
|
|
734
|
+
*/
|
|
735
|
+
export function anchorArea(node: DrawnNode | null): Rect | null;
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* A node's laid-out rect in screen coordinates — where a popup's *trigger*
|
|
739
|
+
* is, rather than where to put the popup. What a surface has to know when
|
|
740
|
+
* it points back at the thing it belongs to: a tooltip's arrow aims at the
|
|
741
|
+
* middle of the trigger, and that stops being the middle of the tooltip as
|
|
742
|
+
* soon as a screen edge slides one of the two.
|
|
743
|
+
*/
|
|
744
|
+
export function screenRect(node: DrawnNode): Rect | null;
|
|
745
|
+
|
|
746
|
+
/** `anchorRect` bound to a ref, recomputed on demand. */
|
|
747
|
+
export function useAnchor(
|
|
748
|
+
ref: RefObject<DrawnNode | null>,
|
|
749
|
+
): (options?: AnchorOptions) => AnchorRect | null;
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* Keeps an `anchorRect` live for as long as `active`, instead of measuring
|
|
753
|
+
* once at open time: a scrolled ancestor, the node's own layout moving it,
|
|
754
|
+
* or the owner window being repositioned by the WM or a script each call
|
|
755
|
+
* `setRect` again with the new rect. `getOptions` is read fresh on every
|
|
756
|
+
* change, so it need not be memoized. `setRect` is only called when the
|
|
757
|
+
* measured rect actually differs from the previous one.
|
|
758
|
+
*
|
|
759
|
+
* If the anchor node scrolls (or is laid out) entirely past a clipping
|
|
760
|
+
* ancestor or the owner window, `onOutOfView` is called instead of moving
|
|
761
|
+
* the popup there — a popup is a real window, not a web element clipped by
|
|
762
|
+
* its ancestors, so following a trigger that is no longer visible would
|
|
763
|
+
* leave it pointing at nothing. Typically `onOutOfView` closes the popup.
|
|
764
|
+
* With an `at` in the options that test is about the sub-rect: a caret
|
|
765
|
+
* leaves the viewport long before the editor around it does.
|
|
766
|
+
*/
|
|
767
|
+
export function useAnchorTracking(
|
|
768
|
+
ref: RefObject<DrawnNode | null>,
|
|
769
|
+
active: boolean,
|
|
770
|
+
getOptions: () => AnchorOptions | null | undefined,
|
|
771
|
+
setRect: (
|
|
772
|
+
next: AnchorRect | null | ((prev: AnchorRect | null) => AnchorRect | null),
|
|
773
|
+
) => void,
|
|
774
|
+
onOutOfView?: () => void,
|
|
775
|
+
): void;
|
|
776
|
+
|
|
777
|
+
// --- drag and drop ---------------------------------------------------------
|
|
778
|
+
|
|
779
|
+
export interface UseDropTargetOptions {
|
|
780
|
+
/** Maps to the `dropAccept` host prop. */
|
|
781
|
+
accept?: DropAccept;
|
|
782
|
+
onDrop?: (ev: DropEvent) => void | Promise<void>;
|
|
783
|
+
onDragOver?: (ev: DragEvent) => void;
|
|
784
|
+
onDragEnter?: (ev: DragEvent) => void;
|
|
785
|
+
onDragLeave?: (ev: DragEvent) => void;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
/**
|
|
789
|
+
* The react-dropzone-shaped convenience over the drop-target host props:
|
|
790
|
+
* spread `dropProps` on any drawn element or window. Only needed when the
|
|
791
|
+
* render itself changes with the drag — a `':drag-over'` style block
|
|
792
|
+
* highlights without any state.
|
|
793
|
+
*/
|
|
794
|
+
export function useDropTarget(options?: UseDropTargetOptions): {
|
|
795
|
+
dropProps: DropTargetProps;
|
|
796
|
+
isOver: boolean;
|
|
797
|
+
isAccepted: boolean;
|
|
798
|
+
};
|
|
799
|
+
|
|
800
|
+
export interface UseDragSourceOptions {
|
|
801
|
+
/** Maps to the `dragData` host prop. */
|
|
802
|
+
data?: DragSourceProps['dragData'];
|
|
803
|
+
/** Maps to `dragActions`. */
|
|
804
|
+
actions?: Array<'copy' | 'move' | 'link'>;
|
|
805
|
+
onDragStart?: (ev: DragSourceEvent) => void;
|
|
806
|
+
onDrag?: (ev: DragSourceEvent) => void;
|
|
807
|
+
onDragEnd?: (ev: DragEndEvent) => void;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
/**
|
|
811
|
+
* The source-side convenience: spread `dragProps` on the node to drag.
|
|
812
|
+
* `position` (screen coordinates, non-null while dragging) is what a
|
|
813
|
+
* `<popup dragPreview>` follows — the drag preview is a live React tree,
|
|
814
|
+
* not a bitmap.
|
|
815
|
+
*/
|
|
816
|
+
export function useDragSource(options?: UseDragSourceOptions): {
|
|
817
|
+
dragProps: DragSourceProps;
|
|
818
|
+
isDragging: boolean;
|
|
819
|
+
position: { x: number; y: number; accepted: boolean } | null;
|
|
820
|
+
};
|