xtralab 0.15.0 → 0.15.2

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 (237) hide show
  1. package/README.md +65 -30
  2. package/lib/about/icons.d.ts +0 -5
  3. package/lib/about/icons.js +0 -5
  4. package/lib/about/index.d.ts +4 -8
  5. package/lib/about/index.js +6 -17
  6. package/lib/agentSessions.d.ts +9 -29
  7. package/lib/agentSessions.js +2 -7
  8. package/lib/askAgent/editorSelection.d.ts +20 -26
  9. package/lib/askAgent/editorSelection.js +11 -26
  10. package/lib/askAgent/icons.d.ts +2 -3
  11. package/lib/askAgent/icons.js +2 -3
  12. package/lib/askAgent/index.d.ts +4 -26
  13. package/lib/askAgent/index.js +54 -158
  14. package/lib/askAgent/popup.d.ts +12 -16
  15. package/lib/askAgent/popup.js +18 -37
  16. package/lib/askAgent/prompt.d.ts +3 -5
  17. package/lib/askAgent/prompt.js +6 -19
  18. package/lib/askAgent/queue.d.ts +11 -21
  19. package/lib/askAgent/queue.js +9 -19
  20. package/lib/askAgent/queuePanel.d.ts +13 -18
  21. package/lib/askAgent/queuePanel.js +15 -37
  22. package/lib/askAgent/targetPicker.d.ts +2 -9
  23. package/lib/askAgent/targetPicker.js +6 -11
  24. package/lib/askAgent/tokens.d.ts +32 -46
  25. package/lib/askAgent/tokens.js +4 -6
  26. package/lib/commandBar/index.d.ts +4 -13
  27. package/lib/commandBar/index.js +21 -39
  28. package/lib/customPanel/index.js +15 -0
  29. package/lib/editorBreadcrumbs/index.d.ts +3 -6
  30. package/lib/editorBreadcrumbs/index.js +10 -6
  31. package/lib/editorBreadcrumbs/widget.d.ts +17 -4
  32. package/lib/editorBreadcrumbs/widget.js +11 -17
  33. package/lib/editorIndent/index.d.ts +4 -12
  34. package/lib/editorIndent/index.js +8 -23
  35. package/lib/fileBrowser/commands.d.ts +29 -19
  36. package/lib/fileBrowser/commands.js +83 -97
  37. package/lib/fileBrowser/contents.d.ts +3 -0
  38. package/lib/fileBrowser/dragAndDrop.d.ts +17 -4
  39. package/lib/fileBrowser/dragAndDrop.js +2 -7
  40. package/lib/fileBrowser/fileBrowser.d.ts +19 -9
  41. package/lib/fileBrowser/fileBrowser.js +70 -222
  42. package/lib/fileBrowser/gitStatus.d.ts +16 -10
  43. package/lib/fileBrowser/gitStatus.js +31 -30
  44. package/lib/fileBrowser/gitignore.d.ts +4 -17
  45. package/lib/fileBrowser/gitignore.js +4 -25
  46. package/lib/fileBrowser/icons.d.ts +7 -17
  47. package/lib/fileBrowser/icons.js +25 -80
  48. package/lib/fileBrowser/index.js +2 -4
  49. package/lib/fileBrowser/widget.d.ts +141 -48
  50. package/lib/fileBrowser/widget.js +102 -4
  51. package/lib/fileTypeIcons/index.js +0 -10
  52. package/lib/git/api.d.ts +5 -13
  53. package/lib/git/api.js +10 -36
  54. package/lib/git/askRequest.d.ts +4 -8
  55. package/lib/git/askRequest.js +6 -20
  56. package/lib/git/commands.d.ts +45 -5
  57. package/lib/git/commands.js +20 -13
  58. package/lib/git/diffModel.js +4 -0
  59. package/lib/git/diffPreferences.d.ts +90 -0
  60. package/lib/git/diffPreferences.js +107 -0
  61. package/lib/git/diffProvider.js +10 -2
  62. package/lib/git/diffSurface.d.ts +64 -63
  63. package/lib/git/diffSurface.js +72 -213
  64. package/lib/git/diffTheme.d.ts +7 -0
  65. package/lib/git/diffTheme.js +23 -0
  66. package/lib/git/diffWidget.d.ts +70 -14
  67. package/lib/git/diffWidget.js +100 -94
  68. package/lib/git/imageDiff.d.ts +14 -6
  69. package/lib/git/imageDiff.js +19 -75
  70. package/lib/git/index.d.ts +0 -3
  71. package/lib/git/index.js +44 -10
  72. package/lib/git/notebookDiff.d.ts +110 -33
  73. package/lib/git/notebookDiff.js +55 -197
  74. package/lib/git/tokens.d.ts +73 -31
  75. package/lib/git/tokens.js +2 -3
  76. package/lib/highlight/index.d.ts +4 -10
  77. package/lib/highlight/index.js +10 -41
  78. package/lib/index.d.ts +0 -9
  79. package/lib/index.js +0 -9
  80. package/lib/launcher/agents.d.ts +55 -51
  81. package/lib/launcher/agents.js +15 -57
  82. package/lib/launcher/availability.d.ts +3 -9
  83. package/lib/launcher/availability.js +3 -9
  84. package/lib/launcher/commands.d.ts +7 -32
  85. package/lib/launcher/commands.js +14 -45
  86. package/lib/launcher/dashboard.d.ts +19 -24
  87. package/lib/launcher/dashboard.js +21 -67
  88. package/lib/launcher/editorRegistry.d.ts +10 -22
  89. package/lib/launcher/editorRegistry.js +14 -18
  90. package/lib/launcher/editors.d.ts +39 -45
  91. package/lib/launcher/editors.js +8 -34
  92. package/lib/launcher/icons.d.ts +0 -12
  93. package/lib/launcher/icons.js +5 -39
  94. package/lib/launcher/index.js +12 -55
  95. package/lib/launcher/invocation.d.ts +4 -10
  96. package/lib/launcher/invocation.js +7 -22
  97. package/lib/launcher/registry.d.ts +9 -7
  98. package/lib/launcher/registry.js +9 -7
  99. package/lib/launcher/tokens.d.ts +10 -22
  100. package/lib/launcher/tokens.js +5 -8
  101. package/lib/menuBar/index.d.ts +3 -10
  102. package/lib/menuBar/index.js +11 -28
  103. package/lib/menus/index.d.ts +3 -9
  104. package/lib/menus/index.js +14 -30
  105. package/lib/omnibox/files.d.ts +2 -4
  106. package/lib/omnibox/files.js +5 -11
  107. package/lib/omnibox/index.d.ts +4 -14
  108. package/lib/omnibox/index.js +9 -27
  109. package/lib/omnibox/model.d.ts +38 -10
  110. package/lib/omnibox/model.js +15 -33
  111. package/lib/omnibox/recents.d.ts +15 -17
  112. package/lib/omnibox/recents.js +12 -17
  113. package/lib/omnibox/tokens.d.ts +5 -10
  114. package/lib/omnibox/tokens.js +2 -6
  115. package/lib/omnibox/widget.d.ts +11 -7
  116. package/lib/omnibox/widget.js +8 -16
  117. package/lib/searchReplace/index.d.ts +4 -20
  118. package/lib/searchReplace/index.js +7 -27
  119. package/lib/showOutput/index.d.ts +3 -12
  120. package/lib/showOutput/index.js +6 -22
  121. package/lib/sidebar/index.d.ts +4 -7
  122. package/lib/sidebar/index.js +5 -12
  123. package/lib/terminalNotifications/index.d.ts +4 -10
  124. package/lib/terminalNotifications/index.js +6 -20
  125. package/lib/terminals/agentTerminals.d.ts +12 -5
  126. package/lib/terminals/agentTerminals.js +25 -44
  127. package/lib/terminals/detection.d.ts +4 -8
  128. package/lib/terminals/detection.js +4 -8
  129. package/lib/terminals/index.d.ts +0 -35
  130. package/lib/terminals/index.js +12 -101
  131. package/lib/terminals/model.d.ts +64 -139
  132. package/lib/terminals/model.js +80 -220
  133. package/lib/terminals/tokens.d.ts +11 -22
  134. package/lib/terminals/tokens.js +2 -2
  135. package/lib/terminals/widget.d.ts +43 -13
  136. package/lib/terminals/widget.js +33 -18
  137. package/lib/topBar/icons.d.ts +3 -8
  138. package/lib/topBar/icons.js +3 -8
  139. package/lib/topBar/index.d.ts +4 -11
  140. package/lib/topBar/index.js +10 -38
  141. package/lib/walkthrough/index.d.ts +4 -9
  142. package/lib/walkthrough/index.js +6 -20
  143. package/lib/walkthrough/panel.d.ts +40 -9
  144. package/lib/walkthrough/panel.js +4 -10
  145. package/package.json +5 -3
  146. package/schema/git-diff-preferences.json +42 -0
  147. package/src/about/icons.ts +0 -5
  148. package/src/about/index.tsx +6 -17
  149. package/src/agentSessions.ts +9 -29
  150. package/src/askAgent/editorSelection.ts +22 -29
  151. package/src/askAgent/icons.ts +2 -3
  152. package/src/askAgent/index.ts +54 -158
  153. package/src/askAgent/popup.tsx +23 -45
  154. package/src/askAgent/prompt.ts +6 -19
  155. package/src/askAgent/queue.ts +13 -24
  156. package/src/askAgent/queuePanel.tsx +21 -46
  157. package/src/askAgent/targetPicker.tsx +5 -15
  158. package/src/askAgent/tokens.ts +32 -46
  159. package/src/commandBar/index.ts +24 -39
  160. package/src/customPanel/index.ts +15 -0
  161. package/src/editorBreadcrumbs/index.ts +10 -6
  162. package/src/editorBreadcrumbs/widget.ts +23 -17
  163. package/src/editorIndent/index.ts +17 -23
  164. package/src/fileBrowser/commands.ts +119 -96
  165. package/src/fileBrowser/contents.ts +3 -0
  166. package/src/fileBrowser/dragAndDrop.ts +17 -7
  167. package/src/fileBrowser/fileBrowser.tsx +86 -230
  168. package/src/fileBrowser/gitStatus.ts +36 -33
  169. package/src/fileBrowser/gitignore.ts +4 -25
  170. package/src/fileBrowser/icons.ts +25 -80
  171. package/src/fileBrowser/index.ts +2 -4
  172. package/src/fileBrowser/widget.tsx +171 -50
  173. package/src/fileTypeIcons/index.ts +0 -10
  174. package/src/git/api.ts +10 -36
  175. package/src/git/askRequest.ts +6 -20
  176. package/src/git/commands.ts +83 -11
  177. package/src/git/diffModel.ts +25 -0
  178. package/src/git/diffPreferences.ts +192 -0
  179. package/src/git/diffProvider.tsx +11 -2
  180. package/src/git/diffSurface.tsx +165 -286
  181. package/src/git/diffTheme.ts +24 -0
  182. package/src/git/diffWidget.tsx +194 -134
  183. package/src/git/imageDiff.tsx +56 -84
  184. package/src/git/index.ts +54 -10
  185. package/src/git/notebookDiff.tsx +214 -240
  186. package/src/git/tokens.ts +73 -31
  187. package/src/highlight/index.ts +10 -41
  188. package/src/index.ts +0 -9
  189. package/src/launcher/agents.ts +64 -95
  190. package/src/launcher/availability.ts +3 -9
  191. package/src/launcher/commands.ts +14 -51
  192. package/src/launcher/dashboard.tsx +49 -88
  193. package/src/launcher/editorRegistry.ts +21 -29
  194. package/src/launcher/editors.ts +39 -58
  195. package/src/launcher/icons.ts +5 -39
  196. package/src/launcher/index.ts +12 -55
  197. package/src/launcher/invocation.ts +7 -22
  198. package/src/launcher/registry.ts +9 -7
  199. package/src/launcher/tokens.ts +10 -22
  200. package/src/menuBar/index.ts +11 -28
  201. package/src/menus/index.ts +14 -30
  202. package/src/omnibox/files.ts +10 -14
  203. package/src/omnibox/index.ts +9 -27
  204. package/src/omnibox/model.ts +50 -38
  205. package/src/omnibox/recents.ts +17 -22
  206. package/src/omnibox/tokens.ts +5 -10
  207. package/src/omnibox/widget.tsx +14 -19
  208. package/src/searchReplace/index.ts +7 -27
  209. package/src/showOutput/index.ts +6 -22
  210. package/src/sidebar/index.ts +20 -12
  211. package/src/terminalNotifications/index.ts +42 -25
  212. package/src/terminals/agentTerminals.ts +25 -49
  213. package/src/terminals/detection.ts +4 -8
  214. package/src/terminals/index.ts +12 -101
  215. package/src/terminals/model.ts +130 -246
  216. package/src/terminals/tokens.ts +11 -22
  217. package/src/terminals/widget.tsx +48 -31
  218. package/src/topBar/icons.ts +3 -8
  219. package/src/topBar/index.ts +21 -44
  220. package/src/walkthrough/index.ts +6 -20
  221. package/src/walkthrough/panel.ts +40 -10
  222. package/style/about.css +2 -7
  223. package/style/askAgent.css +8 -40
  224. package/style/base.css +9 -45
  225. package/style/chrome.css +108 -308
  226. package/style/commandBar.css +4 -20
  227. package/style/customPanel.css +1 -4
  228. package/style/git.css +26 -186
  229. package/style/highlight.css +1 -3
  230. package/style/launcher.css +6 -70
  231. package/style/omnibox.css +2 -14
  232. package/style/showOutput.css +0 -6
  233. package/style/sidebar.css +29 -9
  234. package/style/tabs.css +5 -13
  235. package/style/terminals.css +6 -53
  236. package/style/topBar.css +2 -22
  237. package/style/walkthrough.css +0 -8
