@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,99 @@
1
+ import { cascadeFrame, focusedId, normalise } from './desk.js';
2
+ /*
3
+ * The URL carries which windows are open, which are free, and which has focus —
4
+ * never frames. A shared link should open the same things, not reproduce
5
+ * someone else's window positions on a different screen.
6
+ *
7
+ * #w=notes,clock~,inspector&f=clock
8
+ *
9
+ * `~` marks a free window; the others fill the desk. `f` names the focused window.
10
+ */
11
+ const FLOAT = '~';
12
+ const warned = new Set();
13
+ /** Said once per message: a warning on every parse would be noise, not help. */
14
+ const warnOnce = (message) => {
15
+ if (warned.has(message))
16
+ return;
17
+ warned.add(message);
18
+ console.warn(message);
19
+ };
20
+ export function serialize(state, options = {}) {
21
+ const params = new URLSearchParams();
22
+ if (!state.windows.length)
23
+ return params;
24
+ params.set(options.key ?? 'w', state.windows.map(w => `${encodeURIComponent(w.id)}${w.mode === 'floating' ? FLOAT : ''}`).join(','));
25
+ const focused = focusedId(state);
26
+ if (focused)
27
+ params.set(options.focusKey ?? 'f', focused);
28
+ return params;
29
+ }
30
+ export function parse(params, stage, options = {}) {
31
+ const known = options.isKnown ??
32
+ (id => {
33
+ // Without `isKnown` a stale or hand-edited link opens ids the app cannot render.
34
+ warnOnce(`desk: no isKnown given, so "${id}" from a URL is taken on trust. Pass isKnown to drop unknown windows.`);
35
+ return true;
36
+ });
37
+ const raw = params.get(options.key ?? 'w');
38
+ if (!raw)
39
+ return { windows: [], stack: [] };
40
+ const entries = raw
41
+ .split(',')
42
+ .filter(Boolean)
43
+ .map(token => {
44
+ const floating = token.endsWith(FLOAT);
45
+ return { id: decodeURIComponent(floating ? token.slice(0, -1) : token), floating };
46
+ })
47
+ .filter(e => e.id && known(e.id));
48
+ const windows = entries.map((e, i) => e.floating
49
+ ? { id: e.id, mode: 'floating', frame: cascadeFrame(entries.slice(0, i).filter(x => x.floating).length, stage) }
50
+ : { id: e.id, mode: 'filled' });
51
+ const focus = params.get(options.focusKey ?? 'f');
52
+ const ids = windows.map(w => w.id);
53
+ const stack = focus && ids.includes(focus) ? [...ids.filter(id => id !== focus), focus] : ids;
54
+ return normalise({ windows, stack });
55
+ }
56
+ const openSet = (state) => state.windows.map(w => w.id).join('|');
57
+ /**
58
+ * Keeps the desk and the URL hash in step. Opening or closing a window pushes a
59
+ * history entry, so Back closes it; focus and mode changes replace the entry.
60
+ * Other hash parameters are left alone, so the app can keep using the hash too.
61
+ */
62
+ export function syncWithLocation(desk, stage, options = {}, env) {
63
+ const target = env ?? globalThis;
64
+ const keys = [options.key ?? 'w', options.focusKey ?? 'f'];
65
+ const read = () => new URLSearchParams(target.location.hash.replace(/^#/, ''));
66
+ const fromUrl = () => desk.restore(parse(read(), stage(), options));
67
+ const toUrl = (state, previous) => {
68
+ const params = read();
69
+ keys.forEach(k => params.delete(k));
70
+ serialize(state, options).forEach((value, key) => params.set(key, value));
71
+ const url = `#${params.toString().replace(/%2C/g, ',').replace(/%7E/g, FLOAT)}`;
72
+ if (url === target.location.hash || (url === '#' && !target.location.hash))
73
+ return;
74
+ if (openSet(state) !== openSet(previous))
75
+ target.history.pushState(null, '', url);
76
+ else
77
+ target.history.replaceState(null, '', url);
78
+ };
79
+ // A URL that names windows wins. One that names none adopts whatever the app opened.
80
+ if (read().has(keys[0]))
81
+ fromUrl();
82
+ else if (desk.getState().windows.length)
83
+ toUrl(desk.getState(), desk.getState());
84
+ let previous = desk.getState();
85
+ const unsubscribe = desk.subscribe(state => {
86
+ toUrl(state, previous);
87
+ previous = state;
88
+ });
89
+ const onPop = () => {
90
+ fromUrl();
91
+ previous = desk.getState();
92
+ };
93
+ target.addEventListener('popstate', onPop);
94
+ return () => {
95
+ unsubscribe();
96
+ target.removeEventListener('popstate', onPop);
97
+ };
98
+ }
99
+ //# sourceMappingURL=location.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"location.js","sourceRoot":"","sources":["../../src/core/location.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import type { CommandId } from './commands.js';
2
+ import type { Desk } from './desk.js';
3
+ export type Keymap = Readonly<Record<string, CommandId>>;
4
+ export interface Shortcut {
5
+ readonly key: string;
6
+ readonly mod: boolean;
7
+ readonly shift: boolean;
8
+ readonly alt: boolean;
9
+ readonly ctrl: boolean;
10
+ }
11
+ export declare function parseShortcut(text: string): Shortcut;
12
+ /**
13
+ * Whether the app is running installed, rather than in a browser tab. Only then
14
+ * may it take shortcuts the browser normally owns, such as ⌘W (HIG.md §5).
15
+ */
16
+ export declare const isInstalledApp: () => boolean;
17
+ export declare const isApplePlatform: () => boolean;
18
+ interface KeyLike {
19
+ readonly key: string;
20
+ readonly code?: string;
21
+ readonly metaKey: boolean;
22
+ readonly ctrlKey: boolean;
23
+ readonly shiftKey: boolean;
24
+ readonly altKey: boolean;
25
+ }
26
+ export declare function matchesShortcut(event: KeyLike, shortcut: Shortcut, apple?: boolean): boolean;
27
+ /** How a menu shows a shortcut: `⇧⌘Z` on Apple devices, `Ctrl+Shift+Z` elsewhere. */
28
+ export declare function formatShortcut(text: string, apple?: boolean): string;
29
+ export interface ShortcutOptions {
30
+ readonly target?: EventTarget;
31
+ readonly apple?: boolean;
32
+ }
33
+ /** Performs commands from keyboard shortcuts. Returns a function that stops listening. */
34
+ export declare function bindShortcuts(desk: Desk | null, keymap: Keymap | (() => Keymap), options?: ShortcutOptions): () => void;
35
+ export {};
36
+ //# sourceMappingURL=shortcuts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shortcuts.d.ts","sourceRoot":"","sources":["../../src/core/shortcuts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AASrC,MAAM,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAA;AAExD,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CACvB;AAID,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAUpD;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAO,OACuH,CAAA;AAEzJ,eAAO,MAAM,eAAe,QAAO,OAC0E,CAAA;AAE7G,UAAU,OAAO;IACf,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CACzB;AAaD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,UAAoB,GAAG,OAAO,CAUtG;AAMD,qFAAqF;AACrF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,UAAoB,GAAG,MAAM,CAK9E;AAKD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CACzB;AAED,0FAA0F;AAC1F,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,EAAE,OAAO,GAAE,eAAoB,GAAG,MAAM,IAAI,CAoB3H"}
@@ -0,0 +1,73 @@
1
+ import { perform } from './commands.js';
2
+ const NAMES = { esc: 'escape', return: 'enter', comma: ',', space: ' ', backquote: '`' };
3
+ export function parseShortcut(text) {
4
+ const parts = text.toLowerCase().split('+');
5
+ const key = parts.pop() ?? '';
6
+ return {
7
+ key: NAMES[key] ?? key,
8
+ mod: parts.includes('mod'),
9
+ shift: parts.includes('shift'),
10
+ alt: parts.includes('alt') || parts.includes('option'),
11
+ ctrl: parts.includes('ctrl'),
12
+ };
13
+ }
14
+ /**
15
+ * Whether the app is running installed, rather than in a browser tab. Only then
16
+ * may it take shortcuts the browser normally owns, such as ⌘W (HIG.md §5).
17
+ */
18
+ export const isInstalledApp = () => typeof matchMedia === 'function' && (matchMedia('(display-mode: standalone)').matches || matchMedia('(display-mode: window-controls-overlay)').matches);
19
+ export const isApplePlatform = () => typeof navigator !== 'undefined' && /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent);
20
+ const CODES = {
21
+ BracketLeft: '[', BracketRight: ']', Backquote: '`', Comma: ',', Period: '.', Slash: '/', Semicolon: ';', Quote: "'", Minus: '-', Equal: '=', Backslash: '\\', Space: ' ',
22
+ };
23
+ /** The unmodified key a physical key stands for: ⌥ on a Mac turns `]` into `‘`, but the code is still BracketRight. */
24
+ const keyFromCode = (code) => !code ? undefined
25
+ : code.startsWith('Key') ? code.slice(3).toLowerCase()
26
+ : code.startsWith('Digit') ? code.slice(5)
27
+ : CODES[code];
28
+ export function matchesShortcut(event, shortcut, apple = isApplePlatform()) {
29
+ const wantMeta = apple && shortcut.mod;
30
+ const wantCtrl = shortcut.ctrl || (!apple && shortcut.mod);
31
+ return ((event.key.toLowerCase() === shortcut.key || keyFromCode(event.code) === shortcut.key) &&
32
+ event.metaKey === wantMeta &&
33
+ event.ctrlKey === wantCtrl &&
34
+ event.shiftKey === shortcut.shift &&
35
+ event.altKey === shortcut.alt);
36
+ }
37
+ const GLYPHS = {
38
+ escape: 'Esc', enter: '↩', ',': ',', ' ': 'Space', arrowup: '↑', arrowdown: '↓', arrowleft: '←', arrowright: '→', backspace: '⌫', '`': '`',
39
+ };
40
+ /** How a menu shows a shortcut: `⇧⌘Z` on Apple devices, `Ctrl+Shift+Z` elsewhere. */
41
+ export function formatShortcut(text, apple = isApplePlatform()) {
42
+ const s = parseShortcut(text);
43
+ const key = GLYPHS[s.key] ?? s.key.toUpperCase();
44
+ if (apple)
45
+ return `${s.ctrl ? '⌃' : ''}${s.alt ? '⌥' : ''}${s.shift ? '⇧' : ''}${s.mod ? '⌘' : ''}${key}`;
46
+ return [s.ctrl || s.mod ? 'Ctrl' : '', s.alt ? 'Alt' : '', s.shift ? 'Shift' : '', key].filter(Boolean).join('+');
47
+ }
48
+ const isEditable = (target) => target instanceof Element && (target.closest('input, textarea, select, [contenteditable=""], [contenteditable="true"]') !== null);
49
+ /** Performs commands from keyboard shortcuts. Returns a function that stops listening. */
50
+ export function bindShortcuts(desk, keymap, options = {}) {
51
+ const target = options.target ?? globalThis;
52
+ const bind = (map) => Object.entries(map).map(([text, command]) => ({ shortcut: parseShortcut(text), command }));
53
+ // A keymap given as a function is read at each key press, for menus whose items change.
54
+ const fixed = typeof keymap === 'function' ? null : bind(keymap);
55
+ const onKeyDown = (event) => {
56
+ const key = event;
57
+ if (key.defaultPrevented || key.isComposing)
58
+ return;
59
+ const bindings = fixed ?? bind(keymap());
60
+ const binding = bindings.find(b => matchesShortcut(key, b.shortcut, options.apple));
61
+ if (!binding)
62
+ return;
63
+ // A bare key belongs to whatever is being typed into; a modified one can still be a command.
64
+ const plain = !binding.shortcut.mod && !binding.shortcut.ctrl && !binding.shortcut.alt;
65
+ if (plain && isEditable(key.target))
66
+ return;
67
+ if (perform(desk, binding.command))
68
+ key.preventDefault();
69
+ };
70
+ target.addEventListener('keydown', onKeyDown);
71
+ return () => target.removeEventListener('keydown', onKeyDown);
72
+ }
73
+ //# sourceMappingURL=shortcuts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shortcuts.js","sourceRoot":"","sources":["../../src/core/shortcuts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function titleCase(text: string): string;
2
+ export declare const isTitleCase: (text: string) => boolean;
3
+ //# sourceMappingURL=titles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"titles.d.ts","sourceRoot":"","sources":["../../src/core/titles.ts"],"names":[],"mappings":"AAeA,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAU9C;AAED,eAAO,MAAM,WAAW,SAAU,MAAM,KAAG,OAA0C,CAAA"}
@@ -0,0 +1,26 @@
1
+ /*
2
+ * App and window names are names, so they are written in title case: Ride Card,
3
+ * Parts & Wear, Service History. It is not applied for you, because a window showing one
4
+ * document takes that document's own name, as written. Use `titleCase` where a name
5
+ * is defined, and `isTitleCase` in a test over the names an app defines.
6
+ */
7
+ /** Short words that stay lower case inside a title: articles, conjunctions, short prepositions. */
8
+ const MINOR = new Set(['a', 'an', 'and', 'as', 'at', 'but', 'by', 'for', 'in', 'nor', 'of', 'on', 'or', 'per', 'so', 'the', 'to', 'up', 'via', 'vs', 'yet']);
9
+ // A word someone has already cased on purpose — iPhone, API, macOS — is left alone.
10
+ const deliberate = (word) => /[A-Z]/.test(word.slice(1));
11
+ const capital = (word) => word.charAt(0).toUpperCase() + word.slice(1);
12
+ export function titleCase(text) {
13
+ const words = text.trim().split(/\s+/);
14
+ return words
15
+ .map((word, i) => {
16
+ if (deliberate(word))
17
+ return word;
18
+ const edge = i === 0 || i === words.length - 1;
19
+ if (!edge && MINOR.has(word.toLowerCase()))
20
+ return word.toLowerCase();
21
+ return word.split('-').map(capital).join('-');
22
+ })
23
+ .join(' ');
24
+ }
25
+ export const isTitleCase = (text) => titleCase(text) === text.trim();
26
+ //# sourceMappingURL=titles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"titles.js","sourceRoot":"","sources":["../../src/core/titles.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,mGAAmG;AACnG,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAA;AAE5J,oFAAoF;AACpF,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;AAEhE,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AAE9E,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IACtC,OAAO,KAAK;SACT,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;QACf,IAAI,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAA;QACjC,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,CAAA;QAC9C,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YAAE,OAAO,IAAI,CAAC,WAAW,EAAE,CAAA;QACrE,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC/C,CAAC,CAAC;SACD,IAAI,CAAC,GAAG,CAAC,CAAA;AACd,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,CAAA"}
@@ -0,0 +1,51 @@
1
+ export type WindowId = string;
2
+ export interface Frame {
3
+ readonly x: number;
4
+ readonly y: number;
5
+ readonly width: number;
6
+ readonly height: number;
7
+ }
8
+ export interface Size {
9
+ readonly width: number;
10
+ readonly height: number;
11
+ }
12
+ export type DeskWindow =
13
+ /** Fills the desk, at whatever size the desk is. */
14
+ {
15
+ readonly id: WindowId;
16
+ readonly mode: 'filled';
17
+ } | {
18
+ readonly id: WindowId;
19
+ readonly mode: 'floating';
20
+ readonly frame: Frame;
21
+ };
22
+ export type WindowMode = DeskWindow['mode'];
23
+ export interface DeskState {
24
+ /** Open windows in the order they were opened. Arrange lays them out in this order, so focusing never reshuffles them. */
25
+ readonly windows: readonly DeskWindow[];
26
+ /** Window ids back to front. The last one has focus. */
27
+ readonly stack: readonly WindowId[];
28
+ }
29
+ export interface CascadeOptions {
30
+ readonly maxWidth: number;
31
+ readonly maxHeight: number;
32
+ readonly margin: number;
33
+ readonly step: {
34
+ readonly x: number;
35
+ readonly y: number;
36
+ };
37
+ /** After this many floating windows the cascade wraps back to the top-left. */
38
+ readonly wrap: number;
39
+ }
40
+ export interface DeskOptions {
41
+ readonly cascade?: Partial<CascadeOptions>;
42
+ /** Reports the stage's size, so floating windows open inside it. */
43
+ readonly stage?: () => Size;
44
+ readonly initial?: DeskState;
45
+ }
46
+ export interface OpenOptions {
47
+ /** Open as a free window rather than filling the desk. Given a frame, it floats there. */
48
+ readonly mode?: WindowMode;
49
+ readonly frame?: Frame;
50
+ }
51
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAA;AAE7B,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,MAAM,UAAU;AACpB,oDAAoD;AAClD;IAAE,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClD;IAAE,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAA;AAE/E,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,CAAA;AAE3C,MAAM,WAAW,SAAS;IACxB,0HAA0H;IAC1H,QAAQ,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,CAAA;IACvC,wDAAwD;IACxD,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAA;CACpC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACzD,+EAA+E;IAC/E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAA;IAC1C,oEAAoE;IACpE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,IAAI,CAAA;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAA;CAC7B;AAED,MAAM,WAAW,WAAW;IAC1B,0FAA0F;IAC1F,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAA;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CACvB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":""}