@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.
Files changed (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1095 -2
  3. package/dist/actions/actionCalls.d.ts +50 -0
  4. package/dist/actions/actionRegistry.d.ts +78 -0
  5. package/dist/components/Adaptive.d.ts +116 -0
  6. package/dist/components/AdaptiveAction.d.ts +4 -0
  7. package/dist/components/AdaptiveProvider.d.ts +38 -0
  8. package/dist/components/AdaptiveRegion.d.ts +60 -0
  9. package/dist/components/ClicklessUiErrorBoundary.d.ts +24 -0
  10. package/dist/components/OriginalToolbar.d.ts +21 -0
  11. package/dist/components/PromptBar.d.ts +21 -0
  12. package/dist/components/PromptPanel.d.ts +103 -0
  13. package/dist/components/WorkingDots.d.ts +4 -0
  14. package/dist/components/focusAfterPromptAction.d.ts +15 -0
  15. package/dist/components/hostColorScheme.d.ts +35 -0
  16. package/dist/components/promptPanelStyles.d.ts +14 -0
  17. package/dist/core/applyOperations.d.ts +21 -0
  18. package/dist/core/colorContrast.d.ts +22 -0
  19. package/dist/core/defaultLayout.d.ts +12 -0
  20. package/dist/core/index.d.ts +8 -0
  21. package/dist/core/ownProperties.d.ts +11 -0
  22. package/dist/core/propValues.d.ts +8 -0
  23. package/dist/core/reconcileLayout.d.ts +59 -0
  24. package/dist/core/schemas.gen.d.ts +427 -0
  25. package/dist/core/validateActionCalls.d.ts +28 -0
  26. package/dist/core/validateManifest.d.ts +11 -0
  27. package/dist/core/validateOperations.d.ts +15 -0
  28. package/dist/engine/engineClient.d.ts +231 -0
  29. package/dist/engine/engineErrorMessages.d.ts +13 -0
  30. package/dist/engine/engineResponses.d.ts +201 -0
  31. package/dist/engine/plainReplies.d.ts +2 -0
  32. package/dist/hooks/useActionRunHistory.d.ts +12 -0
  33. package/dist/hooks/useAdaptiveAction.d.ts +11 -0
  34. package/dist/hooks/useAdaptiveRegion.d.ts +34 -0
  35. package/dist/hooks/useChangeHistory.d.ts +32 -0
  36. package/dist/hooks/useDictation.d.ts +50 -0
  37. package/dist/hooks/useEngineReachable.d.ts +5 -0
  38. package/dist/hooks/usePromptBar.d.ts +163 -0
  39. package/dist/hooks/useRegionGroup.d.ts +15 -0
  40. package/dist/index.d.ts +21 -0
  41. package/dist/index.js +6600 -0
  42. package/dist/presets/mergePresets.d.ts +20 -0
  43. package/dist/presets/propPresets.d.ts +305 -0
  44. package/dist/region/changedComponentIds.d.ts +13 -0
  45. package/dist/region/firstPaintOrder.d.ts +19 -0
  46. package/dist/region/previewRequests.d.ts +21 -0
  47. package/dist/region/regionContext.d.ts +96 -0
  48. package/dist/region/regionGroup.d.ts +189 -0
  49. package/dist/region/regionSnapshot.d.ts +52 -0
  50. package/dist/region/regionStore.d.ts +361 -0
  51. package/dist/region/responsiveColumns.d.ts +35 -0
  52. package/dist/region/retrier.d.ts +22 -0
  53. package/dist/region/savedLayoutParsing.d.ts +7 -0
  54. package/dist/region/settleIntoSavedLayout.d.ts +14 -0
  55. package/dist/region/textDirection.d.ts +12 -0
  56. package/dist/region/unsavedChangeSaver.d.ts +45 -0
  57. package/dist/region/unsavedChanges.d.ts +78 -0
  58. package/dist/region/userFacingTitle.d.ts +7 -0
  59. package/package.json +59 -3
@@ -0,0 +1,20 @@
1
+ import type { Capabilities, LayoutItem } from "../core/index.js";
2
+ import type { PropPreset } from "./propPresets.js";
3
+ type OwnDeclaration = {
4
+ description: string | undefined;
5
+ capabilities: Partial<Omit<Capabilities, "props">> | undefined;
6
+ defaults: Partial<Pick<LayoutItem, "w" | "h" | "hidden">>;
7
+ };
8
+ type Declaration = {
9
+ description: string | undefined;
10
+ capabilities: Partial<Capabilities> | undefined;
11
+ defaults: Partial<Pick<LayoutItem, "w" | "h" | "hidden" | "props">>;
12
+ };
13
+ /**
14
+ * A component's declaration with its presets folded in: their props make up
15
+ * `capabilities.props`, their starting values `defaults.props`, and their
16
+ * sentences follow `description` in order. A prop declared by two presets is
17
+ * refused, since its two meanings would contradict.
18
+ */
19
+ export declare function mergePresets(componentId: string, declaration: OwnDeclaration, presets: readonly PropPreset[]): Declaration;
20
+ export {};
@@ -0,0 +1,305 @@
1
+ import type { CSSProperties } from "react";
2
+ import { type PropCapabilities, type PropValue } from "../core/index.js";
3
+ /**
4
+ * A setting users may change, or a few that belong together, with its values
5
+ * and the sentence that tells the model what it means. Pass it in `<Adaptive presets>`:
6
+ * its props and starting values become part of the component's declaration, and
7
+ * its sentence follows `description`, which is where the model learns what each
8
+ * prop means.
9
+ */
10
+ export interface PropPreset<Reading = unknown> {
11
+ /** Which preset this is, such as "stripes". */
12
+ readonly preset: string;
13
+ readonly capabilities: Readonly<Record<string, PropCapabilities>>;
14
+ readonly defaults: Readonly<Record<string, PropValue>>;
15
+ /** One or two sentences naming each of its props, added to the component's description. */
16
+ readonly description: string;
17
+ /**
18
+ * The preset's current value, from the props a render-function child receives.
19
+ * A missing or unexpected value reads as the preset's default.
20
+ */
21
+ read(adaptiveProps: Readonly<Record<string, PropValue>>): Reading;
22
+ }
23
+ /**
24
+ * A custom setting: one whose values the application gives, such as a choice of
25
+ * the application's own views. Its prop takes the name it is given in
26
+ * `<Adaptive presets>`, so `{ order: propPresets.choice(...) }` declares a prop
27
+ * called `order`.
28
+ */
29
+ export interface CustomPreset<Reading = unknown> {
30
+ /** Which preset this is, such as "choice". */
31
+ readonly preset: string;
32
+ /** The preset with its prop given this name. */
33
+ named(propName: string): PropPreset<Reading>;
34
+ }
35
+ /** The presets of one component, each under a name of the integrator's choosing. */
36
+ export type PresetSet = Readonly<Record<string, PropPreset | CustomPreset>>;
37
+ /** The current value of each preset in a set, under the same name. */
38
+ export type PresetValues<Presets extends PresetSet> = {
39
+ [PresetName in keyof Presets]: Presets[PresetName] extends PropPreset<infer Reading> ? Reading : Presets[PresetName] extends CustomPreset<infer Reading> ? Reading : never;
40
+ };
41
+ /** Each preset of a set as a `PropPreset`, a custom one taking its key as its prop's name. */
42
+ export declare function presetsByName(presets: PresetSet): Record<string, PropPreset>;
43
+ /**
44
+ * A chosen colour and the text colour to draw on it: black or white, whichever
45
+ * reads better on that colour.
46
+ */
47
+ export type ColourReading = {
48
+ colour: string;
49
+ /** Black or white, whichever is readable on `colour`. */
50
+ textColour: string;
51
+ };
52
+ /** The options `accent`, `colour` and `stripes` share on what is drawn on the colour and behind it. */
53
+ type ReadabilityOptions = {
54
+ /**
55
+ * Text is drawn on the colour in its reading's `textColour`, as on a button
56
+ * or a selected entry. The planner is then told, and its reply says when a
57
+ * chosen colour turns that text from white to black or back.
58
+ */
59
+ textOn?: boolean;
60
+ /**
61
+ * The colour behind it, written as #rrggbb, such as the page's `#ffffff`. The
62
+ * planner's reply then says when a chosen colour would be hard to see on it:
63
+ * under 3:1 for a colour with no text on it, such as a link or a line, and
64
+ * all but the same as what is behind it, such as white on white, with `textOn`.
65
+ */
66
+ against?: string;
67
+ };
68
+ type Density = "comfortable" | "compact";
69
+ /** `density`: how much room each row or entry takes. Reads as "comfortable" or "compact". */
70
+ declare function density({ initial }?: {
71
+ initial?: Density;
72
+ }): PropPreset<Density>;
73
+ /**
74
+ * `stripes`: colouring every other row. Reads as the stripe colour and the text
75
+ * colour readable on it, or null when off.
76
+ *
77
+ * With `palette`, users choose among the named colours given, such as
78
+ * `{ grey: "#f3f2ee", red: "#b91c1c" }`. Without it, they may choose any colour,
79
+ * held in a second prop, `stripeColour`.
80
+ */
81
+ declare function stripes(options?: ({
82
+ initial?: "off" | "on";
83
+ colour?: string;
84
+ suggested?: readonly string[];
85
+ } & ReadabilityOptions) | {
86
+ palette: Readonly<Record<string, string>>;
87
+ initial?: string;
88
+ }): PropPreset<ColourReading | null>;
89
+ /**
90
+ * `background` and `textColour`. Reads as both colours, with `textColour` turned
91
+ * black or white where the chosen one would be hard to read on the background,
92
+ * as the description promises the model; `chosenTextColour` is the user's choice as is.
93
+ */
94
+ declare function colours({ background, textColour, suggested, }?: {
95
+ background?: string;
96
+ textColour?: string;
97
+ suggested?: readonly string[];
98
+ }): PropPreset<{
99
+ background: string;
100
+ textColour: string;
101
+ chosenTextColour: string;
102
+ /** Both colours as a style, ready to spread onto the component's outer element. */
103
+ style: CSSProperties;
104
+ }>;
105
+ /** `textSize`: the size of the text in pixels, a whole number from `min` to `max`. */
106
+ declare function textSize({ initial, min, max, }?: {
107
+ initial?: number;
108
+ min?: number;
109
+ max?: number;
110
+ }): PropPreset<number>;
111
+ /**
112
+ * Showing or hiding one part of the component, such as
113
+ * `{ trend: propPresets.toggle({ shows: "the line comparing it with last month" }) }`.
114
+ * The prop takes its name from the key and holds "on" or "off"; it reads as true while shown.
115
+ */
116
+ declare function toggle({ shows, initial }: {
117
+ shows: string;
118
+ initial?: boolean;
119
+ }): CustomPreset<boolean>;
120
+ /**
121
+ * One of a list of the application's own values, such as the view of a calendar:
122
+ * `{ view: propPresets.choice({ values: ["day", "week", "month"], initial: "week", means: "how much of the calendar shows at once" }) }`.
123
+ * `means` says what the prop is, in plain words, for the model: "view is …".
124
+ */
125
+ declare function choice<const Value extends string>({ values, initial, means, }: {
126
+ values: readonly Value[];
127
+ initial: NoInfer<Value>;
128
+ means: string;
129
+ }): CustomPreset<Value>;
130
+ /**
131
+ * A number from `min` to `max`, whole unless `whole` is false, such as the corner
132
+ * radius of a button. `means` says what it is, with its unit: "the corner radius in pixels".
133
+ */
134
+ declare function number({ min, max, initial, whole, means, }: {
135
+ min: number;
136
+ max: number;
137
+ initial: number;
138
+ whole?: boolean;
139
+ means: string;
140
+ }): CustomPreset<number>;
141
+ /**
142
+ * Any colour, such as the colour of a chart's bars. `means` says what it colours:
143
+ * "the colour of the bars". `suggested` lists colours to prefer, such as the brand's.
144
+ * Reads as the colour and the text colour readable on it; give `textOn` where
145
+ * text is drawn on it in that text colour, and `against` for the colour behind it.
146
+ */
147
+ declare function colour({ initial, suggested, means, ...readabilityOptions }: {
148
+ initial: string;
149
+ suggested?: readonly string[];
150
+ means: string;
151
+ } & ReadabilityOptions): CustomPreset<ColourReading>;
152
+ /**
153
+ * Which of the application's own entries show, and in what order, such as the
154
+ * columns of a table. `means` says what the list holds: "the columns that show,
155
+ * left to right". All of `values` show to begin with unless `initial` is given;
156
+ * `min` is the fewest the list may hold, and `required` lists entries it must
157
+ * always hold, such as the tab of the page that is open. They can still be moved.
158
+ */
159
+ declare function visibleList<const Value extends string>({ values, initial, min, required, means, }: {
160
+ values: readonly Value[];
161
+ initial?: readonly NoInfer<Value>[];
162
+ min?: number;
163
+ required?: readonly NoInfer<Value>[];
164
+ means: string;
165
+ }): CustomPreset<Value[]>;
166
+ /**
167
+ * `count`: how many entries show, such as rows of a table or bars of a chart.
168
+ * `of` names the entries, in the plural, where the component's title does not
169
+ * make them plain: "months" on a chart titled "Revenue".
170
+ */
171
+ declare function count({ of, min, max, initial, }: {
172
+ of?: string;
173
+ min?: number;
174
+ max: number;
175
+ initial: number;
176
+ }): PropPreset<number>;
177
+ type HighlightReading = {
178
+ /** The highlight colour. */
179
+ colour: string;
180
+ /** Black or white, whichever is readable on the highlight colour. */
181
+ textColour: string;
182
+ /**
183
+ * Whether an entry is highlighted. `position` counts from 0 at the top. `entry`
184
+ * is the entry's value of the measure given to `above` or `below`, or, where
185
+ * `kinds` is given too, `{ measure, kind }`, with `kind` the entry's value of it.
186
+ */
187
+ isHighlighted(position: number, entry?: HighlightedEntry): boolean;
188
+ /**
189
+ * The style for an entry: the highlight colour and readable text where it is
190
+ * highlighted, and nothing where it is not. Pass it to the entry's own `style`,
191
+ * such as `<tr style={highlight.styleFor(rowIndex, row.amount)}>` or
192
+ * `<tr style={highlight.styleFor(rowIndex, { kind: row.status })}>`.
193
+ */
194
+ styleFor(position: number, entry?: HighlightedEntry): CSSProperties | undefined;
195
+ };
196
+ /** An entry's value of the measure, or that and its kind. */
197
+ type HighlightedEntry = number | {
198
+ measure?: number;
199
+ kind?: string;
200
+ };
201
+ /**
202
+ * Colouring the entries that stand out in a list or table: the top few, such as
203
+ * the top 3 (`top`), those whose value of a measure is more than an amount
204
+ * (`above`) or less than one (`below`), or any of these. `entries` names them, in
205
+ * the plural, where the component's title does not make them plain. `measure`
206
+ * says what is compared, with its unit and without "the": "amount invoiced in
207
+ * pounds", or "start time in hours from midnight, such as 13.5 for 1:30 pm".
208
+ * `above` and `below` compare the same value, so given together they name the
209
+ * same measure.
210
+ * `kinds` colours the entries of chosen kinds, from a fixed set the application
211
+ * names in `values`, such as `{ of: "statuses", values: ["booked", "arrived",
212
+ * "cancelled"] }`. The values are kinds an entry falls into, never the entries
213
+ * themselves, so a person's or customer's name is never one.
214
+ * Adds `highlightTop`, `highlightAbove`, `highlightBelow`, `highlightKinds`
215
+ * (whichever are given) and `highlightColour`. 0, or no kinds, turns any of them
216
+ * off, and all start off.
217
+ *
218
+ * None has a largest value unless you give `max`: the amount is compared
219
+ * with the entries shown at the time, so it suits a list whose contents change.
220
+ */
221
+ declare function highlight({ entries, top, above, below, kinds, colour, suggested, }: {
222
+ entries?: string;
223
+ top?: true | {
224
+ max: number;
225
+ };
226
+ above?: {
227
+ measure: string;
228
+ max?: number;
229
+ };
230
+ below?: {
231
+ measure: string;
232
+ max?: number;
233
+ };
234
+ kinds?: {
235
+ of: string;
236
+ values: readonly string[];
237
+ };
238
+ colour?: string;
239
+ suggested?: readonly string[];
240
+ }): PropPreset<HighlightReading>;
241
+ type TextStyle = "regular" | "italic" | "bold" | "bold italic";
242
+ /**
243
+ * `textStyle`: whether the text is bold, italic, both or neither. It leaves
244
+ * letter case alone, so a prop of your own for capitals combines with it.
245
+ * Reads as `{ bold, italic }`; what bold looks like is up to you.
246
+ */
247
+ declare function textStyle({ initial }?: {
248
+ initial?: TextStyle;
249
+ }): PropPreset<{
250
+ bold: boolean;
251
+ italic: boolean;
252
+ }>;
253
+ /**
254
+ * `accent`: the one colour that marks what stands out, such as the selected
255
+ * entry of a menu or today in a calendar. Name what it marks in `marks`.
256
+ * Reads as the colour and the text colour readable on it; give `textOn` where
257
+ * text is drawn on it in that text colour, such as a button's label, and
258
+ * `against` for the colour behind it.
259
+ */
260
+ declare function accent({ marks, colour, suggested, ...readabilityOptions }: {
261
+ marks: string;
262
+ colour?: string;
263
+ suggested?: readonly string[];
264
+ } & ReadabilityOptions): PropPreset<ColourReading>;
265
+ /**
266
+ * The settings users may change, for `<Adaptive presets>`, each under a name of
267
+ * your choosing. Built-in settings (`count`, `highlight`, `density`, `stripes`,
268
+ * `colours`, `textSize`, `textStyle`, `accent`) come with their names, values and
269
+ * wording, shared across applications; use one when it fits. Custom settings
270
+ * (`toggle`, `choice`, `number`, `colour`, `visibleList`) take the application's
271
+ * own values and a few words saying what they mean, and their prop takes the name
272
+ * it is given.
273
+ *
274
+ * @example
275
+ * <Adaptive id="invoices" kind="table" title="Invoices" defaults={{ w: 12, h: 5 }}
276
+ * presets={{
277
+ * columns: propPresets.visibleList({ values: COLUMN_IDS, min: 1, means: "the columns that show, left to right" }),
278
+ * stripes: propPresets.stripes({ suggested: BRAND_COLOURS }),
279
+ * rows: propPresets.density(),
280
+ * }}>
281
+ * {(props, adaptiveControls, presetValues) => (
282
+ * <InvoiceTable
283
+ * columns={presetValues.columns}
284
+ * stripeColour={presetValues.stripes}
285
+ * compact={presetValues.rows === "compact"}
286
+ * />
287
+ * )}
288
+ * </Adaptive>
289
+ */
290
+ export declare const propPresets: {
291
+ count: typeof count;
292
+ highlight: typeof highlight;
293
+ density: typeof density;
294
+ stripes: typeof stripes;
295
+ colours: typeof colours;
296
+ textSize: typeof textSize;
297
+ textStyle: typeof textStyle;
298
+ accent: typeof accent;
299
+ toggle: typeof toggle;
300
+ choice: typeof choice;
301
+ number: typeof number;
302
+ colour: typeof colour;
303
+ visibleList: typeof visibleList;
304
+ };
305
+ export {};
@@ -0,0 +1,13 @@
1
+ import type { Layout } from "../core/index.js";
2
+ /**
3
+ * Components whose own settings differ, plus the smallest set that had to move
4
+ * to turn one order into the other. Components that merely shifted because
5
+ * something else moved past them are left out.
6
+ */
7
+ export declare function findChangedComponentIds(previousLayout: Layout, nextLayout: Layout): ReadonlySet<string>;
8
+ /**
9
+ * The entries of `nextOrder` that are new, or had to move to turn
10
+ * `previousOrder` into it. Entries that merely shifted because something else
11
+ * moved past them are left out.
12
+ */
13
+ export declare function entriesOutOfOrder(previousOrder: readonly string[], nextOrder: readonly string[]): Set<string>;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Where each item is drawn before the region has mounted: on the server and
3
+ * on the first paint. There is no manifest yet, only the saved layout and the
4
+ * items as they render, one after another in the order they are written.
5
+ *
6
+ * A saved item keeps its saved place. One added since the layout was saved
7
+ * goes straight after the item written before it, or first if it is written
8
+ * first, which is where reconciling puts it once the region mounts.
9
+ *
10
+ * "Written before" is taken to be "rendered before". That holds unless part
11
+ * of the region is inside a Suspense boundary that is still waiting while the
12
+ * server sends the rest: items after it then render first, and an added item
13
+ * may be drawn out of place until the region mounts.
14
+ */
15
+ export declare class FirstPaintOrder {
16
+ private placedItems;
17
+ /** `savedIndex` is the item's position in the saved order, or -1 if it is not in it. */
18
+ placeItem(itemId: string, savedIndex: number): number;
19
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * A request whose answer is part of the preview on the screen. A follow-up
3
+ * typed during a preview adds its change to the preview, so one preview can
4
+ * hold several, and is kept or discarded as one change.
5
+ */
6
+ export interface PreviewRequest {
7
+ prompt: string;
8
+ /** What the planner answered: what this request changed from the screen it was typed on. */
9
+ message: string;
10
+ viaVoice: boolean;
11
+ }
12
+ /**
13
+ * How the change the requests made together is told, as it is saved or
14
+ * reported: their prompts one to a line, and their answers one after another.
15
+ * The oldest requests are left out where all of them would be too long to store.
16
+ */
17
+ export declare function describePreviewRequests(previewRequests: readonly PreviewRequest[]): {
18
+ prompt: string;
19
+ message: string;
20
+ viaVoice: boolean;
21
+ };
@@ -0,0 +1,96 @@
1
+ import { useLayoutEffect } from "react";
2
+ import type { Layout } from "../core/index.js";
3
+ import { ActionRegistry } from "../actions/actionRegistry.js";
4
+ import { EngineClient, type EngineOptions } from "../engine/engineClient.js";
5
+ import type { FirstPaintOrder } from "./firstPaintOrder.js";
6
+ import { RegionGroup } from "./regionGroup.js";
7
+ import { RegionStore } from "./regionStore.js";
8
+ export declare class RegionStoreRegistry {
9
+ private storesByRegionId;
10
+ private groupsByRegionIds;
11
+ /** Null when the provider was given no engine. */
12
+ readonly engine: EngineClient | null;
13
+ /** The actions offered on the page right now. */
14
+ readonly actions: ActionRegistry;
15
+ private dictationOffered;
16
+ private promptDrafts;
17
+ private draftListeners;
18
+ constructor(engineOptions: EngineOptions | undefined, userId?: string);
19
+ /**
20
+ * Whether the engine can turn speech into text. Asked once for all the
21
+ * regions on a page. A failed request is not remembered, so it is asked again.
22
+ */
23
+ isDictationOffered(): Promise<boolean>;
24
+ /**
25
+ * The prompt typed for a set of regions and not sent yet, so it is still
26
+ * there when the user comes back to them, as on returning to a page.
27
+ */
28
+ draftFor: (regionIdsKey: string) => string;
29
+ keepDraft: (regionIdsKey: string, draftText: string) => void;
30
+ /** Two bars for the same regions show the same draft, so each hears when it changes. */
31
+ subscribeToDrafts: (draftListener: () => void) => (() => void);
32
+ private latestChangeSequence;
33
+ /** Numbers the changes made in any of these regions, so the newest among several can be told. */
34
+ private nextChangeSequence;
35
+ /**
36
+ * Where the latest action run falls among the changes, in the same
37
+ * numbering, or 0 when none has run since the page was loaded.
38
+ */
39
+ private actionRunSequence;
40
+ private actionRunListeners;
41
+ latestActionRunSequence: () => number;
42
+ /** Notes that an action has just run, after every change made so far. */
43
+ noteActionRun: () => void;
44
+ subscribeToActionRuns: (actionRunListener: () => void) => (() => void);
45
+ /**
46
+ * Stops every store trying the engine again in the background, to save
47
+ * changes or read saved layouts, for when the provider unmounts.
48
+ */
49
+ dispose: () => void;
50
+ /** Lets the stores try the engine again in the background, as when React mounts the provider once more. */
51
+ resume: () => void;
52
+ storeFor(regionId: string): RegionStore;
53
+ /** The regions one prompt bar speaks for. The same ids in the same order give the same group. */
54
+ groupFor(regionIds: readonly string[]): RegionGroup;
55
+ }
56
+ export declare const RegionStoreRegistryContext: import("react").Context<RegionStoreRegistry | null>;
57
+ /**
58
+ * The id an item's element carries in the page, so the region can name its
59
+ * items to assistive technology in the order they are shown. `regionTag` is
60
+ * the region's own `useId`, which keeps the id from matching one the host
61
+ * application uses, or one in another region. Ids in a list of references are
62
+ * separated by spaces, so anything but letters, digits and `-` is written as
63
+ * its character code between two `_`.
64
+ */
65
+ export declare function itemElementId(regionTag: string, itemId: string): string;
66
+ export interface RegionContextValue {
67
+ /** Unique to this region on the page, and the same on the server and in the browser. */
68
+ regionTag: string;
69
+ regionStore: RegionStore;
70
+ /** False when the region draws nothing of its own and the page's containers place its items. */
71
+ regionDrawsGrid: boolean;
72
+ /** The columns the layout is kept in. */
73
+ layoutColumns: number;
74
+ /** The columns drawn on this screen, which may be fewer. */
75
+ drawnColumns: number;
76
+ /** Each item's span on this screen when it has fewer columns than the layout, else null. */
77
+ drawnSpans: ReadonlyMap<string, number> | null;
78
+ /** Lets items render the saved layout on the server and on first paint. */
79
+ initialLayout: Layout | undefined;
80
+ /** The order the saved layout gives every component it knows, on screen or off. */
81
+ initialOrder: readonly string[];
82
+ firstPaintOrder: FirstPaintOrder;
83
+ }
84
+ export declare const RegionContext: import("react").Context<RegionContextValue | null>;
85
+ export declare function useRegionStore(regionId: string): RegionStore;
86
+ /** For ClickLess's own prompt UI, which has nothing to show without the provider. */
87
+ export declare function useRegionStoreRegistry(): RegionStoreRegistry;
88
+ /**
89
+ * For what wraps or runs in the application's own components. Outside a
90
+ * provider, as in the application's tests or stories, each caller gets a
91
+ * registry of its own with no engine: a region shows its defaults and keeps
92
+ * changes in memory, `useAdaptiveRegion` reads the region it sits in (or an
93
+ * empty one of its own outside any region), and an action is offered to no one.
94
+ */
95
+ export declare function useRegionStoreRegistryOrStandIn(): RegionStoreRegistry;
96
+ export declare const useIsomorphicLayoutEffect: typeof useLayoutEffect;
@@ -0,0 +1,189 @@
1
+ import type { Action, ActionCall } from "../core/index.js";
2
+ import { type ConversationTurn, type EngineClient } from "../engine/engineClient.js";
3
+ import type { HistoryPage } from "../engine/engineResponses.js";
4
+ import type { RegionSnapshot } from "./regionSnapshot.js";
5
+ import { type PlannedPreviewOutcome, type RegionStore, type UndoResult } from "./regionStore.js";
6
+ /** What a prompt bar shows of the regions it speaks for. */
7
+ export interface RegionGroupSnapshot {
8
+ /**
9
+ * Each region, in the order they were named. One that is not on the screen
10
+ * has a null manifest, and takes no part in anything until it is.
11
+ */
12
+ regions: readonly {
13
+ regionId: string;
14
+ snapshot: RegionSnapshot;
15
+ }[];
16
+ /** True while a proposed change is on the screen, waiting to be kept or discarded. */
17
+ previewing: boolean;
18
+ canUndo: boolean;
19
+ /**
20
+ * The order of the newest change on the screen an undo would take back,
21
+ * among the changes and action runs since the page was loaded, or 0 when it
22
+ * was made before then. See `RegionStoreRegistry.latestActionRunSequence`.
23
+ */
24
+ newestChangeSequence: number;
25
+ /** True while the regions show how they first looked, in place of their layouts. */
26
+ showingOriginal: boolean;
27
+ /** True when any region on the screen differs from how it first looked. */
28
+ differsFromOriginal: boolean;
29
+ /** True while any region's saved layout is being fetched. */
30
+ loading: boolean;
31
+ /** True when any region's saved layout could not be fetched. */
32
+ loadFailed: boolean;
33
+ /**
34
+ * Which point in the history the screen is at, in the same numbering as
35
+ * `HistoryEntry.revision`: for one region, that region's revision; for
36
+ * several, the latest change's own number (its `changeId`), which the
37
+ * engine counts across regions.
38
+ */
39
+ revision: number;
40
+ hasHistory: boolean;
41
+ /** True while any region shows a change of the application's own that is not saved yet. */
42
+ hasUnsavedChanges: boolean;
43
+ }
44
+ /** What a prompt is planned with besides the regions: what the screen can do, and what was said before. */
45
+ export interface PlanContext {
46
+ actions: readonly Action[];
47
+ conversation: readonly ConversationTurn[];
48
+ /** Files the user attached: their names and types only. */
49
+ attachedFiles: readonly {
50
+ name: string;
51
+ type: string;
52
+ }[];
53
+ /** What a missed request is recorded under when no region is on the screen. */
54
+ screenId: string;
55
+ }
56
+ /** What a prompt bar's request came to: the answer for the user, the actions to run, and what became of the preview. */
57
+ export interface PlannedRequest {
58
+ message: string;
59
+ actionCalls: ActionCall[];
60
+ previewOutcome: PlannedPreviewOutcome;
61
+ }
62
+ /**
63
+ * The regions one prompt bar speaks for, such as a page and the sidebar beside
64
+ * it. A prompt is planned for all of them in one request, and what it changes
65
+ * is previewed, kept, discarded and undone in all of them together, while each
66
+ * region's layout is still stored on its own.
67
+ *
68
+ * A group of one is that region and nothing more: everything is passed
69
+ * straight to its store.
70
+ */
71
+ export declare class RegionGroup {
72
+ private readonly regionStores;
73
+ private readonly engine;
74
+ private readonly singleRegionStore;
75
+ private pendingPreview;
76
+ /** The last preview saved, so an answer planned from it is shown on the layouts it became. */
77
+ private lastSavedPreview;
78
+ private commitInProgress;
79
+ private snapshotListeners;
80
+ private stopListeningToStores;
81
+ private cachedSnapshot;
82
+ private cachedSnapshotInputs;
83
+ private serverSnapshot;
84
+ constructor(regionStores: readonly RegionStore[], engine: EngineClient | null);
85
+ subscribe: (snapshotListener: () => void) => (() => void);
86
+ /**
87
+ * Stops listening to the regions once nothing listens here. While a preview
88
+ * waits it goes on listening, though the prompt bar may be gone, as one in a
89
+ * closed sheet is: if a region then drops its part, as on leaving the page,
90
+ * the preview is still reported as abandoned.
91
+ */
92
+ private stopListeningIfUnwatched;
93
+ getSnapshot: () => RegionGroupSnapshot;
94
+ getServerSnapshot: () => RegionGroupSnapshot;
95
+ /**
96
+ * Asks the engine to turn a request into operations and previews them, in
97
+ * every region they are for. As for one region, a request made while a
98
+ * preview is showing is planned from it, region by region, and its answer
99
+ * is added to it; one made with none showing replaces any that appears
100
+ * meanwhile, as if discarded.
101
+ */
102
+ planFromPrompt: (prompt: string, viaVoice?: boolean, planContext?: PlanContext) => Promise<PlannedRequest>;
103
+ /** Previews the operations, in every region they are for, or none of them if any no longer fits. */
104
+ private showNewPreview;
105
+ /**
106
+ * Adds a follow-up's operations to the preview it was planned from: each
107
+ * region's after its part of the preview, in a region the preview had not
108
+ * changed as its first part. Nothing changes if any region no longer fits.
109
+ * A follow-up that takes the whole preview back leaves nothing to keep, so
110
+ * the preview counts as discarded.
111
+ */
112
+ private addToPreview;
113
+ /**
114
+ * Sends a plan request made from `preview`. When the engine says the preview
115
+ * no longer applies to the saved layouts it was made on, it can never be
116
+ * saved, so it is taken off, as one that left the screen.
117
+ */
118
+ private answeringForPreview;
119
+ /**
120
+ * Saves the preview: every region's part, or none. Resolves to null when
121
+ * there is no preview. One that no longer fits is taken off the screen.
122
+ */
123
+ commitPreview: () => Promise<{
124
+ applied: boolean;
125
+ } | null>;
126
+ /** Takes the preview off the screen, in every region, without saving it. */
127
+ cancelPreview: () => void;
128
+ /** `cancelPreview`, for when the user chose not to keep it. The engine is told, once. */
129
+ discardPreview: () => void;
130
+ /**
131
+ * `cancelPreview`, for when the preview leaves the screen before the user
132
+ * chose, because a region it changed dropped its part. The engine is told, once.
133
+ */
134
+ private abandonPreview;
135
+ /** Record-keeping only: the user is never made to wait on it or told it failed. One being saved is not reported. */
136
+ private reportPreviewNotKept;
137
+ /**
138
+ * Takes back the latest change among the regions on the screen, in each of
139
+ * them it reached, on the screen or not: a prompt that changed two is undone
140
+ * in both. The result says when part of it stays in place elsewhere.
141
+ */
142
+ undoLastChange: () => Promise<UndoResult>;
143
+ /**
144
+ * Shows every region as it first looked, before any change, without saving
145
+ * anything, or goes back to their layouts. A preview, or any change, ends it.
146
+ */
147
+ showOriginal: (shown: boolean) => void;
148
+ /**
149
+ * Returns the screen to how it was after the given saved change; 0 is as it
150
+ * was before any. Resolves to the number of the latest saved change afterwards.
151
+ */
152
+ restoreRevision: (revision: number) => Promise<number>;
153
+ /** Saved changes, newest first. For several regions each entry is one change, whichever regions it reached. */
154
+ readHistory: (options: {
155
+ limit: number;
156
+ before?: number;
157
+ promptedOnly?: boolean;
158
+ }) => Promise<HistoryPage>;
159
+ private savePreview;
160
+ /**
161
+ * Shows what the engine answered, in each of `regionStores` whose layout it
162
+ * changed, with the operations that changed it. Every other region, one off
163
+ * the screen as well, gives way to it, unless it is an undo, which is no new
164
+ * change. A preview no longer describes the screen.
165
+ */
166
+ private acceptAnswer;
167
+ /** `regionStores` and every other region of the group holding changes not saved yet, which go first. */
168
+ private withUnsavedChanges;
169
+ /**
170
+ * When the engine says a region changed elsewhere, nothing was saved in any
171
+ * of them. The ones it names are fetched again before failing, which takes
172
+ * the preview off the screen.
173
+ */
174
+ private reloadingOnConflict;
175
+ /**
176
+ * Waits its turn in every one of the regions, so a change to several does
177
+ * not cross one made to any of them alone. Turns are always taken in the
178
+ * same order, so two groups that share regions cannot wait on each other.
179
+ * `writeChange` is given the change's `sequence`, taken once the first turn has
180
+ * begun: a change made in any of the regions while it waits for the others
181
+ * is newer than it.
182
+ */
183
+ private oneWriteAtATime;
184
+ private storesOnScreen;
185
+ private onStoreChange;
186
+ private isStillShowing;
187
+ private notifyListeners;
188
+ private computeSnapshot;
189
+ }