@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,40 @@
1
+ import type { Desk } from './desk.js';
2
+ export type CommandId = string;
3
+ /** Marks a window's element, so the chain can start at the key window. */
4
+ export declare const WINDOW_ATTRIBUTE = "data-desk-window";
5
+ /** Marks the stage, the desk-level responder. */
6
+ export declare const STAGE_ATTRIBUTE = "data-desk-stage";
7
+ export type CommandHandler<Args = unknown> = (args: Args) => void;
8
+ export interface CommandOptions {
9
+ /** Whether the handler can act right now. Asked before performing and when a menu opens. Default: always. */
10
+ readonly enabled?: () => boolean;
11
+ }
12
+ /**
13
+ * Makes `element` a responder for `command`. Returns a function that removes it.
14
+ * Attach to `document` for an app-level responder.
15
+ */
16
+ export declare function addCommandHandler<Args = unknown>(element: EventTarget, command: CommandId, handler: CommandHandler<Args>, options?: CommandOptions): () => void;
17
+ export interface ChainOptions {
18
+ /** Start here instead of at the focused element. */
19
+ readonly from?: Element | null;
20
+ readonly document?: Document;
21
+ }
22
+ /** Where a command starts: focus inside the key window, else the key window, else the stage, else the document. */
23
+ export declare function chainStart(desk: Desk | null, options?: ChainOptions): EventTarget;
24
+ export declare const windowElement: (doc: ParentNode, id: string) => Element | null;
25
+ /** Sends a command along the chain. Returns whether anything handled it. */
26
+ export declare function perform<Args = unknown>(desk: Desk | null, command: CommandId, args?: Args, options?: ChainOptions): boolean;
27
+ /** Asks the chain whether a command would be handled right now. */
28
+ export declare function canPerform(desk: Desk | null, command: CommandId, options?: ChainOptions): boolean;
29
+ /** The commands the desk itself answers, at the stage. */
30
+ export declare const DeskCommands: {
31
+ readonly closeWindow: 'desk.window.close';
32
+ /** Fills the key window, or frees it: the green control. */
33
+ readonly zoomWindow: 'desk.window.zoom';
34
+ /** Answered by a mounted Desktop, which knows the space windows are laid out in. */
35
+ readonly arrange: 'desk.window.arrange';
36
+ readonly nextWindow: 'desk.window.next';
37
+ readonly previousWindow: 'desk.window.previous';
38
+ };
39
+ export declare function addDeskCommands(stage: EventTarget, desk: Desk): () => void;
40
+ //# sourceMappingURL=commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/core/commands.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAgBrC,MAAM,MAAM,SAAS,GAAG,MAAM,CAAA;AAE9B,0EAA0E;AAC1E,eAAO,MAAM,gBAAgB,qBAAqB,CAAA;AAClD,iDAAiD;AACjD,eAAO,MAAM,eAAe,oBAAoB,CAAA;AAgBhD,MAAM,MAAM,cAAc,CAAC,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;AAEjE,MAAM,WAAW,cAAc;IAC7B,6GAA6G;IAC7G,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,OAAO,CAAA;CACjC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,GAAG,OAAO,EAC9C,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,SAAS,EAClB,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,EAC7B,OAAO,GAAE,cAAmB,GAC3B,MAAM,IAAI,CAyBZ;AAED,MAAM,WAAW,YAAY;IAC3B,oDAAoD;IACpD,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAA;CAC7B;AAED,mHAAmH;AACnH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO,GAAE,YAAiB,GAAG,WAAW,CAQrF;AAED,eAAO,MAAM,aAAa,QAAS,UAAU,MAAM,MAAM,KAAG,OAAO,GAAG,IAC2C,CAAA;AAEjH,4EAA4E;AAC5E,wBAAgB,OAAO,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAI/H;AAED,mEAAmE;AACnE,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAIrG;AAED,0DAA0D;AAC1D,eAAO,MAAM,YAAY;aACvB,WAAW,EAAE,mBAAmB;IAChC,4DAA4D;aAC5D,UAAU,EAAE,kBAAkB;IAC9B,oFAAoF;aACpF,OAAO,EAAE,qBAAqB;aAC9B,UAAU,EAAE,kBAAkB;aAC9B,cAAc,EAAE,sBAAsB;CAC9B,CAAA;AAEV,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,IAAI,CAe1E"}
@@ -0,0 +1,92 @@
1
+ import { focusedId } from './desk.js';
2
+ /** Marks a window's element, so the chain can start at the key window. */
3
+ export const WINDOW_ATTRIBUTE = 'data-desk-window';
4
+ /** Marks the stage, the desk-level responder. */
5
+ export const STAGE_ATTRIBUTE = 'data-desk-stage';
6
+ const PERFORM = 'desk:perform';
7
+ const QUERY = 'desk:can-perform';
8
+ /**
9
+ * Makes `element` a responder for `command`. Returns a function that removes it.
10
+ * Attach to `document` for an app-level responder.
11
+ */
12
+ export function addCommandHandler(element, command, handler, options = {}) {
13
+ const enabled = options.enabled ?? (() => true);
14
+ const onPerform = (event) => {
15
+ const detail = event.detail;
16
+ if (detail.command !== command)
17
+ return;
18
+ event.stopPropagation();
19
+ if (!enabled())
20
+ return;
21
+ detail.handled = true;
22
+ handler(detail.args);
23
+ };
24
+ const onQuery = (event) => {
25
+ const detail = event.detail;
26
+ if (detail.command !== command)
27
+ return;
28
+ event.stopPropagation();
29
+ detail.enabled = enabled();
30
+ };
31
+ element.addEventListener(PERFORM, onPerform);
32
+ element.addEventListener(QUERY, onQuery);
33
+ return () => {
34
+ element.removeEventListener(PERFORM, onPerform);
35
+ element.removeEventListener(QUERY, onQuery);
36
+ };
37
+ }
38
+ /** Where a command starts: focus inside the key window, else the key window, else the stage, else the document. */
39
+ export function chainStart(desk, options = {}) {
40
+ if (options.from)
41
+ return options.from;
42
+ const doc = options.document ?? globalThis.document;
43
+ const key = desk ? focusedId(desk.getState()) : null;
44
+ const window = key ? windowElement(doc, key) : null;
45
+ const active = doc.activeElement;
46
+ if (window && active && window.contains(active))
47
+ return active;
48
+ return window ?? doc.querySelector(`[${STAGE_ATTRIBUTE}]`) ?? doc;
49
+ }
50
+ export const windowElement = (doc, id) => [...doc.querySelectorAll(`[${WINDOW_ATTRIBUTE}]`)].find(el => el.getAttribute(WINDOW_ATTRIBUTE) === id) ?? null;
51
+ /** Sends a command along the chain. Returns whether anything handled it. */
52
+ export function perform(desk, command, args, options = {}) {
53
+ const detail = { command, args, handled: false };
54
+ chainStart(desk, options).dispatchEvent(new CustomEvent(PERFORM, { detail, bubbles: true, composed: true }));
55
+ return detail.handled;
56
+ }
57
+ /** Asks the chain whether a command would be handled right now. */
58
+ export function canPerform(desk, command, options = {}) {
59
+ const detail = { command, enabled: undefined };
60
+ chainStart(desk, options).dispatchEvent(new CustomEvent(QUERY, { detail, bubbles: true, composed: true }));
61
+ return detail.enabled ?? false;
62
+ }
63
+ /** The commands the desk itself answers, at the stage. */
64
+ export const DeskCommands = {
65
+ closeWindow: 'desk.window.close',
66
+ /** Fills the key window, or frees it: the green control. */
67
+ zoomWindow: 'desk.window.zoom',
68
+ /** Answered by a mounted Desktop, which knows the space windows are laid out in. */
69
+ arrange: 'desk.window.arrange',
70
+ nextWindow: 'desk.window.next',
71
+ previousWindow: 'desk.window.previous',
72
+ };
73
+ export function addDeskCommands(stage, desk) {
74
+ const key = () => focusedId(desk.getState());
75
+ const cycle = (step) => {
76
+ const { windows } = desk.getState();
77
+ const current = windows.findIndex(w => w.id === key());
78
+ const next = windows[(current + step + windows.length) % windows.length];
79
+ if (next)
80
+ desk.focus(next.id);
81
+ };
82
+ const removers = [
83
+ addCommandHandler(stage, DeskCommands.closeWindow, () => { const id = key(); if (id)
84
+ desk.close(id); }, { enabled: () => key() !== null }),
85
+ addCommandHandler(stage, DeskCommands.zoomWindow, () => { const id = key(); if (id)
86
+ desk.toggleMode(id); }, { enabled: () => key() !== null }),
87
+ addCommandHandler(stage, DeskCommands.nextWindow, () => cycle(1), { enabled: () => desk.getState().windows.length > 1 }),
88
+ addCommandHandler(stage, DeskCommands.previousWindow, () => cycle(-1), { enabled: () => desk.getState().windows.length > 1 }),
89
+ ];
90
+ return () => removers.forEach(remove => remove());
91
+ }
92
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/core/commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import type { CascadeOptions, DeskOptions, DeskState, DeskWindow, Frame, OpenOptions, Size, WindowId } from './types.js';
2
+ export interface Desk {
3
+ getState(): DeskState;
4
+ subscribe(listener: (state: DeskState) => void): () => void;
5
+ /** Opens a window filling the desk, over the ones already open, or brings it to the front if it is open. */
6
+ open(id: WindowId, options?: OpenOptions): void;
7
+ /** Opens another window of the same kind — `query#2` beside `query` — and returns its id. */
8
+ openInstance(type: string, options?: OpenOptions): WindowId;
9
+ close(id: WindowId): void;
10
+ closeAll(): void;
11
+ focus(id: WindowId): void;
12
+ /** Frees a window: where it last was, or at the next step of the cascade. Given a frame, puts it there. */
13
+ float(id: WindowId, frame?: Frame): void;
14
+ /** Makes a window fill the desk, remembering where it was so freeing it again puts it back. */
15
+ fill(id: WindowId): void;
16
+ /** Zooms: fills a free window, or frees a filled one. */
17
+ toggleMode(id: WindowId): void;
18
+ /** Places windows exactly where they are given, as free windows. Arrange uses it. */
19
+ placeAll(frames: Readonly<Record<WindowId, Frame>>): void;
20
+ /** Replaces the whole state, e.g. from a URL. Unknown shapes are normalised, not trusted. */
21
+ restore(state: DeskState): void;
22
+ setStage(stage: () => Size): void;
23
+ }
24
+ export declare const EMPTY: DeskState;
25
+ export declare const focusedId: (state: DeskState) => WindowId | null;
26
+ /**
27
+ * Two windows onto the same thing — a second query beside the first — are the
28
+ * same kind with different ids: `query`, then `query#2`. The part before the
29
+ * `#` says what to render; the whole id says which one this is.
30
+ */
31
+ export declare const windowType: (id: WindowId) => string;
32
+ export declare const instancesOf: (state: DeskState, type: string) => readonly DeskWindow[];
33
+ export declare const isOpen: (state: DeskState, id: WindowId) => boolean;
34
+ export declare function cascadeFrame(floatingCount: number, stage: Size, options?: CascadeOptions): Frame;
35
+ /** Which cascade step a frame sits on, or -1 once it has been dragged off one. */
36
+ export declare function cascadeSlot(frame: Frame, stage: Size, options?: CascadeOptions): number;
37
+ /**
38
+ * The next free step of the cascade. Counting floating windows is not enough: a
39
+ * window closed from the middle frees its step, and the count wraps — either way
40
+ * a new window would open exactly on top of one already there, hiding it.
41
+ */
42
+ export declare function nextCascadeFrame(windows: readonly DeskWindow[], stage: Size, options?: CascadeOptions): Frame;
43
+ /** Drops duplicate ids and makes the stack agree with the windows. */
44
+ export declare function normalise(state: DeskState): DeskState;
45
+ export declare function createDesk(options?: DeskOptions): Desk;
46
+ //# sourceMappingURL=desk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"desk.d.ts","sourceRoot":"","sources":["../../src/core/desk.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,WAAW,EACX,SAAS,EACT,UAAU,EACV,KAAK,EACL,WAAW,EACX,IAAI,EACJ,QAAQ,EACT,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,IAAI;IACnB,QAAQ,IAAI,SAAS,CAAA;IACrB,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,GAAG,MAAM,IAAI,CAAA;IAC3D,4GAA4G;IAC5G,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,IAAI,CAAA;IAC/C,6FAA6F;IAC7F,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAA;IAC3D,KAAK,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAAA;IACzB,QAAQ,IAAI,IAAI,CAAA;IAChB,KAAK,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAAA;IACzB,2GAA2G;IAC3G,KAAK,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,CAAA;IACxC,+FAA+F;IAC/F,IAAI,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAAA;IACxB,yDAAyD;IACzD,UAAU,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAAA;IAC9B,qFAAqF;IACrF,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,GAAG,IAAI,CAAA;IACzD,6FAA6F;IAC7F,OAAO,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAA;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,GAAG,IAAI,CAAA;CAClC;AAED,eAAO,MAAM,KAAK,EAAE,SAAsC,CAAA;AAY1D,eAAO,MAAM,SAAS,UAAW,SAAS,KAAG,QAAQ,GAAG,IAAkC,CAAA;AAE1F;;;;GAIG;AACH,eAAO,MAAM,UAAU,OAAQ,QAAQ,KAAG,MAAgC,CAAA;AAE1E,eAAO,MAAM,WAAW,UAAW,SAAS,QAAQ,MAAM,KAAG,SAAS,UAAU,EAC1B,CAAA;AAEtD,eAAO,MAAM,MAAM,UAAW,SAAS,MAAM,QAAQ,KAAG,OAA+C,CAAA;AAEvG,wBAAgB,YAAY,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,GAAE,cAAgC,GAAG,KAAK,CAUjH;AAED,kFAAkF;AAClF,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,GAAE,cAAgC,GAAG,MAAM,CAMxG;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,GAAE,cAAgC,GAAG,KAAK,CAM9H;AAED,sEAAsE;AACtE,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CAMrD;AAED,wBAAgB,UAAU,CAAC,OAAO,GAAE,WAAgB,GAAG,IAAI,CA6H1D"}
@@ -0,0 +1,178 @@
1
+ export const EMPTY = { windows: [], stack: [] };
2
+ const DEFAULT_CASCADE = {
3
+ maxWidth: 720,
4
+ maxHeight: 520,
5
+ margin: 16,
6
+ step: { x: 32, y: 28 },
7
+ wrap: 6,
8
+ };
9
+ const DEFAULT_STAGE = { width: 1024, height: 768 };
10
+ export const focusedId = (state) => state.stack.at(-1) ?? null;
11
+ /**
12
+ * Two windows onto the same thing — a second query beside the first — are the
13
+ * same kind with different ids: `query`, then `query#2`. The part before the
14
+ * `#` says what to render; the whole id says which one this is.
15
+ */
16
+ export const windowType = (id) => id.split('#')[0] ?? id;
17
+ export const instancesOf = (state, type) => state.windows.filter(w => windowType(w.id) === type);
18
+ export const isOpen = (state, id) => state.windows.some(w => w.id === id);
19
+ export function cascadeFrame(floatingCount, stage, options = DEFAULT_CASCADE) {
20
+ const width = Math.max(0, Math.min(options.maxWidth, stage.width - options.margin * 2));
21
+ const height = Math.max(0, Math.min(options.maxHeight, stage.height - options.margin * 2));
22
+ const n = floatingCount % options.wrap;
23
+ return {
24
+ x: Math.min(options.margin + n * options.step.x, Math.max(0, stage.width - width - options.margin)),
25
+ y: Math.min(options.margin + n * options.step.y, Math.max(0, stage.height - height - options.margin)),
26
+ width,
27
+ height,
28
+ };
29
+ }
30
+ /** Which cascade step a frame sits on, or -1 once it has been dragged off one. */
31
+ export function cascadeSlot(frame, stage, options = DEFAULT_CASCADE) {
32
+ for (let slot = 0; slot < options.wrap; slot++) {
33
+ const candidate = cascadeFrame(slot, stage, options);
34
+ if (candidate.x === frame.x && candidate.y === frame.y)
35
+ return slot;
36
+ }
37
+ return -1;
38
+ }
39
+ /**
40
+ * The next free step of the cascade. Counting floating windows is not enough: a
41
+ * window closed from the middle frees its step, and the count wraps — either way
42
+ * a new window would open exactly on top of one already there, hiding it.
43
+ */
44
+ export function nextCascadeFrame(windows, stage, options = DEFAULT_CASCADE) {
45
+ const taken = new Set(windows.flatMap(w => (w.mode === 'floating' ? [cascadeSlot(w.frame, stage, options)] : [])));
46
+ for (let slot = 0; slot < options.wrap; slot++)
47
+ if (!taken.has(slot))
48
+ return cascadeFrame(slot, stage, options);
49
+ return cascadeFrame(taken.size % options.wrap, stage, options);
50
+ }
51
+ /** Drops duplicate ids and makes the stack agree with the windows. */
52
+ export function normalise(state) {
53
+ const windows = state.windows.filter((w, i, all) => all.findIndex(o => o.id === w.id) === i);
54
+ const ids = new Set(windows.map(w => w.id));
55
+ const stacked = state.stack.filter((id, i, all) => ids.has(id) && all.indexOf(id) === i);
56
+ const unstacked = windows.map(w => w.id).filter(id => !stacked.includes(id));
57
+ return { windows, stack: [...unstacked, ...stacked] };
58
+ }
59
+ export function createDesk(options = {}) {
60
+ const cascade = { ...DEFAULT_CASCADE, ...options.cascade };
61
+ let stage = options.stage ?? (() => DEFAULT_STAGE);
62
+ let state = normalise(options.initial ?? EMPTY);
63
+ const listeners = new Set();
64
+ const commit = (next) => {
65
+ if (next === state)
66
+ return;
67
+ state = next;
68
+ listeners.forEach(listener => listener(state));
69
+ };
70
+ const toFront = (s, id) => s.stack.at(-1) === id ? s : { ...s, stack: [...s.stack.filter(x => x !== id), id] };
71
+ const nextFrame = (s) => nextCascadeFrame(s.windows, stage(), cascade);
72
+ const replace = (s, window) => ({
73
+ ...s,
74
+ windows: s.windows.map(w => (w.id === window.id ? window : w)),
75
+ });
76
+ const find = (id) => state.windows.find(w => w.id === id);
77
+ /** Where each window was last free, so filling it and freeing it again is not a surprise. */
78
+ const remembered = new Map();
79
+ /** A remembered frame is only worth restoring while it still lands on this screen. */
80
+ const fits = (frame) => {
81
+ if (!frame)
82
+ return undefined;
83
+ const { width, height } = stage();
84
+ return frame.x + 40 <= width && frame.y + 20 <= height && frame.x >= 0 && frame.y >= 0 ? frame : undefined;
85
+ };
86
+ // Plain functions rather than methods, so `const { open } = desk` works.
87
+ const float = (id, frame) => {
88
+ const window = find(id);
89
+ if (!window)
90
+ return;
91
+ if (window.mode === 'floating' && !frame)
92
+ return;
93
+ const next = frame ?? fits(remembered.get(id)) ?? nextFrame(state);
94
+ if (frame)
95
+ remembered.set(id, frame);
96
+ commit(toFront(replace(state, { id, mode: 'floating', frame: next }), id));
97
+ };
98
+ const fill = (id) => {
99
+ const window = find(id);
100
+ if (!window || window.mode === 'filled')
101
+ return;
102
+ remembered.set(id, window.frame);
103
+ commit(toFront(replace(state, { id, mode: 'filled' }), id));
104
+ };
105
+ return {
106
+ getState: () => state,
107
+ subscribe(listener) {
108
+ listeners.add(listener);
109
+ return () => {
110
+ listeners.delete(listener);
111
+ };
112
+ },
113
+ open(id, opts = {}) {
114
+ if (find(id)) {
115
+ commit(toFront(state, id));
116
+ return;
117
+ }
118
+ const mode = opts.mode ?? (opts.frame ? 'floating' : 'filled');
119
+ const window = mode === 'filled' ? { id, mode } : { id, mode, frame: opts.frame ?? nextFrame(state) };
120
+ commit({ windows: [...state.windows, window], stack: [...state.stack, id] });
121
+ },
122
+ openInstance(type, opts = {}) {
123
+ const taken = new Set(state.windows.map(w => w.id));
124
+ let id = type;
125
+ for (let n = 2; taken.has(id); n++)
126
+ id = `${type}#${n}`;
127
+ this.open(id, opts);
128
+ return id;
129
+ },
130
+ close(id) {
131
+ if (find(id))
132
+ commit({ windows: state.windows.filter(w => w.id !== id), stack: state.stack.filter(x => x !== id) });
133
+ },
134
+ closeAll() {
135
+ if (state.windows.length)
136
+ commit(EMPTY);
137
+ },
138
+ focus(id) {
139
+ if (find(id))
140
+ commit(toFront(state, id));
141
+ },
142
+ float,
143
+ fill,
144
+ toggleMode(id) {
145
+ const window = find(id);
146
+ if (!window)
147
+ return;
148
+ if (window.mode === 'filled')
149
+ float(id);
150
+ else
151
+ fill(id);
152
+ },
153
+ placeAll(frames) {
154
+ const ids = Object.keys(frames);
155
+ if (!ids.length)
156
+ return;
157
+ ids.forEach(id => {
158
+ const frame = frames[id];
159
+ if (frame)
160
+ remembered.set(id, frame);
161
+ });
162
+ commit({
163
+ ...state,
164
+ windows: state.windows.map(w => {
165
+ const frame = frames[w.id];
166
+ return frame ? { id: w.id, mode: 'floating', frame } : w;
167
+ }),
168
+ });
169
+ },
170
+ restore(next) {
171
+ commit(normalise(next));
172
+ },
173
+ setStage(next) {
174
+ stage = next;
175
+ },
176
+ };
177
+ }
178
+ //# sourceMappingURL=desk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"desk.js","sourceRoot":"","sources":["../../src/core/desk.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import type { WindowId } from './types.js';
2
+ export interface DeskEvent<T = unknown> {
3
+ readonly topic: string;
4
+ readonly payload: T;
5
+ /** The window it came from, when it came from one. */
6
+ readonly from: WindowId | null;
7
+ readonly at: number;
8
+ }
9
+ export type EventHandler<T = unknown> = (event: DeskEvent<T>) => void;
10
+ export interface SubscribeOptions {
11
+ /**
12
+ * Deliver the last event on this topic straight away, if there was one. A window
13
+ * opened by the event that concerns it would otherwise miss it by a frame.
14
+ */
15
+ readonly replay?: boolean;
16
+ }
17
+ export interface Bus {
18
+ publish<T>(topic: string, payload: T, options?: {
19
+ readonly from?: WindowId | null;
20
+ }): DeskEvent<T>;
21
+ subscribe<T>(topic: string, handler: EventHandler<T>, options?: SubscribeOptions): () => void;
22
+ /** The last event on a topic, if one has been published. */
23
+ last<T>(topic: string): DeskEvent<T> | undefined;
24
+ }
25
+ export declare function topicMatches(pattern: string, topic: string): boolean;
26
+ export declare function createBus(): Bus;
27
+ export declare const InputCommands: {
28
+ /** Brings up the bar. A menu item can perform this, as a shortcut does. */
29
+ readonly open: 'desk.input.open';
30
+ /** Sent with the text. A window that takes typed input answers this. */
31
+ readonly submit: 'desk.input.submit';
32
+ /** Asks the chain how the bar should present itself for the key window. */
33
+ readonly describe: 'desk.input.describe';
34
+ };
35
+ /** Filled in by whichever responder answers `desk.input.describe`. */
36
+ export interface InputDescription {
37
+ placeholder?: string;
38
+ /** What the text will reach, for the bar to show: "Rides", "Chat". */
39
+ target?: string;
40
+ disabled?: boolean;
41
+ }
42
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/core/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAW1C,MAAM,WAAW,SAAS,CAAC,CAAC,GAAG,OAAO;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAA;IACnB,sDAAsD;IACtD,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAA;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,MAAM,YAAY,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;AAErE,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAC1B;AAED,MAAM,WAAW,GAAG;IAClB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAA;KAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;IAClG,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,MAAM,IAAI,CAAA;IAC7F,4DAA4D;IAC5D,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAA;CACjD;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAKpE;AAED,wBAAgB,SAAS,IAAI,GAAG,CAoC/B;AAID,eAAO,MAAM,aAAa;IACxB,2EAA2E;aAC3E,IAAI,EAAE,iBAAiB;IACvB,wEAAwE;aACxE,MAAM,EAAE,mBAAmB;IAC3B,2EAA2E;aAC3E,QAAQ,EAAE,qBAAqB;CACvB,CAAA;AAEV,sEAAsE;AACtE,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB"}
@@ -0,0 +1,54 @@
1
+ export function topicMatches(pattern, topic) {
2
+ if (pattern === '*' || pattern === topic)
3
+ return true;
4
+ if (!pattern.endsWith('.*'))
5
+ return false;
6
+ const branch = pattern.slice(0, -2);
7
+ return topic === branch || topic.startsWith(`${branch}.`);
8
+ }
9
+ export function createBus() {
10
+ const subscribers = new Set();
11
+ const latest = new Map();
12
+ return {
13
+ publish(topic, payload, options = {}) {
14
+ const event = { topic, payload, from: options.from ?? null, at: Date.now() };
15
+ latest.set(topic, event);
16
+ // Copy first: a handler may subscribe or unsubscribe while this one is being delivered.
17
+ for (const subscriber of [...subscribers]) {
18
+ if (subscribers.has(subscriber) && topicMatches(subscriber.pattern, topic)) {
19
+ ;
20
+ subscriber.handler(event);
21
+ }
22
+ }
23
+ return event;
24
+ },
25
+ subscribe(topic, handler, options = {}) {
26
+ const subscriber = { pattern: topic, handler: handler };
27
+ subscribers.add(subscriber);
28
+ if (options.replay) {
29
+ const previous = [...latest.values()]
30
+ .filter(event => topicMatches(topic, event.topic))
31
+ .sort((a, b) => a.at - b.at)
32
+ .at(-1);
33
+ if (previous)
34
+ handler(previous);
35
+ }
36
+ return () => {
37
+ subscribers.delete(subscriber);
38
+ };
39
+ },
40
+ last(topic) {
41
+ return latest.get(topic);
42
+ },
43
+ };
44
+ }
45
+ /* ── Typed input: text with no target, which goes to the key window ── */
46
+ export const InputCommands = {
47
+ /** Brings up the bar. A menu item can perform this, as a shortcut does. */
48
+ open: 'desk.input.open',
49
+ /** Sent with the text. A window that takes typed input answers this. */
50
+ submit: 'desk.input.submit',
51
+ /** Asks the chain how the bar should present itself for the key window. */
52
+ describe: 'desk.input.describe',
53
+ };
54
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/core/events.ts"],"names":[],"mappings":"AAoCA,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,KAAa;IACzD,IAAI,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,KAAK;QAAE,OAAO,IAAI,CAAA;IACrD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAA;IACzC,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IACnC,OAAO,KAAK,KAAK,MAAM,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,CAAC,CAAA;AAC3D,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,MAAM,WAAW,GAAG,IAAI,GAAG,EAAqD,CAAA;IAChF,MAAM,MAAM,GAAG,IAAI,GAAG,EAA8B,CAAA;IAEpD,OAAO;QACL,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE;YAClC,MAAM,KAAK,GAA8B,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAA;YACvG,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,KAA2B,CAAC,CAAA;YAC9C,wFAAwF;YACxF,KAAK,MAAM,UAAU,IAAI,CAAC,GAAG,WAAW,CAAC,EAAE,CAAC;gBAC1C,IAAI,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,YAAY,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC;oBAC3E,CAAC;oBAAC,UAAU,CAAC,OAAwC,CAAC,KAAK,CAAC,CAAA;gBAC9D,CAAC;YACH,CAAC;YACD,OAAO,KAAK,CAAA;QACd,CAAC;QAED,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE;YACpC,MAAM,UAAU,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAA8B,EAAE,CAAA;YAC9E,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;YAC3B,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACnB,MAAM,QAAQ,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;qBAClC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;qBACjD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;qBAC3B,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;gBACT,IAAI,QAAQ;oBAAG,OAAiC,CAAC,QAAQ,CAAC,CAAA;YAC5D,CAAC;YACD,OAAO,GAAG,EAAE;gBACV,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;YAChC,CAAC,CAAA;QACH,CAAC;QAED,IAAI,CAAC,KAAK;YACR,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,CAAiC,CAAA;QAC1D,CAAC;KACF,CAAA;AACH,CAAC;AAED,0EAA0E;AAE1E,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,2EAA2E;IAC3E,IAAI,EAAE,iBAAiB;IACvB,wEAAwE;IACxE,MAAM,EAAE,mBAAmB;IAC3B,2EAA2E;IAC3E,QAAQ,EAAE,qBAAqB;CACvB,CAAA"}
@@ -0,0 +1,13 @@
1
+ export { createDesk, cascadeFrame, cascadeSlot, focusedId, instancesOf, isOpen, nextCascadeFrame, normalise, windowType, EMPTY, } from './desk.js';
2
+ export type { Desk } from './desk.js';
3
+ export { addCommandHandler, addDeskCommands, canPerform, chainStart, DeskCommands, perform, STAGE_ATTRIBUTE, WINDOW_ATTRIBUTE, windowElement, } from './commands.js';
4
+ export type { ChainOptions, CommandHandler, CommandId, CommandOptions } from './commands.js';
5
+ export { createBus, InputCommands, topicMatches } from './events.js';
6
+ export type { Bus, DeskEvent, EventHandler, InputDescription, SubscribeOptions } from './events.js';
7
+ export { bindShortcuts, formatShortcut, isApplePlatform, isInstalledApp, matchesShortcut, parseShortcut } from './shortcuts.js';
8
+ export type { Keymap, Shortcut, ShortcutOptions } from './shortcuts.js';
9
+ export { parse, serialize, syncWithLocation } from './location.js';
10
+ export { isTitleCase, titleCase } from './titles.js';
11
+ export type { LocationEnv, LocationOptions } from './location.js';
12
+ export type { CascadeOptions, DeskOptions, DeskState, DeskWindow, Frame, OpenOptions, Size, WindowId, WindowMode, } from './types.js';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,YAAY,EACZ,WAAW,EACX,SAAS,EACT,WAAW,EACX,MAAM,EACN,gBAAgB,EAChB,SAAS,EACT,UAAU,EACV,KAAK,GACN,MAAM,WAAW,CAAA;AAClB,YAAY,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,UAAU,EACV,UAAU,EACV,YAAY,EACZ,OAAO,EACP,eAAe,EACf,gBAAgB,EAChB,aAAa,GACd,MAAM,eAAe,CAAA;AACtB,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC5F,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AACpE,YAAY,EAAE,GAAG,EAAE,SAAS,EAAE,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AACnG,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAC/H,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AACvE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAClE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACpD,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACjE,YAAY,EACV,cAAc,EACd,WAAW,EACX,SAAS,EACT,UAAU,EACV,KAAK,EACL,WAAW,EACX,IAAI,EACJ,QAAQ,EACR,UAAU,GACX,MAAM,YAAY,CAAA"}
@@ -0,0 +1,7 @@
1
+ export { createDesk, cascadeFrame, cascadeSlot, focusedId, instancesOf, isOpen, nextCascadeFrame, normalise, windowType, EMPTY, } from './desk.js';
2
+ export { addCommandHandler, addDeskCommands, canPerform, chainStart, DeskCommands, perform, STAGE_ATTRIBUTE, WINDOW_ATTRIBUTE, windowElement, } from './commands.js';
3
+ export { createBus, InputCommands, topicMatches } from './events.js';
4
+ export { bindShortcuts, formatShortcut, isApplePlatform, isInstalledApp, matchesShortcut, parseShortcut } from './shortcuts.js';
5
+ export { parse, serialize, syncWithLocation } from './location.js';
6
+ export { isTitleCase, titleCase } from './titles.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,YAAY,EACZ,WAAW,EACX,SAAS,EACT,WAAW,EACX,MAAM,EACN,gBAAgB,EAChB,SAAS,EACT,UAAU,EACV,KAAK,GACN,MAAM,WAAW,CAAA;AAElB,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,UAAU,EACV,UAAU,EACV,YAAY,EACZ,OAAO,EACP,eAAe,EACf,gBAAgB,EAChB,aAAa,GACd,MAAM,eAAe,CAAA;AAEtB,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAEpE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAE/H,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAClE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,30 @@
1
+ import type { Desk } from './desk.js';
2
+ import type { DeskState, Size, WindowId } from './types.js';
3
+ export interface LocationOptions {
4
+ /** Hash parameter that holds the windows. Default `w`. */
5
+ readonly key?: string;
6
+ /** Hash parameter that holds the focused window. Default `f`. */
7
+ readonly focusKey?: string;
8
+ /** Ids the app can render. Anything else in a URL is dropped. */
9
+ readonly isKnown?: (id: WindowId) => boolean;
10
+ }
11
+ export declare function serialize(state: DeskState, options?: LocationOptions): URLSearchParams;
12
+ export declare function parse(params: URLSearchParams, stage: Size, options?: LocationOptions): DeskState;
13
+ export interface LocationEnv {
14
+ readonly location: {
15
+ hash: string;
16
+ };
17
+ readonly history: {
18
+ pushState(data: unknown, unused: string, url: string): void;
19
+ replaceState(data: unknown, unused: string, url: string): void;
20
+ };
21
+ addEventListener(type: 'popstate', listener: () => void): void;
22
+ removeEventListener(type: 'popstate', listener: () => void): void;
23
+ }
24
+ /**
25
+ * Keeps the desk and the URL hash in step. Opening or closing a window pushes a
26
+ * history entry, so Back closes it; focus and mode changes replace the entry.
27
+ * Other hash parameters are left alone, so the app can keep using the hash too.
28
+ */
29
+ export declare function syncWithLocation(desk: Desk, stage: () => Size, options?: LocationOptions, env?: LocationEnv): () => void;
30
+ //# sourceMappingURL=location.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"location.d.ts","sourceRoot":"","sources":["../../src/core/location.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,KAAK,EAAE,SAAS,EAAc,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAsBvE,MAAM,WAAW,eAAe;IAC9B,0DAA0D;IAC1D,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,iEAAiE;IACjE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,KAAK,OAAO,CAAA;CAC7C;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,GAAE,eAAoB,GAAG,eAAe,CAU1F;AAED,wBAAgB,KAAK,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,GAAE,eAAoB,GAAG,SAAS,CA8BpG;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACnC,QAAQ,CAAC,OAAO,EAAE;QAAE,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;IACjJ,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAA;IAC9D,mBAAmB,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAA;CAClE;AAID;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,GAAE,eAAoB,EAAE,GAAG,CAAC,EAAE,WAAW,GAAG,MAAM,IAAI,CAmC5H"}