@liberation-data/desk 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 (172) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +4 -0
  3. package/README.md +436 -0
  4. package/dist/core/commands.d.ts +40 -0
  5. package/dist/core/commands.d.ts.map +1 -0
  6. package/dist/core/commands.js +92 -0
  7. package/dist/core/commands.js.map +1 -0
  8. package/dist/core/desk.d.ts +46 -0
  9. package/dist/core/desk.d.ts.map +1 -0
  10. package/dist/core/desk.js +178 -0
  11. package/dist/core/desk.js.map +1 -0
  12. package/dist/core/events.d.ts +42 -0
  13. package/dist/core/events.d.ts.map +1 -0
  14. package/dist/core/events.js +54 -0
  15. package/dist/core/events.js.map +1 -0
  16. package/dist/core/index.d.ts +13 -0
  17. package/dist/core/index.d.ts.map +1 -0
  18. package/dist/core/index.js +7 -0
  19. package/dist/core/index.js.map +1 -0
  20. package/dist/core/location.d.ts +30 -0
  21. package/dist/core/location.d.ts.map +1 -0
  22. package/dist/core/location.js +99 -0
  23. package/dist/core/location.js.map +1 -0
  24. package/dist/core/shortcuts.d.ts +36 -0
  25. package/dist/core/shortcuts.d.ts.map +1 -0
  26. package/dist/core/shortcuts.js +73 -0
  27. package/dist/core/shortcuts.js.map +1 -0
  28. package/dist/core/titles.d.ts +3 -0
  29. package/dist/core/titles.d.ts.map +1 -0
  30. package/dist/core/titles.js +26 -0
  31. package/dist/core/titles.js.map +1 -0
  32. package/dist/core/types.d.ts +51 -0
  33. package/dist/core/types.d.ts.map +1 -0
  34. package/dist/core/types.js +2 -0
  35. package/dist/core/types.js.map +1 -0
  36. package/dist/desk.css +2550 -0
  37. package/dist/react/Desktop.d.ts +24 -0
  38. package/dist/react/Desktop.d.ts.map +1 -0
  39. package/dist/react/Desktop.js +212 -0
  40. package/dist/react/Desktop.js.map +1 -0
  41. package/dist/react/Dock.d.ts +42 -0
  42. package/dist/react/Dock.d.ts.map +1 -0
  43. package/dist/react/Dock.js +103 -0
  44. package/dist/react/Dock.js.map +1 -0
  45. package/dist/react/MenuBar.d.ts +64 -0
  46. package/dist/react/MenuBar.d.ts.map +1 -0
  47. package/dist/react/MenuBar.js +245 -0
  48. package/dist/react/MenuBar.js.map +1 -0
  49. package/dist/react/appFrame.d.ts +37 -0
  50. package/dist/react/appFrame.d.ts.map +1 -0
  51. package/dist/react/appFrame.js +119 -0
  52. package/dist/react/appFrame.js.map +1 -0
  53. package/dist/react/arrange.d.ts +24 -0
  54. package/dist/react/arrange.d.ts.map +1 -0
  55. package/dist/react/arrange.js +61 -0
  56. package/dist/react/arrange.js.map +1 -0
  57. package/dist/react/commands.d.ts +23 -0
  58. package/dist/react/commands.d.ts.map +1 -0
  59. package/dist/react/commands.js +41 -0
  60. package/dist/react/commands.js.map +1 -0
  61. package/dist/react/context.d.ts +25 -0
  62. package/dist/react/context.d.ts.map +1 -0
  63. package/dist/react/context.js +28 -0
  64. package/dist/react/context.js.map +1 -0
  65. package/dist/react/controls.d.ts +111 -0
  66. package/dist/react/controls.d.ts.map +1 -0
  67. package/dist/react/controls.js +83 -0
  68. package/dist/react/controls.js.map +1 -0
  69. package/dist/react/conversation.d.ts +41 -0
  70. package/dist/react/conversation.d.ts.map +1 -0
  71. package/dist/react/conversation.js +73 -0
  72. package/dist/react/conversation.js.map +1 -0
  73. package/dist/react/dnd.d.ts +51 -0
  74. package/dist/react/dnd.d.ts.map +1 -0
  75. package/dist/react/dnd.js +138 -0
  76. package/dist/react/dnd.js.map +1 -0
  77. package/dist/react/dragContext.d.ts +32 -0
  78. package/dist/react/dragContext.d.ts.map +1 -0
  79. package/dist/react/dragContext.js +14 -0
  80. package/dist/react/dragContext.js.map +1 -0
  81. package/dist/react/events.d.ts +41 -0
  82. package/dist/react/events.d.ts.map +1 -0
  83. package/dist/react/events.js +91 -0
  84. package/dist/react/events.js.map +1 -0
  85. package/dist/react/index.d.ts +43 -0
  86. package/dist/react/index.d.ts.map +1 -0
  87. package/dist/react/index.js +22 -0
  88. package/dist/react/index.js.map +1 -0
  89. package/dist/react/layers.d.ts +5 -0
  90. package/dist/react/layers.d.ts.map +1 -0
  91. package/dist/react/layers.js +65 -0
  92. package/dist/react/layers.js.map +1 -0
  93. package/dist/react/overlays.d.ts +67 -0
  94. package/dist/react/overlays.d.ts.map +1 -0
  95. package/dist/react/overlays.js +98 -0
  96. package/dist/react/overlays.js.map +1 -0
  97. package/dist/react/popup.d.ts +21 -0
  98. package/dist/react/popup.d.ts.map +1 -0
  99. package/dist/react/popup.js +94 -0
  100. package/dist/react/popup.js.map +1 -0
  101. package/dist/react/search.d.ts +33 -0
  102. package/dist/react/search.d.ts.map +1 -0
  103. package/dist/react/search.js +82 -0
  104. package/dist/react/search.js.map +1 -0
  105. package/dist/react/setupProgress.d.ts +35 -0
  106. package/dist/react/setupProgress.d.ts.map +1 -0
  107. package/dist/react/setupProgress.js +68 -0
  108. package/dist/react/setupProgress.js.map +1 -0
  109. package/dist/react/shell.d.ts +17 -0
  110. package/dist/react/shell.d.ts.map +1 -0
  111. package/dist/react/shell.js +13 -0
  112. package/dist/react/shell.js.map +1 -0
  113. package/dist/react/sidebar.d.ts +23 -0
  114. package/dist/react/sidebar.d.ts.map +1 -0
  115. package/dist/react/sidebar.js +26 -0
  116. package/dist/react/sidebar.js.map +1 -0
  117. package/dist/react/table.d.ts +39 -0
  118. package/dist/react/table.d.ts.map +1 -0
  119. package/dist/react/table.js +86 -0
  120. package/dist/react/table.js.map +1 -0
  121. package/dist/react/tasks.d.ts +41 -0
  122. package/dist/react/tasks.d.ts.map +1 -0
  123. package/dist/react/tasks.js +79 -0
  124. package/dist/react/tasks.js.map +1 -0
  125. package/dist/react/tour.d.ts +42 -0
  126. package/dist/react/tour.d.ts.map +1 -0
  127. package/dist/react/tour.js +68 -0
  128. package/dist/react/tour.js.map +1 -0
  129. package/dist/react/windowBoundary.d.ts +22 -0
  130. package/dist/react/windowBoundary.d.ts.map +1 -0
  131. package/dist/react/windowBoundary.js +50 -0
  132. package/dist/react/windowBoundary.js.map +1 -0
  133. package/dist/react/wizard.d.ts +41 -0
  134. package/dist/react/wizard.d.ts.map +1 -0
  135. package/dist/react/wizard.js +60 -0
  136. package/dist/react/wizard.js.map +1 -0
  137. package/llms.txt +410 -0
  138. package/package.json +64 -0
  139. package/src/core/commands.ts +142 -0
  140. package/src/core/desk.ts +229 -0
  141. package/src/core/events.ts +99 -0
  142. package/src/core/index.ts +43 -0
  143. package/src/core/location.ts +127 -0
  144. package/src/core/shortcuts.ts +119 -0
  145. package/src/core/titles.ts +28 -0
  146. package/src/core/types.ts +49 -0
  147. package/src/desk.css +2550 -0
  148. package/src/react/Desktop.tsx +349 -0
  149. package/src/react/Dock.tsx +258 -0
  150. package/src/react/MenuBar.tsx +350 -0
  151. package/src/react/appFrame.tsx +183 -0
  152. package/src/react/arrange.ts +82 -0
  153. package/src/react/commands.ts +60 -0
  154. package/src/react/context.tsx +55 -0
  155. package/src/react/controls.tsx +364 -0
  156. package/src/react/conversation.tsx +208 -0
  157. package/src/react/dnd.tsx +189 -0
  158. package/src/react/dragContext.tsx +60 -0
  159. package/src/react/events.tsx +149 -0
  160. package/src/react/index.ts +64 -0
  161. package/src/react/layers.ts +66 -0
  162. package/src/react/overlays.tsx +254 -0
  163. package/src/react/popup.tsx +176 -0
  164. package/src/react/search.tsx +177 -0
  165. package/src/react/setupProgress.ts +113 -0
  166. package/src/react/shell.tsx +27 -0
  167. package/src/react/sidebar.tsx +84 -0
  168. package/src/react/table.tsx +176 -0
  169. package/src/react/tasks.tsx +176 -0
  170. package/src/react/tour.tsx +183 -0
  171. package/src/react/windowBoundary.tsx +110 -0
  172. package/src/react/wizard.tsx +150 -0
