react-x11 2.6.0 → 2.7.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 +5 -3
- package/package.json +10 -3
- package/src/activate.js +12 -0
- package/src/anchor.js +6 -0
- package/src/appearance.js +351 -28
- package/src/appearancehooks.js +5 -2
- package/src/application.js +41 -0
- package/src/cocoa/app.js +358 -20
- package/src/cocoa/bezels.js +51 -1
- package/src/cocoa/context2d.js +271 -25
- package/src/cocoa/dnd.js +347 -0
- package/src/cocoa/dock.js +39 -0
- package/src/cocoa/filepanels.js +155 -0
- package/src/cocoa/fonts.js +93 -2
- package/src/cocoa/globalmenu.js +41 -33
- package/src/cocoa/notifications.js +244 -0
- package/src/cocoa/permissions.js +74 -0
- package/src/cocoa/presenter.js +190 -2
- package/src/cocoa/statusitem.js +112 -0
- package/src/cocoa/window.js +85 -4
- package/src/components/Button.js +20 -1
- package/src/components/Checkbox.js +17 -2
- package/src/components/Menu.js +108 -38
- package/src/components/Radio.js +17 -2
- package/src/components/Select.js +159 -27
- package/src/components/Switch.js +8 -1
- package/src/components/native.js +99 -0
- package/src/components/theme.js +37 -20
- package/src/desktopsettings.js +34 -2
- package/src/dnd.js +92 -3
- package/src/errors.js +6 -3
- package/src/filedialog.js +81 -16
- package/src/index.d.ts +17 -1
- package/src/index.js +17 -0
- package/src/launcher.js +170 -0
- package/src/launcherhooks.js +81 -0
- package/src/nodes.js +553 -35
- package/src/notificationhooks.js +56 -0
- package/src/notifications.js +558 -0
- package/src/palette.js +144 -8
- package/src/permissionhooks.js +89 -0
- package/src/permissions.js +196 -0
- package/src/screens.js +39 -4
- package/src/style.d.ts +10 -4
- package/src/style.js +1 -0
- package/src/styles.js +161 -15
- package/src/textselection.js +1 -4
- package/src/trayhooks.js +90 -0
- package/src/types/appearance.d.ts +24 -0
- package/src/types/components.d.ts +10 -0
- package/src/types/elements.d.ts +14 -0
- package/src/types/events.d.ts +14 -0
- package/src/types/filedialog.d.ts +18 -7
- package/src/types/launcher.d.ts +43 -0
- package/src/types/notifications.d.ts +113 -0
- package/src/types/permissions.d.ts +100 -0
- package/src/types/style.d.ts +30 -2
- package/src/types/system.d.ts +5 -3
- package/src/types/tray.d.ts +54 -0
- package/src/windowid.js +23 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Desktop notifications — a banner outside the app's own windows. See
|
|
3
|
+
* docs/notifications.md.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { NtkApp } from './nodes.js';
|
|
7
|
+
|
|
8
|
+
/** Which rung of the ladder answered — or would. */
|
|
9
|
+
export type NotificationBackend =
|
|
10
|
+
'cocoa' | 'dbus' | 'osascript' | 'notify-send';
|
|
11
|
+
|
|
12
|
+
export type NotificationUrgency = 'low' | 'normal' | 'critical';
|
|
13
|
+
|
|
14
|
+
/** Why a banner went away: the freedesktop reasons. */
|
|
15
|
+
export type NotificationCloseReason =
|
|
16
|
+
'expired' | 'dismissed' | 'closed' | 'unknown';
|
|
17
|
+
|
|
18
|
+
export interface NotificationAction {
|
|
19
|
+
/** Reported to `onAction`. `'default'` is the click on the banner itself
|
|
20
|
+
* and not a name for an action of your own. */
|
|
21
|
+
key: string;
|
|
22
|
+
label?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface NotificationOptions {
|
|
26
|
+
/** The one line every daemon shows. Required. */
|
|
27
|
+
summary: string;
|
|
28
|
+
body?: string;
|
|
29
|
+
/** macOS only; folded into the body elsewhere. */
|
|
30
|
+
subtitle?: string;
|
|
31
|
+
/** An icon-theme name, or an absolute path to an image. Rungs that cannot
|
|
32
|
+
* show one ignore it. */
|
|
33
|
+
icon?: string;
|
|
34
|
+
urgency?: NotificationUrgency;
|
|
35
|
+
/** Milliseconds until it expires on its own; `0` never; absent is the
|
|
36
|
+
* daemon's default. */
|
|
37
|
+
timeout?: number;
|
|
38
|
+
/** Buttons on the banner. Dropped, with a development warning, on a daemon
|
|
39
|
+
* without the `actions` capability; never sent on the shell-out rungs. */
|
|
40
|
+
actions?: NotificationAction[];
|
|
41
|
+
onAction?: (key: string) => void;
|
|
42
|
+
onClose?: (reason: NotificationCloseReason) => void;
|
|
43
|
+
/** `true` posts without a sound on macOS. */
|
|
44
|
+
silent?: boolean;
|
|
45
|
+
/** A freedesktop category hint (`'transfer.complete'`, …). */
|
|
46
|
+
category?: string;
|
|
47
|
+
/** Keep the banner after an action is invoked (freedesktop `resident`). */
|
|
48
|
+
resident?: boolean;
|
|
49
|
+
/** The name a daemon shows for the sender; the process title otherwise. */
|
|
50
|
+
appName?: string;
|
|
51
|
+
/** The desktop-entry id the banner is attributed to; the registration's
|
|
52
|
+
* `appId` otherwise. */
|
|
53
|
+
appId?: string;
|
|
54
|
+
/** Opaque data round-tripped on the macOS rung. */
|
|
55
|
+
userInfo?: Record<string, unknown>;
|
|
56
|
+
/** Force a rung, for kiosks and for tests. */
|
|
57
|
+
backend?: NotificationBackend;
|
|
58
|
+
/** The connection whose centre to post through, when there are several. */
|
|
59
|
+
app?: NtkApp;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface NotificationHandle {
|
|
63
|
+
/** The daemon's id, the centre's identifier, or `null` where the rung has
|
|
64
|
+
* none (a shell-out). */
|
|
65
|
+
readonly id: number | string | null;
|
|
66
|
+
readonly backend: NotificationBackend;
|
|
67
|
+
/** Replace the banner in place. On a shell-out rung without an id this
|
|
68
|
+
* posts a fresh one. */
|
|
69
|
+
update(patch: Partial<NotificationOptions>): Promise<NotificationHandle>;
|
|
70
|
+
/** Take it down. Nothing on a shell-out rung. */
|
|
71
|
+
close(): Promise<void>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Nothing on this machine can show a notification. A **typed** rejection,
|
|
76
|
+
* the `NoFileDialogError` rule; `useNotifier().available` is that branch as
|
|
77
|
+
* render state. A centre that exists and *refused* (the user turned the
|
|
78
|
+
* app's notifications off) rejects with the platform's own error instead —
|
|
79
|
+
* a refusal is not fallen through.
|
|
80
|
+
*/
|
|
81
|
+
export declare class NoNotificationServiceError extends Error {
|
|
82
|
+
readonly name: 'NoNotificationServiceError';
|
|
83
|
+
readonly cause?: unknown;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Show a notification on the best rung this machine has. */
|
|
87
|
+
export declare function notify(
|
|
88
|
+
options: NotificationOptions,
|
|
89
|
+
): Promise<NotificationHandle>;
|
|
90
|
+
|
|
91
|
+
/** Which rung this machine lands on, without posting anything. `null`
|
|
92
|
+
* means {@link notify} would reject. */
|
|
93
|
+
export declare function notificationBackend(
|
|
94
|
+
options?: Pick<NotificationOptions, 'app' | 'backend'>,
|
|
95
|
+
): Promise<NotificationBackend | null>;
|
|
96
|
+
|
|
97
|
+
export interface Notifier {
|
|
98
|
+
notify(
|
|
99
|
+
options: Omit<NotificationOptions, 'app'>,
|
|
100
|
+
): Promise<NotificationHandle>;
|
|
101
|
+
/** Settled once the ladder has been probed; false where `notify` would
|
|
102
|
+
* reject. */
|
|
103
|
+
available: boolean;
|
|
104
|
+
backend: NotificationBackend | null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Notifications for a component: `notify` bound to the tree's connection,
|
|
108
|
+
* `available` and `backend` as render state. */
|
|
109
|
+
export declare function useNotifier(
|
|
110
|
+
defaults?: Omit<NotificationOptions, 'app' | 'summary'> & {
|
|
111
|
+
summary?: string;
|
|
112
|
+
},
|
|
113
|
+
): Notifier;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permissions: may this app use the camera, the microphone, the screen, the
|
|
3
|
+
* accessibility APIs — and how does it ask? See docs/permissions.md.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { NtkApp } from './nodes.js';
|
|
7
|
+
|
|
8
|
+
export type PermissionKind =
|
|
9
|
+
| 'camera'
|
|
10
|
+
| 'microphone'
|
|
11
|
+
| 'screen-recording'
|
|
12
|
+
| 'accessibility'
|
|
13
|
+
| 'input-monitoring'
|
|
14
|
+
| 'automation'
|
|
15
|
+
| 'location';
|
|
16
|
+
|
|
17
|
+
/** The panes `openPrivacySettings` reaches: every kind, plus the two with no
|
|
18
|
+
* API because reading the folder is the prompt. */
|
|
19
|
+
export type PrivacyPane =
|
|
20
|
+
PermissionKind | 'files-and-folders' | 'full-disk-access';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* `'granted'`, `'denied'` and `'restricted'` (MDM or parental controls — the
|
|
24
|
+
* user cannot grant it) are the platform's; `'prompt'` is not decided yet, a
|
|
25
|
+
* request would ask; `'unknown'` is "nothing here can say", a fact about the
|
|
26
|
+
* machine rather than the permission.
|
|
27
|
+
*/
|
|
28
|
+
export type PermissionStatus =
|
|
29
|
+
'granted' | 'denied' | 'restricted' | 'prompt' | 'unknown';
|
|
30
|
+
|
|
31
|
+
export interface PermissionOptions {
|
|
32
|
+
/** The connection whose backend to ask, when there are several. */
|
|
33
|
+
app?: NtkApp;
|
|
34
|
+
/** `automation` only: the bundle id of the app to send Apple Events to.
|
|
35
|
+
* Only a running target has an answer. */
|
|
36
|
+
target?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Nothing on this machine can ask. A **typed** rejection, so a caller keeps
|
|
41
|
+
* the feature behind it rather than crashing; `usePermission().available`
|
|
42
|
+
* is that branch as render state, and `permissionStatus()` foretells it
|
|
43
|
+
* with `'unknown'`.
|
|
44
|
+
*/
|
|
45
|
+
export declare class NoPermissionServiceError extends Error {
|
|
46
|
+
readonly name: 'NoPermissionServiceError';
|
|
47
|
+
readonly cause?: unknown;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Which rung answers here: `'cocoa'`, or `null` where a status would be
|
|
51
|
+
* `'unknown'` and a request would reject. Synchronous. */
|
|
52
|
+
export declare function permissionBackend(
|
|
53
|
+
options?: Pick<PermissionOptions, 'app'>,
|
|
54
|
+
): 'cocoa' | null;
|
|
55
|
+
|
|
56
|
+
/** Whether this app may use `kind`, without prompting. Never rejects for
|
|
57
|
+
* anything about the machine. */
|
|
58
|
+
export declare function permissionStatus(
|
|
59
|
+
kind: PermissionKind,
|
|
60
|
+
options?: PermissionOptions,
|
|
61
|
+
): Promise<PermissionStatus>;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Ask for `kind` — the system's prompt where there is one — and resolve
|
|
65
|
+
* with the status once the user has answered. Rejects with
|
|
66
|
+
* {@link NoPermissionServiceError} where nothing can ask.
|
|
67
|
+
*/
|
|
68
|
+
export declare function requestPermission(
|
|
69
|
+
kind: PermissionKind,
|
|
70
|
+
options?: PermissionOptions,
|
|
71
|
+
): Promise<PermissionStatus>;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* System Settings › Privacy & Security › `pane`, or the Privacy pane with
|
|
75
|
+
* none. Through the bridge where there is one, by `open` on any Mac
|
|
76
|
+
* otherwise. Resolves to whether anything opened — `false` off macOS.
|
|
77
|
+
*/
|
|
78
|
+
export declare function openPrivacySettings(
|
|
79
|
+
pane?: PrivacyPane | null,
|
|
80
|
+
options?: Pick<PermissionOptions, 'app'>,
|
|
81
|
+
): Promise<boolean>;
|
|
82
|
+
|
|
83
|
+
export interface Permission {
|
|
84
|
+
/** `'unknown'` until read; re-read after each `request()`. */
|
|
85
|
+
status: PermissionStatus;
|
|
86
|
+
/** Whether this backend has an authorization API at all. */
|
|
87
|
+
available: boolean;
|
|
88
|
+
/** Ask, and update `status`. A second call while one is in flight
|
|
89
|
+
* returns the same promise. */
|
|
90
|
+
request(): Promise<PermissionStatus>;
|
|
91
|
+
/** Re-read the status on your own cue. */
|
|
92
|
+
refresh(): Promise<PermissionStatus>;
|
|
93
|
+
openSettings(): Promise<boolean>;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** A permission for a component: the status as render state. */
|
|
97
|
+
export declare function usePermission(
|
|
98
|
+
kind: PermissionKind,
|
|
99
|
+
options?: Pick<PermissionOptions, 'target'>,
|
|
100
|
+
): Permission;
|
package/src/types/style.d.ts
CHANGED
|
@@ -310,6 +310,16 @@ export interface StyleProperties extends LayoutStyle, PaintStyle, TextStyle {
|
|
|
310
310
|
* a 16px control can have a 24px target without the layout moving.
|
|
311
311
|
*/
|
|
312
312
|
hitSlop?: HitSlop;
|
|
313
|
+
/**
|
|
314
|
+
* Declares this node a container for the `'@container …'` blocks below it
|
|
315
|
+
* — CSS's `container-type` and `container-name` in one property. `true`
|
|
316
|
+
* answers the unnamed queries; a name answers those and the ones that say
|
|
317
|
+
* it, so `'@container sidebar width >= 400'` reaches past any nearer
|
|
318
|
+
* container to the one called `sidebar`. `false` takes back a declaration
|
|
319
|
+
* from earlier in a style array. Changes nothing about this node itself.
|
|
320
|
+
* See docs/styling.md#container-queries.
|
|
321
|
+
*/
|
|
322
|
+
container?: boolean | string;
|
|
313
323
|
}
|
|
314
324
|
|
|
315
325
|
/**
|
|
@@ -361,6 +371,21 @@ export type Animation = { [K in keyof StyleProperties]?: AnimationSpec };
|
|
|
361
371
|
*/
|
|
362
372
|
export type SizeQuery = `@${'width' | 'height'} ${string}`;
|
|
363
373
|
|
|
374
|
+
/**
|
|
375
|
+
* A container query — `'@container width >= 400'`, or
|
|
376
|
+
* `'@container sidebar width >= 400'` naming the container: what a style
|
|
377
|
+
* can ask about the box it is inside rather than the window it is in. The
|
|
378
|
+
* container is the nearest ancestor whose style declares `container` (for
|
|
379
|
+
* the named form, the nearest carrying that name). Like a size query it may
|
|
380
|
+
* set layout properties; unlike one it is answered *after* the layout pass,
|
|
381
|
+
* since a container's size is what the pass produces.
|
|
382
|
+
*/
|
|
383
|
+
export type ContainerQuery = `@container ${string}`;
|
|
384
|
+
|
|
385
|
+
/** A capability query — `'@supports transparency'`: what a style can ask
|
|
386
|
+
* about the server. */
|
|
387
|
+
export type SupportsQuery = `@supports ${string}`;
|
|
388
|
+
|
|
364
389
|
/** The named blocks a style may carry, beside its own properties. */
|
|
365
390
|
export interface StyleBlocks {
|
|
366
391
|
transition?: Transition;
|
|
@@ -401,10 +426,13 @@ export interface StyleBlocks {
|
|
|
401
426
|
|
|
402
427
|
/**
|
|
403
428
|
* A style: the properties themselves, the state blocks, and any number of
|
|
404
|
-
*
|
|
429
|
+
* query blocks keyed `'@width >= 600'`, `'@container width >= 400'` or
|
|
430
|
+
* `'@supports transparency'`.
|
|
405
431
|
*/
|
|
406
432
|
export type Style = StyleProperties &
|
|
407
|
-
StyleBlocks & {
|
|
433
|
+
StyleBlocks & {
|
|
434
|
+
[K in SizeQuery | ContainerQuery | SupportsQuery]?: StyleProperties;
|
|
435
|
+
};
|
|
408
436
|
|
|
409
437
|
/**
|
|
410
438
|
* What a `style` prop accepts: an object, or a nested array of them with
|
package/src/types/system.d.ts
CHANGED
|
@@ -234,9 +234,11 @@ export interface DesktopSettings {
|
|
|
234
234
|
readonly doubleClickDistance: number;
|
|
235
235
|
/** How far a press moves before it is a drag rather than a click. */
|
|
236
236
|
readonly dragThreshold: number;
|
|
237
|
-
/** `'xsettings'
|
|
238
|
-
* the
|
|
239
|
-
|
|
237
|
+
/** `'xsettings'`; `'macos'` on the Cocoa backend, where only `animations`
|
|
238
|
+
* comes from the system (reduce motion) and the rest are the defaults; or
|
|
239
|
+
* null where no settings daemon answered and these are the renderer's own
|
|
240
|
+
* defaults. */
|
|
241
|
+
readonly source: 'xsettings' | 'macos' | 'test' | null;
|
|
240
242
|
}
|
|
241
243
|
|
|
242
244
|
/**
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The system tray: `useTray()`. See docs/desktop.md "The tray".
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { MenuItem } from './components.js';
|
|
6
|
+
|
|
7
|
+
export interface TrayClickEvent {
|
|
8
|
+
button: 'left' | 'right' | 'middle';
|
|
9
|
+
/** The item's screen rect, global top-left coordinates in points — the
|
|
10
|
+
* anchor for a popup of your own. */
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
width: number;
|
|
14
|
+
height: number;
|
|
15
|
+
clickCount: number;
|
|
16
|
+
shift: boolean;
|
|
17
|
+
control: boolean;
|
|
18
|
+
option: boolean;
|
|
19
|
+
command: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface TrayOptions {
|
|
23
|
+
/** An SF Symbol name (`'bell.badge'`), or the bytes of a PNG. Drawn as a
|
|
24
|
+
* template image so it follows the bar's light and dark. */
|
|
25
|
+
icon?: string | Uint8Array | null;
|
|
26
|
+
/** Text beside the icon, or alone. */
|
|
27
|
+
title?: string | null;
|
|
28
|
+
tooltip?: string | null;
|
|
29
|
+
/** The menu a click opens — `MenuBar`'s item vocabulary. Without one,
|
|
30
|
+
* clicks reach `onClick`. */
|
|
31
|
+
menu?: MenuItem[] | null;
|
|
32
|
+
onClick?: (event: TrayClickEvent) => void;
|
|
33
|
+
visible?: boolean;
|
|
34
|
+
/** `false` keeps a PNG's own colours instead of drawing it as a template. */
|
|
35
|
+
template?: boolean;
|
|
36
|
+
/** `'variable'` (default) | `'square'` | a width in points. */
|
|
37
|
+
length?: 'variable' | 'square' | number;
|
|
38
|
+
/** The image's size in points, `[width, height]`. */
|
|
39
|
+
iconSize?: [number, number];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface TrayState {
|
|
43
|
+
/** Whether this backend has a tray at all — false on X11 today (#353). */
|
|
44
|
+
available: boolean;
|
|
45
|
+
/** Reserved. */
|
|
46
|
+
rect: null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* An icon in the system tray while this component is mounted; every field
|
|
51
|
+
* follows its value, and the item is removed on unmount. `null` means no
|
|
52
|
+
* item. Inert off the cocoa backend, with `available: false`.
|
|
53
|
+
*/
|
|
54
|
+
export declare function useTray(options: TrayOptions | null): TrayState;
|
package/src/windowid.js
CHANGED
|
@@ -39,6 +39,29 @@ export function windowIdOf(target) {
|
|
|
39
39
|
return null;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* The window **object** behind anything `windowIdOf` accepts — ntk's on X11,
|
|
44
|
+
* the cocoa backend's `CocoaWindow` — or `null`. The same walk, one step
|
|
45
|
+
* short of the id: a `<window>` ref holds the object itself, a `<window>`
|
|
46
|
+
* node has it as `window`, a drawn node reaches it through its `root`. A raw
|
|
47
|
+
* XID resolves to nothing, because the number alone does not say which
|
|
48
|
+
* connection issued it.
|
|
49
|
+
*
|
|
50
|
+
* Not public. The file dialog reaches the app a window belongs to through
|
|
51
|
+
* it, which is how a call names the backend whose native panel it wants
|
|
52
|
+
* without ever naming a backend.
|
|
53
|
+
*/
|
|
54
|
+
export function windowOf(target) {
|
|
55
|
+
if (target == null || typeof target === 'number') return null;
|
|
56
|
+
if (typeof target === 'object' && 'current' in target && !target.isWindow) {
|
|
57
|
+
return windowOf(target.current);
|
|
58
|
+
}
|
|
59
|
+
if (typeof target.window?.id === 'number') return target.window;
|
|
60
|
+
if (typeof target.root?.window?.id === 'number') return target.root.window;
|
|
61
|
+
if (typeof target.id === 'number') return target;
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
42
65
|
/**
|
|
43
66
|
* `windowIdOf` bound to a ref: returns a **getter**, stable across renders,
|
|
44
67
|
* the same shape `useAnchor` has. It is a getter rather than the id itself
|