@dxos/plugin-script 0.7.4-staging.f7e8224 → 0.7.5-labs.071a3e2

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 (267) hide show
  1. package/dist/lib/browser/{AutomationPanel-PMTZROAZ.mjs → AutomationPanel-J3SZ5L3Y.mjs} +4 -11
  2. package/dist/lib/browser/AutomationPanel-J3SZ5L3Y.mjs.map +7 -0
  3. package/dist/lib/browser/ScriptContainer-LGW52UAJ.mjs +688 -0
  4. package/dist/lib/browser/ScriptContainer-LGW52UAJ.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-2UXYECEH.mjs +236 -0
  6. package/dist/lib/browser/chunk-2UXYECEH.mjs.map +7 -0
  7. package/dist/lib/browser/{chunk-K7KY6YMG.mjs → chunk-45LXDWNF.mjs} +2 -2
  8. package/dist/lib/browser/chunk-6MOQ4BP3.mjs +15 -0
  9. package/dist/lib/browser/chunk-6MOQ4BP3.mjs.map +7 -0
  10. package/dist/lib/browser/chunk-FVVCAWNP.mjs +21 -0
  11. package/dist/lib/browser/chunk-FVVCAWNP.mjs.map +7 -0
  12. package/dist/lib/browser/chunk-N46LE7FS.mjs +40 -0
  13. package/dist/lib/browser/chunk-N46LE7FS.mjs.map +7 -0
  14. package/dist/lib/browser/{chunk-4UTRJLQ3.mjs → chunk-SDHKTS6H.mjs} +2 -51
  15. package/dist/lib/browser/{chunk-4UTRJLQ3.mjs.map → chunk-SDHKTS6H.mjs.map} +4 -4
  16. package/dist/lib/browser/chunk-VIX22OMB.mjs +60 -0
  17. package/dist/lib/browser/chunk-VIX22OMB.mjs.map +7 -0
  18. package/dist/lib/browser/compiler-K3FNRDDN.mjs +84 -0
  19. package/dist/lib/browser/compiler-K3FNRDDN.mjs.map +7 -0
  20. package/dist/lib/browser/index.mjs +109 -357
  21. package/dist/lib/browser/index.mjs.map +4 -4
  22. package/dist/lib/browser/intent-resolver-CMKQTLBG.mjs +45 -0
  23. package/dist/lib/browser/intent-resolver-CMKQTLBG.mjs.map +7 -0
  24. package/dist/lib/browser/meta.json +1 -1
  25. package/dist/lib/browser/react-surface-XACNR5NR.mjs +65 -0
  26. package/dist/lib/browser/react-surface-XACNR5NR.mjs.map +7 -0
  27. package/dist/lib/browser/settings-SZCDKHWO.mjs +24 -0
  28. package/dist/lib/browser/settings-SZCDKHWO.mjs.map +7 -0
  29. package/dist/lib/browser/types.mjs +10 -0
  30. package/dist/lib/node/{AutomationPanel-AAGQREH7.cjs → AutomationPanel-4M55FURO.cjs} +16 -17
  31. package/dist/lib/node/AutomationPanel-4M55FURO.cjs.map +7 -0
  32. package/dist/lib/node/ScriptContainer-UI2MDBYG.cjs +692 -0
  33. package/dist/lib/node/ScriptContainer-UI2MDBYG.cjs.map +7 -0
  34. package/dist/lib/node/{chunk-6LYX73ZT.cjs → chunk-5UH3F7TA.cjs} +11 -8
  35. package/dist/lib/node/chunk-5UH3F7TA.cjs.map +7 -0
  36. package/dist/lib/node/chunk-73345ZL6.cjs +264 -0
  37. package/dist/lib/node/chunk-73345ZL6.cjs.map +7 -0
  38. package/dist/lib/node/{meta.cjs → chunk-ALY3N6PW.cjs} +12 -8
  39. package/dist/lib/node/chunk-ALY3N6PW.cjs.map +7 -0
  40. package/dist/lib/node/chunk-DJGLGRQV.cjs +60 -0
  41. package/dist/lib/node/chunk-DJGLGRQV.cjs.map +7 -0
  42. package/dist/lib/node/{chunk-4INUJLXL.cjs → chunk-IID7WUQS.cjs} +6 -6
  43. package/dist/lib/node/chunk-PKT5DD3O.cjs +70 -0
  44. package/dist/lib/node/chunk-PKT5DD3O.cjs.map +7 -0
  45. package/dist/lib/node/{chunk-WPP65EYS.cjs → chunk-T4TXCRN5.cjs} +6 -44
  46. package/dist/lib/node/chunk-T4TXCRN5.cjs.map +7 -0
  47. package/dist/lib/node/compiler-P2HQB22H.cjs +104 -0
  48. package/dist/lib/node/compiler-P2HQB22H.cjs.map +7 -0
  49. package/dist/lib/node/index.cjs +106 -346
  50. package/dist/lib/node/index.cjs.map +4 -4
  51. package/dist/lib/node/intent-resolver-V5ASU5DW.cjs +59 -0
  52. package/dist/lib/node/intent-resolver-V5ASU5DW.cjs.map +7 -0
  53. package/dist/lib/node/meta.json +1 -1
  54. package/dist/lib/node/react-surface-Y3RD5FW7.cjs +84 -0
  55. package/dist/lib/node/react-surface-Y3RD5FW7.cjs.map +7 -0
  56. package/dist/lib/node/settings-SZFSMSKM.cjs +38 -0
  57. package/dist/lib/node/settings-SZFSMSKM.cjs.map +7 -0
  58. package/dist/lib/node/{types/index.cjs → types.cjs} +6 -8
  59. package/dist/lib/node/types.cjs.map +7 -0
  60. package/dist/lib/node-esm/{AutomationPanel-ETQEDY5I.mjs → AutomationPanel-W6SKG35R.mjs} +4 -11
  61. package/dist/lib/node-esm/AutomationPanel-W6SKG35R.mjs.map +7 -0
  62. package/dist/lib/node-esm/ScriptContainer-F7SNP53Z.mjs +689 -0
  63. package/dist/lib/node-esm/ScriptContainer-F7SNP53Z.mjs.map +7 -0
  64. package/dist/lib/node-esm/{chunk-OFYGBUNI.mjs → chunk-CGF7EOGD.mjs} +2 -2
  65. package/dist/lib/node-esm/chunk-CP5LXTK5.mjs +16 -0
  66. package/dist/lib/node-esm/chunk-CP5LXTK5.mjs.map +7 -0
  67. package/dist/lib/node-esm/{chunk-4SRPREUK.mjs → chunk-G76M6O46.mjs} +2 -51
  68. package/dist/lib/node-esm/{chunk-4SRPREUK.mjs.map → chunk-G76M6O46.mjs.map} +4 -4
  69. package/dist/lib/node-esm/chunk-NBAL5DXN.mjs +62 -0
  70. package/dist/lib/node-esm/chunk-NBAL5DXN.mjs.map +7 -0
  71. package/dist/lib/node-esm/{chunk-SLTZMY34.mjs → chunk-P2V2Y5LV.mjs} +7 -4
  72. package/dist/lib/node-esm/chunk-P2V2Y5LV.mjs.map +7 -0
  73. package/dist/lib/node-esm/chunk-PRGBYF4B.mjs +237 -0
  74. package/dist/lib/node-esm/chunk-PRGBYF4B.mjs.map +7 -0
  75. package/dist/lib/node-esm/chunk-UNQFIERE.mjs +41 -0
  76. package/dist/lib/node-esm/chunk-UNQFIERE.mjs.map +7 -0
  77. package/dist/lib/node-esm/compiler-PDN46H4Y.mjs +85 -0
  78. package/dist/lib/node-esm/compiler-PDN46H4Y.mjs.map +7 -0
  79. package/dist/lib/node-esm/index.mjs +109 -357
  80. package/dist/lib/node-esm/index.mjs.map +4 -4
  81. package/dist/lib/node-esm/intent-resolver-75BHFRUK.mjs +46 -0
  82. package/dist/lib/node-esm/intent-resolver-75BHFRUK.mjs.map +7 -0
  83. package/dist/lib/node-esm/meta.json +1 -1
  84. package/dist/lib/node-esm/react-surface-PKUVZH4S.mjs +66 -0
  85. package/dist/lib/node-esm/react-surface-PKUVZH4S.mjs.map +7 -0
  86. package/dist/lib/node-esm/settings-GR4O2WHZ.mjs +25 -0
  87. package/dist/lib/node-esm/settings-GR4O2WHZ.mjs.map +7 -0
  88. package/dist/lib/node-esm/types.mjs +11 -0
  89. package/dist/types/src/ScriptPlugin.d.ts +1 -3
  90. package/dist/types/src/ScriptPlugin.d.ts.map +1 -1
  91. package/dist/types/src/capabilities/capabilities.d.ts +5 -0
  92. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -0
  93. package/dist/types/src/capabilities/compiler.d.ts +4 -0
  94. package/dist/types/src/capabilities/compiler.d.ts.map +1 -0
  95. package/dist/types/src/capabilities/index.d.ts +6 -0
  96. package/dist/types/src/capabilities/index.d.ts.map +1 -0
  97. package/dist/types/src/capabilities/intent-resolver.d.ts +4 -0
  98. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -0
  99. package/dist/types/src/capabilities/react-surface.d.ts +4 -0
  100. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  101. package/dist/types/src/capabilities/settings.d.ts +4 -0
  102. package/dist/types/src/capabilities/settings.d.ts.map +1 -0
  103. package/dist/types/src/components/AutomationPanel/AutomationPanel.d.ts +2 -2
  104. package/dist/types/src/components/AutomationPanel/AutomationPanel.d.ts.map +1 -1
  105. package/dist/types/src/components/ScriptContainer.d.ts +10 -2
  106. package/dist/types/src/components/ScriptContainer.d.ts.map +1 -1
  107. package/dist/types/src/components/ScriptSettings/ScriptSettings.d.ts.map +1 -1
  108. package/dist/types/src/components/ScriptSettingsPanel.d.ts +1 -1
  109. package/dist/types/src/components/ScriptSettingsPanel.d.ts.map +1 -1
  110. package/dist/types/src/components/ScriptToolbar/ScriptToolbar.d.ts +11 -0
  111. package/dist/types/src/components/ScriptToolbar/ScriptToolbar.d.ts.map +1 -0
  112. package/dist/types/src/components/{Toolbar/Toolbar.stories.d.ts → ScriptToolbar/ScriptToolbar.stories.d.ts} +1 -1
  113. package/dist/types/src/components/ScriptToolbar/ScriptToolbar.stories.d.ts.map +1 -0
  114. package/dist/types/src/components/ScriptToolbar/index.d.ts +2 -0
  115. package/dist/types/src/components/ScriptToolbar/index.d.ts.map +1 -0
  116. package/dist/types/src/components/TypescriptEditor/TypescriptEditor.d.ts +4 -2
  117. package/dist/types/src/components/TypescriptEditor/TypescriptEditor.d.ts.map +1 -1
  118. package/dist/types/src/components/TypescriptEditor/TypescriptEditor.stories.d.ts.map +1 -1
  119. package/dist/types/src/components/index.d.ts +1 -1
  120. package/dist/types/src/components/index.d.ts.map +1 -1
  121. package/dist/types/src/hooks/deploy.d.ts +48 -0
  122. package/dist/types/src/hooks/deploy.d.ts.map +1 -0
  123. package/dist/types/src/hooks/format.d.ts +25 -0
  124. package/dist/types/src/hooks/format.d.ts.map +1 -0
  125. package/dist/types/src/hooks/index.d.ts +7 -0
  126. package/dist/types/src/hooks/index.d.ts.map +1 -0
  127. package/dist/types/src/hooks/template.d.ts +31 -0
  128. package/dist/types/src/hooks/template.d.ts.map +1 -0
  129. package/dist/types/src/hooks/useToolbarAction.d.ts +14 -0
  130. package/dist/types/src/hooks/useToolbarAction.d.ts.map +1 -0
  131. package/dist/types/src/hooks/useToolbarState.d.ts +10 -0
  132. package/dist/types/src/hooks/useToolbarState.d.ts.map +1 -0
  133. package/dist/types/src/hooks/view.d.ts +33 -0
  134. package/dist/types/src/hooks/view.d.ts.map +1 -0
  135. package/dist/types/src/index.d.ts +2 -4
  136. package/dist/types/src/index.d.ts.map +1 -1
  137. package/dist/types/src/meta.d.ts +2 -2
  138. package/dist/types/src/meta.d.ts.map +1 -1
  139. package/dist/types/src/templates/echo.d.ts.map +1 -1
  140. package/dist/types/src/templates/email.d.ts +2 -1
  141. package/dist/types/src/templates/email.d.ts.map +1 -1
  142. package/dist/types/src/templates/forex-effect.d.ts +6 -0
  143. package/dist/types/src/templates/forex-effect.d.ts.map +1 -0
  144. package/dist/types/src/templates/forex.d.ts +1 -1
  145. package/dist/types/src/templates/forex.d.ts.map +1 -1
  146. package/dist/types/src/{templates.d.ts → templates/index.d.ts} +1 -1
  147. package/dist/types/src/templates/index.d.ts.map +1 -0
  148. package/dist/types/src/translations.d.ts +54 -0
  149. package/dist/types/src/translations.d.ts.map +1 -1
  150. package/dist/types/src/types.d.ts +30 -0
  151. package/dist/types/src/types.d.ts.map +1 -0
  152. package/dist/types/tsconfig.tsbuildinfo +1 -0
  153. package/package.json +46 -55
  154. package/src/ScriptPlugin.tsx +57 -145
  155. package/src/bundler/bundler.test.ts +4 -3
  156. package/src/capabilities/capabilities.ts +12 -0
  157. package/src/capabilities/compiler.ts +33 -0
  158. package/src/capabilities/index.ts +12 -0
  159. package/src/capabilities/intent-resolver.ts +46 -0
  160. package/src/capabilities/react-surface.tsx +54 -0
  161. package/src/capabilities/settings.ts +14 -0
  162. package/src/compiler/compiler.browser.test.ts +1 -1
  163. package/src/components/AutomationPanel/AutomationPanel.tsx +2 -4
  164. package/src/components/FrameContainer/FrameContainer.tsx +1 -1
  165. package/src/components/ScriptContainer.tsx +69 -9
  166. package/src/components/ScriptSettings/ScriptSettings.tsx +28 -4
  167. package/src/components/ScriptSettingsPanel.tsx +139 -52
  168. package/src/components/{Toolbar/Toolbar.stories.tsx → ScriptToolbar/ScriptToolbar.stories.tsx} +2 -2
  169. package/src/components/ScriptToolbar/ScriptToolbar.tsx +53 -0
  170. package/src/components/{Toolbar → ScriptToolbar}/index.ts +1 -1
  171. package/src/components/TypescriptEditor/TypescriptEditor.stories.tsx +2 -0
  172. package/src/components/TypescriptEditor/TypescriptEditor.tsx +73 -8
  173. package/src/hooks/deploy.ts +158 -0
  174. package/src/hooks/format.ts +47 -0
  175. package/src/hooks/index.ts +11 -0
  176. package/src/hooks/template.ts +64 -0
  177. package/src/hooks/useToolbarAction.ts +54 -0
  178. package/src/hooks/useToolbarState.ts +16 -0
  179. package/src/hooks/view.ts +52 -0
  180. package/src/index.ts +2 -6
  181. package/src/meta.ts +4 -2
  182. package/src/templates/echo.ts +5 -1
  183. package/src/templates/email.ts +26 -23
  184. package/src/templates/forex-effect.ts +42 -0
  185. package/src/templates/forex.ts +21 -13
  186. package/src/{templates.ts → templates/index.ts} +12 -5
  187. package/src/translations.ts +20 -1
  188. package/src/types.ts +39 -0
  189. package/dist/lib/browser/AutomationPanel-PMTZROAZ.mjs.map +0 -7
  190. package/dist/lib/browser/ScriptContainer-RYZFYCNK.mjs +0 -425
  191. package/dist/lib/browser/ScriptContainer-RYZFYCNK.mjs.map +0 -7
  192. package/dist/lib/browser/chunk-C7VBULMK.mjs +0 -18
  193. package/dist/lib/browser/chunk-C7VBULMK.mjs.map +0 -7
  194. package/dist/lib/browser/chunk-QFZUFT5G.mjs +0 -48
  195. package/dist/lib/browser/chunk-QFZUFT5G.mjs.map +0 -7
  196. package/dist/lib/browser/chunk-U3OP64V4.mjs +0 -123
  197. package/dist/lib/browser/chunk-U3OP64V4.mjs.map +0 -7
  198. package/dist/lib/browser/edge/index.mjs +0 -19
  199. package/dist/lib/browser/meta.mjs +0 -9
  200. package/dist/lib/browser/types/index.mjs +0 -12
  201. package/dist/lib/browser/types/index.mjs.map +0 -7
  202. package/dist/lib/node/AutomationPanel-AAGQREH7.cjs.map +0 -7
  203. package/dist/lib/node/ScriptContainer-FZ44UIRC.cjs +0 -427
  204. package/dist/lib/node/ScriptContainer-FZ44UIRC.cjs.map +0 -7
  205. package/dist/lib/node/chunk-6LYX73ZT.cjs.map +0 -7
  206. package/dist/lib/node/chunk-CS25QNKZ.cjs +0 -151
  207. package/dist/lib/node/chunk-CS25QNKZ.cjs.map +0 -7
  208. package/dist/lib/node/chunk-DQYAU2CJ.cjs +0 -67
  209. package/dist/lib/node/chunk-DQYAU2CJ.cjs.map +0 -7
  210. package/dist/lib/node/chunk-WPP65EYS.cjs.map +0 -7
  211. package/dist/lib/node/edge/index.cjs +0 -41
  212. package/dist/lib/node/edge/index.cjs.map +0 -7
  213. package/dist/lib/node/meta.cjs.map +0 -7
  214. package/dist/lib/node/types/index.cjs.map +0 -7
  215. package/dist/lib/node-esm/AutomationPanel-ETQEDY5I.mjs.map +0 -7
  216. package/dist/lib/node-esm/ScriptContainer-3PKDW34A.mjs +0 -426
  217. package/dist/lib/node-esm/ScriptContainer-3PKDW34A.mjs.map +0 -7
  218. package/dist/lib/node-esm/chunk-36DLLQ6E.mjs +0 -125
  219. package/dist/lib/node-esm/chunk-36DLLQ6E.mjs.map +0 -7
  220. package/dist/lib/node-esm/chunk-GMVPKT6A.mjs +0 -49
  221. package/dist/lib/node-esm/chunk-GMVPKT6A.mjs.map +0 -7
  222. package/dist/lib/node-esm/chunk-SLTZMY34.mjs.map +0 -7
  223. package/dist/lib/node-esm/edge/index.mjs +0 -20
  224. package/dist/lib/node-esm/edge/index.mjs.map +0 -7
  225. package/dist/lib/node-esm/meta.mjs +0 -10
  226. package/dist/lib/node-esm/meta.mjs.map +0 -7
  227. package/dist/lib/node-esm/types/index.mjs +0 -13
  228. package/dist/lib/node-esm/types/index.mjs.map +0 -7
  229. package/dist/types/src/components/ScriptBlock/ScriptBlock.d.ts +0 -12
  230. package/dist/types/src/components/ScriptBlock/ScriptBlock.d.ts.map +0 -1
  231. package/dist/types/src/components/ScriptBlock/ScriptBlock.stories.d.ts +0 -6
  232. package/dist/types/src/components/ScriptBlock/ScriptBlock.stories.d.ts.map +0 -1
  233. package/dist/types/src/components/ScriptBlock/index.d.ts +0 -2
  234. package/dist/types/src/components/ScriptBlock/index.d.ts.map +0 -1
  235. package/dist/types/src/components/ScriptEditor.d.ts +0 -9
  236. package/dist/types/src/components/ScriptEditor.d.ts.map +0 -1
  237. package/dist/types/src/components/Toolbar/Toolbar.d.ts +0 -23
  238. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +0 -1
  239. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +0 -1
  240. package/dist/types/src/components/Toolbar/index.d.ts +0 -2
  241. package/dist/types/src/components/Toolbar/index.d.ts.map +0 -1
  242. package/dist/types/src/edge/functions.d.ts +0 -25
  243. package/dist/types/src/edge/functions.d.ts.map +0 -1
  244. package/dist/types/src/edge/index.d.ts +0 -2
  245. package/dist/types/src/edge/index.d.ts.map +0 -1
  246. package/dist/types/src/templates.d.ts.map +0 -1
  247. package/dist/types/src/types/index.d.ts +0 -3
  248. package/dist/types/src/types/index.d.ts.map +0 -1
  249. package/dist/types/src/types/schema.d.ts +0 -71
  250. package/dist/types/src/types/schema.d.ts.map +0 -1
  251. package/dist/types/src/types/types.d.ts +0 -8
  252. package/dist/types/src/types/types.d.ts.map +0 -1
  253. package/src/components/ScriptBlock/ScriptBlock.stories.tsx +0 -52
  254. package/src/components/ScriptBlock/ScriptBlock.tsx +0 -102
  255. package/src/components/ScriptBlock/index.ts +0 -5
  256. package/src/components/ScriptEditor.tsx +0 -191
  257. package/src/components/Toolbar/Toolbar.tsx +0 -177
  258. package/src/edge/functions.ts +0 -116
  259. package/src/edge/index.ts +0 -7
  260. package/src/types/index.ts +0 -6
  261. package/src/types/schema.ts +0 -44
  262. package/src/types/types.ts +0 -29
  263. /package/dist/lib/browser/{chunk-K7KY6YMG.mjs.map → chunk-45LXDWNF.mjs.map} +0 -0
  264. /package/dist/lib/browser/{edge/index.mjs.map → types.mjs.map} +0 -0
  265. /package/dist/lib/node/{chunk-4INUJLXL.cjs.map → chunk-IID7WUQS.cjs.map} +0 -0
  266. /package/dist/lib/node-esm/{chunk-OFYGBUNI.mjs.map → chunk-CGF7EOGD.mjs.map} +0 -0
  267. /package/dist/lib/{browser/meta.mjs.map → node-esm/types.mjs.map} +0 -0
