@deck.gl-community/widgets 9.2.8 → 9.3.0-beta.1

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 (295) hide show
  1. package/README.md +9 -1
  2. package/dist/graph-widgets/_deprecate/long-press-button.d.ts.map +1 -0
  3. package/dist/graph-widgets/_deprecate/long-press-button.js.map +1 -0
  4. package/dist/graph-widgets/_deprecate/view-control-widget.d.ts.map +1 -0
  5. package/dist/graph-widgets/_deprecate/view-control-widget.js.map +1 -0
  6. package/dist/{widgets → graph-widgets}/long-press-button.d.ts +1 -0
  7. package/dist/graph-widgets/long-press-button.d.ts.map +1 -0
  8. package/dist/{widgets → graph-widgets}/long-press-button.js +1 -0
  9. package/dist/graph-widgets/long-press-button.js.map +1 -0
  10. package/dist/graph-widgets/long-press-controller.d.ts.map +1 -0
  11. package/dist/graph-widgets/long-press-controller.js.map +1 -0
  12. package/dist/{widgets → graph-widgets}/pan-widget.d.ts +3 -2
  13. package/dist/graph-widgets/pan-widget.d.ts.map +1 -0
  14. package/dist/{widgets → graph-widgets}/pan-widget.js +19 -15
  15. package/dist/graph-widgets/pan-widget.js.map +1 -0
  16. package/dist/{widgets → graph-widgets}/zoom-range-widget.d.ts +3 -3
  17. package/dist/graph-widgets/zoom-range-widget.d.ts.map +1 -0
  18. package/dist/{widgets → graph-widgets}/zoom-range-widget.js +24 -23
  19. package/dist/graph-widgets/zoom-range-widget.js.map +1 -0
  20. package/dist/html-overlay-widgets/html-cluster-widget.d.ts.map +1 -0
  21. package/dist/html-overlay-widgets/html-cluster-widget.js.map +1 -0
  22. package/dist/{widgets → html-overlay-widgets}/html-overlay-item.d.ts +1 -0
  23. package/dist/html-overlay-widgets/html-overlay-item.d.ts.map +1 -0
  24. package/dist/html-overlay-widgets/html-overlay-item.js.map +1 -0
  25. package/dist/{widgets → html-overlay-widgets}/html-overlay-widget.d.ts +1 -1
  26. package/dist/html-overlay-widgets/html-overlay-widget.d.ts.map +1 -0
  27. package/dist/{widgets → html-overlay-widgets}/html-overlay-widget.js +2 -2
  28. package/dist/html-overlay-widgets/html-overlay-widget.js.map +1 -0
  29. package/dist/{widgets → html-overlay-widgets}/html-tooltip-widget.d.ts +1 -0
  30. package/dist/html-overlay-widgets/html-tooltip-widget.d.ts.map +1 -0
  31. package/dist/html-overlay-widgets/html-tooltip-widget.js.map +1 -0
  32. package/dist/index.cjs +5102 -82
  33. package/dist/index.cjs.map +4 -4
  34. package/dist/index.d.ts +33 -12
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +27 -6
  37. package/dist/index.js.map +1 -1
  38. package/dist/keyboard-shortcuts/keyboard-shortcuts-manager.d.ts +18 -0
  39. package/dist/keyboard-shortcuts/keyboard-shortcuts-manager.d.ts.map +1 -0
  40. package/dist/keyboard-shortcuts/keyboard-shortcuts-manager.js +47 -0
  41. package/dist/keyboard-shortcuts/keyboard-shortcuts-manager.js.map +1 -0
  42. package/dist/keyboard-shortcuts/keyboard-shortcuts.d.ts +22 -0
  43. package/dist/keyboard-shortcuts/keyboard-shortcuts.d.ts.map +1 -0
  44. package/dist/keyboard-shortcuts/keyboard-shortcuts.js +83 -0
  45. package/dist/keyboard-shortcuts/keyboard-shortcuts.js.map +1 -0
  46. package/dist/lib/settings/settings.d.ts +17 -0
  47. package/dist/lib/settings/settings.d.ts.map +1 -0
  48. package/dist/lib/settings/settings.js +140 -0
  49. package/dist/lib/settings/settings.js.map +1 -0
  50. package/dist/ready-to-upstream-widgets/reset-view-widget.d.ts +21 -0
  51. package/dist/ready-to-upstream-widgets/reset-view-widget.d.ts.map +1 -0
  52. package/dist/ready-to-upstream-widgets/reset-view-widget.js +29 -0
  53. package/dist/ready-to-upstream-widgets/reset-view-widget.js.map +1 -0
  54. package/dist/widget-components/icon-button.d.ts +12 -0
  55. package/dist/widget-components/icon-button.d.ts.map +1 -0
  56. package/dist/widget-components/icon-button.js +12 -0
  57. package/dist/widget-components/icon-button.js.map +1 -0
  58. package/dist/widget-components/select-widget-component.d.ts +15 -0
  59. package/dist/widget-components/select-widget-component.d.ts.map +1 -0
  60. package/dist/widget-components/select-widget-component.js +229 -0
  61. package/dist/widget-components/select-widget-component.js.map +1 -0
  62. package/dist/widget-panels/box-widget.d.ts +43 -0
  63. package/dist/widget-panels/box-widget.d.ts.map +1 -0
  64. package/dist/widget-panels/box-widget.js +191 -0
  65. package/dist/widget-panels/box-widget.js.map +1 -0
  66. package/dist/widget-panels/box-widget.test.d.ts +2 -0
  67. package/dist/widget-panels/box-widget.test.d.ts.map +1 -0
  68. package/dist/widget-panels/box-widget.test.js +41 -0
  69. package/dist/widget-panels/box-widget.test.js.map +1 -0
  70. package/dist/widget-panels/full-screen-panel-widget.d.ts +33 -0
  71. package/dist/widget-panels/full-screen-panel-widget.d.ts.map +1 -0
  72. package/dist/widget-panels/full-screen-panel-widget.js +153 -0
  73. package/dist/widget-panels/full-screen-panel-widget.js.map +1 -0
  74. package/dist/widget-panels/full-screen-panel-widget.test.d.ts +2 -0
  75. package/dist/widget-panels/full-screen-panel-widget.test.d.ts.map +1 -0
  76. package/dist/widget-panels/full-screen-panel-widget.test.js +40 -0
  77. package/dist/widget-panels/full-screen-panel-widget.test.js.map +1 -0
  78. package/dist/widget-panels/heap-memory-widget.d.ts +26 -0
  79. package/dist/widget-panels/heap-memory-widget.d.ts.map +1 -0
  80. package/dist/widget-panels/heap-memory-widget.js +156 -0
  81. package/dist/widget-panels/heap-memory-widget.js.map +1 -0
  82. package/dist/widget-panels/keyboard-shortcuts-widget.d.ts +46 -0
  83. package/dist/widget-panels/keyboard-shortcuts-widget.d.ts.map +1 -0
  84. package/dist/widget-panels/keyboard-shortcuts-widget.js +301 -0
  85. package/dist/widget-panels/keyboard-shortcuts-widget.js.map +1 -0
  86. package/dist/widget-panels/modal-widget.d.ts +62 -0
  87. package/dist/widget-panels/modal-widget.d.ts.map +1 -0
  88. package/dist/widget-panels/modal-widget.js +309 -0
  89. package/dist/widget-panels/modal-widget.js.map +1 -0
  90. package/dist/widget-panels/modal-widget.test.d.ts +2 -0
  91. package/dist/widget-panels/modal-widget.test.d.ts.map +1 -0
  92. package/dist/widget-panels/modal-widget.test.js +103 -0
  93. package/dist/widget-panels/modal-widget.test.js.map +1 -0
  94. package/dist/widget-panels/omni-box-widget.d.ts +59 -0
  95. package/dist/widget-panels/omni-box-widget.d.ts.map +1 -0
  96. package/dist/widget-panels/omni-box-widget.js +562 -0
  97. package/dist/widget-panels/omni-box-widget.js.map +1 -0
  98. package/dist/widget-panels/omni-box-widget.test.d.ts +2 -0
  99. package/dist/widget-panels/omni-box-widget.test.d.ts.map +1 -0
  100. package/dist/widget-panels/omni-box-widget.test.js +49 -0
  101. package/dist/widget-panels/omni-box-widget.test.js.map +1 -0
  102. package/dist/widget-panels/reset-view-widget.d.ts +20 -0
  103. package/dist/widget-panels/reset-view-widget.d.ts.map +1 -0
  104. package/dist/widget-panels/reset-view-widget.js +28 -0
  105. package/dist/widget-panels/reset-view-widget.js.map +1 -0
  106. package/dist/widget-panels/settings-panel.d.ts +49 -0
  107. package/dist/widget-panels/settings-panel.d.ts.map +1 -0
  108. package/dist/widget-panels/settings-panel.js +263 -0
  109. package/dist/widget-panels/settings-panel.js.map +1 -0
  110. package/dist/widget-panels/settings-panel.test.d.ts +2 -0
  111. package/dist/widget-panels/settings-panel.test.d.ts.map +1 -0
  112. package/dist/widget-panels/settings-panel.test.js +217 -0
  113. package/dist/widget-panels/settings-panel.test.js.map +1 -0
  114. package/dist/widget-panels/sidebar-widget.d.ts +65 -0
  115. package/dist/widget-panels/sidebar-widget.d.ts.map +1 -0
  116. package/dist/widget-panels/sidebar-widget.js +339 -0
  117. package/dist/widget-panels/sidebar-widget.js.map +1 -0
  118. package/dist/widget-panels/sidebar-widget.test.d.ts +2 -0
  119. package/dist/widget-panels/sidebar-widget.test.d.ts.map +1 -0
  120. package/dist/widget-panels/sidebar-widget.test.js +175 -0
  121. package/dist/widget-panels/sidebar-widget.test.js.map +1 -0
  122. package/dist/widget-panels/stats-panel.d.ts +34 -0
  123. package/dist/widget-panels/stats-panel.d.ts.map +1 -0
  124. package/dist/widget-panels/stats-panel.js +61 -0
  125. package/dist/widget-panels/stats-panel.js.map +1 -0
  126. package/dist/widget-panels/stats-panel.test.d.ts +2 -0
  127. package/dist/widget-panels/stats-panel.test.d.ts.map +1 -0
  128. package/dist/widget-panels/stats-panel.test.js +36 -0
  129. package/dist/widget-panels/stats-panel.test.js.map +1 -0
  130. package/dist/widget-panels/text-editor-panel-monaco-runtime.d.ts +17 -0
  131. package/dist/widget-panels/text-editor-panel-monaco-runtime.d.ts.map +1 -0
  132. package/dist/widget-panels/text-editor-panel-monaco-runtime.js +69 -0
  133. package/dist/widget-panels/text-editor-panel-monaco-runtime.js.map +1 -0
  134. package/dist/widget-panels/text-editor-panel.d.ts +42 -0
  135. package/dist/widget-panels/text-editor-panel.d.ts.map +1 -0
  136. package/dist/widget-panels/text-editor-panel.js +249 -0
  137. package/dist/widget-panels/text-editor-panel.js.map +1 -0
  138. package/dist/widget-panels/text-editor-panel.test.d.ts +2 -0
  139. package/dist/widget-panels/text-editor-panel.test.d.ts.map +1 -0
  140. package/dist/widget-panels/text-editor-panel.test.js +393 -0
  141. package/dist/widget-panels/text-editor-panel.test.js.map +1 -0
  142. package/dist/widget-panels/time-measure-widget.d.ts +49 -0
  143. package/dist/widget-panels/time-measure-widget.d.ts.map +1 -0
  144. package/dist/widget-panels/time-measure-widget.js +351 -0
  145. package/dist/widget-panels/time-measure-widget.js.map +1 -0
  146. package/dist/widget-panels/toast-manager.d.ts +24 -0
  147. package/dist/widget-panels/toast-manager.d.ts.map +1 -0
  148. package/dist/widget-panels/toast-manager.js +96 -0
  149. package/dist/widget-panels/toast-manager.js.map +1 -0
  150. package/dist/widget-panels/toast-manager.test.d.ts +2 -0
  151. package/dist/widget-panels/toast-manager.test.d.ts.map +1 -0
  152. package/dist/widget-panels/toast-manager.test.js +75 -0
  153. package/dist/widget-panels/toast-manager.test.js.map +1 -0
  154. package/dist/widget-panels/toast-widget.d.ts +20 -0
  155. package/dist/widget-panels/toast-widget.d.ts.map +1 -0
  156. package/dist/widget-panels/toast-widget.js +207 -0
  157. package/dist/widget-panels/toast-widget.js.map +1 -0
  158. package/dist/widget-panels/toast-widget.test.d.ts +2 -0
  159. package/dist/widget-panels/toast-widget.test.d.ts.map +1 -0
  160. package/dist/widget-panels/toast-widget.test.js +81 -0
  161. package/dist/widget-panels/toast-widget.test.js.map +1 -0
  162. package/dist/widget-panels/toggle-widget.d.ts +34 -0
  163. package/dist/widget-panels/toggle-widget.d.ts.map +1 -0
  164. package/dist/widget-panels/toggle-widget.js +46 -0
  165. package/dist/widget-panels/toggle-widget.js.map +1 -0
  166. package/dist/widget-panels/toolbar-widget.d.ts +53 -0
  167. package/dist/widget-panels/toolbar-widget.d.ts.map +1 -0
  168. package/dist/widget-panels/toolbar-widget.js +160 -0
  169. package/dist/widget-panels/toolbar-widget.js.map +1 -0
  170. package/dist/widget-panels/toolbar-widget.test.d.ts +2 -0
  171. package/dist/widget-panels/toolbar-widget.test.d.ts.map +1 -0
  172. package/dist/widget-panels/toolbar-widget.test.js +105 -0
  173. package/dist/widget-panels/toolbar-widget.test.js.map +1 -0
  174. package/dist/widget-panels/widget-containers.d.ts +275 -0
  175. package/dist/widget-panels/widget-containers.d.ts.map +1 -0
  176. package/dist/widget-panels/widget-containers.js +761 -0
  177. package/dist/widget-panels/widget-containers.js.map +1 -0
  178. package/dist/widget-panels/widget-containers.test.d.ts +2 -0
  179. package/dist/widget-panels/widget-containers.test.d.ts.map +1 -0
  180. package/dist/widget-panels/widget-containers.test.js +337 -0
  181. package/dist/widget-panels/widget-containers.test.js.map +1 -0
  182. package/dist/widget-panels/y-zoom-widget.d.ts +66 -0
  183. package/dist/widget-panels/y-zoom-widget.d.ts.map +1 -0
  184. package/dist/widget-panels/y-zoom-widget.js +264 -0
  185. package/dist/widget-panels/y-zoom-widget.js.map +1 -0
  186. package/dist/widget-panels/y-zoom-widget.test.d.ts +2 -0
  187. package/dist/widget-panels/y-zoom-widget.test.d.ts.map +1 -0
  188. package/dist/widget-panels/y-zoom-widget.test.js +71 -0
  189. package/dist/widget-panels/y-zoom-widget.test.js.map +1 -0
  190. package/dist/widgets/heap-memory-widget.d.ts +26 -0
  191. package/dist/widgets/heap-memory-widget.d.ts.map +1 -0
  192. package/dist/widgets/heap-memory-widget.js +158 -0
  193. package/dist/widgets/heap-memory-widget.js.map +1 -0
  194. package/dist/widgets/keyboard-shortcuts-widget.d.ts +28 -0
  195. package/dist/widgets/keyboard-shortcuts-widget.d.ts.map +1 -0
  196. package/dist/widgets/keyboard-shortcuts-widget.js +125 -0
  197. package/dist/widgets/keyboard-shortcuts-widget.js.map +1 -0
  198. package/dist/widgets/omni-box-widget.d.ts +59 -0
  199. package/dist/widgets/omni-box-widget.d.ts.map +1 -0
  200. package/dist/widgets/omni-box-widget.js +493 -0
  201. package/dist/widgets/omni-box-widget.js.map +1 -0
  202. package/dist/widgets/settings-widget.d.ts +64 -0
  203. package/dist/widgets/settings-widget.d.ts.map +1 -0
  204. package/dist/widgets/settings-widget.js +148 -0
  205. package/dist/widgets/settings-widget.js.map +1 -0
  206. package/dist/widgets/view-manager-utils.d.ts +1 -1
  207. package/dist/widgets/view-manager-utils.d.ts.map +1 -1
  208. package/dist/widgets/view-manager-utils.js.map +1 -1
  209. package/package.json +4 -3
  210. package/src/{widgets → graph-widgets}/long-press-button.tsx +1 -0
  211. package/src/{widgets → graph-widgets}/pan-widget.tsx +30 -23
  212. package/src/{widgets → graph-widgets}/zoom-range-widget.tsx +36 -34
  213. package/src/{widgets → html-overlay-widgets}/html-overlay-item.tsx +1 -0
  214. package/src/{widgets → html-overlay-widgets}/html-overlay-widget.tsx +2 -2
  215. package/src/{widgets → html-overlay-widgets}/html-tooltip-widget.tsx +1 -0
  216. package/src/index.ts +109 -12
  217. package/src/keyboard-shortcuts/keyboard-shortcuts-manager.ts +58 -0
  218. package/src/keyboard-shortcuts/keyboard-shortcuts.ts +113 -0
  219. package/src/keyboard-shortcuts/keyboard-shortcuts.ts.disabled +107 -0
  220. package/src/lib/settings/settings.ts +203 -0
  221. package/src/ready-to-upstream-widgets/reset-view-widget.tsx +57 -0
  222. package/src/widget-components/icon-button.tsx +38 -0
  223. package/src/widget-components/select-widget-component.tsx +354 -0
  224. package/src/widget-panels/box-widget.test.tsx +50 -0
  225. package/src/widget-panels/box-widget.tsx +284 -0
  226. package/src/widget-panels/full-screen-panel-widget.test.tsx +49 -0
  227. package/src/widget-panels/full-screen-panel-widget.tsx +223 -0
  228. package/src/widget-panels/heap-memory-widget.tsx +221 -0
  229. package/src/widget-panels/keyboard-shortcuts-widget.tsx +511 -0
  230. package/src/widget-panels/modal-widget.test.tsx +124 -0
  231. package/src/widget-panels/modal-widget.tsx +464 -0
  232. package/src/widget-panels/omni-box-widget.test.tsx +59 -0
  233. package/src/widget-panels/omni-box-widget.tsx +849 -0
  234. package/src/widget-panels/reset-view-widget.tsx +56 -0
  235. package/src/widget-panels/settings-panel.test.tsx +286 -0
  236. package/src/widget-panels/settings-panel.tsx +619 -0
  237. package/src/widget-panels/sidebar-widget.test.tsx +215 -0
  238. package/src/widget-panels/sidebar-widget.tsx +525 -0
  239. package/src/widget-panels/stats-panel.test.tsx +41 -0
  240. package/src/widget-panels/stats-panel.tsx +108 -0
  241. package/src/widget-panels/text-editor-panel-monaco-runtime.ts +97 -0
  242. package/src/widget-panels/text-editor-panel.test.tsx +618 -0
  243. package/src/widget-panels/text-editor-panel.tsx +375 -0
  244. package/src/widget-panels/time-measure-widget.tsx +445 -0
  245. package/src/widget-panels/toast-manager.test.ts +98 -0
  246. package/src/widget-panels/toast-manager.ts +134 -0
  247. package/src/widget-panels/toast-widget.test.tsx +105 -0
  248. package/src/widget-panels/toast-widget.tsx +293 -0
  249. package/src/widget-panels/toggle-widget.tsx +93 -0
  250. package/src/widget-panels/toolbar-widget.test.ts +129 -0
  251. package/src/widget-panels/toolbar-widget.tsx +293 -0
  252. package/src/widget-panels/widget-containers.test.tsx +453 -0
  253. package/src/widget-panels/widget-containers.tsx +1330 -0
  254. package/src/widget-panels/worker-modules.d.ts +7 -0
  255. package/src/widget-panels/y-zoom-widget.test.tsx +101 -0
  256. package/src/widget-panels/y-zoom-widget.tsx +376 -0
  257. package/src/widgets/heap-memory-widget.tsx +223 -0
  258. package/src/widgets/keyboard-shortcuts-widget.tsx +245 -0
  259. package/src/widgets/omni-box-widget.tsx +768 -0
  260. package/src/widgets/settings-widget.tsx +277 -0
  261. package/src/widgets/view-manager-utils.ts +1 -1
  262. package/dist/_deprecate/long-press-button.d.ts.map +0 -1
  263. package/dist/_deprecate/long-press-button.js.map +0 -1
  264. package/dist/_deprecate/view-control-widget.d.ts.map +0 -1
  265. package/dist/_deprecate/view-control-widget.js.map +0 -1
  266. package/dist/widgets/html-cluster-widget.d.ts.map +0 -1
  267. package/dist/widgets/html-cluster-widget.js.map +0 -1
  268. package/dist/widgets/html-overlay-item.d.ts.map +0 -1
  269. package/dist/widgets/html-overlay-item.js.map +0 -1
  270. package/dist/widgets/html-overlay-widget.d.ts.map +0 -1
  271. package/dist/widgets/html-overlay-widget.js.map +0 -1
  272. package/dist/widgets/html-tooltip-widget.d.ts.map +0 -1
  273. package/dist/widgets/html-tooltip-widget.js.map +0 -1
  274. package/dist/widgets/long-press-button.d.ts.map +0 -1
  275. package/dist/widgets/long-press-button.js.map +0 -1
  276. package/dist/widgets/long-press-controller.d.ts.map +0 -1
  277. package/dist/widgets/long-press-controller.js.map +0 -1
  278. package/dist/widgets/pan-widget.d.ts.map +0 -1
  279. package/dist/widgets/pan-widget.js.map +0 -1
  280. package/dist/widgets/zoom-range-widget.d.ts.map +0 -1
  281. package/dist/widgets/zoom-range-widget.js.map +0 -1
  282. /package/dist/{_deprecate → graph-widgets/_deprecate}/long-press-button.d.ts +0 -0
  283. /package/dist/{_deprecate → graph-widgets/_deprecate}/long-press-button.js +0 -0
  284. /package/dist/{_deprecate → graph-widgets/_deprecate}/view-control-widget.d.ts +0 -0
  285. /package/dist/{_deprecate → graph-widgets/_deprecate}/view-control-widget.js +0 -0
  286. /package/dist/{widgets → graph-widgets}/long-press-controller.d.ts +0 -0
  287. /package/dist/{widgets → graph-widgets}/long-press-controller.js +0 -0
  288. /package/dist/{widgets → html-overlay-widgets}/html-cluster-widget.d.ts +0 -0
  289. /package/dist/{widgets → html-overlay-widgets}/html-cluster-widget.js +0 -0
  290. /package/dist/{widgets → html-overlay-widgets}/html-overlay-item.js +0 -0
  291. /package/dist/{widgets → html-overlay-widgets}/html-tooltip-widget.js +0 -0
  292. /package/src/{_deprecate → graph-widgets/_deprecate}/long-press-button.tsx +0 -0
  293. /package/src/{_deprecate → graph-widgets/_deprecate}/view-control-widget.tsx +0 -0
  294. /package/src/{widgets → graph-widgets}/long-press-controller.ts +0 -0
  295. /package/src/{widgets → html-overlay-widgets}/html-cluster-widget.ts +0 -0
