@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,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;