@@ -2,23 +2,19 @@ import * as React from 'react';
2
2
 
3
3
  import type { TranslationBundle } from '@jupyterlab/translation';
4
4
 
5
+ import type { ImageDiffViewMode } from './diffPreferences';
6
+
5
7
  /**
6
8
  * xtralab's image diff, registered in place of `@jupyterlab/git:image-diff`.
7
- *
8
- * The git server base64-encodes binary content, so both diff hosts receive
9
- * the two sides as base64 strings through the same `content()` getters used
10
- * for text. This module turns those strings into `<img>` elements and
11
- * offers the 2-up / swipe / onion-skin comparison modes; no diffing library
12
- * is involved (`@pierre/diffs` is text-only).
9
+ * Both sides arrive base64-encoded through the same `content()` getters used
10
+ * for text; the 2-up/swipe/onion views are hand-rolled (`@pierre/diffs` is
11
+ * text-only).
13
12
  */
14
13
 
15
14
  /**
16
- * Raster image extensions xtralab renders as an image diff, mapped to the
17
- * MIME subtype used in the `data:image/<subtype>;base64,…` URL.
18
- *
19
- * `.svg` is intentionally absent: it is XML text, so the `@pierre/diffs`
20
- * text diff (the fallback provider) is more useful for it than an image
21
- * comparison.
15
+ * Raster extensions mapped to the `data:image/<subtype>` MIME subtype.
16
+ * `.svg` is intentionally absent: it is XML text, so the fallback text diff
17
+ * is more useful than an image comparison.
22
18
  */