@@ -2,20 +2,80 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import React from 'react';
5
+ import React, { useMemo } from 'react';
6
6
 
7
- import { fullyQualifiedId } from '@dxos/react-client/echo';
8
- import { useAttendableAttributes } from '@dxos/react-ui-attention';
7
+ import { type ScriptType } from '@dxos/functions';
8
+ import { createDocAccessor, getSpace } from '@dxos/react-client/echo';
9
+ import { useIdentity } from '@dxos/react-client/halo';
10
+ import { type ThemedClassName } from '@dxos/react-ui';
11
+ import { createDataExtensions, listener, stackItemContentEditorClassNames } from '@dxos/react-ui-editor';
12
+ import { StackItem } from '@dxos/react-ui-stack';
9
13
  import { mx } from '@dxos/react-ui-theme';
10
14
 
11
- import { ScriptEditor, type ScriptEditorProps } from './ScriptEditor';
15
+ import { DebugPanel } from './DebugPanel';
16
+ import { ScriptToolbar } from './ScriptToolbar';
17
+ import { TypescriptEditor, type TypescriptEditorProps } from './TypescriptEditor';
18
+ import { useDeployState, useToolbarState } from '../hooks';
19
+ import { type ScriptSettingsProps } from '../types';
20
+
21
+ export type ScriptEditorProps = ThemedClassName<{
22
+ script: ScriptType;
23
+ settings?: ScriptSettingsProps;
24
+ role?: string;
25
+ }> &
26
+ Pick<TypescriptEditorProps, 'env'>;
27
+
28
+ export const ScriptContainer = ({
29
+ role,
30
+ classNames,
31
+ script,
32
+ settings = { editorInputMode: 'vscode' },
33
+ env,
34
+ }: ScriptEditorProps) => {
35
+ const identity = useIdentity();
36
+ const space = getSpace(script);
37
+
38
+ const extensions = useMemo(
39
+ () => [
40
+ listener({
41
+ onChange: (text) => {
42
+ if (script.source.target && script.source.target.content !== text) {
43
+ script.changed = true;
44
+ }
45
+ },
46
+ }),
47
+ createDataExtensions({
48
+ id: script.id,
49
+ text: script.source.target && createDocAccessor(script.source.target, ['content']),
50
+ space,
51
+ identity,
52
+ }),
53
+ ],
54
+ [script, script.source.target, space, identity],
55
+ );
56
+
57
+ const state = useToolbarState({ view: 'editor' });
58
+ useDeployState({ state, script });
12
59
 
13
- const ScriptContainer = ({ script, ...props }: ScriptEditorProps) => {
14
- const attendableAttrs = useAttendableAttributes(fullyQualifiedId(script));
15
60
  return (
16
- <div role='none' className={mx('flex row-span-2 w-full overflow-hidden attention-surface')} {...attendableAttrs}>
17
- <ScriptEditor {...props} script={script} />
18
- </div>
61
+ <StackItem.Content toolbar>
62
+ <ScriptToolbar state={state} role={role} script={script} />
63
+ <div role='none' className={mx('flex flex-col w-full overflow-hidden divide-y divide-separator', classNames)}>
64
+ {state.view !== 'debug' && (
65
+ <TypescriptEditor
66
+ id={script.id}
67
+ env={env}
68
+ initialValue={script.source?.target?.content}
69
+ extensions={extensions}
70
+ className={stackItemContentEditorClassNames(role)}
71
+ inputMode={settings.editorInputMode}
72
+ toolbar
73
+ />
74
+ )}
75
+
76
+ {state.view !== 'editor' && <DebugPanel functionUrl={state.functionUrl} />}
77
+ </div>
78
+ </StackItem.Content>
19
79
  );
20
80
  };
21
81
 
@@ -6,8 +6,9 @@ import React from 'react';
6
6
 
7
7
  import { type Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
8
8
  import { useClient } from '@dxos/react-client';
9
- import { Button, useTranslation } from '@dxos/react-ui';
10
- import { DeprecatedFormInput } from '@dxos/react-ui-form';
9
+ import { Button, Select, useTranslation } from '@dxos/react-ui';
10
+ import { type EditorInputMode, EditorInputModes } from '@dxos/react-ui-editor';
11
+ import { DeprecatedFormContainer, DeprecatedFormInput } from '@dxos/react-ui-form';
11
12
 
12
13
  import { SCRIPT_PLUGIN } from '../../meta';
13
14
  import { type ScriptSettingsProps } from '../../types';
@@ -38,10 +39,33 @@ export const ScriptSettings = ({ settings }: { settings: ScriptSettingsProps })
38
39
  };
39
40
 
40
41
  return (
41
- <>
42
+ <DeprecatedFormContainer>
43
+ {/* TODO(wittjosiah): Hide outside of dev environments. */}
42
44
  <DeprecatedFormInput label={t('authenticate action label')}>
43
45
  <Button onClick={handleAuthenticate}>{t('authenticate button label')}</Button>
44
46
  </DeprecatedFormInput>
45
- </>
47
+
48
+ <DeprecatedFormInput label={t('editor input mode label')}>
49
+ <Select.Root
50
+ value={settings.editorInputMode ?? 'default'}
51
+ onValueChange={(value) => {
52
+ settings.editorInputMode = value as EditorInputMode;
53
+ }}
54
+ >
55
+ <Select.TriggerButton placeholder={t('select editor input mode placeholder')} />
56
+ <Select.Portal>
57
+ <Select.Content>
58
+ <Select.Viewport>
59
+ {EditorInputModes.map((mode) => (
60
+ <Select.Option key={mode} value={mode}>
61
+ {t(`settings editor input mode ${mode} label`)}
62
+ </Select.Option>
63
+ ))}
64
+ </Select.Viewport>
65
+ </Select.Content>
66
+ </Select.Portal>
67
+ </Select.Root>
68
+ </DeprecatedFormInput>
69
+ </DeprecatedFormContainer>
46
70
  );
47
71
  };