@@ -0,0 +1,97 @@
1
+ import type * as MonacoNamespace from 'monaco-editor';
2
+
3
+ /**
4
+ * Shared Monaco runtime services used by the text-editor widget panel.
5
+ */
6
+ export type TextEditorMonacoRuntime = {
7
+ /** Monaco module namespace used for model and editor creation. */
8
+ monaco: typeof MonacoNamespace;
9
+ /** Registers or replaces the JSON schema associated with one model URI. */
10
+ configureJsonSchema: (modelUri: string, schema?: Record<string, unknown>) => void;
11
+ /** Removes the JSON schema associated with one model URI. */
12
+ clearJsonSchema: (modelUri: string) => void;
13
+ };
14
+
15
+ let monacoRuntimePromise: Promise<TextEditorMonacoRuntime> | undefined;
16
+ const jsonSchemasByModelUri = new Map<string, Record<string, unknown>>();
17
+
18
+ /**
19
+ * Lazily loads the Monaco runtime and returns the shared editor services singleton.
20
+ */
21
+ export async function loadTextEditorMonacoRuntime(): Promise<TextEditorMonacoRuntime> {
22
+ monacoRuntimePromise ??= createTextEditorMonacoRuntime();
23
+ return monacoRuntimePromise;
24
+ }
25
+
26
+ /**
27
+ * Creates the Monaco runtime singleton used by text-editor widget panels.
28
+ */
29
+ async function createTextEditorMonacoRuntime(): Promise<TextEditorMonacoRuntime> {
30
+ configureMonacoEnvironment();
31
+
32
+ const [monaco] = await Promise.all([
33
+ import('monaco-editor'),
34
+ import('monaco-editor/esm/vs/language/json/monaco.contribution')
35
+ ]);
36
+
37
+ return {
38
+ monaco,
39
+ configureJsonSchema: (modelUri, schema) => {
40
+ if (schema === undefined) {
41
+ jsonSchemasByModelUri.delete(modelUri);
42
+ } else {
43
+ jsonSchemasByModelUri.set(modelUri, schema);
44
+ }
45
+
46
+ applyJsonDiagnostics(monaco);
47
+ },
48
+ clearJsonSchema: (modelUri) => {
49
+ jsonSchemasByModelUri.delete(modelUri);
50
+ applyJsonDiagnostics(monaco);
51
+ }
52
+ };
53
+ }
54
+
55
+ /**
56
+ * Installs Monaco worker resolution into the current browser-like runtime once.
57
+ */
58
+ function configureMonacoEnvironment(): void {
59
+ const runtimeTarget = globalThis as typeof globalThis & {
60
+ MonacoEnvironment?: {
61
+ getWorker: (_workerId: string, label: string) => Worker;
62
+ };
63
+ };
64
+
65
+ if (runtimeTarget.MonacoEnvironment) {
66
+ return;
67
+ }
68
+
69
+ runtimeTarget.MonacoEnvironment = {
70
+ getWorker: (_workerId, label) => {
71
+ if (label === 'json') {
72
+ return new Worker(
73
+ new URL('monaco-editor/esm/vs/language/json/json.worker.js', import.meta.url),
74
+ {type: 'module'}
75
+ );
76
+ }
77
+ return new Worker(new URL('monaco-editor/esm/vs/editor/editor.worker.js', import.meta.url), {
78
+ type: 'module'
79
+ });
80
+ }
81
+ };
82
+ }
83
+
84
+ /**
85
+ * Recomputes Monaco JSON diagnostics from the active schema registry.
86
+ */
87
+ function applyJsonDiagnostics(monaco: typeof MonacoNamespace): void {
88
+ monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
89
+ validate: true,
90
+ enableSchemaRequest: false,
91
+ schemas: [...jsonSchemasByModelUri.entries()].map(([modelUri, schema]) => ({
92
+ uri: `${modelUri}#schema`,
93
+ fileMatch: [modelUri],
94
+ schema
95
+ }))
96
+ });
97
+ }
@@ -0,0 +1,618 @@
1
+ /** @jsxImportSource preact */
2
+ import {DarkTheme, LightTheme} from '@deck.gl/widgets';
3
+ import {h, render} from 'preact';
4
+ import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
5
+
6
+ import {WidgetContainerRenderer, asPanelContainer} from './widget-containers';
7
+ import {TextEditorPanel} from './text-editor-panel';
8
+
9
+ const monacoHarness = vi.hoisted(() => {
10
+ type FakeListener = () => void;
11
+ type FakeModel = {
12
+ uri: {toString: () => string};
13
+ language: string;
14
+ getValue: () => string;
15
+ setValue: (nextValue: string) => void;
16
+ onDidChangeContent: (listener: FakeListener) => {dispose: () => void};
17
+ dispose: ReturnType<typeof vi.fn>;
18
+ emitUserInput: (nextValue: string) => void;
19
+ };
20
+ type FakeEditor = {
21
+ updateOptions: ReturnType<typeof vi.fn>;
22
+ dispose: ReturnType<typeof vi.fn>;
23
+ };
24
+
25
+ const modelsByUri = new Map<string, FakeModel>();
26
+ const configureJsonSchema = vi.fn();
27
+ const clearJsonSchema = vi.fn();
28
+ const setTheme = vi.fn();
29
+ const loadTextEditorMonacoRuntime = vi.fn();
30
+ let lastCreatedModel: FakeModel | null = null;
31
+ let lastCreatedEditor: FakeEditor | null = null;
32
+
33
+ /**
34
+ * Builds a fake Monaco runtime used by the text-editor widget tests.
35
+ */
36
+ function createRuntime() {
37
+ return {
38
+ monaco: {
39
+ Uri: {
40
+ parse: (uri: string) => ({
41
+ toString: () => uri
42
+ })
43
+ },
44
+ editor: {
45
+ getModel: (uri: {toString: () => string}) => modelsByUri.get(uri.toString()) ?? null,
46
+ createModel: (value: string, language: string, uri: {toString: () => string}) => {
47
+ let currentValue = value;
48
+ const listeners = new Set<FakeListener>();
49
+ const model: FakeModel = {
50
+ uri,
51
+ language,
52
+ getValue: () => currentValue,
53
+ setValue: (nextValue: string) => {
54
+ currentValue = nextValue;
55
+ listeners.forEach((listener) => listener());
56
+ },
57
+ onDidChangeContent: (listener: FakeListener) => {
58
+ listeners.add(listener);
59
+ return {
60
+ dispose: () => listeners.delete(listener)
61
+ };
62
+ },
63
+ dispose: vi.fn(),
64
+ emitUserInput: (nextValue: string) => {
65
+ currentValue = nextValue;
66
+ listeners.forEach((listener) => listener());
67
+ }
68
+ };
69
+ modelsByUri.set(uri.toString(), model);
70
+ lastCreatedModel = model;
71
+ return model;
72
+ },
73
+ create: (_hostElement: HTMLElement, _options: unknown) => {
74
+ const editor: FakeEditor = {
75
+ updateOptions: vi.fn(),
76
+ dispose: vi.fn()
77
+ };
78
+ lastCreatedEditor = editor;
79
+ return editor;
80
+ },
81
+ setModelLanguage: (model: FakeModel, language: string) => {
82
+ model.language = language;
83
+ },
84
+ setTheme
85
+ }
86
+ },
87
+ configureJsonSchema,
88
+ clearJsonSchema
89
+ };
90
+ }
91
+
92
+ /**
93
+ * Resets the fake Monaco harness to the default resolved runtime state.
94
+ */
95
+ function reset() {
96
+ modelsByUri.clear();
97
+ configureJsonSchema.mockReset();
98
+ clearJsonSchema.mockReset();
99
+ setTheme.mockReset();
100
+ loadTextEditorMonacoRuntime.mockReset();
101
+ loadTextEditorMonacoRuntime.mockResolvedValue(createRuntime());
102
+ lastCreatedModel = null;
103
+ lastCreatedEditor = null;
104
+ }
105
+
106
+ /**
107
+ * Returns the most recently created fake Monaco model.
108
+ */
109
+ function getLastCreatedModel(): FakeModel | null {
110
+ return lastCreatedModel;
111
+ }
112
+
113
+ /**
114
+ * Returns the most recently created fake Monaco editor.
115
+ */
116
+ function getLastCreatedEditor(): FakeEditor | null {
117
+ return lastCreatedEditor;
118
+ }
119
+
120
+ return {
121
+ clearJsonSchema,
122
+ configureJsonSchema,
123
+ createRuntime,
124
+ getLastCreatedEditor,
125
+ getLastCreatedModel,
126
+ loadTextEditorMonacoRuntime,
127
+ reset,
128
+ setTheme
129
+ };
130
+ });
131
+
132
+ vi.mock('./text-editor-panel-monaco-runtime', () => ({
133
+ loadTextEditorMonacoRuntime: monacoHarness.loadTextEditorMonacoRuntime
134
+ }));
135
+
136
+ /**
137
+ * Flushes queued microtasks so Preact effects and mocked async loaders settle.
138
+ */
139
+ async function flushMicrotasks(): Promise<void> {
140
+ await Promise.resolve();
141
+ await Promise.resolve();
142
+ await new Promise((resolve) => setTimeout(resolve, 0));
143
+ await Promise.resolve();
144
+ await new Promise((resolve) => setTimeout(resolve, 0));
145
+ }
146
+
147
+ /**
148
+ * Waits until a test predicate becomes true or fails after a bounded number of retries.
149
+ */
150
+ async function waitForCondition(
151
+ predicate: () => boolean,
152
+ message: string,
153
+ attempts = 8
154
+ ): Promise<void> {
155
+ for (let attempt = 0; attempt < attempts; attempt += 1) {
156
+ if (predicate()) {
157
+ return;
158
+ }
159
+ await flushMicrotasks();
160
+ }
161
+
162
+ throw new Error(message);
163
+ }
164
+
165
+ afterEach(() => {
166
+ for (const rootElement of [...document.body.children]) {
167
+ render(null, rootElement as HTMLElement);
168
+ }
169
+ document.body.innerHTML = '';
170
+ });
171
+
172
+ beforeEach(() => {
173
+ monacoHarness.reset();
174
+ });
175
+
176
+ describe('TextEditorPanel', () => {
177
+ it('creates a widget panel with the expected id and title', () => {
178
+ const panel = new TextEditorPanel({
179
+ id: 'text-editor',
180
+ title: 'Text editor'
181
+ });
182
+
183
+ expect(panel.id).toBe('text-editor');
184
+ expect(panel.title).toBe('Text editor');
185
+ });
186
+
187
+ it('renders a loading state before monaco resolves', () => {
188
+ const root = document.createElement('div');
189
+ document.body.appendChild(root);
190
+ let resolveRuntime: ((value: unknown) => void) | undefined;
191
+ const pendingRuntime = new Promise((resolve) => {
192
+ resolveRuntime = resolve;
193
+ });
194
+ monacoHarness.loadTextEditorMonacoRuntime.mockReturnValueOnce(pendingRuntime);
195
+
196
+ render(new TextEditorPanel({id: 'loading', title: 'Loading'}).content, root);
197
+
198
+ expect(root.querySelector('[data-text-editor-loading]')?.textContent).toContain(
199
+ 'Loading editor'
200
+ );
201
+ expect(root.querySelector('[data-text-editor-host]')).toBeNull();
202
+
203
+ resolveRuntime?.(monacoHarness.createRuntime());
204
+ });
205
+
206
+ it('initializes from defaultValue when uncontrolled', async () => {
207
+ const root = document.createElement('div');
208
+ document.body.appendChild(root);
209
+
210
+ render(
211
+ new TextEditorPanel({
212
+ id: 'uncontrolled',
213
+ title: 'Uncontrolled',
214
+ defaultValue: '{\"alpha\":1}'
215
+ }).content,
216
+ root
217
+ );
218
+ await waitForCondition(
219
+ () => monacoHarness.getLastCreatedModel() !== null,
220
+ 'Expected Monaco model to be created for uncontrolled panel.'
221
+ );
222
+
223
+ expect(monacoHarness.getLastCreatedModel()?.getValue()).toBe('{"alpha":1}');
224
+ expect(root.querySelector('[data-text-editor-host]')).toBeTruthy();
225
+ });
226
+
227
+ it('uses the light Monaco theme by default', async () => {
228
+ const root = document.createElement('div');
229
+ document.body.appendChild(root);
230
+
231
+ render(
232
+ h(WidgetContainerRenderer, {
233
+ container: asPanelContainer(new TextEditorPanel({id: 'light', title: 'Light'}))
234
+ }),
235
+ root
236
+ );
237
+
238
+ await waitForCondition(
239
+ () => monacoHarness.getLastCreatedModel() !== null,
240
+ 'Expected Monaco model to be created for light theme panel.'
241
+ );
242
+
243
+ expect(monacoHarness.setTheme).toHaveBeenCalledWith('vs');
244
+ });
245
+
246
+ it('uses the dark Monaco theme for a dark panel override', async () => {
247
+ const root = document.createElement('div');
248
+ document.body.appendChild(root);
249
+
250
+ render(
251
+ h(WidgetContainerRenderer, {
252
+ container: asPanelContainer(
253
+ new TextEditorPanel({
254
+ id: 'dark',
255
+ title: 'Dark',
256
+ theme: 'dark'
257
+ })
258
+ )
259
+ }),
260
+ root
261
+ );
262
+
263
+ await waitForCondition(
264
+ () => monacoHarness.getLastCreatedModel() !== null,
265
+ 'Expected Monaco model to be created for dark theme panel.'
266
+ );
267
+
268
+ expect(monacoHarness.setTheme).toHaveBeenCalledWith('vs-dark');
269
+ });
270
+
271
+ it('uses custom Monaco theme ids when provided', async () => {
272
+ const root = document.createElement('div');
273
+ document.body.appendChild(root);
274
+
275
+ render(
276
+ h(WidgetContainerRenderer, {
277
+ container: asPanelContainer(
278
+ new TextEditorPanel({
279
+ id: 'custom-theme',
280
+ title: 'Custom theme',
281
+ theme: 'dark',
282
+ lightMonacoTheme: 'custom-light',
283
+ darkMonacoTheme: 'custom-dark'
284
+ })
285
+ )
286
+ }),
287
+ root
288
+ );
289
+
290
+ await waitForCondition(
291
+ () => monacoHarness.getLastCreatedModel() !== null,
292
+ 'Expected Monaco model to be created for custom theme panel.'
293
+ );
294
+
295
+ expect(monacoHarness.setTheme).toHaveBeenCalledWith('custom-dark');
296
+ });
297
+
298
+ it('updates the Monaco theme when the effective panel theme changes', async () => {
299
+ const root = document.createElement('div');
300
+ document.body.appendChild(root);
301
+
302
+ render(
303
+ h(WidgetContainerRenderer, {
304
+ container: asPanelContainer(
305
+ new TextEditorPanel({
306
+ id: 'theme-switch',
307
+ title: 'Theme switch',
308
+ theme: 'dark'
309
+ })
310
+ )
311
+ }),
312
+ root
313
+ );
314
+ await waitForCondition(
315
+ () => monacoHarness.getLastCreatedModel() !== null,
316
+ 'Expected Monaco model to be created before theme update.'
317
+ );
318
+
319
+ render(
320
+ h(WidgetContainerRenderer, {
321
+ container: asPanelContainer(
322
+ new TextEditorPanel({
323
+ id: 'theme-switch',
324
+ title: 'Theme switch',
325
+ theme: 'light'
326
+ })
327
+ )
328
+ }),
329
+ root
330
+ );
331
+ await flushMicrotasks();
332
+
333
+ await waitForCondition(
334
+ () => monacoHarness.setTheme.mock.lastCall?.[0] === 'vs',
335
+ 'Expected Monaco theme to update to the light theme.'
336
+ );
337
+ expect(monacoHarness.setTheme).toHaveBeenLastCalledWith('vs');
338
+ });
339
+
340
+ it('updates to the custom light Monaco theme when the effective panel theme changes', async () => {
341
+ const root = document.createElement('div');
342
+ document.body.appendChild(root);
343
+
344
+ render(
345
+ h(WidgetContainerRenderer, {
346
+ container: asPanelContainer(
347
+ new TextEditorPanel({
348
+ id: 'custom-theme-switch',
349
+ title: 'Custom theme switch',
350
+ theme: 'dark',
351
+ lightMonacoTheme: 'custom-light',
352
+ darkMonacoTheme: 'custom-dark'
353
+ })
354
+ )
355
+ }),
356
+ root
357
+ );
358
+ await waitForCondition(
359
+ () => monacoHarness.getLastCreatedModel() !== null,
360
+ 'Expected Monaco model to be created before custom theme update.'
361
+ );
362
+
363
+ render(
364
+ h(WidgetContainerRenderer, {
365
+ container: asPanelContainer(
366
+ new TextEditorPanel({
367
+ id: 'custom-theme-switch',
368
+ title: 'Custom theme switch',
369
+ theme: 'light',
370
+ lightMonacoTheme: 'custom-light',
371
+ darkMonacoTheme: 'custom-dark'
372
+ })
373
+ )
374
+ }),
375
+ root
376
+ );
377
+ await flushMicrotasks();
378
+
379
+ await waitForCondition(
380
+ () => monacoHarness.setTheme.mock.lastCall?.[0] === 'custom-light',
381
+ 'Expected Monaco theme to update to the custom light theme.'
382
+ );
383
+ expect(monacoHarness.setTheme).toHaveBeenLastCalledWith('custom-light');
384
+ });
385
+
386
+ it('updates the Monaco theme when inherited widget theme variables change', async () => {
387
+ const widgetContainer = document.createElement('div');
388
+ const root = document.createElement('div');
389
+ widgetContainer.className = 'deck-widget-container';
390
+ widgetContainer.style.setProperty('--menu-background', LightTheme['--menu-background'] ?? '');
391
+ widgetContainer.appendChild(root);
392
+ document.body.appendChild(widgetContainer);
393
+
394
+ render(
395
+ h(WidgetContainerRenderer, {
396
+ container: asPanelContainer(
397
+ new TextEditorPanel({
398
+ id: 'theme-vars-switch',
399
+ title: 'Theme vars switch'
400
+ })
401
+ )
402
+ }),
403
+ root
404
+ );
405
+ await waitForCondition(
406
+ () => monacoHarness.getLastCreatedModel() !== null,
407
+ 'Expected Monaco model to be created before inherited theme update.'
408
+ );
409
+ expect(monacoHarness.setTheme).toHaveBeenLastCalledWith('vs');
410
+
411
+ widgetContainer.style.setProperty('--menu-background', DarkTheme['--menu-background'] ?? '');
412
+ await waitForCondition(
413
+ () => monacoHarness.setTheme.mock.lastCall?.[0] === 'vs-dark',
414
+ 'Expected Monaco theme to update after inherited widget theme changes.'
415
+ );
416
+
417
+ expect(monacoHarness.setTheme).toHaveBeenLastCalledWith('vs-dark');
418
+ });
419
+
420
+ it('respects controlled value updates', async () => {
421
+ const root = document.createElement('div');
422
+ document.body.appendChild(root);
423
+
424
+ render(
425
+ new TextEditorPanel({
426
+ id: 'controlled',
427
+ title: 'Controlled',
428
+ value: '{"alpha":1}'
429
+ }).content,
430
+ root
431
+ );
432
+ await waitForCondition(
433
+ () => monacoHarness.getLastCreatedModel() !== null,
434
+ 'Expected Monaco model to be created for controlled panel.'
435
+ );
436
+ expect(monacoHarness.getLastCreatedModel()?.getValue()).toBe('{"alpha":1}');
437
+
438
+ render(
439
+ new TextEditorPanel({
440
+ id: 'controlled',
441
+ title: 'Controlled',
442
+ value: '{"alpha":2}'
443
+ }).content,
444
+ root
445
+ );
446
+ await waitForCondition(
447
+ () => monacoHarness.getLastCreatedModel()?.getValue() === '{"alpha":2}',
448
+ 'Expected controlled Monaco value to update after rerender.'
449
+ );
450
+
451
+ expect(monacoHarness.getLastCreatedModel()?.getValue()).toBe('{"alpha":2}');
452
+ });
453
+
454
+ it('calls onValueChange when the editor content changes', async () => {
455
+ const root = document.createElement('div');
456
+ document.body.appendChild(root);
457
+ const onValueChange = vi.fn();
458
+
459
+ render(
460
+ new TextEditorPanel({
461
+ id: 'changes',
462
+ title: 'Changes',
463
+ defaultValue: 'start',
464
+ onValueChange
465
+ }).content,
466
+ root
467
+ );
468
+ await waitForCondition(
469
+ () => monacoHarness.getLastCreatedModel() !== null,
470
+ 'Expected Monaco model before simulating user input.'
471
+ );
472
+
473
+ monacoHarness.getLastCreatedModel()?.emitUserInput('next');
474
+ await waitForCondition(
475
+ () => onValueChange.mock.calls.length > 0,
476
+ 'Expected onValueChange to be called after simulated input.'
477
+ );
478
+
479
+ expect(onValueChange).toHaveBeenLastCalledWith('next');
480
+ });
481
+
482
+ it('applies JSON-schema configuration only in json mode', async () => {
483
+ const root = document.createElement('div');
484
+ document.body.appendChild(root);
485
+
486
+ render(
487
+ new TextEditorPanel({
488
+ id: 'json-editor',
489
+ title: 'JSON editor',
490
+ jsonSchema: {
491
+ type: 'object'
492
+ }
493
+ }).content,
494
+ root
495
+ );
496
+ await waitForCondition(
497
+ () => monacoHarness.configureJsonSchema.mock.calls.length > 0,
498
+ 'Expected JSON schema registration for JSON editor.'
499
+ );
500
+
501
+ expect(monacoHarness.configureJsonSchema).toHaveBeenCalledWith(
502
+ 'inmemory://deck-gl-community/widgets/json-editor',
503
+ {type: 'object'}
504
+ );
505
+
506
+ render(
507
+ new TextEditorPanel({
508
+ id: 'plain-editor',
509
+ title: 'Plain editor',
510
+ language: 'plaintext',
511
+ jsonSchema: {
512
+ type: 'object'
513
+ }
514
+ }).content,
515
+ root
516
+ );
517
+ await waitForCondition(
518
+ () =>
519
+ monacoHarness.clearJsonSchema.mock.calls.some(
520
+ ([uri]) => uri === 'inmemory://deck-gl-community/widgets/plain-editor'
521
+ ),
522
+ 'Expected plain-text mode to clear JSON schema registration.'
523
+ );
524
+
525
+ expect(monacoHarness.clearJsonSchema).toHaveBeenCalledWith(
526
+ 'inmemory://deck-gl-community/widgets/plain-editor'
527
+ );
528
+ });
529
+
530
+ it('updates schema registration when jsonSchema changes', async () => {
531
+ const root = document.createElement('div');
532
+ document.body.appendChild(root);
533
+
534
+ render(
535
+ new TextEditorPanel({
536
+ id: 'schema-editor',
537
+ title: 'Schema editor',
538
+ jsonSchema: {
539
+ type: 'object',
540
+ required: ['alpha']
541
+ }
542
+ }).content,
543
+ root
544
+ );
545
+ await flushMicrotasks();
546
+
547
+ render(
548
+ new TextEditorPanel({
549
+ id: 'schema-editor',
550
+ title: 'Schema editor',
551
+ jsonSchema: {
552
+ type: 'object',
553
+ required: ['beta']
554
+ }
555
+ }).content,
556
+ root
557
+ );
558
+ await flushMicrotasks();
559
+
560
+ await waitForCondition(
561
+ () =>
562
+ monacoHarness.configureJsonSchema.mock.lastCall?.[0] ===
563
+ 'inmemory://deck-gl-community/widgets/schema-editor' &&
564
+ JSON.stringify(monacoHarness.configureJsonSchema.mock.lastCall?.[1]) ===
565
+ JSON.stringify({
566
+ type: 'object',
567
+ required: ['beta']
568
+ }),
569
+ 'Expected schema registration to update after jsonSchema changes.'
570
+ );
571
+ expect(monacoHarness.configureJsonSchema).toHaveBeenLastCalledWith(
572
+ 'inmemory://deck-gl-community/widgets/schema-editor',
573
+ {
574
+ type: 'object',
575
+ required: ['beta']
576
+ }
577
+ );
578
+ });
579
+
580
+ it('disposes editor resources on unmount', async () => {
581
+ const root = document.createElement('div');
582
+ document.body.appendChild(root);
583
+
584
+ render(new TextEditorPanel({id: 'dispose', title: 'Dispose'}).content, root);
585
+ await waitForCondition(
586
+ () =>
587
+ monacoHarness.getLastCreatedModel() !== null &&
588
+ monacoHarness.getLastCreatedEditor() !== null,
589
+ 'Expected Monaco resources before unmount.'
590
+ );
591
+
592
+ const model = monacoHarness.getLastCreatedModel();
593
+ const editor = monacoHarness.getLastCreatedEditor();
594
+
595
+ render(null, root);
596
+ await flushMicrotasks();
597
+
598
+ expect(editor?.dispose).toHaveBeenCalledTimes(1);
599
+ expect(model?.dispose).toHaveBeenCalledTimes(1);
600
+ expect(monacoHarness.clearJsonSchema).toHaveBeenCalledWith(
601
+ 'inmemory://deck-gl-community/widgets/dispose'
602
+ );
603
+ });
604
+
605
+ it('renders a load error fallback when monaco loading fails', async () => {
606
+ const root = document.createElement('div');
607
+ document.body.appendChild(root);
608
+ monacoHarness.loadTextEditorMonacoRuntime.mockRejectedValueOnce(new Error('boom'));
609
+
610
+ render(new TextEditorPanel({id: 'error', title: 'Error'}).content, root);
611
+ await waitForCondition(
612
+ () => (root.querySelector('[data-text-editor-error]')?.textContent ?? '').includes('boom'),
613
+ 'Expected text editor error fallback to render when Monaco loading fails.'
614
+ );
615
+
616
+ expect(root.querySelector('[data-text-editor-error]')?.textContent).toContain('boom');
617
+ });
618
+ });