@clickless/react 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +1095 -2
- package/dist/actions/actionCalls.d.ts +50 -0
- package/dist/actions/actionRegistry.d.ts +78 -0
- package/dist/components/Adaptive.d.ts +116 -0
- package/dist/components/AdaptiveAction.d.ts +4 -0
- package/dist/components/AdaptiveProvider.d.ts +38 -0
- package/dist/components/AdaptiveRegion.d.ts +60 -0
- package/dist/components/ClicklessUiErrorBoundary.d.ts +24 -0
- package/dist/components/OriginalToolbar.d.ts +21 -0
- package/dist/components/PromptBar.d.ts +21 -0
- package/dist/components/PromptPanel.d.ts +103 -0
- package/dist/components/WorkingDots.d.ts +4 -0
- package/dist/components/focusAfterPromptAction.d.ts +15 -0
- package/dist/components/hostColorScheme.d.ts +35 -0
- package/dist/components/promptPanelStyles.d.ts +14 -0
- package/dist/core/applyOperations.d.ts +21 -0
- package/dist/core/colorContrast.d.ts +22 -0
- package/dist/core/defaultLayout.d.ts +12 -0
- package/dist/core/index.d.ts +8 -0
- package/dist/core/ownProperties.d.ts +11 -0
- package/dist/core/propValues.d.ts +8 -0
- package/dist/core/reconcileLayout.d.ts +59 -0
- package/dist/core/schemas.gen.d.ts +427 -0
- package/dist/core/validateActionCalls.d.ts +28 -0
- package/dist/core/validateManifest.d.ts +11 -0
- package/dist/core/validateOperations.d.ts +15 -0
- package/dist/engine/engineClient.d.ts +231 -0
- package/dist/engine/engineErrorMessages.d.ts +13 -0
- package/dist/engine/engineResponses.d.ts +201 -0
- package/dist/engine/plainReplies.d.ts +2 -0
- package/dist/hooks/useActionRunHistory.d.ts +12 -0
- package/dist/hooks/useAdaptiveAction.d.ts +11 -0
- package/dist/hooks/useAdaptiveRegion.d.ts +34 -0
- package/dist/hooks/useChangeHistory.d.ts +32 -0
- package/dist/hooks/useDictation.d.ts +50 -0
- package/dist/hooks/useEngineReachable.d.ts +5 -0
- package/dist/hooks/usePromptBar.d.ts +163 -0
- package/dist/hooks/useRegionGroup.d.ts +15 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +6600 -0
- package/dist/presets/mergePresets.d.ts +20 -0
- package/dist/presets/propPresets.d.ts +305 -0
- package/dist/region/changedComponentIds.d.ts +13 -0
- package/dist/region/firstPaintOrder.d.ts +19 -0
- package/dist/region/previewRequests.d.ts +21 -0
- package/dist/region/regionContext.d.ts +96 -0
- package/dist/region/regionGroup.d.ts +189 -0
- package/dist/region/regionSnapshot.d.ts +52 -0
- package/dist/region/regionStore.d.ts +361 -0
- package/dist/region/responsiveColumns.d.ts +35 -0
- package/dist/region/retrier.d.ts +22 -0
- package/dist/region/savedLayoutParsing.d.ts +7 -0
- package/dist/region/settleIntoSavedLayout.d.ts +14 -0
- package/dist/region/textDirection.d.ts +12 -0
- package/dist/region/unsavedChangeSaver.d.ts +45 -0
- package/dist/region/unsavedChanges.d.ts +78 -0
- package/dist/region/userFacingTitle.d.ts +7 -0
- package/package.json +59 -3
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Layout, LayoutChange, Manifest } from "../core/index.js";
|
|
2
|
+
export interface RegionSnapshot {
|
|
3
|
+
/** Built from the mounted `Adaptive` components. Null until the region has mounted. */
|
|
4
|
+
manifest: Manifest | null;
|
|
5
|
+
/**
|
|
6
|
+
* The committed layout. `order` and `items` hold the components on screen;
|
|
7
|
+
* `offScreen` holds what is kept for the ones that are not.
|
|
8
|
+
*/
|
|
9
|
+
layout: Layout | null;
|
|
10
|
+
/** A proposed layout awaiting `commitPreview`, `discardPreview` or `cancelPreview`. */
|
|
11
|
+
preview: Layout | null;
|
|
12
|
+
/**
|
|
13
|
+
* How the region first looked, before any change, while it is shown in place
|
|
14
|
+
* of the layout. Null otherwise, and always while there is a preview.
|
|
15
|
+
*/
|
|
16
|
+
original: Layout | null;
|
|
17
|
+
/** True when what is on the screen differs from how it first looked. */
|
|
18
|
+
differsFromOriginal: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Ids of the components the preview, or the original while it is shown,
|
|
21
|
+
* draws differently from the layout. Empty when neither is showing.
|
|
22
|
+
*/
|
|
23
|
+
changedComponentIds: ReadonlySet<string>;
|
|
24
|
+
/**
|
|
25
|
+
* How the saved layout had to change to fit the components now on screen:
|
|
26
|
+
* components new in this version, settings the manifest no longer allows,
|
|
27
|
+
* and what was dropped for good (components past the limit kept off screen,
|
|
28
|
+
* or entries with nothing saved). Empty when it fits. Components that are
|
|
29
|
+
* only off screen for now, such as another tab's, are not changes.
|
|
30
|
+
*/
|
|
31
|
+
savedLayoutAdjustments: readonly LayoutChange[];
|
|
32
|
+
/** True while the saved layout is being fetched from the engine. */
|
|
33
|
+
loading: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* True when the saved layout could not be fetched, so the screen may not
|
|
36
|
+
* show it. It is fetched again on its own, a few seconds later and then less
|
|
37
|
+
* often, and at once when the engine answers again after being out of
|
|
38
|
+
* reach; false once it has been.
|
|
39
|
+
*/
|
|
40
|
+
loadFailed: boolean;
|
|
41
|
+
canUndo: boolean;
|
|
42
|
+
/** Number of the latest saved change. 0 when there is none, or no engine. */
|
|
43
|
+
revision: number;
|
|
44
|
+
/** True when changes are stored by the engine, so there is a history to read. */
|
|
45
|
+
hasHistory: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* True while a change made with the application's own controls is shown but
|
|
48
|
+
* not saved yet, as when the engine cannot be reached. It is saved when the
|
|
49
|
+
* engine is back.
|
|
50
|
+
*/
|
|
51
|
+
hasUnsavedChanges: boolean;
|
|
52
|
+
}
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import { type Layout, type ApplyOperationsOutcome, type Component, type Manifest, type Operation } from "../core/index.js";
|
|
2
|
+
import { type EngineClient, type PreviewToPlanFrom } from "../engine/engineClient.js";
|
|
3
|
+
import type { HistoryPage, LayoutResponse, PlanResponse, UndoneChange } from "../engine/engineResponses.js";
|
|
4
|
+
import type { RegionSnapshot } from "./regionSnapshot.js";
|
|
5
|
+
import { type PreviewRequest } from "./previewRequests.js";
|
|
6
|
+
import { textDirectionToPlanWith } from "./textDirection.js";
|
|
7
|
+
/** How an undo went. */
|
|
8
|
+
export interface UndoResult {
|
|
9
|
+
/**
|
|
10
|
+
* True when part of the undone change stays in place in a region this undo
|
|
11
|
+
* was not asked about, such as one on another page, because that region
|
|
12
|
+
* changed again since.
|
|
13
|
+
*/
|
|
14
|
+
keptElsewhere: boolean;
|
|
15
|
+
/** The change taken back, or null when that is not known, as from an engine that does not say. */
|
|
16
|
+
undoneChange: UndoneChange | null;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* What became of the preview when a planner's answer came: a new one shows,
|
|
20
|
+
* holding that answer only; the answer was added to the one showing; nothing
|
|
21
|
+
* is shown for it, as for a question or a preview taken back whole; or it no
|
|
22
|
+
* longer fits the screen, and any preview showing is left as it was.
|
|
23
|
+
*/
|
|
24
|
+
export type PlannedPreviewOutcome = "new" | "addedTo" | "none" | "doesNotFit";
|
|
25
|
+
/** A preview a prompt is planned from, taken as planning starts. */
|
|
26
|
+
export interface PreviewToBuildOn {
|
|
27
|
+
/** Handed back to `showPlannedPreview`, so the answer is added to this preview and no other. */
|
|
28
|
+
readonly handle: PendingPreview;
|
|
29
|
+
/** What the plan request carries of it. */
|
|
30
|
+
readonly planWith: PreviewToPlanFrom;
|
|
31
|
+
}
|
|
32
|
+
/** A change shown and not saved yet. Only the region's own store reads inside it. */
|
|
33
|
+
export interface PendingPreview {
|
|
34
|
+
layout: Layout;
|
|
35
|
+
operations: readonly Operation[];
|
|
36
|
+
/** The requests whose answers make it up, oldest first; none for one that did not come from a prompt. */
|
|
37
|
+
requests: readonly PreviewRequest[];
|
|
38
|
+
}
|
|
39
|
+
/** What an engine's answer to an undo says about how it went. */
|
|
40
|
+
export declare const undoResultOf: (undoAnswer: {
|
|
41
|
+
notUndoneIn?: string[];
|
|
42
|
+
undone?: unknown;
|
|
43
|
+
}) => UndoResult;
|
|
44
|
+
export interface RegionConfig {
|
|
45
|
+
regionId: string;
|
|
46
|
+
version: string;
|
|
47
|
+
columns: number;
|
|
48
|
+
title?: string;
|
|
49
|
+
/** Present, as false, only for a region that draws no grid of its own. */
|
|
50
|
+
grid?: false;
|
|
51
|
+
}
|
|
52
|
+
export type LayoutChangeHandler = (layout: Layout, operations: readonly Operation[]) => void;
|
|
53
|
+
/**
|
|
54
|
+
* What a turn to write does first with the changes not saved yet: send them,
|
|
55
|
+
* send them and refuse to go on if any could not be saved, or leave them.
|
|
56
|
+
*/
|
|
57
|
+
export type UnsavedChangesFirst = "save" | "saveOrRefuse" | "leave";
|
|
58
|
+
/**
|
|
59
|
+
* Where a layout the engine gave came from: a fresh read, the saving of a
|
|
60
|
+
* change not saved yet, an undo, or a change saved by prompt or restore, with
|
|
61
|
+
* the `sequence` it took when it began.
|
|
62
|
+
*/
|
|
63
|
+
export type SavedLayoutSource = "read" | "savedUnsavedChange" | "undo" | {
|
|
64
|
+
laterChangeSequence: number;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Holds one region's state. With an engine, every committed change is sent to
|
|
68
|
+
* it and its answer is the truth; without one, changes live in memory only.
|
|
69
|
+
*
|
|
70
|
+
* A change made with the application's own controls (one without a prompt)
|
|
71
|
+
* never waits on the engine: it is shown at once and saved behind the scenes.
|
|
72
|
+
* While the engine cannot be reached it is kept for the visit and saved when
|
|
73
|
+
* the engine is back, unless what it changed reads differently in the saved
|
|
74
|
+
* layout by then (see `carryOverUnsavedChanges`). Changes reach the engine in
|
|
75
|
+
* the order they were made: a prompt's change or a restore waits for the
|
|
76
|
+
* older ones to be saved, and is refused if they cannot be. An undo leaves
|
|
77
|
+
* them, since it takes the newest back itself when that is one of them.
|
|
78
|
+
*/
|
|
79
|
+
export declare class RegionStore {
|
|
80
|
+
readonly regionId: string;
|
|
81
|
+
private readonly engine;
|
|
82
|
+
private readonly nextChangeSequence;
|
|
83
|
+
onLayoutChange: LayoutChangeHandler | undefined;
|
|
84
|
+
/**
|
|
85
|
+
* The columns this screen draws the layout in, set by the region as the
|
|
86
|
+
* screen's width changes. The planner is told when they are fewer than the
|
|
87
|
+
* layout's, so its replies describe what the user sees.
|
|
88
|
+
*/
|
|
89
|
+
drawnColumns: number | null;
|
|
90
|
+
private regionConfig;
|
|
91
|
+
private registeredComponents;
|
|
92
|
+
private savedLayout;
|
|
93
|
+
private pendingPreview;
|
|
94
|
+
/** The last preview saved, so an answer planned from it is shown on the layout it became. */
|
|
95
|
+
private lastSavedPreview;
|
|
96
|
+
/** True while the region shows how it first looked in place of the layout. */
|
|
97
|
+
private originalShown;
|
|
98
|
+
private snapshotListeners;
|
|
99
|
+
private savedLayoutListeners;
|
|
100
|
+
private cachedSnapshot;
|
|
101
|
+
private latestSavedRevision;
|
|
102
|
+
private latestSavedChangeId;
|
|
103
|
+
private savedLayoutLoading;
|
|
104
|
+
private loadFailed;
|
|
105
|
+
private loadStarted;
|
|
106
|
+
private engineAnswered;
|
|
107
|
+
private commitInProgress;
|
|
108
|
+
private engineCanUndo;
|
|
109
|
+
/** Without an engine: the layout before each change, and the change, oldest first. */
|
|
110
|
+
private undoStack;
|
|
111
|
+
private writeQueue;
|
|
112
|
+
/** Shown on top of `savedLayout`. Only ever holds anything with an engine. */
|
|
113
|
+
private readonly unsavedChanges;
|
|
114
|
+
/** The `sequence` of each saved change an undo here could take back, oldest first. */
|
|
115
|
+
private savedChangeSequences;
|
|
116
|
+
private stopListeningToReachability;
|
|
117
|
+
private readonly loadRetrier;
|
|
118
|
+
private readonly unsavedChangeSaver;
|
|
119
|
+
/**
|
|
120
|
+
* `nextChangeSequence` numbers changes across the regions of one provider, so the
|
|
121
|
+
* newest among several regions can be told.
|
|
122
|
+
*/
|
|
123
|
+
constructor(regionId: string, engine: EngineClient | null, nextChangeSequence: () => number);
|
|
124
|
+
/** Anything else getting an answer is a sign the engine is back: what waits to be tried again is tried now. */
|
|
125
|
+
private listenToReachability;
|
|
126
|
+
/** The `sequence` of the newest change not saved yet, or 0 when there is none. */
|
|
127
|
+
get newestUnsavedChangeSequence(): number;
|
|
128
|
+
/** True while a change not saved yet may still be saved, whether or not the region is on the screen. */
|
|
129
|
+
get hasSaveableUnsavedChanges(): boolean;
|
|
130
|
+
/**
|
|
131
|
+
* The `sequence` of the newest change here an undo could take back, saved or
|
|
132
|
+
* not, or 0 when there is none from this visit.
|
|
133
|
+
*/
|
|
134
|
+
get newestChangeSequence(): number;
|
|
135
|
+
/** The highest `sequence` among the saved changes here that an undo could still take back, or 0. */
|
|
136
|
+
get newestSavedChangeSequence(): number;
|
|
137
|
+
/** Kept in the order the engine took them, so an undo takes the last off as the engine does. */
|
|
138
|
+
private recordSavedChange;
|
|
139
|
+
/** A `sequence` for a change saved by prompt or restore, taken when it begins. */
|
|
140
|
+
takeChangeSequence: () => number;
|
|
141
|
+
/** True when the newest change here is one not saved yet, which only this screen can take back. */
|
|
142
|
+
private newestChangeIsUnsaved;
|
|
143
|
+
/** True when the saved layout of a region on the screen could not be read, and no read is under way. */
|
|
144
|
+
private get needsLoadRetry();
|
|
145
|
+
/** The number of the latest saved change, as the engine last gave it. */
|
|
146
|
+
get savedRevision(): number;
|
|
147
|
+
/** The number, counted across all the user's regions, of the change that made the latest revision. */
|
|
148
|
+
get latestChangeId(): number;
|
|
149
|
+
subscribe: (snapshotListener: () => void) => (() => void);
|
|
150
|
+
getSnapshot: () => RegionSnapshot;
|
|
151
|
+
getServerSnapshot: () => RegionSnapshot;
|
|
152
|
+
/** A layout set earlier in the session wins over `initialLayout`, so it survives a remount. */
|
|
153
|
+
mountRegion: (mountedRegionConfig: RegionConfig, initialLayout: Layout | undefined) => (() => void);
|
|
154
|
+
/** Reads the saved layout before the region mounts, unless it has been read or is being read. */
|
|
155
|
+
preloadSavedLayout: () => void;
|
|
156
|
+
private startLoading;
|
|
157
|
+
/** Reads the engine's copy again. If that fails, the region keeps the layout it has. */
|
|
158
|
+
private refreshSavedLayout;
|
|
159
|
+
/** The element an item is drawn in, or null if it is not mounted. */
|
|
160
|
+
elementOf: (componentId: string) => Element | null;
|
|
161
|
+
/** Which way the page reads where this region is drawn, as a plan request carries it. */
|
|
162
|
+
textDirectionToPlanWith: () => ReturnType<typeof textDirectionToPlanWith>;
|
|
163
|
+
/** What the planner is told about the screen besides the manifest: only what differs from a wide one. */
|
|
164
|
+
drawnColumnsToPlanWith: () => {
|
|
165
|
+
drawnColumns?: number;
|
|
166
|
+
};
|
|
167
|
+
registerComponent: (component: Component, element: Element | null) => (() => void);
|
|
168
|
+
/**
|
|
169
|
+
* Validates the operations and commits them if all are valid.
|
|
170
|
+
*
|
|
171
|
+
* A change from a prompt is shown once the engine has saved it, and rejects
|
|
172
|
+
* with an `EngineError` if the engine cannot be reached or the layout changed
|
|
173
|
+
* elsewhere. A change without a prompt, as from the application's own
|
|
174
|
+
* controls, is shown and resolves at once, and is saved behind the scenes:
|
|
175
|
+
* later, if the engine cannot be reached.
|
|
176
|
+
*/
|
|
177
|
+
applyOperations: (operations: readonly Operation[], prompt?: string, message?: string, viaVoice?: boolean) => Promise<ApplyOperationsOutcome>;
|
|
178
|
+
/**
|
|
179
|
+
* `applyOperations` for a change that is shown before the engine has it.
|
|
180
|
+
* Async so that a fault, such as a region that is not mounted, rejects as it
|
|
181
|
+
* does for every other change.
|
|
182
|
+
*/
|
|
183
|
+
private applyAtOnce;
|
|
184
|
+
/**
|
|
185
|
+
* Sends the changes not saved yet to the engine, oldest first. Run at the
|
|
186
|
+
* start of each turn to write but an undo's (see `oneWriteAtATime`), so they
|
|
187
|
+
* reach the engine before anything made after them. Never rejects: what
|
|
188
|
+
* could not be saved is tried again later.
|
|
189
|
+
*/
|
|
190
|
+
private saveUnsavedChanges;
|
|
191
|
+
/**
|
|
192
|
+
* Drops the changes kept for this visit only that are older than a change
|
|
193
|
+
* saved by prompt or restore in another region of the same prompt box,
|
|
194
|
+
* which did not reach this one. They would otherwise be undone before it.
|
|
195
|
+
*/
|
|
196
|
+
giveWayToLaterChange: (laterChangeSequence: number) => void;
|
|
197
|
+
/**
|
|
198
|
+
* Stops trying the engine again in the background, to save changes or to
|
|
199
|
+
* read the saved layout, for when the provider holding this store has gone.
|
|
200
|
+
*/
|
|
201
|
+
dispose: () => void;
|
|
202
|
+
/** Takes up what `dispose` stopped, as when React mounts the provider once more. */
|
|
203
|
+
resume: () => void;
|
|
204
|
+
/** A turn to write with nothing of its own to write: it saves what is not saved yet, in turn. */
|
|
205
|
+
private queueSavingUnsavedChanges;
|
|
206
|
+
/** Shows the result of the operations without committing it. */
|
|
207
|
+
previewOperations: (operations: readonly Operation[], prompt?: string, message?: string, viaVoice?: boolean) => ApplyOperationsOutcome;
|
|
208
|
+
private showPreview;
|
|
209
|
+
/**
|
|
210
|
+
* Saves the preview. Resolves to null when there is none. A preview that
|
|
211
|
+
* turns out not to be valid is taken off the screen, since it can never be saved.
|
|
212
|
+
*/
|
|
213
|
+
commitPreview: () => Promise<ApplyOperationsOutcome | null>;
|
|
214
|
+
/**
|
|
215
|
+
* Shows the region as it first looked, before any change, without saving
|
|
216
|
+
* anything, or goes back to its layout. A preview, or any change to the
|
|
217
|
+
* layout, ends it.
|
|
218
|
+
*/
|
|
219
|
+
showOriginal: (shown: boolean) => void;
|
|
220
|
+
/** Takes the preview off the screen without saving it. */
|
|
221
|
+
cancelPreview: () => void;
|
|
222
|
+
/**
|
|
223
|
+
* `cancelPreview`, for when the user themselves chose not to keep it. The
|
|
224
|
+
* engine is told, so the application's team can see where a prompt's result
|
|
225
|
+
* was not what its user meant. A preview that did not come from a prompt has
|
|
226
|
+
* nothing to say about that and is only cancelled, as is one that is already
|
|
227
|
+
* being saved.
|
|
228
|
+
*/
|
|
229
|
+
discardPreview: () => void;
|
|
230
|
+
/**
|
|
231
|
+
* Tells the engine the preview from a prompt was not kept. One that is being
|
|
232
|
+
* saved is not reported. Record-keeping only: the user is never made to wait
|
|
233
|
+
* on it or told it failed.
|
|
234
|
+
*/
|
|
235
|
+
private reportPreviewNotKept;
|
|
236
|
+
/**
|
|
237
|
+
* Returns to the layout before the last committed change. A change not saved
|
|
238
|
+
* yet is taken back at once, on this screen alone, as the engine never had it.
|
|
239
|
+
*/
|
|
240
|
+
undoLastChange: () => Promise<UndoResult>;
|
|
241
|
+
/**
|
|
242
|
+
* Takes back the newest change, if it is one not saved yet and not on its
|
|
243
|
+
* way to the engine. Returns it, or null when there was none to take back.
|
|
244
|
+
*/
|
|
245
|
+
private takeBackUnsavedChange;
|
|
246
|
+
/**
|
|
247
|
+
* Puts a committed change on the screen: any preview goes, and the host is
|
|
248
|
+
* told. Returns the layout shown, or null when the region is not mounted.
|
|
249
|
+
*/
|
|
250
|
+
private showChange;
|
|
251
|
+
/**
|
|
252
|
+
* Returns the screen to how it was after the given saved change; 0 is the
|
|
253
|
+
* original layout. Later changes stay in the history. Resolves to the number
|
|
254
|
+
* of the saved change the restore itself made.
|
|
255
|
+
*/
|
|
256
|
+
restoreRevision: (revision: number) => Promise<number>;
|
|
257
|
+
/**
|
|
258
|
+
* Saved changes, newest first, `limit` at a time. Pass `before` to read older
|
|
259
|
+
* ones, and `promptedOnly` to leave out changes that were not made by prompt.
|
|
260
|
+
*/
|
|
261
|
+
readHistory: (options: {
|
|
262
|
+
limit: number;
|
|
263
|
+
before?: number;
|
|
264
|
+
promptedOnly?: boolean;
|
|
265
|
+
}) => Promise<HistoryPage>;
|
|
266
|
+
/**
|
|
267
|
+
* Asks the engine to turn a request into operations and previews them.
|
|
268
|
+
* The returned message is written for the user.
|
|
269
|
+
*
|
|
270
|
+
* A request made while a preview is showing is planned from that preview,
|
|
271
|
+
* so a follow-up such as "bigger again" builds on what the user is looking
|
|
272
|
+
* at: the operations answered are what it changes from there, and are added
|
|
273
|
+
* to the preview, which is then kept or discarded as one change. An answer
|
|
274
|
+
* with nothing to change, such as a question, leaves the preview as it is.
|
|
275
|
+
* If the saved layout changed elsewhere since the preview was made, it is
|
|
276
|
+
* fetched again, which takes the preview off, and this rejects with an
|
|
277
|
+
* `EngineError` whose code is "conflict". If no answer comes, the preview
|
|
278
|
+
* stays, and can still be kept.
|
|
279
|
+
*/
|
|
280
|
+
planFromPrompt: (prompt: string, viaVoice?: boolean) => Promise<PlanResponse>;
|
|
281
|
+
/** `planFromPrompt`, saying what became of the preview. */
|
|
282
|
+
planAndShowPreview: (prompt: string, viaVoice?: boolean) => Promise<{
|
|
283
|
+
planResponse: PlanResponse;
|
|
284
|
+
previewOutcome: PlannedPreviewOutcome;
|
|
285
|
+
}>;
|
|
286
|
+
/**
|
|
287
|
+
* The preview a prompt typed now is planned from, or null when there is
|
|
288
|
+
* none. One being saved is not built on: it is about to be the saved layout.
|
|
289
|
+
*/
|
|
290
|
+
previewToBuildOn: () => PreviewToBuildOn | null;
|
|
291
|
+
/**
|
|
292
|
+
* Sends a plan request made with `previewToBuildOn`. When the engine says the
|
|
293
|
+
* preview no longer applies to the saved layout it was made on, the preview
|
|
294
|
+
* can never be saved, so it is taken off, as one that left the screen.
|
|
295
|
+
*/
|
|
296
|
+
answeringForPreview: <T>(previewToBuildOn: PreviewToBuildOn | null, sendRequest: () => Promise<T>) => Promise<T>;
|
|
297
|
+
/**
|
|
298
|
+
* Shows what the planner proposed for a prompt. Planned from the preview in
|
|
299
|
+
* `previewBuiltOn`, it is added to that preview while it still shows; one
|
|
300
|
+
* that takes the whole preview back leaves nothing to keep, so the preview
|
|
301
|
+
* counts as discarded. Planned from the saved layout, it replaces any
|
|
302
|
+
* preview that was showing, which counts as discarded.
|
|
303
|
+
*/
|
|
304
|
+
showPlannedPreview: (operations: readonly Operation[], previewRequest: PreviewRequest, previewBuiltOn: PreviewToBuildOn | null) => PlannedPreviewOutcome;
|
|
305
|
+
/**
|
|
306
|
+
* Shows a layout the engine stored for this region in a change it made to
|
|
307
|
+
* several at once, as `applyOperations` does for a change to this one.
|
|
308
|
+
*/
|
|
309
|
+
acceptSavedLayout: (layoutResponse: LayoutResponse, operations: readonly Operation[], layoutSource: Exclude<SavedLayoutSource, "read" | "savedUnsavedChange">) => void;
|
|
310
|
+
/**
|
|
311
|
+
* Runs one saved change at a time. Each is checked against, and sent with the
|
|
312
|
+
* number of, the change before it, so two made in quick succession do not
|
|
313
|
+
* both claim to follow the same one. Without an engine nothing waits.
|
|
314
|
+
* `unsavedChangesFirst` says what happens first to the changes not saved yet: an
|
|
315
|
+
* undo leaves them, since it takes the newest back itself; a prompt's change
|
|
316
|
+
* or a restore is refused when they cannot be saved, so it never reaches the
|
|
317
|
+
* engine ahead of an older one.
|
|
318
|
+
*/
|
|
319
|
+
oneWriteAtATime: <T>(writeChange: () => Promise<T>, unsavedChangesFirst?: UnsavedChangesFirst) => Promise<T>;
|
|
320
|
+
/** Throws why the changes not saved yet could not be saved, if any still wait. */
|
|
321
|
+
private refuseWhileUnsaved;
|
|
322
|
+
/** When the engine says the layout changed elsewhere, fetches it before failing. */
|
|
323
|
+
private reloadingOnConflict;
|
|
324
|
+
/**
|
|
325
|
+
* Fetches the engine's copy of the layout, which replaces the one shown and
|
|
326
|
+
* takes any preview off: on every mount, and after the engine said this
|
|
327
|
+
* region changed elsewhere.
|
|
328
|
+
*/
|
|
329
|
+
loadSavedLayout: () => Promise<void>;
|
|
330
|
+
/**
|
|
331
|
+
* Calls `savedLayoutListener` when the engine has answered for the saved layout, just
|
|
332
|
+
* before the screen is told, while it still shows what it showed before.
|
|
333
|
+
*/
|
|
334
|
+
beforeSavedLayoutIsShown: (savedLayoutListener: () => void) => (() => void);
|
|
335
|
+
/**
|
|
336
|
+
* Takes the engine's copy as the saved layout. Changes not saved yet stay on
|
|
337
|
+
* top of it. After a fresh read or an undo, those that cannot be carried
|
|
338
|
+
* over to it are still shown for the rest of the visit, so nothing changes
|
|
339
|
+
* under the user, but are never saved. A change saved by prompt or restore
|
|
340
|
+
* stands over the older ones: those kept for the visit only, and those that
|
|
341
|
+
* cannot be carried over to it, go.
|
|
342
|
+
*/
|
|
343
|
+
private acceptEngineLayout;
|
|
344
|
+
/** Tells the host. A fault in its handler is reported, and does not stop the SDK keeping its own state right. */
|
|
345
|
+
private reportLayoutChange;
|
|
346
|
+
/**
|
|
347
|
+
* What the operations would do to the saved layout, without doing it.
|
|
348
|
+
* `fallbackManifest` stands in for the manifest when the region is no longer mounted.
|
|
349
|
+
*/
|
|
350
|
+
applyToCurrentLayout: (operations: readonly Operation[], fallbackManifest?: Manifest | null) => {
|
|
351
|
+
manifest: Manifest;
|
|
352
|
+
applyOutcome: ApplyOperationsOutcome;
|
|
353
|
+
};
|
|
354
|
+
/**
|
|
355
|
+
* The screen changed under the preview, as on leaving the page, so it no
|
|
356
|
+
* longer describes it: it is taken off and reported as abandoned.
|
|
357
|
+
*/
|
|
358
|
+
private dropPendingPreview;
|
|
359
|
+
private notifyListeners;
|
|
360
|
+
private computeSnapshot;
|
|
361
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** A region's columns: one number, or the columns to draw from each screen width up, in pixels. */
|
|
2
|
+
export type RegionColumns = number | Readonly<Record<number, number>>;
|
|
3
|
+
/**
|
|
4
|
+
* The columns a region's layout is kept in, and the columns it is drawn in on
|
|
5
|
+
* this screen.
|
|
6
|
+
*
|
|
7
|
+
* With breakpoints, the layout is kept in the widest one's columns whatever the
|
|
8
|
+
* screen, so the planner, the saved layout and every check see one grid, and a
|
|
9
|
+
* change made on a phone does not narrow what the user set for a wide screen.
|
|
10
|
+
* A narrower screen draws the same layout in fewer columns (see `drawnSpans`).
|
|
11
|
+
* The server, and the first paint in the browser, draw the widest.
|
|
12
|
+
*/
|
|
13
|
+
export declare function useResponsiveColumns(columns: RegionColumns): {
|
|
14
|
+
layoutColumns: number;
|
|
15
|
+
drawnColumns: number;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* How many drawn columns an item `w` columns wide in the layout spans, on its
|
|
19
|
+
* own: its share of the width, rounded. Used only before the region has
|
|
20
|
+
* mounted; after that `drawnSpans` places whole rows.
|
|
21
|
+
*/
|
|
22
|
+
export declare function drawnSpan(width: number, layoutColumns: number, drawnColumns: number): number;
|
|
23
|
+
/**
|
|
24
|
+
* How many drawn columns each item spans, worked out a row at a time so the
|
|
25
|
+
* rows stay as they are on a wide screen: an item covering columns `start` to
|
|
26
|
+
* `end` of the wide grid covers the same share of the narrow one, rounded at
|
|
27
|
+
* its edges, so the spans of one row add up to the drawn columns. Items are
|
|
28
|
+
* given in the order they are drawn, with their width and height, and each
|
|
29
|
+
* list is one grid.
|
|
30
|
+
*/
|
|
31
|
+
export declare function drawnSpans(grids: readonly (readonly {
|
|
32
|
+
id: string;
|
|
33
|
+
w: number;
|
|
34
|
+
h: number;
|
|
35
|
+
}[])[], layoutColumns: number, drawnColumns: number): ReadonlyMap<string, number>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tries something again later, less often each time it fails, and at once
|
|
3
|
+
* when the device comes back online. Stopped, as when the provider holding it
|
|
4
|
+
* has gone, it schedules nothing until started again.
|
|
5
|
+
*/
|
|
6
|
+
export declare class Retrier {
|
|
7
|
+
private readonly attemptAgain;
|
|
8
|
+
private retryTimer;
|
|
9
|
+
private nextRetryDelayMs;
|
|
10
|
+
private stopped;
|
|
11
|
+
constructor(attemptAgain: () => void);
|
|
12
|
+
get isWaiting(): boolean;
|
|
13
|
+
/** Tries again later, unless already waiting to or stopped. */
|
|
14
|
+
schedule(): void;
|
|
15
|
+
/** Tries again at once, if it was waiting to. */
|
|
16
|
+
retryNow: () => void;
|
|
17
|
+
/** What it was waiting to try worked, so the next failure waits the shortest time again. */
|
|
18
|
+
succeeded(): void;
|
|
19
|
+
cancel(): void;
|
|
20
|
+
stop(): void;
|
|
21
|
+
start(): void;
|
|
22
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Layout } from "../core/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* The layout if it has the shape of one, else null. A saved layout comes from
|
|
4
|
+
* storage the SDK does not control, and one that is cut short or from another
|
|
5
|
+
* format must fall back to the default instead of breaking the screen.
|
|
6
|
+
*/
|
|
7
|
+
export declare function parseSavedLayout(savedLayout: unknown): Layout | null;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Layout } from "../core/index.js";
|
|
2
|
+
import type { RegionStore } from "./regionStore.js";
|
|
3
|
+
/**
|
|
4
|
+
* While the saved layout is being fetched the region shows what it has, often
|
|
5
|
+
* the default, and nothing waits for the engine. When the saved layout arrives,
|
|
6
|
+
* each item that it puts somewhere else glides there from where it was, and an
|
|
7
|
+
* item that was not drawn fades in, so the change reads as the screen settling
|
|
8
|
+
* rather than jumping. Users who ask for less motion get the change at once.
|
|
9
|
+
*
|
|
10
|
+
* Where items were is read the moment the engine answers, while the screen
|
|
11
|
+
* still shows the old layout, so scrolling or the page's own content moving
|
|
12
|
+
* while the engine was slow makes nothing slide.
|
|
13
|
+
*/
|
|
14
|
+
export declare function useSettleIntoSavedLayout(regionStore: RegionStore, layout: Layout | null): void;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { TextDirection } from "../engine/engineClient.js";
|
|
2
|
+
/**
|
|
3
|
+
* Which way the page reads where `element` is drawn, or at its root without
|
|
4
|
+
* one. Read from the browser, so it holds however the page set it: a `dir`
|
|
5
|
+
* attribute on the element or a parent, or a stylesheet's `direction`. A
|
|
6
|
+
* `lang` attribute alone does not change it.
|
|
7
|
+
*/
|
|
8
|
+
export declare function textDirectionAt(element: Element | null | undefined): TextDirection;
|
|
9
|
+
/** The direction as a plan request carries it: only when the page reads right to left. */
|
|
10
|
+
export declare function textDirectionToPlanWith(element: Element | null | undefined): {
|
|
11
|
+
textDirection?: TextDirection;
|
|
12
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { LayoutResponse } from "../engine/engineResponses.js";
|
|
2
|
+
import type { UnsavedChange } from "./unsavedChanges.js";
|
|
3
|
+
/** What the saver needs from the region whose changes it saves. */
|
|
4
|
+
export interface UnsavedChangeSaverHost {
|
|
5
|
+
/** The oldest change the engine may still take. */
|
|
6
|
+
nextChangeToSave(): UnsavedChange | undefined;
|
|
7
|
+
/** Runs before the first change is sent, so each is sent against the layout the engine has. */
|
|
8
|
+
prepareToSave(): Promise<void>;
|
|
9
|
+
sendChange(change: UnsavedChange): Promise<LayoutResponse>;
|
|
10
|
+
/** Fetches the engine's copy, after it said the layout changed elsewhere. */
|
|
11
|
+
reloadSavedLayout(): Promise<void>;
|
|
12
|
+
changeSaved(change: UnsavedChange, layoutResponse: LayoutResponse): void;
|
|
13
|
+
/** Asks for a turn to write, in which `save` runs. */
|
|
14
|
+
queueSaving(): void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Saves a region's unsaved changes behind the scenes. What the engine could
|
|
18
|
+
* not take is tried again later, sooner if the device comes back online.
|
|
19
|
+
*/
|
|
20
|
+
export declare class UnsavedChangeSaver {
|
|
21
|
+
private readonly host;
|
|
22
|
+
private savingChange;
|
|
23
|
+
private lastSaveFailure;
|
|
24
|
+
private readonly retrier;
|
|
25
|
+
constructor(host: UnsavedChangeSaverHost);
|
|
26
|
+
/** The change on its way to the engine right now, if any. */
|
|
27
|
+
get changeBeingSaved(): UnsavedChange | null;
|
|
28
|
+
get isWaitingToRetry(): boolean;
|
|
29
|
+
/** Why the last attempt to save stopped short, or null when everything it tried was saved. */
|
|
30
|
+
get lastFailure(): unknown;
|
|
31
|
+
/**
|
|
32
|
+
* Sends the changes the engine may still take, oldest first. Never rejects:
|
|
33
|
+
* what could not be saved is tried again later.
|
|
34
|
+
*/
|
|
35
|
+
save(): Promise<void>;
|
|
36
|
+
/** Tries again later, unless already waiting to, stopped, or there is nothing to save. */
|
|
37
|
+
scheduleRetry(): void;
|
|
38
|
+
/** Tries again at once, if it was waiting to. */
|
|
39
|
+
retryNow(): void;
|
|
40
|
+
/** Nothing is left to save, so nothing needs trying again. */
|
|
41
|
+
cancelRetry(): void;
|
|
42
|
+
/** Tries nothing more until `start`, even after a save already under way fails. */
|
|
43
|
+
stop(): void;
|
|
44
|
+
start(): void;
|
|
45
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { type Layout, type Manifest, type Operation } from "../core/index.js";
|
|
2
|
+
/** A change made with the application's own controls that the engine has not saved yet. */
|
|
3
|
+
export interface UnsavedChange {
|
|
4
|
+
operations: readonly Operation[];
|
|
5
|
+
/** The screen it was made on, for saving it after the region has gone. */
|
|
6
|
+
manifest: Manifest;
|
|
7
|
+
/**
|
|
8
|
+
* Counted across the regions of one provider, so the newest change among
|
|
9
|
+
* several can be undone first. Only the order of these numbers means anything.
|
|
10
|
+
*/
|
|
11
|
+
sequence: number;
|
|
12
|
+
/**
|
|
13
|
+
* False once it will never be saved: the engine refused it for good, or it
|
|
14
|
+
* clashes with the saved layout read since it was made. It is then kept for
|
|
15
|
+
* this visit only, and gives way to the next change that is saved.
|
|
16
|
+
*/
|
|
17
|
+
saveable: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A region's changes not saved yet, oldest first, shown on top of its saved
|
|
21
|
+
* layout until the engine has them.
|
|
22
|
+
*/
|
|
23
|
+
export declare class UnsavedChangeList {
|
|
24
|
+
private readonly nextChangeSequence;
|
|
25
|
+
private changes;
|
|
26
|
+
constructor(nextChangeSequence: () => number);
|
|
27
|
+
get isEmpty(): boolean;
|
|
28
|
+
/** True while any of them may still be saved. */
|
|
29
|
+
get hasSaveable(): boolean;
|
|
30
|
+
/** The `sequence` of the newest, or 0 when there is none. */
|
|
31
|
+
get newestSequence(): number;
|
|
32
|
+
/** The screen the newest was made on, for when the region is no longer mounted. */
|
|
33
|
+
get newestManifest(): Manifest | undefined;
|
|
34
|
+
/** The oldest the engine may still take. */
|
|
35
|
+
nextToSave(): UnsavedChange | undefined;
|
|
36
|
+
add(operations: readonly Operation[], manifest: Manifest): void;
|
|
37
|
+
/** Takes back the newest, unless it is `changeBeingSaved`. Returns the one taken back, or null. */
|
|
38
|
+
takeBackNewest(changeBeingSaved: UnsavedChange | null): UnsavedChange | null;
|
|
39
|
+
/**
|
|
40
|
+
* The engine has `change` now. It goes, and so do the changes kept for the
|
|
41
|
+
* visit only that were made before it: changes are saved oldest first, so
|
|
42
|
+
* those are all that come before it, and it is newer than every one of them.
|
|
43
|
+
*/
|
|
44
|
+
dropSavedChange(change: UnsavedChange): void;
|
|
45
|
+
/**
|
|
46
|
+
* Drops the changes kept for the visit only that are older than a change
|
|
47
|
+
* saved by prompt or restore, numbered `laterChangeSequence`, which
|
|
48
|
+
* stands over them. Returns true when there were any.
|
|
49
|
+
*/
|
|
50
|
+
giveWayTo(laterChangeSequence: number): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* After a fresh read of the saved layout, carries the changes from the
|
|
53
|
+
* layout they were made on to it (see `carryOverUnsavedChanges`). Those that
|
|
54
|
+
* cannot be carried are kept for the visit only.
|
|
55
|
+
*/
|
|
56
|
+
carryOverToReadLayout(manifest: Manifest, shownLayout: Layout, savedLayout: Layout): void;
|
|
57
|
+
/**
|
|
58
|
+
* After a change saved by prompt or restore, numbered
|
|
59
|
+
* `laterChangeSequence`: the older changes are carried over to the layout it
|
|
60
|
+
* made where they can be and dropped where they cannot, since it stands over
|
|
61
|
+
* them. Those made while it was on its way are newer, and stay as they are.
|
|
62
|
+
*/
|
|
63
|
+
carryOverToLaterChange(manifest: Manifest, shownLayout: Layout, savedLayout: Layout, laterChangeSequence: number): void;
|
|
64
|
+
/** The layout with every change that fits it laid on top. One that does not waits, unshown, until it does. */
|
|
65
|
+
applyTo(manifest: Manifest, layout: Layout): Layout;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The changes that can be carried from the layout they were made on,
|
|
69
|
+
* `shownLayout`, to the saved layout the engine has now given, `savedLayout`.
|
|
70
|
+
* A change is carried only when what it acts on reads the same in both: a
|
|
71
|
+
* setting the user changed while their saved layout could not be read, or
|
|
72
|
+
* that was changed elsewhere meanwhile, is not overwritten with a value worked
|
|
73
|
+
* out from a screen they were not shown. One whose component is not on the
|
|
74
|
+
* screen now is carried as it is when what it acts on reads the same: it is
|
|
75
|
+
* saved with the screen it was made on. Both layouts must be reconciled
|
|
76
|
+
* against `manifest`.
|
|
77
|
+
*/
|
|
78
|
+
export declare function carryOverUnsavedChanges(manifest: Manifest, shownLayout: Layout, savedLayout: Layout, changes: readonly UnsavedChange[]): UnsavedChange[];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Component } from "../core/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* The component's title, for text the user reads, or null when it has none of
|
|
4
|
+
* its own. A component given no title carries its id as its title, for the
|
|
5
|
+
* planner, and an id such as "txns" means nothing to the user.
|
|
6
|
+
*/
|
|
7
|
+
export declare function userFacingTitleOf(component: Pick<Component, "id" | "title">): string | null;
|