@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,50 @@
|
|
|
1
|
+
import { type Action, type ActionCall } from "../core/index.js";
|
|
2
|
+
import { type ActionArguments, type ActionDefinition, type RegisteredAction } from "./actionRegistry.js";
|
|
3
|
+
/** An action call checked against what the page offers, ready to confirm or run. */
|
|
4
|
+
export interface PreparedActionCall {
|
|
5
|
+
registeredAction: RegisteredAction;
|
|
6
|
+
actionArguments: ActionArguments;
|
|
7
|
+
/** What the user is asked to confirm, or told is happening. */
|
|
8
|
+
summary: string;
|
|
9
|
+
mode: "read" | "write";
|
|
10
|
+
/**
|
|
11
|
+
* The action's `run` as it was when the summary was written. What runs is
|
|
12
|
+
* what the user was shown, even if the component offering it has since
|
|
13
|
+
* re-rendered for something else, such as another customer's record.
|
|
14
|
+
*/
|
|
15
|
+
run: ActionDefinition["run"];
|
|
16
|
+
/** Whether the planner is told what `run` said, as the action opted in when it was offered. */
|
|
17
|
+
shareResultWithPlanner: boolean;
|
|
18
|
+
/** Whether a read's result is shown to the user, as the action opted in when it was offered. */
|
|
19
|
+
showResult: boolean;
|
|
20
|
+
}
|
|
21
|
+
/** Said when the planner asked for an action the page no longer offers as it was. */
|
|
22
|
+
export declare const ACTION_NO_LONGER_AVAILABLE_MESSAGE = "That can't be done on this screen right now.";
|
|
23
|
+
/** Said when the screen changed while a change waited to be confirmed, so it was not made. */
|
|
24
|
+
export declare const SCREEN_CHANGED_BEFORE_CONFIRM_MESSAGE = "This screen changed, so that wasn't done. Please ask again.";
|
|
25
|
+
/**
|
|
26
|
+
* Checks the planner's calls against the actions on the page now, which may
|
|
27
|
+
* have changed while it worked, and fills each file parameter with the file
|
|
28
|
+
* itself. Null when any call no longer fits, or is for an action the page now
|
|
29
|
+
* declares differently from what the planner was shown, such as a change it
|
|
30
|
+
* now offers as something that runs at once.
|
|
31
|
+
*/
|
|
32
|
+
export declare function prepareActionCalls(registeredActions: readonly RegisteredAction[], actionCalls: readonly ActionCall[], attachedFiles: readonly File[], declarationsSent: readonly Action[]): PreparedActionCall[] | null;
|
|
33
|
+
/** A parameter's name as words, for a parameter given no description: `phoneNumber` is "phone number". */
|
|
34
|
+
export declare function wordsOfName(parameterName: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Runs one call. Resolves to whether it worked, what to tell the user, and
|
|
37
|
+
* what to tell the planner: the action's title and how it ended, or what the
|
|
38
|
+
* user was told when the action shares it.
|
|
39
|
+
*/
|
|
40
|
+
export declare function runActionCall(preparedCall: PreparedActionCall): Promise<{
|
|
41
|
+
done: boolean;
|
|
42
|
+
text: string;
|
|
43
|
+
noteForPlanner: string;
|
|
44
|
+
returnedText: boolean;
|
|
45
|
+
}>;
|
|
46
|
+
/**
|
|
47
|
+
* What the planner is told of calls that never ran, and why, such as
|
|
48
|
+
* "cancelled": their titles only, never what the user was shown of them.
|
|
49
|
+
*/
|
|
50
|
+
export declare function describeNotRunForPlanner(preparedCalls: readonly PreparedActionCall[], reason: string): string;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { Action, ActionParameter } from "../core/index.js";
|
|
2
|
+
/** What a file parameter is given when the action runs: the file itself. */
|
|
3
|
+
export type ActionArgumentValue = string | number | boolean | File;
|
|
4
|
+
export type ActionArguments = Record<string, ActionArgumentValue>;
|
|
5
|
+
/** What an application gives to offer one action. */
|
|
6
|
+
export interface ActionDefinition {
|
|
7
|
+
/** How the planner names it: a letter, then letters, digits or _. Unique on the page. */
|
|
8
|
+
name: string;
|
|
9
|
+
/** What users would call it, such as "Change your name". Shown when asking them to confirm. */
|
|
10
|
+
title: string;
|
|
11
|
+
/** When to use it, for the planner. */
|
|
12
|
+
description?: string;
|
|
13
|
+
/**
|
|
14
|
+
* `write` (the default) changes something, so the user confirms before it runs.
|
|
15
|
+
* `read` only changes what is shown, such as opening a page or a tab, and runs
|
|
16
|
+
* at once. A read action must not change data.
|
|
17
|
+
*/
|
|
18
|
+
mode?: "read" | "write";
|
|
19
|
+
/** What it needs, by name. Text, numbers, true or false, or a file the user attached. */
|
|
20
|
+
parameters?: Record<string, ActionParameter>;
|
|
21
|
+
/**
|
|
22
|
+
* The sentence the user confirms, such as "Change your name to Joshua King?".
|
|
23
|
+
* Without it, the title is shown with each value given.
|
|
24
|
+
*/
|
|
25
|
+
confirm?: (actionArguments: ActionArguments) => string;
|
|
26
|
+
/**
|
|
27
|
+
* Carries the action out, with the user's own sign-in, as your own screens
|
|
28
|
+
* would. For a `write` action, what it resolves to, if text, is shown to the
|
|
29
|
+
* user; otherwise "Done.". A `read` action's result is shown only with
|
|
30
|
+
* `showResult`, since the planner's reply already says what it is showing.
|
|
31
|
+
* Throw an `ActionError` to show the user why it could not be done, whatever
|
|
32
|
+
* the mode.
|
|
33
|
+
*/
|
|
34
|
+
run: (actionArguments: ActionArguments) => unknown;
|
|
35
|
+
/**
|
|
36
|
+
* True to tell the planner what `run` resolves to, or the `ActionError`
|
|
37
|
+
* message, so a later request can build on it ("now email that invoice").
|
|
38
|
+
* That text then goes to the AI model (Anthropic) with the user's next few
|
|
39
|
+
* requests. Off by default: the planner is told only the action's title and
|
|
40
|
+
* whether it was done, failed or was cancelled, while the user still sees
|
|
41
|
+
* the full sentence.
|
|
42
|
+
*/
|
|
43
|
+
shareResultWithPlanner?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* For a `read` action: true to show the user the sentence `run` resolves to,
|
|
46
|
+
* under the planner's reply. A read that resolves to no sentence stays quiet. For a read whose answer the user needs before they
|
|
47
|
+
* decide, such as the new times a later change in the same request would
|
|
48
|
+
* use. Off by default, so actions that open or filter a page stay quiet.
|
|
49
|
+
*/
|
|
50
|
+
showResult?: boolean;
|
|
51
|
+
}
|
|
52
|
+
/** An action as it is offered on the page now. */
|
|
53
|
+
export interface RegisteredAction {
|
|
54
|
+
declaration: Action;
|
|
55
|
+
/** The definition as last rendered, so `run` and `confirm` may be inline functions. */
|
|
56
|
+
definition: () => ActionDefinition;
|
|
57
|
+
}
|
|
58
|
+
/** Thrown from an action's `run` to tell the user, in a sentence, why it could not be done. */
|
|
59
|
+
export declare class ActionError extends Error {
|
|
60
|
+
constructor(userMessage: string);
|
|
61
|
+
}
|
|
62
|
+
export declare function declarationOf(definition: ActionDefinition): Action;
|
|
63
|
+
/**
|
|
64
|
+
* The actions offered on the page right now. Each registers while the component
|
|
65
|
+
* that offers it is mounted, so the planner sees only what the screen can do.
|
|
66
|
+
*/
|
|
67
|
+
export declare class ActionRegistry {
|
|
68
|
+
private registered;
|
|
69
|
+
private cachedActions;
|
|
70
|
+
private listeners;
|
|
71
|
+
subscribe: (listener: () => void) => (() => void);
|
|
72
|
+
/** Stable until the actions on offer change. */
|
|
73
|
+
getActions: () => readonly RegisteredAction[];
|
|
74
|
+
/** Offers an action until the returned function is called. */
|
|
75
|
+
register(registeredAction: RegisteredAction): () => void;
|
|
76
|
+
private changed;
|
|
77
|
+
}
|
|
78
|
+
export declare const getServerActions: () => readonly RegisteredAction[];
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { type CSSProperties, type ReactNode } from "react";
|
|
2
|
+
import { type ApplyOperationsOutcome, type Capabilities, type LayoutItem, type PropValue } from "../core/index.js";
|
|
3
|
+
import { type PresetSet, type PresetValues } from "../presets/propPresets.js";
|
|
4
|
+
export interface AdaptiveProps<Presets extends PresetSet = PresetSet> {
|
|
5
|
+
/**
|
|
6
|
+
* Any name but "__proto__", which a saved layout cannot carry. The same goes
|
|
7
|
+
* for prop names; note that one written as `{ __proto__: … }` is not an entry
|
|
8
|
+
* at all in JavaScript, so that prop simply does not exist.
|
|
9
|
+
*/
|
|
10
|
+
id: string;
|
|
11
|
+
/** What the component is, in a word: "chart", "table", "card". Shown to the model. */
|
|
12
|
+
kind?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Human name, as a user would refer to it. Shown to the model, and to the
|
|
15
|
+
* user in what the panel says. Without one the model is given the id, and
|
|
16
|
+
* the user is told of "a section".
|
|
17
|
+
*/
|
|
18
|
+
title?: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
/** A locked component cannot be changed by any operation. */
|
|
21
|
+
locked?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Names the items that share one container of the page, such as the cards
|
|
24
|
+
* of one tab or the links of one menu. Items are put in order only among
|
|
25
|
+
* those with the same group, and a request to move one to another group is
|
|
26
|
+
* refused with an explanation. Items without one form a group of their own.
|
|
27
|
+
* In a region with `grid={false}`, only items with a group can be moved.
|
|
28
|
+
*/
|
|
29
|
+
group?: string;
|
|
30
|
+
/**
|
|
31
|
+
* How users may arrange the component. Anything not declared is refused.
|
|
32
|
+
*
|
|
33
|
+
* - `move`, `hide`: on unless set to false. Moving is off for an item with no
|
|
34
|
+
* `group` in a region with `grid={false}`.
|
|
35
|
+
* - `resize`: `{ minW, maxW, minH, maxH }`, in columns and rows. Off unless given.
|
|
36
|
+
*
|
|
37
|
+
* Settings users may change, such as a colour or which columns show, are
|
|
38
|
+
* declared in `presets`.
|
|
39
|
+
*/
|
|
40
|
+
capabilities?: Partial<Omit<Capabilities, "props">>;
|
|
41
|
+
/**
|
|
42
|
+
* `w` and `h` are the item's width in columns and height in rows. Give both
|
|
43
|
+
* or neither: they are needed in a region's grid, and an item without them,
|
|
44
|
+
* such as a button or a menu, is sized by the page and cannot be resized.
|
|
45
|
+
*/
|
|
46
|
+
defaults?: Partial<Pick<LayoutItem, "w" | "h" | "hidden">>;
|
|
47
|
+
/**
|
|
48
|
+
* The settings users may change, from `propPresets`, each under a name of your
|
|
49
|
+
* choosing. Use a built-in one when it fits, such as `{ rows: propPresets.density() }`;
|
|
50
|
+
* otherwise a custom one, such as
|
|
51
|
+
* `{ view: propPresets.choice({ values: ["day", "week"], initial: "week", means: "how much shows at once" }) }`.
|
|
52
|
+
* Each brings its starting value and a sentence telling the model what it means,
|
|
53
|
+
* added after `description`. A render-function child receives each one's current
|
|
54
|
+
* value under the same name, as its third argument: ClickLess stores the value,
|
|
55
|
+
* and what it changes on screen is up to you.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* <Adaptive id="pipeline" title="Sales pipeline" defaults={{ w: 8, h: 4 }}
|
|
59
|
+
* presets={{ accent: propPresets.accent({ marks: "the deal that is due soonest" }) }}>
|
|
60
|
+
* {(props, adaptiveControls, presetValues) => <PipelineBoard accentColor={presetValues.accent} />}
|
|
61
|
+
* </Adaptive>
|
|
62
|
+
*/
|
|
63
|
+
presets?: Presets;
|
|
64
|
+
className?: string;
|
|
65
|
+
/**
|
|
66
|
+
* Styles for the item's wrapper. `gridColumn` and `gridRow` are set by the
|
|
67
|
+
* layout for an item with a size, `order` for an item in a region's grid or
|
|
68
|
+
* in a group that has been moved, and `display` while the item is hidden,
|
|
69
|
+
* so those are not taken from here.
|
|
70
|
+
*/
|
|
71
|
+
style?: CSSProperties;
|
|
72
|
+
/**
|
|
73
|
+
* Set when the component outlines the parts a change reaches itself, with
|
|
74
|
+
* `changeOutline`. Its own outline is then kept for what changes the whole
|
|
75
|
+
* section: hiding, moving or resizing it.
|
|
76
|
+
*/
|
|
77
|
+
marksChanges?: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Pass a function to receive the stored value of every prop the presets
|
|
80
|
+
* declare, under its prop name (the name `setProp` takes), controls for
|
|
81
|
+
* changing them from your own UI, and the current value of each preset in
|
|
82
|
+
* `presets`, under the name given there.
|
|
83
|
+
*/
|
|
84
|
+
children: ReactNode | ((props: Record<string, PropValue>, adaptiveControls: AdaptiveControls, presetValues: PresetValues<Presets>) => ReactNode);
|
|
85
|
+
}
|
|
86
|
+
export interface AdaptiveControls {
|
|
87
|
+
/**
|
|
88
|
+
* Changes one of this component's props, as a prompt would: it is validated,
|
|
89
|
+
* saved for the user and can be undone. Use it for controls you build
|
|
90
|
+
* yourself, such as a column picker. Unlike a prompt's change, it takes effect
|
|
91
|
+
* at once, without waiting for the engine, and its promise resolves at once:
|
|
92
|
+
* it is saved behind the scenes, later if the engine cannot be reached.
|
|
93
|
+
* Resolving means the change is shown, not saved: it is kept for the visit
|
|
94
|
+
* only if it clashes with the user's saved layout or the engine refuses it.
|
|
95
|
+
* `hasUnsavedChanges` from `useAdaptiveRegion` says whether any change is
|
|
96
|
+
* still waiting to be saved.
|
|
97
|
+
*/
|
|
98
|
+
setProp: (propName: string, propValue: PropValue) => Promise<ApplyOperationsOutcome>;
|
|
99
|
+
/**
|
|
100
|
+
* Whether a preview, or the original while "See original" shows it, draws
|
|
101
|
+
* one of this component's props differently from the user's version. Give
|
|
102
|
+
* the prop's name, or the name of a preset in `presets` for all of its props. With
|
|
103
|
+
* `entry`, whether that entry of a list prop is new there or had to move,
|
|
104
|
+
* such as one column of a table. False when neither is showing.
|
|
105
|
+
*/
|
|
106
|
+
isChanged: (propName: string, entry?: string) => boolean;
|
|
107
|
+
/**
|
|
108
|
+
* The outline a changed section gets, for the part of this component that
|
|
109
|
+
* shows `propName`, or one `entry` of it, where `isChanged` says it changed,
|
|
110
|
+
* and nothing elsewhere. Pass it to that part's own `style`, such as
|
|
111
|
+
* `<th style={adaptiveControls.changeOutline("columns", column)}>`, and set
|
|
112
|
+
* `marksChanges` on the component.
|
|
113
|
+
*/
|
|
114
|
+
changeOutline: (propName: string, entry?: string) => CSSProperties | undefined;
|
|
115
|
+
}
|
|
116
|
+
export declare function Adaptive<Presets extends PresetSet = PresetSet>({ id, kind, title, description: ownDescription, locked, group, capabilities: ownCapabilities, defaults: ownDefaults, presets, className, style, marksChanges, children, }: AdaptiveProps<Presets>): import("react").JSX.Element;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ActionDefinition } from "../actions/actionRegistry.js";
|
|
2
|
+
export type AdaptiveActionProps = ActionDefinition;
|
|
3
|
+
/** `useAdaptiveAction` as a component, for offering an action from JSX. Renders nothing. */
|
|
4
|
+
export declare function AdaptiveAction(props: AdaptiveActionProps): null;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { EngineOptions } from "../engine/engineClient.js";
|
|
3
|
+
import { type ColorSchemeSetting } from "./hostColorScheme.js";
|
|
4
|
+
export interface AdaptiveProviderProps {
|
|
5
|
+
/**
|
|
6
|
+
* Who is signed in: the user id your backend puts in the token's `sub`.
|
|
7
|
+
* When it changes, everything inside the provider is mounted afresh, so
|
|
8
|
+
* nothing the last user typed or changed is shown to the next one. A token
|
|
9
|
+
* `getToken` gives for anyone else is never sent, so nothing the last user
|
|
10
|
+
* left unsaved is saved to the next one's account, even when signing out
|
|
11
|
+
* shows a page without ClickLess. A provider is for one tenant too: where
|
|
12
|
+
* someone can switch tenant without a reload, give the provider the tenant
|
|
13
|
+
* as its `key`.
|
|
14
|
+
*/
|
|
15
|
+
userId: string;
|
|
16
|
+
/**
|
|
17
|
+
* Connects regions to the ClickLess engine, which stores each user's layout
|
|
18
|
+
* and plans changes from prompts. Read once for each signed-in user. Without it,
|
|
19
|
+
* layouts live in memory and `onLayoutChange` is the only way to persist them.
|
|
20
|
+
*/
|
|
21
|
+
engine?: EngineOptions;
|
|
22
|
+
/**
|
|
23
|
+
* Regions whose saved layouts are read from the engine as soon as the
|
|
24
|
+
* provider mounts, before they are on the screen, such as a sidebar that a
|
|
25
|
+
* phone only draws once its menu is opened. Each then shows its saved layout
|
|
26
|
+
* the moment it mounts, rather than its default for as long as the read
|
|
27
|
+
* takes. A region not listed is read when it first mounts. Read once for
|
|
28
|
+
* each signed-in user, like `engine`.
|
|
29
|
+
*/
|
|
30
|
+
preloadRegions?: readonly string[];
|
|
31
|
+
/**
|
|
32
|
+
* The colours of every PromptPanel and PromptBar inside that sets none of
|
|
33
|
+
* its own: "light", "dark", or "auto" (the default) to follow the page.
|
|
34
|
+
*/
|
|
35
|
+
colorScheme?: ColorSchemeSetting;
|
|
36
|
+
children: ReactNode;
|
|
37
|
+
}
|
|
38
|
+
export declare function AdaptiveProvider({ userId, colorScheme, ...signedInUserProviderProps }: AdaptiveProviderProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { type CSSProperties, type ReactNode } from "react";
|
|
2
|
+
import { type Layout } from "../core/index.js";
|
|
3
|
+
import type { LayoutChangeHandler } from "../region/regionStore.js";
|
|
4
|
+
import { type RegionColumns } from "../region/responsiveColumns.js";
|
|
5
|
+
export interface AdaptiveRegionProps {
|
|
6
|
+
id: string;
|
|
7
|
+
/**
|
|
8
|
+
* Bump when a release changes the set of components or their capabilities.
|
|
9
|
+
* Components that merely come and go while the application runs, such as
|
|
10
|
+
* the content of a tab, need nothing: what the user set on them is kept
|
|
11
|
+
* while they are off screen.
|
|
12
|
+
*/
|
|
13
|
+
version: string;
|
|
14
|
+
/**
|
|
15
|
+
* Whether the region lays its items out in a grid of its own, as it does
|
|
16
|
+
* unless told otherwise. With `false` it draws nothing of its own: each item
|
|
17
|
+
* stays in whichever of your containers it is written in, such as a header,
|
|
18
|
+
* a menu or your own card grid, and the region can span all of them. Items
|
|
19
|
+
* that share a container are given the same `group`, and only items with a
|
|
20
|
+
* group can be moved. `className` and `style` are not used then.
|
|
21
|
+
*/
|
|
22
|
+
grid?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Columns in the region's grid. With `grid={false}`, the columns of your own
|
|
25
|
+
* grids that items with a size sit in, which is as wide as they can be made.
|
|
26
|
+
*
|
|
27
|
+
* For a grid that has fewer columns on narrow screens, give the columns from
|
|
28
|
+
* each screen width up, in pixels, such as `{ 0: 1, 768: 12 }`. Users arrange
|
|
29
|
+
* the widest grid; a narrower screen draws that arrangement in its own
|
|
30
|
+
* columns, each item keeping its share of the width, so a change made on a
|
|
31
|
+
* phone keeps what was set for a wide screen. With `grid={false}`, use the
|
|
32
|
+
* same widths and columns as your own grids.
|
|
33
|
+
*/
|
|
34
|
+
columns?: RegionColumns;
|
|
35
|
+
/**
|
|
36
|
+
* What users call this part of the screen, such as "Sidebar". Give one to
|
|
37
|
+
* each region when a prompt bar speaks for several, so that "in the sidebar"
|
|
38
|
+
* is understood and replies can say where a change was made.
|
|
39
|
+
*/
|
|
40
|
+
title?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Height of one row of the grid, in pixels, or `"auto"` for rows as tall as
|
|
43
|
+
* their content, such as a table whose height follows its rows.
|
|
44
|
+
*/
|
|
45
|
+
rowHeight?: number | "auto";
|
|
46
|
+
/** Gap between items, in pixels. */
|
|
47
|
+
gap?: number;
|
|
48
|
+
/**
|
|
49
|
+
* The user's saved layout. Read once, when the region first mounts. One that
|
|
50
|
+
* cannot be read is ignored and the default is shown. With an engine it is
|
|
51
|
+
* only what shows until the engine's own copy arrives, which then replaces it.
|
|
52
|
+
*/
|
|
53
|
+
initialLayout?: Layout;
|
|
54
|
+
/** Called after every committed change. Persist the layout here. */
|
|
55
|
+
onLayoutChange?: LayoutChangeHandler;
|
|
56
|
+
className?: string;
|
|
57
|
+
style?: CSSProperties;
|
|
58
|
+
children: ReactNode;
|
|
59
|
+
}
|
|
60
|
+
export declare function AdaptiveRegion({ id, version, grid, columns, title, rowHeight, gap, initialLayout, onLayoutChange, className, style, children, }: AdaptiveRegionProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Component, type ReactNode } from "react";
|
|
2
|
+
interface ClicklessUiErrorBoundaryProps {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
/** When this changes, a panel or bar that failed to draw is tried again: it now speaks for other regions. */
|
|
5
|
+
resetKey: string;
|
|
6
|
+
}
|
|
7
|
+
interface ClicklessUiErrorBoundaryState {
|
|
8
|
+
drawingFailed: boolean;
|
|
9
|
+
/** The `resetKey` of the last drawing, failed or not. */
|
|
10
|
+
drawnForKey: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Draws nothing in place of the SDK's own panel or bar if drawing it in the
|
|
14
|
+
* browser fails, so a fault there never takes the host's page down with it.
|
|
15
|
+
* The page, its own controls and its layouts go on working. React reports the
|
|
16
|
+
* fault. Pointing the panel or bar at other regions tries drawing it again.
|
|
17
|
+
*/
|
|
18
|
+
export declare class ClicklessUiErrorBoundary extends Component<ClicklessUiErrorBoundaryProps, ClicklessUiErrorBoundaryState> {
|
|
19
|
+
state: ClicklessUiErrorBoundaryState;
|
|
20
|
+
static getDerivedStateFromError(): Partial<ClicklessUiErrorBoundaryState>;
|
|
21
|
+
static getDerivedStateFromProps(props: ClicklessUiErrorBoundaryProps, state: ClicklessUiErrorBoundaryState): Partial<ClicklessUiErrorBoundaryState> | null;
|
|
22
|
+
render(): ReactNode;
|
|
23
|
+
}
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface OriginalToolbarProps {
|
|
2
|
+
showingOriginal: boolean;
|
|
3
|
+
differsFromOriginal: boolean;
|
|
4
|
+
/** True when the original can be put back, which needs a history kept by the engine. */
|
|
5
|
+
canRevert: boolean;
|
|
6
|
+
isBusy: boolean;
|
|
7
|
+
previewing: boolean;
|
|
8
|
+
showOriginal: (shown: boolean) => void;
|
|
9
|
+
revertToOriginal: () => void;
|
|
10
|
+
/** Wraps each button's click handler, so the focus is not lost when the button goes. */
|
|
11
|
+
thenKeepFocus: (buttonAction: () => void) => (event: {
|
|
12
|
+
currentTarget: HTMLElement;
|
|
13
|
+
}) => void;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The bar pinned under the panel's title, so going back to the start never
|
|
17
|
+
* means scrolling to the top of a long history. It offers a look at how the
|
|
18
|
+
* screen first looked and a way to put that back; during the look, it says so
|
|
19
|
+
* and offers the way out of it.
|
|
20
|
+
*/
|
|
21
|
+
export declare function OriginalToolbar({ showingOriginal, differsFromOriginal, canRevert, isBusy, previewing, showOriginal, revertToOriginal, thenKeepFocus, }: OriginalToolbarProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type CSSProperties } from "react";
|
|
2
|
+
import { type ColorSchemeSetting } from "./hostColorScheme.js";
|
|
3
|
+
export interface PromptBarProps {
|
|
4
|
+
/**
|
|
5
|
+
* The region the bar changes. Give several ids when the screen is made of
|
|
6
|
+
* more than one region, such as a page and a shared sidebar: one prompt is
|
|
7
|
+
* then planned, previewed, kept and undone across all of them.
|
|
8
|
+
* A list may name up to 8 regions.
|
|
9
|
+
*/
|
|
10
|
+
regionId: string | readonly string[];
|
|
11
|
+
placeholder?: string;
|
|
12
|
+
className?: string;
|
|
13
|
+
style?: CSSProperties;
|
|
14
|
+
/**
|
|
15
|
+
* The colours it is drawn in: "light", "dark", or "auto" to follow the page.
|
|
16
|
+
* Default: AdaptiveProvider's `colorScheme`, which is "auto" unless set.
|
|
17
|
+
*/
|
|
18
|
+
colorScheme?: ColorSchemeSetting;
|
|
19
|
+
}
|
|
20
|
+
/** A ready-made prompt bar. For a custom one, use `usePromptBar`. */
|
|
21
|
+
export declare function PromptBar(props: PromptBarProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { type ColorSchemeSetting } from "./hostColorScheme.js";
|
|
3
|
+
/** The wording of the microphone button and of what replaces it while the user speaks. */
|
|
4
|
+
export interface DictationLabels {
|
|
5
|
+
/** The microphone button's name, read out by screen readers and shown on hover. */
|
|
6
|
+
speak: string;
|
|
7
|
+
/** Shown while the browser hands over the microphone. */
|
|
8
|
+
starting: string;
|
|
9
|
+
/** Shown while the user is speaking. */
|
|
10
|
+
listening: string;
|
|
11
|
+
/** Shown while what they said is turned into text. */
|
|
12
|
+
transcribing: string;
|
|
13
|
+
/** The button that ends the recording and keeps it. */
|
|
14
|
+
done: string;
|
|
15
|
+
/** The button that throws the recording away. */
|
|
16
|
+
cancel: string;
|
|
17
|
+
}
|
|
18
|
+
/** What a microphone button of your own is given by `renderDictationButton`. */
|
|
19
|
+
export interface DictationButtonProps {
|
|
20
|
+
/** Asks for the microphone and starts recording. */
|
|
21
|
+
start: () => void;
|
|
22
|
+
/** True while the panel is working on something else, when speaking cannot begin. */
|
|
23
|
+
disabled: boolean;
|
|
24
|
+
/** The button's name, from `dictationLabels.speak`. */
|
|
25
|
+
label: string;
|
|
26
|
+
}
|
|
27
|
+
type VerticalEdge = "bottom" | "top";
|
|
28
|
+
type HorizontalEdge = "right" | "left";
|
|
29
|
+
/** The corner of the screen the panel's button sits in. */
|
|
30
|
+
export type PromptPanelPosition = `${VerticalEdge}-${HorizontalEdge}`;
|
|
31
|
+
export interface PromptPanelProps {
|
|
32
|
+
/**
|
|
33
|
+
* The region the panel changes. Give several ids when the screen is made of
|
|
34
|
+
* more than one region, such as a page and a sidebar every page shares:
|
|
35
|
+
* `regionId={["dashboard", "sidebar"]}`. One prompt is then planned across
|
|
36
|
+
* all of them, and its preview is kept, discarded and undone in all of them
|
|
37
|
+
* together, while each region's layout is still saved on its own. A region
|
|
38
|
+
* that is not on the screen is left out until it is.
|
|
39
|
+
* A list may name up to 8 regions.
|
|
40
|
+
*/
|
|
41
|
+
regionId: string | readonly string[];
|
|
42
|
+
/**
|
|
43
|
+
* The corner of the screen the button sits in. The panel opens from the same
|
|
44
|
+
* corner: above the button at the bottom of the screen, below it at the top.
|
|
45
|
+
* Default "bottom-right". Any other value is treated as "bottom-right". To
|
|
46
|
+
* move the button in from the edges, for example
|
|
47
|
+
* clear of a tab bar, set `--clickless-launcher-offset-x` and
|
|
48
|
+
* `--clickless-launcher-offset-y` to a length with its unit: `0px`, not `0`.
|
|
49
|
+
*/
|
|
50
|
+
position?: PromptPanelPosition;
|
|
51
|
+
/**
|
|
52
|
+
* Text on the button that opens the panel. While a preview is waiting and
|
|
53
|
+
* the panel is minimised, the button reads "Keep or discard?" instead, and
|
|
54
|
+
* "Seeing original" while the screen shows how it first looked. While
|
|
55
|
+
* personalising is not available the button is dimmed, and still opens the
|
|
56
|
+
* panel, which says why and can still undo.
|
|
57
|
+
*/
|
|
58
|
+
label?: string;
|
|
59
|
+
/** The panel's heading, and its name for screen readers. */
|
|
60
|
+
title?: string;
|
|
61
|
+
placeholder?: string;
|
|
62
|
+
/** How many past changes to show at first, and to load each time. */
|
|
63
|
+
pageSize?: number;
|
|
64
|
+
defaultOpen?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Close the panel when the user clicks elsewhere on the page. Default true.
|
|
67
|
+
* A click elsewhere, like the Escape key, is easy to do by accident, so
|
|
68
|
+
* neither closes it while a preview is waiting, because Keep and Discard are
|
|
69
|
+
* in it. Nor does a click elsewhere while the user is in the middle of a
|
|
70
|
+
* request: while one is being worked on, while there is one in the box, or
|
|
71
|
+
* while the answer to the latest one is showing, as when it says to open a
|
|
72
|
+
* tab on the page and ask again. The Minimise button and the button that
|
|
73
|
+
* opened it always do.
|
|
74
|
+
*/
|
|
75
|
+
closeOnOutsideClick?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Offer a microphone button for speaking a request. It appears only when the
|
|
78
|
+
* engine is set up to turn speech into text and the browser can record.
|
|
79
|
+
* What the user says goes to the engine's speech-to-text provider, so it is
|
|
80
|
+
* off unless you turn it on.
|
|
81
|
+
*/
|
|
82
|
+
dictation?: boolean;
|
|
83
|
+
/** Replaces any of the microphone's wording. What is left out keeps its default. */
|
|
84
|
+
dictationLabels?: Partial<DictationLabels>;
|
|
85
|
+
/**
|
|
86
|
+
* Draws the microphone button in place of the built-in one, in the same spot
|
|
87
|
+
* and only when the built-in one would show, so it needs `dictation` too.
|
|
88
|
+
* Give your button `props.label` as its accessible name.
|
|
89
|
+
*/
|
|
90
|
+
renderDictationButton?: (props: DictationButtonProps) => ReactNode;
|
|
91
|
+
/**
|
|
92
|
+
* The colours it is drawn in: "light", "dark", or "auto" to follow the page.
|
|
93
|
+
* Default: AdaptiveProvider's `colorScheme`, which is "auto" unless set.
|
|
94
|
+
*/
|
|
95
|
+
colorScheme?: ColorSchemeSetting;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* A button that stays in the corner of the screen and opens a panel for
|
|
99
|
+
* describing changes, with the user's past changes above the prompt. The page
|
|
100
|
+
* stays usable beside it, so a preview can be seen while deciding.
|
|
101
|
+
*/
|
|
102
|
+
export declare function PromptPanel(props: PromptPanelProps): import("react").JSX.Element;
|
|
103
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** What a request shows while its answer is being worked out. */
|
|
2
|
+
export declare const WORKING_WORDING = "Working on it\u2026";
|
|
3
|
+
/** Three dots that light up in turn, drawn inline because the SDK ships no stylesheet. Still for reduced motion. */
|
|
4
|
+
export declare function WorkingDots(): import("react").JSX.Element;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type RefObject } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Keeps the keyboard focus somewhere once a button of the panel or bar has
|
|
4
|
+
* done its work. Keep, Discard, Undo, OK and Restore can leave the page when
|
|
5
|
+
* used, which would drop the focus on the page's body: it goes back to the
|
|
6
|
+
* button if that is still there, else to the prompt box. A user who has moved
|
|
7
|
+
* on to something else meanwhile keeps their place, and a press or focus
|
|
8
|
+
* anywhere else forgets the button, so a later render never moves the focus.
|
|
9
|
+
*
|
|
10
|
+
* `actionsSettled` is true while nothing a button began is still under way.
|
|
11
|
+
* Returns a wrapper for a button's click handler.
|
|
12
|
+
*/
|
|
13
|
+
export declare function useFocusAfterPromptAction(promptInput: RefObject<HTMLElement | null>, actionsSettled: boolean): (buttonAction: () => void) => (event: {
|
|
14
|
+
currentTarget: HTMLElement;
|
|
15
|
+
}) => void;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type CSSProperties } from "react";
|
|
2
|
+
export type ColorScheme = "light" | "dark";
|
|
3
|
+
/** The panel's and bar's colours: always light, always dark, or "auto" to follow the page. */
|
|
4
|
+
export type ColorSchemeSetting = ColorScheme | "auto";
|
|
5
|
+
/** The setting AdaptiveProvider gives every panel and bar inside it that sets none of its own. */
|
|
6
|
+
export declare const ColorSchemeSettingContext: import("react").Context<ColorSchemeSetting>;
|
|
7
|
+
/**
|
|
8
|
+
* The built-in colours for a scheme, to set on the outermost element of the
|
|
9
|
+
* panel or bar. Every colour there is written as the page's own
|
|
10
|
+
* --clickless-<name> if it sets one, else --clickless-built-in-<name>, else the
|
|
11
|
+
* light colour, so a page that maps the colours itself keeps them.
|
|
12
|
+
*/
|
|
13
|
+
export declare function builtInColorVariables(colorScheme: ColorScheme): CSSProperties;
|
|
14
|
+
/**
|
|
15
|
+
* The colours a panel or bar is drawn in: its own `colorScheme`, else its
|
|
16
|
+
* provider's, else, for "auto" or anything not understood, the page's.
|
|
17
|
+
*
|
|
18
|
+
* The page's is whether it is drawn dark, so the panel can match it without
|
|
19
|
+
* being told, followed as it changes. It is read from the page's own
|
|
20
|
+
* background, which is how a page shows its theme whichever way it switches
|
|
21
|
+
* it (a class, an attribute, the system setting). A page that paints no
|
|
22
|
+
* background on <html> or <body> is read from a theme attribute or class
|
|
23
|
+
* there, its `color-scheme`, or the background in the middle of the screen,
|
|
24
|
+
* and the system setting only when none of them says. Light for a page that
|
|
25
|
+
* sets any of the colours on its root or body. The server, and the first
|
|
26
|
+
* paint, assume light unless the colours are chosen.
|
|
27
|
+
*/
|
|
28
|
+
export declare function usePanelColorScheme(colorScheme: ColorSchemeSetting | undefined): ColorScheme;
|
|
29
|
+
/**
|
|
30
|
+
* How light a computed colour looks, from 0 to 1, or null when it is
|
|
31
|
+
* transparent or in a form not read here. Browsers give computed colours as
|
|
32
|
+
* rgb(), or in the space they were written in, such as oklch() for a page that
|
|
33
|
+
* uses Tailwind 4.
|
|
34
|
+
*/
|
|
35
|
+
export declare function lightnessOf(cssColor: string): number | null;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CSSProperties } from "react";
|
|
2
|
+
export declare const borderStyle = "1px solid var(--clickless-border, var(--clickless-built-in-border, #d6d3cb))";
|
|
3
|
+
export declare const surfaceColor = "var(--clickless-surface, var(--clickless-built-in-surface, #fff))";
|
|
4
|
+
export declare const mutedColor = "var(--clickless-muted, var(--clickless-built-in-muted, #52514e))";
|
|
5
|
+
export declare const dangerColor = "var(--clickless-danger, var(--clickless-built-in-danger, #a82a2a))";
|
|
6
|
+
export declare const recordingColor = "var(--clickless-recording, var(--clickless-danger, var(--clickless-built-in-danger, #a82a2a)))";
|
|
7
|
+
export declare const controlStyle: CSSProperties;
|
|
8
|
+
export declare const buttonStyle: CSSProperties;
|
|
9
|
+
export declare const primaryButtonStyle: CSSProperties;
|
|
10
|
+
export declare const linkButtonStyle: CSSProperties;
|
|
11
|
+
export declare const userBubbleStyle: CSSProperties;
|
|
12
|
+
export declare const replyBubbleStyle: CSSProperties;
|
|
13
|
+
export declare const historyEntryDetailsStyle: CSSProperties;
|
|
14
|
+
export declare const attachmentChipStyle: CSSProperties;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Layout, Manifest, Operation } from "./schemas.gen.js";
|
|
2
|
+
import { type OperationError } from "./validateOperations.js";
|
|
3
|
+
export type ApplyOperationsOutcome = {
|
|
4
|
+
applied: true;
|
|
5
|
+
layout: Layout;
|
|
6
|
+
} | {
|
|
7
|
+
applied: false;
|
|
8
|
+
errors: OperationError[];
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Validates the whole list, then applies it in order. Nothing is applied if any
|
|
12
|
+
* operation is invalid, or if the result would leave nothing showing in a
|
|
13
|
+
* region that showed something (see `findEmptyRegionFailure`). The input
|
|
14
|
+
* layout is never mutated.
|
|
15
|
+
*
|
|
16
|
+
* Throws if the layout's `order` and `items` do not hold exactly the manifest's
|
|
17
|
+
* components, which means it was not reconciled against this manifest. What
|
|
18
|
+
* the layout keeps in `offScreen` is carried through untouched, except that
|
|
19
|
+
* resetting the whole region drops it.
|
|
20
|
+
*/
|
|
21
|
+
export declare function applyOperations(manifest: Manifest, layout: Layout, operations: readonly Operation[]): ApplyOperationsOutcome;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The WCAG contrast ratio between two hex colours, from 1 (identical) to
|
|
3
|
+
* 21 (black on white). Returns 1 if either value is not a hex colour.
|
|
4
|
+
*/
|
|
5
|
+
export declare function contrastRatio(firstColour: string, secondColour: string): number;
|
|
6
|
+
/**
|
|
7
|
+
* Black or white, whichever is easier to read on the given background.
|
|
8
|
+
* Use it for text drawn over a colour the user chose. Anything that is not a
|
|
9
|
+
* hex colour, such as `rgb(...)` or a colour name, is treated as a light
|
|
10
|
+
* background.
|
|
11
|
+
*/
|
|
12
|
+
export declare function readableTextColor(backgroundColour: string): "#000000" | "#ffffff";
|
|
13
|
+
/**
|
|
14
|
+
* A text colour the user chose, kept only where it can be read. Returns
|
|
15
|
+
* `textColour` if it contrasts enough with `backgroundColour`, and otherwise black or
|
|
16
|
+
* white, whichever reads better. A background that is not a hex colour cannot
|
|
17
|
+
* be judged, so `textColour` is returned as it is.
|
|
18
|
+
*
|
|
19
|
+
* `minimumContrastRatio` defaults to 4.5, the WCAG AA ratio for body text. Use
|
|
20
|
+
* 3 for large or bold text.
|
|
21
|
+
*/
|
|
22
|
+
export declare function ensureReadableTextColor(textColour: string, backgroundColour: string, minimumContrastRatio?: number): string;
|