@@ -0,0 +1,41 @@
1
+ import type { ReactNode } from 'react';
2
+ export type TaskState = 'waiting' | 'working' | 'done' | 'failed';
3
+ export interface Task {
4
+ readonly id: string;
5
+ readonly name: ReactNode;
6
+ /** The line under the name, until the task reports its own. */
7
+ readonly detail?: ReactNode;
8
+ /** The work. `report` replaces the line under the name while it runs: "12 of 24". Throw to fail. */
9
+ readonly run: (report: (detail: ReactNode) => void) => unknown;
10
+ }
11
+ export interface TaskProgress {
12
+ readonly id: string;
13
+ readonly name: ReactNode;
14
+ readonly state: TaskState;
15
+ readonly detail?: ReactNode;
16
+ /** Why it failed, for a person. */
17
+ readonly error?: string;
18
+ }
19
+ export interface Tasks {
20
+ readonly items: readonly TaskProgress[];
21
+ readonly running: boolean;
22
+ readonly done: boolean;
23
+ readonly failed: boolean;
24
+ /** Runs every task not yet done, in order. After a failure, this is the retry. */
25
+ readonly start: () => void;
26
+ /** Forgets what ran and runs everything again: for a setup step entered a second time. */
27
+ readonly restart: () => void;
28
+ }
29
+ export declare function useTasks(tasks: readonly Task[]): Tasks;
30
+ export interface ChecklistProps {
31
+ readonly items: readonly TaskProgress[];
32
+ /** Offered beside a failed task. */
33
+ readonly onRetry?: () => void;
34
+ /** A bar above the list, filling as tasks finish. Default true. */
35
+ readonly progress?: boolean;
36
+ readonly label?: string;
37
+ readonly className?: string;
38
+ }
39
+ /** Tasks as a person watches them: waiting, working, done, or failed with the reason. */
40
+ export declare function Checklist({ items, onRetry, progress, label, className }: ChecklistProps): import("react").JSX.Element;
41
+ //# sourceMappingURL=tasks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../../src/react/tasks.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAUtC,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAA;AAEjE,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAA;IAC3B,oGAAoG;IACpG,QAAQ,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,KAAK,OAAO,CAAA;CAC/D;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAA;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAA;IAC3B,mCAAmC;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAA;IACvC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,kFAAkF;IAClF,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAA;IAC1B,0FAA0F;IAC1F,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAC7B;AAQD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,KAAK,CAwEtD;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAA;IACvC,oCAAoC;IACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IAC7B,mEAAmE;IACnE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED,yFAAyF;AACzF,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,QAAe,EAAE,KAAkB,EAAE,SAAS,EAAE,EAAE,cAAc,+BA0C3G"}
@@ -0,0 +1,79 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useRef, useState } from 'react';
3
+ import { Button } from './controls.js';
4
+ export function useTasks(tasks) {
5
+ // The latest tasks, so a task's `run` sees the answers given since the step was drawn.
6
+ const latest = useRef(tasks);
7
+ latest.current = tasks;
8
+ const [status, setStatus] = useState({});
9
+ const statusNow = useRef(status);
10
+ statusNow.current = status;
11
+ // A run that has been superseded — by a restart, or by leaving — stops touching state.
12
+ const generation = useRef(0);
13
+ const [running, setRunning] = useState(false);
14
+ useEffect(() => () => {
15
+ generation.current += 1;
16
+ }, []);
17
+ const run = useCallback(async (from) => {
18
+ const mine = ++generation.current;
19
+ const set = (id, next) => {
20
+ if (generation.current !== mine)
21
+ return;
22
+ statusNow.current = { ...statusNow.current, [id]: next };
23
+ setStatus(statusNow.current);
24
+ };
25
+ setRunning(true);
26
+ for (const task of latest.current) {
27
+ if (from[task.id]?.state === 'done')
28
+ continue;
29
+ set(task.id, { state: 'working' });
30
+ try {
31
+ await task.run(detail => set(task.id, { state: 'working', reported: detail }));
32
+ set(task.id, { state: 'done', reported: statusNow.current[task.id]?.reported });
33
+ }
34
+ catch (failure) {
35
+ set(task.id, { state: 'failed', error: failure instanceof Error ? failure.message : String(failure) });
36
+ break;
37
+ }
38
+ if (generation.current !== mine)
39
+ return;
40
+ }
41
+ if (generation.current === mine)
42
+ setRunning(false);
43
+ }, []);
44
+ const start = useCallback(() => {
45
+ if (running)
46
+ return;
47
+ void run(statusNow.current);
48
+ }, [run, running]);
49
+ const restart = useCallback(() => {
50
+ statusNow.current = {};
51
+ setStatus({});
52
+ void run({});
53
+ }, [run]);
54
+ const items = tasks.map((task) => {
55
+ const s = status[task.id];
56
+ const detail = s?.reported ?? task.detail;
57
+ return {
58
+ id: task.id,
59
+ name: task.name,
60
+ state: s?.state ?? 'waiting',
61
+ ...(detail === undefined ? {} : { detail }),
62
+ ...(s?.error === undefined ? {} : { error: s.error }),
63
+ };
64
+ });
65
+ return {
66
+ items,
67
+ running,
68
+ done: items.length > 0 && items.every(item => item.state === 'done'),
69
+ failed: items.some(item => item.state === 'failed'),
70
+ start,
71
+ restart,
72
+ };
73
+ }
74
+ /** Tasks as a person watches them: waiting, working, done, or failed with the reason. */
75
+ export function Checklist({ items, onRetry, progress = true, label = 'Progress', className }) {
76
+ const done = items.filter(item => item.state === 'done').length;
77
+ return (_jsxs("div", { className: ['desk-checklist', className].filter(Boolean).join(' '), children: [progress && (_jsx("div", { className: "desk-progress", role: "progressbar", "aria-label": label, "aria-valuemin": 0, "aria-valuemax": items.length, "aria-valuenow": done, children: _jsx("i", { style: { width: `${items.length ? (done / items.length) * 100 : 0}%` } }) })), _jsx("ul", { className: "desk-tasks", "aria-label": label, children: items.map(item => (_jsxs("li", { className: "desk-task", "data-state": item.state, children: [_jsx("span", { className: "desk-task-mark", "aria-hidden": "true", children: item.state === 'done' ? '✓' : item.state === 'failed' ? '!' : '' }), _jsxs("span", { className: "desk-task-text", children: [_jsx("span", { className: "desk-task-name", children: item.name }), item.state === 'failed' ? (_jsx("span", { className: "desk-task-error", role: "alert", children: item.error })) : (item.detail !== undefined && _jsx("span", { className: "desk-task-detail", children: item.detail }))] }), item.state === 'failed' && onRetry && (_jsx(Button, { size: "small", onClick: onRetry, children: "Try again" }))] }, item.id))) })] }));
78
+ }
79
+ //# sourceMappingURL=tasks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tasks.js","sourceRoot":"","sources":["../../src/react/tasks.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { DeskEvent } from '../core/events.js';
3
+ import type { WindowId } from '../core/types.js';
4
+ export interface TourStep {
5
+ /** Opened and made key before the step is shown. */
6
+ readonly window?: WindowId;
7
+ /** What to point at: a `data-tour` name, or any CSS selector. */
8
+ readonly point?: string;
9
+ readonly caption: ReactNode;
10
+ /** Hands over: the bar offers Done and Skip instead of Next. */
11
+ readonly yourTurn?: boolean;
12
+ /**
13
+ * The event that means the person has done it — `ride.selected`, or a topic and a test.
14
+ * The tour moves on by itself when it arrives, so nobody has to say Done.
15
+ */
16
+ readonly until?: string | {
17
+ readonly topic: string;
18
+ readonly when: (event: DeskEvent) => boolean;
19
+ };
20
+ }
21
+ export interface Tour {
22
+ readonly id: string;
23
+ readonly name: string;
24
+ /** What the tour shows, in a sentence: said when it is offered. */
25
+ readonly description?: ReactNode;
26
+ readonly steps: readonly TourStep[];
27
+ }
28
+ export interface TourBarProps {
29
+ readonly tour: Tour;
30
+ /** Called when the last step is finished. */
31
+ readonly onFinish?: () => void;
32
+ /** Called when the person stops early. */
33
+ readonly onStop?: () => void;
34
+ /**
35
+ * Ask first: the bar invites the person to take the tour, and starts only if they say so.
36
+ * For the first time someone reaches the desktop, where nobody should be dropped without a word.
37
+ */
38
+ readonly offer?: boolean;
39
+ readonly className?: string;
40
+ }
41
+ export declare function TourBar({ tour, onFinish, onStop, offer, className }: TourBarProps): import("react").JSX.Element | null;
42
+ //# sourceMappingURL=tour.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tour.d.ts","sourceRoot":"","sources":["../../src/react/tour.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAahD,MAAM,WAAW,QAAQ;IACvB,oDAAoD;IACpD,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAA;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;IAC3B,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAC3B;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAA;KAAE,CAAA;CACnG;AAED,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,mEAAmE;IACnE,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,CAAA;IAChC,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAA;CACpC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;IACnB,6CAA6C;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IAC9B,0CAA0C;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IAC5B;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAC5B;AAcD,wBAAgB,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,YAAY,sCAqHjF"}
@@ -0,0 +1,68 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useRef, useState } from 'react';
3
+ import { Button } from './controls.js';
4
+ import { useDesk } from './context.js';
5
+ import { useBus } from './events.js';
6
+ const POINTED = 'data-desk-tour-pointed';
7
+ function point(step) {
8
+ if (!step?.point)
9
+ return () => { };
10
+ const selector = step.point.startsWith('[') || step.point.includes('.') || step.point.includes('#') ? step.point : `[data-tour="${step.point}"]`;
11
+ const element = document.querySelector(selector);
12
+ if (!element)
13
+ return () => { };
14
+ element.setAttribute(POINTED, '');
15
+ element.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
16
+ return () => element.removeAttribute(POINTED);
17
+ }
18
+ export function TourBar({ tour, onFinish, onStop, offer, className }) {
19
+ const desk = useDesk();
20
+ const bus = useBus();
21
+ const [offered, setOffered] = useState(offer ?? false);
22
+ const [index, setIndex] = useState(0);
23
+ const step = offered ? undefined : tour.steps[index];
24
+ const total = tour.steps.length;
25
+ const stop = useRef(() => { });
26
+ // Enter the step: open the window it is about, then point at its control.
27
+ useEffect(() => {
28
+ if (!step)
29
+ return;
30
+ if (step.window)
31
+ desk.open(step.window);
32
+ stop.current();
33
+ // A frame later: the window it just opened has to exist before it can be pointed at.
34
+ const frame = requestAnimationFrame(() => {
35
+ stop.current = point(step);
36
+ });
37
+ return () => {
38
+ cancelAnimationFrame(frame);
39
+ stop.current();
40
+ stop.current = () => { };
41
+ };
42
+ }, [desk, step, index]);
43
+ const go = useCallback((to) => {
44
+ if (to >= total) {
45
+ onFinish?.();
46
+ return;
47
+ }
48
+ setIndex(Math.max(0, to));
49
+ }, [total, onFinish]);
50
+ // A step that waits for the person moves on when what it asked for happens.
51
+ const until = step?.until;
52
+ useEffect(() => {
53
+ if (!until)
54
+ return undefined;
55
+ const topic = typeof until === 'string' ? until : until.topic;
56
+ return bus.subscribe(topic, event => {
57
+ if (typeof until === 'string' || until.when(event))
58
+ go(index + 1);
59
+ });
60
+ }, [bus, until, go, index]);
61
+ if (offered) {
62
+ return (_jsxs("div", { className: ['desk-tour', className].filter(Boolean).join(' '), role: "region", "aria-label": `Tour: ${tour.name}`, children: [_jsxs("div", { className: "desk-tour-head", children: [_jsx("b", { children: tour.name }), _jsxs("span", { className: "desk-tour-count", children: [total, " steps"] })] }), tour.description && _jsx("p", { className: "desk-tour-caption", children: tour.description }), _jsxs("div", { className: "desk-tour-actions", children: [_jsx("span", { className: "desk-tour-spacer" }), _jsx(Button, { size: "small", onClick: () => onStop?.(), children: "Not now" }), _jsx(Button, { size: "small", intent: "default", onClick: () => setOffered(false), children: "Show me" })] })] }));
63
+ }
64
+ if (!step)
65
+ return null;
66
+ return (_jsxs("div", { className: ['desk-tour', className].filter(Boolean).join(' '), role: "region", "aria-label": `Tour: ${tour.name}`, children: [_jsxs("div", { className: "desk-tour-head", children: [_jsx("b", { children: tour.name }), _jsxs("span", { className: "desk-tour-count", children: ["Step ", index + 1, " of ", total] }), _jsx(Button, { size: "small", intent: "quiet", "aria-label": "Stop the tour", onClick: () => onStop?.(), children: "\u2715" })] }), _jsx("div", { className: "desk-tour-progress", role: "presentation", children: _jsx("i", { style: { width: `${((index + 1) / total) * 100}%` } }) }), _jsxs("p", { className: "desk-tour-caption", "data-your-turn": step.yourTurn || undefined, children: [step.yourTurn && _jsx("span", { className: "desk-tour-turn", children: "Your turn" }), step.caption] }), _jsxs("div", { className: "desk-tour-actions", children: [_jsx(Button, { size: "small", intent: "quiet", onClick: () => setIndex(0), children: "Restart" }), _jsx(Button, { size: "small", intent: "quiet", onClick: () => setIndex(index), children: "Show me again" }), _jsx("span", { className: "desk-tour-spacer" }), step.yourTurn ? (_jsxs(_Fragment, { children: [_jsx(Button, { size: "small", onClick: () => go(index + 1), children: "Skip" }), !step.until && (_jsx(Button, { size: "small", intent: "default", onClick: () => go(index + 1), children: "Done" }))] })) : (_jsxs(_Fragment, { children: [_jsx(Button, { size: "small", disabled: index === 0, onClick: () => go(index - 1), children: "\u2039 Back" }), _jsx(Button, { size: "small", intent: "default", onClick: () => go(index + 1), children: index === total - 1 ? 'Finish' : 'Next ›' })] }))] })] }));
67
+ }
68
+ //# sourceMappingURL=tour.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tour.js","sourceRoot":"","sources":["../../src/react/tour.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { ComponentType, ReactNode } from 'react';
2
+ import type { WindowId } from '../core/types.js';
3
+ export type WindowLoading = (id: WindowId) => ReactNode;
4
+ export type WindowFailed = (id: WindowId, error: Error, reload: () => void) => ReactNode;
5
+ export declare function WindowBoundary({ id, loading, failed, children, }: {
6
+ readonly id: WindowId;
7
+ readonly loading: WindowLoading | undefined;
8
+ readonly failed: WindowFailed | undefined;
9
+ readonly children: ReactNode;
10
+ }): import("react").JSX.Element;
11
+ /**
12
+ * A window whose code loads when it is first opened.
13
+ *
14
+ * const RoutePlanner = lazyWindow(() => import('./apps/RoutePlanner'))
15
+ *
16
+ * Unlike `React.lazy`, a load that fails is not remembered: Reload in the window
17
+ * tries the import again, so a dropped connection is not permanent.
18
+ */
19
+ export declare function lazyWindow<P extends object>(load: () => Promise<{
20
+ default: ComponentType<P>;
21
+ }>): ComponentType<P>;
22
+ //# sourceMappingURL=windowBoundary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windowBoundary.d.ts","sourceRoot":"","sources":["../../src/react/windowBoundary.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAkC,SAAS,EAAE,MAAM,OAAO,CAAA;AACrF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAUhD,MAAM,MAAM,aAAa,GAAG,CAAC,EAAE,EAAE,QAAQ,KAAK,SAAS,CAAA;AACvD,MAAM,MAAM,YAAY,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,IAAI,KAAK,SAAS,CAAA;AA0DxF,wBAAgB,cAAc,CAAC,EAC7B,EAAE,EACF,OAAO,EACP,MAAM,EACN,QAAQ,GACT,EAAE;IACD,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,aAAa,GAAG,SAAS,CAAA;IAC3C,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,CAAA;IACzC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAC7B,+BAMA;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;IAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;CAAE,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAYjH"}
@@ -0,0 +1,50 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Component, createContext, lazy, Suspense, useContext } from 'react';
3
+ import { Button } from './controls.js';
4
+ /** How many times this window has been reloaded: a lazy window loads afresh for each. */
5
+ const AttemptContext = createContext(0);
6
+ const defaultLoading = () => (_jsx("div", { className: "desk-window-status", role: "status", children: "Loading\u2026" }));
7
+ const defaultFailed = (_id, error, reload) => (_jsxs("div", { className: "desk-window-status", role: "alert", children: [_jsx("b", { children: "This window could not open" }), _jsx("span", { className: "desk-window-status-detail", children: error.message }), _jsx(Button, { size: "small", onClick: reload, children: "Reload" })] }));
8
+ class WindowErrorBoundary extends Component {
9
+ state = { error: null, attempt: 0 };
10
+ static getDerivedStateFromError(error) {
11
+ return { error: error instanceof Error ? error : new Error(String(error)) };
12
+ }
13
+ componentDidCatch(error, info) {
14
+ // Still reported: a window that cannot open is a bug somebody should hear about.
15
+ console.error(`desk: window "${this.props.id}" could not open`, error, info.componentStack);
16
+ }
17
+ reload = () => this.setState(state => ({ error: null, attempt: state.attempt + 1 }));
18
+ render() {
19
+ const { error, attempt } = this.state;
20
+ if (error)
21
+ return (this.props.failed ?? defaultFailed)(this.props.id, error, this.reload);
22
+ // A fresh key remounts the content, so a reload really starts again.
23
+ return (_jsx(AttemptContext.Provider, { value: attempt, children: this.props.children }, attempt));
24
+ }
25
+ }
26
+ export function WindowBoundary({ id, loading, failed, children, }) {
27
+ return (_jsx(WindowErrorBoundary, { id: id, failed: failed, children: _jsx(Suspense, { fallback: (loading ?? defaultLoading)(id), children: children }) }));
28
+ }
29
+ /**
30
+ * A window whose code loads when it is first opened.
31
+ *
32
+ * const RoutePlanner = lazyWindow(() => import('./apps/RoutePlanner'))
33
+ *
34
+ * Unlike `React.lazy`, a load that fails is not remembered: Reload in the window
35
+ * tries the import again, so a dropped connection is not permanent.
36
+ */
37
+ export function lazyWindow(load) {
38
+ const byAttempt = new Map();
39
+ function LazyWindow(props) {
40
+ const attempt = useContext(AttemptContext);
41
+ let Loaded = byAttempt.get(attempt);
42
+ if (!Loaded) {
43
+ Loaded = lazy(load);
44
+ byAttempt.set(attempt, Loaded);
45
+ }
46
+ return _jsx(Loaded, { ...props });
47
+ }
48
+ return LazyWindow;
49
+ }
50
+ //# sourceMappingURL=windowBoundary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windowBoundary.js","sourceRoot":"","sources":["../../src/react/windowBoundary.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { ReactNode } from 'react';
2
+ export interface WizardStep {
3
+ readonly id: string;
4
+ /** Named in the progress row, and announced as the step changes. */
5
+ readonly name: string;
6
+ readonly title: ReactNode;
7
+ readonly description?: ReactNode;
8
+ readonly body?: ReactNode;
9
+ /** Above the title. */
10
+ readonly glyph?: ReactNode;
11
+ /** Continue is offered only when this is true. Default: always. */
12
+ readonly complete?: boolean;
13
+ /** Replaces Continue's label on this step. */
14
+ readonly continueLabel?: string;
15
+ /** A quiet way past this step: "Set up later". */
16
+ readonly skip?: {
17
+ readonly label: string;
18
+ readonly onSkip: () => void;
19
+ };
20
+ /** Nothing to do but wait: no Back, and Continue waits for `complete`. */
21
+ readonly working?: boolean;
22
+ readonly onEnter?: () => void;
23
+ /**
24
+ * Work Continue does before moving on: create the account, check the key, download the maps.
25
+ * While it runs, Continue says so and nothing can be pressed twice. Throw to stay on the step
26
+ * and show why, in the step; return `false` to stay without a message.
27
+ */
28
+ readonly onContinue?: () => unknown;
29
+ /** Continue's label while `onContinue` runs. Default: "Working…". */
30
+ readonly busyLabel?: string;
31
+ }
32
+ export interface WizardProps {
33
+ readonly steps: readonly WizardStep[];
34
+ readonly index: number;
35
+ readonly onIndexChange: (index: number) => void;
36
+ readonly onFinish: () => void;
37
+ readonly label?: string;
38
+ readonly className?: string;
39
+ }
40
+ export declare function Wizard({ steps, index, onIndexChange, onFinish, label, className }: WizardProps): import("react").JSX.Element | null;
41
+ //# sourceMappingURL=wizard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wizard.d.ts","sourceRoot":"","sources":["../../src/react/wizard.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAYtC,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,oEAAoE;IACpE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAA;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,CAAA;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAA;IACzB,uBAAuB;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAA;IAC1B,mEAAmE;IACnE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAC3B,8CAA8C;IAC9C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B,kDAAkD;IAClD,QAAQ,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAA;KAAE,CAAA;IACvE,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,OAAO,CAAA;IACnC,qEAAqE;IACrE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAA;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED,wBAAgB,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAe,EAAE,SAAS,EAAE,EAAE,WAAW,sCAmGxG"}
@@ -0,0 +1,60 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from 'react';
3
+ import { Button } from './controls.js';
4
+ export function Wizard({ steps, index, onIndexChange, onFinish, label = 'Setup', className }) {
5
+ const step = steps[index];
6
+ const [direction, setDirection] = useState('forward');
7
+ const previous = useRef(index);
8
+ const heading = useRef(null);
9
+ const entered = useRef(undefined);
10
+ entered.current = step?.onEnter;
11
+ const [busy, setBusy] = useState(false);
12
+ const [error, setError] = useState(null);
13
+ // The step a running `onContinue` belongs to: if the person has gone back meanwhile, its result is stale.
14
+ const running = useRef(null);
15
+ // Only when the step changes: a step whose body has a field re-renders on every
16
+ // keystroke, and moving focus to the heading then would eat what was being typed.
17
+ useEffect(() => {
18
+ setDirection(index >= previous.current ? 'forward' : 'back');
19
+ setBusy(false);
20
+ setError(null);
21
+ running.current = null;
22
+ previous.current = index;
23
+ entered.current?.();
24
+ // Focus the new step's heading, so a screen reader announces it and the
25
+ // keyboard starts at the top of the pane rather than back at the buttons.
26
+ heading.current?.focus();
27
+ }, [index]);
28
+ if (!step)
29
+ return null;
30
+ const last = index === steps.length - 1;
31
+ const canContinue = step.complete ?? true;
32
+ const go = (to) => (to >= steps.length ? onFinish() : onIndexChange(Math.max(0, to)));
33
+ const next = async () => {
34
+ if (!step.onContinue)
35
+ return go(index + 1);
36
+ if (running.current !== null)
37
+ return;
38
+ running.current = index;
39
+ setBusy(true);
40
+ setError(null);
41
+ try {
42
+ const result = await step.onContinue();
43
+ if (running.current !== index)
44
+ return;
45
+ running.current = null;
46
+ setBusy(false);
47
+ if (result !== false)
48
+ go(index + 1);
49
+ }
50
+ catch (failure) {
51
+ if (running.current !== index)
52
+ return;
53
+ running.current = null;
54
+ setBusy(false);
55
+ setError(failure instanceof Error ? failure.message : String(failure));
56
+ }
57
+ };
58
+ return (_jsxs("section", { className: ['desk-wizard', className].filter(Boolean).join(' '), "aria-label": label, children: [_jsxs("div", { className: "desk-wizard-content", "data-direction": direction, children: [step.glyph && _jsx("div", { className: "desk-wizard-glyph", "aria-hidden": "true", children: step.glyph }), _jsx("h1", { ref: heading, tabIndex: -1, className: "desk-wizard-title", children: step.title }), step.description && _jsx("p", { className: "desk-wizard-description", children: step.description }), step.body, error && (_jsx("p", { className: "desk-wizard-error", role: "alert", children: error }))] }, step.id), _jsxs("footer", { className: "desk-wizard-foot", children: [_jsx("ol", { className: "desk-wizard-steps", "aria-label": "Progress", children: steps.map((other, i) => (_jsx("li", { className: "desk-wizard-dot", "data-state": i === index ? 'now' : i < index ? 'done' : 'ahead', "aria-current": i === index ? 'step' : undefined, children: _jsx("span", { className: "desk-wizard-dot-name", children: other.name }) }, other.id))) }), _jsx("span", { className: "desk-wizard-step-name", "aria-live": "polite", children: step.name }), _jsxs("div", { className: "desk-wizard-actions", children: [step.skip && (_jsx(Button, { intent: "quiet", disabled: busy, onClick: step.skip.onSkip, children: step.skip.label })), index > 0 && !step.working && (_jsx(Button, { disabled: busy, onClick: () => go(index - 1), children: "Back" })), _jsx(Button, { intent: "default", disabled: !canContinue || busy, "aria-busy": busy || undefined, onClick: () => void next(), children: busy ? (step.busyLabel ?? 'Working…') : (step.continueLabel ?? (last ? 'Done' : 'Continue')) })] })] })] }));
59
+ }
60
+ //# sourceMappingURL=wizard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wizard.js","sourceRoot":"","sources":["../../src/react/wizard.tsx"],"names":[],"mappings":"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"}