@@ -2,15 +2,22 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import React, { type ChangeEvent, useCallback } from 'react';
5
+ import { Octokit } from '@octokit/core';
6
+ import React, { type ChangeEvent, useCallback, useEffect, useState } from 'react';
6
7
 
8
+ import { createIntent, SettingsAction, useIntentDispatcher } from '@dxos/app-framework';
9
+ import { FunctionType, type ScriptType, getInvocationUrl, getUserFunctionUrlInMetadata } from '@dxos/functions';
10
+ import { log } from '@dxos/log';
7
11
  import { useClient } from '@dxos/react-client';
8
12
  import { Filter, getMeta, getSpace, useQuery } from '@dxos/react-client/echo';
9
- import { Button, Icon, Input, useControlledValue, useTranslation } from '@dxos/react-ui';
13
+ import { Button, Clipboard, Input, Separator, useControlledValue, useTranslation } from '@dxos/react-ui';
14
+ import { AccessTokenType } from '@dxos/schema';
10
15
 
11
- import { getInvocationUrl, getUserFunctionUrlInMetadata } from '../edge';
12
16
  import { SCRIPT_PLUGIN } from '../meta';
13
- import { FunctionType, type ScriptType } from '../types';
17
+
18
+ // TODO(wittjosiah): Factor out.
19
+ // From https://stackoverflow.com/a/67243723/2804332
20
+ const kebabize = (str: string) => str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, ($, ofs) => (ofs ? '-' : '') + $.toLowerCase());
14
21
 