23
19
  const IMAGE_DATA_TYPES: Record<string, string> = {
24
20
  '.png': 'png',
@@ -30,9 +26,6 @@ const IMAGE_DATA_TYPES: Record<string, string> = {
30
26
  '.ico': 'x-icon'
31
27
  };
32
28
 
33
- /**
34
- * The file extensions registered as the xtralab image diff provider.
35
- */
36
29
  export const IMAGE_DIFF_EXTENSIONS = Object.keys(IMAGE_DATA_TYPES);
37
30
 
38
31
  /**
@@ -49,46 +42,14 @@ export function imageDataType(path: string): string | null {
49
42
  }
50
43
 
51
44
  /**
52
- * Comparison layouts, matching jupyterlab-git's image diff modes.
53
- */
54
- type ImageDiffViewMode = '2-up' | 'swipe' | 'onion';
55
-
56
- const IMAGE_DIFF_VIEW_MODE_STORAGE_KEY = 'xtralab:image-diff-view-mode';
57
-
58
- function readStoredImageViewMode(): ImageDiffViewMode {
59
- try {
60
- const raw = window.localStorage.getItem(IMAGE_DIFF_VIEW_MODE_STORAGE_KEY);
61
- if (raw === '2-up' || raw === 'swipe' || raw === 'onion') {
62
- return raw;
63
- }
64
- } catch {
65
- // localStorage can throw in privacy/sandboxed contexts — 2-up is the
66
- // sensible default anyway.
67
- }
68
- return '2-up';
69
- }
70
-
71
- function writeStoredImageViewMode(mode: ImageDiffViewMode): void {
72
- try {
73
- window.localStorage.setItem(IMAGE_DIFF_VIEW_MODE_STORAGE_KEY, mode);
74
- } catch {
75
- // Best-effort.
76
- }
77
- }
78
-
79
- /**
80
- * Strip whitespace from a base64 payload. Python's `base64.encodebytes`
81
- * (used by the git server) inserts a newline every 76 characters; most
82
- * browsers tolerate that inside a `data:` URL but some are stricter, and
83
- * the cleaned length also lets us size the file accurately.
45
+ * Strip whitespace from a base64 payload: the server's `base64.encodebytes`
46
+ * inserts newlines some browsers reject in `data:` URLs, and the cleaned
47
+ * length sizes the file accurately.
84
48
  */
85
49
  function cleanBase64(value: string): string {
86
50
  return value.replace(/\s+/g, '');
87
51
  }
88
52
 
89
- /**
90
- * Decoded byte length of a (whitespace-free) base64 string.
91
- */
92
53
  function base64ByteLength(clean: string): number {
93
54
  if (clean.length === 0) {
94
55
  return 0;
@@ -111,13 +72,25 @@ function formatBytes(bytes: number): string {
111
72
  return `${value.toFixed(value < 10 ? 1 : 0)} ${units[unit]}`;
112
73
  }
113
74
 
75
+ /**
76
+ * One side of the image comparison, decoded from its base64 payload.
77
+ */
114
78
  interface IImageSide {
115
79
  /**
116
80
  * Cleaned base64 payload; empty string means the side does not exist.
117
81
  */
118
82
  data: string;
83
+ /**
84
+ * Whether this side exists; added and deleted files lack one side.
85
+ */
119
86
  present: boolean;
87
+ /**
88
+ * The `data:` URI for the image, or `null` when the side is absent.
89
+ */
120
90
  uri: string | null;
91
+ /**
92
+ * Decoded size of the payload in bytes.
93
+ */
121
94
  bytes: number;
122
95
  }
123
96
 
@@ -132,6 +105,9 @@ function toSide(raw: string, fileType: string): IImageSide {
132
105
  };
133
106
  }
134
107
 
108
+ /**
109
+ * Props for {@link ImageDiffView}.
110
+ */
135
111
  interface IImageDiffViewProps {
136
112
  /**
137
113
  * Base64 of the reference (old) revision; empty when added.
@@ -145,6 +121,14 @@ interface IImageDiffViewProps {
145
121
  * MIME subtype from {@link imageDataType}.
146
122
  */
147
123
  fileType: string;
124
+ /**
125
+ * The selected comparison mode (host-controlled).
126
+ */
127
+ mode: ImageDiffViewMode;
128
+ /**
129
+ * Called when the user picks another comparison mode.
130
+ */
131
+ onModeChange: (mode: ImageDiffViewMode) => void;
148
132
  /**
149
133
  * Translation bundle for user-facing strings.
150
134
  */
@@ -152,12 +136,11 @@ interface IImageDiffViewProps {
152
136
  }
153
137
 
154
138
  /**
155
- * The image comparison surface: a segmented mode selector (reusing the
156
- * diff segmented-control styling so it matches the Notebook/JSON toggle)
157
- * plus the selected 2-up / swipe / onion-skin view.
139
+ * The image comparison surface: a mode selector (reusing the diff widget's
140
+ * segmented-control styling) plus the selected 2-up / swipe / onion view.
158
141
  */
159
142
  export function ImageDiffView(props: IImageDiffViewProps): React.ReactElement {
160
- const { reference, challenger, fileType, trans } = props;
143
+ const { reference, challenger, fileType, mode, onModeChange, trans } = props;
161
144
  const ref = React.useMemo(
162
145
  () => toSide(reference, fileType),
163
146
  [reference, fileType]
@@ -167,14 +150,6 @@ export function ImageDiffView(props: IImageDiffViewProps): React.ReactElement {
167
150
  [challenger, fileType]
168
151
  );
169
152
 
170
- const [mode, setMode] = React.useState<ImageDiffViewMode>(() =>
171
- readStoredImageViewMode()
172
- );
173
- const changeMode = React.useCallback((next: ImageDiffViewMode) => {
174
- setMode(next);
175
- writeStoredImageViewMode(next);
176
- }, []);
177
-
178
153
  return (
179
154
  <div className="jp-xtralab-ImageDiff">
180
155
  <div className="jp-xtralab-ImageDiff-header">
@@ -197,7 +172,7 @@ export function ImageDiffView(props: IImageDiffViewProps): React.ReactElement {
197
172
  aria-selected={mode === value}
198
173
  data-active={mode === value}
199
174
  className="jp-xtralab-DiffWidget-segmentedButton"
200
- onClick={() => changeMode(value)}
175
+ onClick={() => onModeChange(value)}
201
176
  >
202
177
  {label}
203
178
  </button>
@@ -217,9 +192,21 @@ export function ImageDiffView(props: IImageDiffViewProps): React.ReactElement {
217
192
  );
218
193
  }
219
194
 
195
+ /**
196
+ * Props shared by the 2-up, swipe, and onion-skin views.
197
+ */
220
198
  interface ISideViewProps {
199
+ /**
200
+ * The reference (old) side.
201
+ */
221
202
  reference: IImageSide;
203
+ /**
204
+ * The challenger (new) side.
205
+ */
222
206
  challenger: IImageSide;
207
+ /**
208
+ * Translation bundle for user-facing strings.
209
+ */
223
210
  trans: TranslationBundle;
224
211
  }
225
212
 
@@ -303,11 +290,6 @@ function TwoUp({
303
290
  );
304
291
  }
305
292
 
306
- /**
307
- * Range slider shared by the swipe and onion-skin views. A native
308
- * `<input type="range">` (styled via CSS) keeps the bundle free of a UI
309
- * component dependency.
310
- */
311
293
  function RangeSlider(props: {
312
294
  value: number;
313
295
  onChange: (value: number) => void;
@@ -329,11 +311,9 @@ function RangeSlider(props: {
329
311
  }
330
312
 
331
313
  /**
332
- * Fit a `naturalWidth × naturalHeight` image inside an `areaWidth ×
333
- * areaHeight` box without upscaling past its intrinsic size — the same
334
- * "contain, never enlarge" rule the 2-up and onion views get for free from
335
- * `max-width/height: 100%; width/height: auto`. Returns the displayed pixel
336
- * box, or `null` until both the image and the area have been measured.
314
+ * Fit an image inside an area without upscaling past its intrinsic size —
315
+ * the "contain, never enlarge" rule the other views get from CSS. Returns
316
+ * the displayed pixel box, or `null` until both sizes are measured.
337
317
  */
338
318
  function containBox(
339
319
  naturalWidth: number,
@@ -357,9 +337,6 @@ function containBox(
357
337
  return { width: naturalWidth * scale, height: naturalHeight * scale };
358
338
  }
359
339
 
360
- /**
361
- * Track an element's content-box size, kept current across layout changes.
362
- */
363
340
  function useElementSize(): readonly [
364
341
  React.RefObject<HTMLDivElement>,
365
342
  { width: number; height: number }
@@ -396,13 +373,9 @@ function Swipe({
396
373
  const [areaRef, area] = useElementSize();
397
374
  const frameRef = React.useRef<HTMLDivElement>(null);
398
375
 
399
- // Display both revisions in a single box — the union of their intrinsic
400
- // sizes, scaled down to fit but never enlarged — and size the frame to
401
- // exactly that box. The divider's `left: N%`, the pointer-to-percent
402
- // mapping (below) and each image's `clip-path` inset then all resolve
403
- // against the same width, so the white line sits precisely on the seam
404
- // between the two revisions at every position. A full-width frame instead
405
- // let the line drift off the seam by as much as half the letterbox.
376
+ // Size the frame to the union box of both revisions so the divider %, the
377
+ // pointer mapping and the clip-paths all resolve against the same width;
378
+ // a full-width frame lets the line drift off the seam.
406
379
  const naturalWidth = Math.max(refSize?.[0] ?? 0, challSize?.[0] ?? 0);
407
380
  const naturalHeight = Math.max(refSize?.[1] ?? 0, challSize?.[1] ?? 0);
408
381
  const box = containBox(naturalWidth, naturalHeight, area.width, area.height);
@@ -422,7 +395,6 @@ function Swipe({
422
395
 
423
396
  const onPointerDown = React.useCallback(
424
397
  (event: React.PointerEvent<HTMLDivElement>) => {
425
- // Only react to the primary pointer (left click / touch / pen tip).
426
398
  if (event.button !== 0) {
427
399
  return;
428
400
  }
package/src/git/index.ts CHANGED
@@ -4,6 +4,8 @@ import {
4
4
  } from '@jupyterlab/application';
5
5
  import { IThemeManager, WidgetTracker } from '@jupyterlab/apputils';
6
6
  import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
7
+ import { ISettingRegistry } from '@jupyterlab/settingregistry';
8
+ import { IStateDB } from '@jupyterlab/statedb';
7
9
  import { ITranslator, nullTranslator } from '@jupyterlab/translation';
8
10
 
9
11
  import { IAskAgent } from '../askAgent/tokens';
@@ -16,33 +18,76 @@ import {
16
18
  pinnedDiffWidgetId,
17
19
  registerGitCommands
18
20
  } from './commands';
21
+ import { DiffPreferences, IDiffPreferences } from './diffPreferences';
19
22
  import diffProviderPlugin from './diffProvider';
20
23
  import { IFileChange } from './tokens';
21
24
 
22
25
  const GIT_DIFF_COMMAND_PLUGIN_ID = 'xtralab:git-diff-command';
26
+ const GIT_DIFF_PREFERENCES_PLUGIN_ID = 'xtralab:git-diff-preferences';
23
27
  const GIT_DIFF_TRACKER_NAMESPACE = 'xtralab-git-diff';
24
28
 
25
29
  /**
26
- * The launcher's git diff command plugin.
27
- *
28
- * The upstream git panel stays enabled; this plugin only gives the launcher
29
- * its own `xtralab:git:open-diff` command and preview/pinned-tab tracking.
30
+ * The display choices shared by the launcher diff and the Git panel diff.
31
+ */
32
+ const diffPreferencesPlugin: JupyterFrontEndPlugin<IDiffPreferences> = {
33
+ id: GIT_DIFF_PREFERENCES_PLUGIN_ID,
34
+ description:
35
+ 'Keeps the git diff display choices in the settings and the state database.',
36
+ autoStart: true,
37
+ provides: IDiffPreferences,
38
+ optional: [ISettingRegistry, IStateDB],
39
+ activate: (
40
+ app: JupyterFrontEnd,
41
+ settingRegistry: ISettingRegistry | null,
42
+ state: IStateDB | null
43
+ ): IDiffPreferences => {
44
+ const preferences = new DiffPreferences();
45
+ if (settingRegistry !== null) {
46
+ settingRegistry
47
+ .load(GIT_DIFF_PREFERENCES_PLUGIN_ID)
48
+ .then(settings => preferences.connectSettings(settings))
49
+ .catch(reason => {
50
+ console.error(
51
+ `xtralab: failed to load settings for ${GIT_DIFF_PREFERENCES_PLUGIN_ID}`,
52
+ reason
53
+ );
54
+ });
55
+ }
56
+ if (state !== null) {
57
+ preferences.connectState(state).catch(reason => {
58
+ console.error('xtralab: failed to restore the diff split', reason);
59
+ });
60
+ }
61
+ return preferences;
62
+ }
63
+ };
64
+
65
+ /**
66
+ * The launcher's git diff command plugin. The upstream git panel stays
67
+ * enabled; this only adds `xtralab:git:open-diff` and preview/pinned-tab
68
+ * tracking.
30
69
  */
31
70
  const diffCommandPlugin: JupyterFrontEndPlugin<void> = {
32
71
  id: GIT_DIFF_COMMAND_PLUGIN_ID,
33
72
  description:
34
73
  "The launcher dashboard's side-by-side git diff command, powered by @pierre/diffs.",
35
74
  autoStart: true,
36
- optional: [IThemeManager, IRenderMimeRegistry, ITranslator, IAskAgent],
75
+ optional: [
76
+ IThemeManager,
77
+ IRenderMimeRegistry,
78
+ ITranslator,
79
+ IAskAgent,
80
+ IDiffPreferences
81
+ ],
37
82
  activate: (
38
83
  app: JupyterFrontEnd,
39
84
  themeManager: IThemeManager | null,
40
85
  rendermime: IRenderMimeRegistry | null,
41
86
  translator: ITranslator | null,
42
- askAgent: IAskAgent | null
87
+ askAgent: IAskAgent | null,
88
+ preferences: IDiffPreferences | null
43
89
  ): void => {
44
90
  const trans = (translator ?? nullTranslator).load('jupyterlab');
45
- // Track open diffs so repeated opens reveal the existing tab.
46
91
  const tracker = new WidgetTracker<DiffMainAreaWidget>({
47
92
  namespace: GIT_DIFF_TRACKER_NAMESPACE
48
93
  });
@@ -64,6 +109,7 @@ const diffCommandPlugin: JupyterFrontEndPlugin<void> = {
64
109
  contentsManager: app.serviceManager.contents,
65
110
  rendermime,
66
111
  askAgent,
112
+ preferences: preferences ?? new DiffPreferences(),
67
113
  trans,
68
114
  trackDiff: widget => tracker.add(widget),
69
115
  onPinned: current => {
@@ -86,10 +132,8 @@ const diffCommandPlugin: JupyterFrontEndPlugin<void> = {
86
132
  }
87
133
  };
88
134
 
89
- /**
90
- * Plugins contributed by xtralab's git integration.
91
- */
92
135
  const plugins: JupyterFrontEndPlugin<unknown>[] = [
136
+ diffPreferencesPlugin,
93
137
  diffCommandPlugin,
94
138
  diffProviderPlugin
95
139
  ];