15
22
  export type ScriptSettingsPanelProps = {
16
23
  script: ScriptType;
@@ -18,16 +25,37 @@ export type ScriptSettingsPanelProps = {
18
25
 
19
26
  export const ScriptSettingsPanel = ({ script }: ScriptSettingsPanelProps) => {
20
27
  const { t } = useTranslation(SCRIPT_PLUGIN);
28
+ const { dispatchPromise: dispatch } = useIntentDispatcher();
21
29
  const client = useClient();
22
30
  const space = getSpace(script);
23
31
  const [fn] = useQuery(space, Filter.schema(FunctionType, { source: script }));
32
+ const [githubToken] = useQuery(space, Filter.schema(AccessTokenType, { source: 'github.com' }));
33
+ const gistKey = getMeta(script).keys.find(({ source }) => source === 'github.com');
34
+ const [gistUrl, setGistUrl] = useState<string | undefined>();
24
35
 
25
- const handleNameChange = useCallback(
26
- (event: ChangeEvent<HTMLInputElement>) => {
27
- script.name = event.target.value;
28
- },
29
- [script],
30
- );
36
+ useEffect(() => {
37
+ const token = githubToken?.token;
38
+ const gistId = gistKey?.id;
39
+ if (!token || !gistId) {
40
+ setGistUrl(undefined);
41
+ return;
42
+ }
43
+
44
+ const timeout = setTimeout(async () => {
45
+ try {
46
+ const octokit = new Octokit({ auth: githubToken.token });
47
+ const response = await octokit.request('GET /gists/{gist_id}', {
48
+ gist_id: gistId,
49
+ });
50
+ setGistUrl(response.data.html_url);
51
+ } catch (err) {
52
+ log.catch(err);
53
+ setGistUrl(undefined);
54
+ }
55
+ });
56
+
57
+ return () => clearTimeout(timeout);
58
+ }, [githubToken, gistKey]);
31
59
 
32
60
  const [binding, setBinding] = useControlledValue(fn?.binding ?? '');
33
61
  const handleBindingChange = useCallback(
@@ -47,55 +75,114 @@ export const ScriptSettingsPanel = ({ script }: ScriptSettingsPanelProps) => {
47
75
  spaceId: space?.id,
48
76
  });
49
77
 
50
- // TODO(wittjosiah): Use ClipboardProvider.
51
- const handleCopy = useCallback(() => functionUrl && navigator.clipboard.writeText(functionUrl), [functionUrl]);
78
+ const handleOpenTokenManager = useCallback(
79
+ () => dispatch(createIntent(SettingsAction.Open, { plugin: 'dxos.org/plugin/token-manager' })),
80
+ [],
81
+ );
82
+
83
+ const [publishing, setPublishing] = useState(false);
84
+ const handlePublish = useCallback(async () => {
85
+ setPublishing(true);
86
+ const octokit = new Octokit({ auth: githubToken.token });
87
+ const source = await script.source.load();
88
+ const filename = script.name ? kebabize(script.name) : 'composer-script';
89
+ const files = { [`${filename}.ts`]: { content: source.content } };
90
+
91
+ try {
92
+ // TODO(wittjosiah): Factor out to intent.
93
+ const meta = getMeta(script);
94
+ const githubKey = meta.keys.find(({ source }) => source === 'github.com');
95
+ const gistId = githubKey?.id;
96
+ if (gistId) {
97
+ await octokit.request('PATCH /gists/{gist_id}', {
98
+ gist_id: gistId,
99
+ files,
100
+ });
101
+ } else {
102
+ const response = await octokit.request('POST /gists', {
103
+ public: true,
104
+ files,
105
+ });
106
+ if (response.data.id) {
107
+ meta.keys.push({ source: 'github.com', id: response.data.id });
108
+ }
109
+ }
110
+ } finally {
111
+ setPublishing(false);
112
+ }
113
+ }, [script, githubToken]);
52
114
 
53
115
  return (
54
- <div role='form' className='flex flex-col w-full p-2 gap-4'>
55
- <Input.Root>
56
- <div role='none' className='flex flex-col gap-1'>
57
- <Input.Label>{t('name label')}</Input.Label>
58
- <Input.TextInput
59
- placeholder={t('object title placeholder')}
60
- value={script.name ?? ''}
61
- onChange={handleNameChange}
62
- />
63
- </div>
64
- </Input.Root>
65
- {fn && (
116
+ <>
117
+ <div role='form' className='flex flex-col w-full p-2 gap-4'>
118
+ <Input.Root>
119
+ <div role='none' className='flex flex-col gap-1'>
120
+ <Input.Label>{t('description label')}</Input.Label>
121
+ <Input.TextInput
122
+ placeholder={t('description placeholder')}
123
+ value={script.description ?? ''}
124
+ onChange={(event) => {
125
+ script.description = event.target.value;
126
+ }}
127
+ />
128
+ </div>
129
+ </Input.Root>
130
+ </div>
131
+ {fn && functionUrl && (
66
132
  <>
67
- <hr className='border-separator' />
68
- <h2>{t('remote function settings heading')}</h2>
69
- <Input.Root>
70
- <div role='none' className='flex flex-col gap-1'>
71
- <Input.Label>{t('function url label')}</Input.Label>
72
- <div role='none' className='flex gap-1'>
133
+ <Separator />
134
+ <div role='form' className='flex flex-col w-full p-2 gap-4'>
135
+ <h2>{t('remote function settings heading')}</h2>
136
+ <Input.Root>
137
+ <div role='none' className='flex flex-col gap-1'>
138
+ <Input.Label>{t('function url label')}</Input.Label>
139
+ <div role='none' className='flex gap-1'>
140
+ <Input.TextInput
141
+ disabled
142
+ value={functionUrl}
143
+ onChange={(event) => {
144
+ fn.name = event.target.value;
145
+ }}
146
+ />
147
+ <Clipboard.IconButton value={functionUrl} />
148
+ </div>
149
+ </div>
150
+ </Input.Root>
151
+ <Input.Root>
152
+ <div role='none' className='flex flex-col gap-1'>
153
+ <Input.Label>{t('function binding label')}</Input.Label>
73
154
  <Input.TextInput
74
- disabled
75
- value={functionUrl}
76
- onChange={(event) => {
77
- fn.name = event.target.value;
78
- }}
155
+ placeholder={t('function binding placeholder')}
156
+ value={binding}
157
+ onChange={handleBindingChange}
158
+ onBlur={handleBindingBlur}
79
159
  />
80
- <Button onClick={handleCopy}>
81
- <Icon icon='ph--copy--regular' size={4} />
82
- </Button>
83
160
  </div>
84
- </div>
85
- </Input.Root>
86
- <Input.Root>
87
- <div role='none' className='flex flex-col gap-1'>
88
- <Input.Label>{t('function binding label')}</Input.Label>
89
- <Input.TextInput
90
- placeholder={t('function binding placeholder')}
91
- value={binding}
92
- onChange={handleBindingChange}
93
- onBlur={handleBindingBlur}
94
- />
95
- </div>
96
- </Input.Root>
161
+ </Input.Root>
162
+ </div>
97
163
  </>
98
164
  )}
99
- </div>
165
+ <Separator />
166
+ <div className='flex flex-col w-full p-2 gap-4'>
167
+ <div>
168
+ <h2>{t('script publish settings label')}</h2>
169
+ <p className='text-description text-sm'>{t('script publish settings description')}</p>
170
+ </div>
171
+ {!githubToken && (
172
+ <div className='flex flex-col items-center justify-center gap-2'>
173
+ <span>{t('no github token label')}</span>
174
+ <Button onClick={handleOpenTokenManager}>{t('open token manager label')}</Button>
175
+ </div>
176
+ )}
177
+ {githubToken && (
178
+ <div className='flex justify-end gap-2'>
179
+ {gistUrl && <Clipboard.IconButton value={gistUrl} />}
180
+ <Button disabled={publishing} onClick={handlePublish}>
181
+ {t(publishing ? 'publishing label' : 'publish label')}
182
+ </Button>
183
+ </div>
184
+ )}
185
+ </div>
186
+ </>
100
187
  );
101
188
  };
@@ -8,7 +8,7 @@ import { type Meta } from '@storybook/react';
8
8
 
9
9
  import { withLayout, withTheme } from '@dxos/storybook-utils';
10
10
 
11
- import { Toolbar } from './Toolbar';
11
+ import { ScriptToolbar } from './ScriptToolbar';
12
12
  import { templates } from '../../templates';
13
13
 
14
14
  export const Default = {
@@ -23,7 +23,7 @@ export const Default = {
23
23
 
24
24
  const meta: Meta = {
25
25
  title: 'plugins/plugin-script/Toolbar',
26
- component: Toolbar,
26
+ component: ScriptToolbar,
27
27
  decorators: [withTheme, withLayout({ tooltips: true })],
28
28
  };
29
29
 
@@ -0,0 +1,53 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import React, { useCallback } from 'react';
6
+
7
+ import { type ScriptType } from '@dxos/functions';
8
+ import { fullyQualifiedId } from '@dxos/react-client/echo';
9
+ import { ElevationProvider, type ThemedClassName } from '@dxos/react-ui';
10
+ import { stackItemContentToolbarClassNames } from '@dxos/react-ui-editor';
11
+ import { createGapSeparator, MenuProvider, ToolbarMenu, useMenuActions } from '@dxos/react-ui-menu';
12
+
13
+ import {
14
+ type ScriptToolbarState,
15
+ createDeploy,
16
+ createFormat,
17
+ createTemplateSelect,
18
+ createView,
19
+ useToolbarAction,
20
+ } from '../../hooks';
21
+
22
+ export type ScriptToolbarProps = ThemedClassName<{
23
+ role?: string;
24
+ script: ScriptType;
25
+ state: ScriptToolbarState;
26
+ }>;
27
+
28
+ const createToolbar = (state: ScriptToolbarState) => {
29
+ const templateSelect = createTemplateSelect();
30
+ const format = createFormat();
31
+ const gap = createGapSeparator();
32
+ const deploy = createDeploy(state);
33
+ const view = createView(state);
34
+ return {
35
+ nodes: [...templateSelect.nodes, ...format.nodes, ...gap.nodes, ...deploy.nodes, ...view.nodes],
36
+ edges: [...templateSelect.edges, ...format.edges, ...gap.edges, ...deploy.edges, ...view.edges],
37
+ };
38
+ };
39
+
40
+ export const ScriptToolbar = ({ script, role, state, classNames }: ScriptToolbarProps) => {
41
+ const handleAction = useToolbarAction({ state, script });
42
+ const toolbarCreator = useCallback(() => createToolbar(state), [state]);
43
+ const menu = useMenuActions(toolbarCreator);
44
+ return (
45
+ <div role='none' className={stackItemContentToolbarClassNames(role)}>
46
+ <ElevationProvider elevation={role === 'section' ? 'positioned' : 'base'}>
47
+ <MenuProvider {...menu} onAction={handleAction} attendableId={fullyQualifiedId(script)}>
48
+ <ToolbarMenu classNames={classNames} />
49
+ </MenuProvider>
50
+ </ElevationProvider>
51
+ </div>
52
+ );
53
+ };
@@ -2,4 +2,4 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- export * from './Toolbar';
5
+ export * from './ScriptToolbar';
@@ -9,6 +9,7 @@ import React, { useMemo } from 'react';
9
9
 
10
10
  import { createDocAccessor, createObject } from '@dxos/react-client/echo';
11
11
  import { createDataExtensions } from '@dxos/react-ui-editor';
12
+ import { withTheme } from '@dxos/storybook-utils';
12
13
 
13
14
  import { TypescriptEditor } from './TypescriptEditor';
14
15
  import { templates } from '../../templates';
@@ -37,6 +38,7 @@ const meta: Meta = {
37
38
  title: 'plugins/plugin-script/TypescriptEditor',
38
39
  component: TypescriptEditor,
39
40
  render: DefaultStory,
41
+ decorators: [withTheme],
40
42
  };
41
43
 
42
44
  export default meta;
@@ -3,18 +3,26 @@
3
3
  //
4
4
 
5
5
  import { javascript } from '@codemirror/lang-javascript';
6
+ import { defaultHighlightStyle } from '@codemirror/language';
7
+ import { Prec } from '@codemirror/state';
8
+ import { oneDarkHighlightStyle } from '@codemirror/theme-one-dark';
9
+ import { keymap } from '@codemirror/view';
10
+ import { tags } from '@lezer/highlight';
6
11
  import { type VirtualTypeScriptEnvironment } from '@typescript/vfs';
7
- import { tsSync, tsFacet, tsLinter, tsAutocomplete, tsHover } from '@valtown/codemirror-ts';
12
+ import { continueKeymap } from '@valtown/codemirror-continue';
13
+ import { tsSync, tsFacet, tsLinter, tsAutocomplete, tsHover, type HoverInfo } from '@valtown/codemirror-ts';
8
14
  import React from 'react';
9
15
 
10
- import { useThemeContext } from '@dxos/react-ui';
16
+ import { type ThemeMode, useThemeContext } from '@dxos/react-ui';
11
17
  import {
12
18
  autocomplete,
13
19
  createBasicExtensions,
14
20
  createThemeExtensions,
15
21
  editorFullWidth,
16
- editorGutter,
22
+ type EditorInputMode,
17
23
  editorMonospace,
24
+ EditorView,
25
+ folding,
18
26
  InputModeExtensions,
19
27
  useTextEditor,
20
28
  type UseTextEditorProps,
@@ -23,7 +31,9 @@ import { nonNullable } from '@dxos/util';
23
31
 
24
32
  export type TypescriptEditorProps = {
25
33
  id: string;
34
+ inputMode?: EditorInputMode;
26
35
  env?: VirtualTypeScriptEnvironment;
36
+ toolbar?: boolean;
27
37
  } & Pick<UseTextEditorProps, 'className' | 'initialValue' | 'extensions' | 'scrollTo' | 'selection'>;
28
38
 
29
39
  export const TypescriptEditor = ({
@@ -34,6 +44,8 @@ export const TypescriptEditor = ({
34
44
  extensions,
35
45
  scrollTo,
36
46
  selection,
47
+ toolbar,
48
+ inputMode = 'vscode',
37
49
  }: TypescriptEditorProps) => {
38
50
  const { themeMode } = useThemeContext();
39
51
  const { parentRef, focusAttributes } = useTextEditor(
@@ -56,24 +68,77 @@ export const TypescriptEditor = ({
56
68
  content: { className: editorFullWidth },
57
69
  },
58
70
  }),
59
- editorGutter,
71
+ // NOTE: Not using default editor gutter because folding for code works best right beside text.
72
+ EditorView.theme({
73
+ '.cm-gutters': {
74
+ // Match margin from content.
75
+ marginTop: '16px',
76
+ },
77
+ }),
78
+ InputModeExtensions[inputMode],
79
+ folding(),
80
+ // Continues block comments when you hit Enter.
81
+ Prec.high(keymap.of(continueKeymap)),
60
82
  // TODO(burdon): Factor out.
61
83
  [
62
84
  editorMonospace,
63
85
  javascript({ typescript: true }),
64
86
  // https://github.com/val-town/codemirror-ts
65
87
  autocomplete({ override: env ? [tsAutocomplete()] : [] }),
66
- env ? [tsFacet.of({ env, path: `/src/${id}.ts` }), tsSync(), tsLinter(), tsHover()] : [],
67
- InputModeExtensions.vscode,
88
+ env
89
+ ? [
90
+ tsFacet.of({ env, path: `/src/${id}.ts` }),
91
+ tsSync(),
92
+ tsLinter(),
93
+ tsHover({ renderTooltip: createTooltipRenderer(themeMode) }),
94
+ ]
95
+ : [],
68
96
  ],
69
97
  ].filter(nonNullable),
70
98
  selection,
71
99
  scrollTo,
72
100
  }),
73
- [id, extensions, themeMode, selection, scrollTo],
101
+ [id, extensions, themeMode, inputMode, selection, scrollTo],
102
+ );
103
+
104
+ return (
105
+ <div ref={parentRef} data-toolbar={toolbar ? 'enabled' : 'disabled'} className={className} {...focusAttributes} />
74
106
  );
107
+ };
108
+
109
+ const createTooltipRenderer = (themeMode: ThemeMode) => {
110
+ const theme = themeMode === 'dark' ? oneDarkHighlightStyle : defaultHighlightStyle;
111
+
112
+ const classFromKind = (_kind: string) => {
113
+ // E.g., localName, methodName, parameterName, etc.
114
+ const kind = _kind.endsWith('Name') ? 'name' : _kind;
115
+ const validTag = kind in tags;
116
+ if (!validTag) {
117
+ return '';
118
+ }
119
+
120
+ const tag = tags[kind as keyof typeof tags];
121
+ if (typeof tag === 'function') {
122
+ return '';
123
+ }
124
+
125
+ return theme.style([tag]) ?? '';
126
+ };
127
+
128
+ return (info: HoverInfo) => {
129
+ const div = document.createElement('div');
130
+ div.className = 'p-1 rounded border border-separator bg-baseSurface xs:max-w-80 max-w-lg';
131
+
132
+ if (info.quickInfo?.displayParts) {
133
+ for (const part of info.quickInfo.displayParts) {
134
+ const span = div.appendChild(document.createElement('span'));
135
+ span.className = classFromKind(part.kind);
136
+ span.innerText = part.text;
137
+ }
138
+ }
75
139
 
76
- return <div ref={parentRef} className={className} {...focusAttributes} />;
140
+ return { dom: div };
141
+ };
77
142
  };
78
143
 
79
144
  export default TypescriptEditor;