@next-buildr/editor 2.0.0 → 3.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (645) hide show
  1. package/README.md +7 -0
  2. package/UPGRADING.md +322 -0
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/app/builder-editor.test.js +223 -18
  5. package/dist/app/config.d.ts +27 -4
  6. package/dist/app/config.d.ts.map +1 -1
  7. package/dist/app/config.js +4 -3
  8. package/dist/app/contracts.d.ts +40 -0
  9. package/dist/app/contracts.d.ts.map +1 -0
  10. package/dist/app/contracts.js +4 -0
  11. package/dist/app/editor-app.d.ts.map +1 -1
  12. package/dist/app/editor-app.js +316 -24
  13. package/dist/app/editor-app.test.js +144 -6
  14. package/dist/app/layout.d.ts +11 -2
  15. package/dist/app/layout.d.ts.map +1 -1
  16. package/dist/app/layout.js +170 -9
  17. package/dist/app/manifest.d.ts +7 -2
  18. package/dist/app/manifest.d.ts.map +1 -1
  19. package/dist/app/manifest.js +16 -4
  20. package/dist/app/shell-panels.d.ts +15 -0
  21. package/dist/app/shell-panels.d.ts.map +1 -1
  22. package/dist/app/small-screen.test.js +2 -2
  23. package/dist/app/stage-slots.d.ts +9 -0
  24. package/dist/app/stage-slots.d.ts.map +1 -0
  25. package/dist/app/stage-slots.js +10 -0
  26. package/dist/app/status-info.d.ts +2 -3
  27. package/dist/app/status-info.d.ts.map +1 -1
  28. package/dist/app/status-info.js +49 -16
  29. package/dist/canvas-host/canvas-frame.d.ts +13 -1
  30. package/dist/canvas-host/canvas-frame.d.ts.map +1 -1
  31. package/dist/canvas-host/canvas-frame.js +96 -8
  32. package/dist/canvas-host/canvas-frame.test.js +156 -3
  33. package/dist/canvas-host/host.d.ts +6 -0
  34. package/dist/canvas-host/host.d.ts.map +1 -1
  35. package/dist/canvas-host/host.js +116 -4
  36. package/dist/canvas-host/host.test.js +195 -6
  37. package/dist/clipboard/clipboard.d.ts +1 -1
  38. package/dist/clipboard/clipboard.d.ts.map +1 -1
  39. package/dist/clipboard/clipboard.js +5 -0
  40. package/dist/clipboard/clipboard.test.js +21 -1
  41. package/dist/clipboard/format.d.ts +3 -1
  42. package/dist/clipboard/format.d.ts.map +1 -1
  43. package/dist/clipboard/react.d.ts +1 -1
  44. package/dist/clipboard/react.d.ts.map +1 -1
  45. package/dist/clipboard/react.js +49 -3
  46. package/dist/dialogs/external-source.d.ts +15 -0
  47. package/dist/dialogs/external-source.d.ts.map +1 -0
  48. package/dist/dialogs/external-source.js +18 -0
  49. package/dist/dialogs/index.d.ts +4 -0
  50. package/dist/dialogs/index.d.ts.map +1 -1
  51. package/dist/dialogs/index.js +2 -0
  52. package/dist/dialogs/media-picker/index.d.ts +2 -2
  53. package/dist/dialogs/media-picker/index.d.ts.map +1 -1
  54. package/dist/dialogs/media-picker/index.js +1 -1
  55. package/dist/dialogs/media-picker/media-picker.d.ts +5 -0
  56. package/dist/dialogs/media-picker/media-picker.d.ts.map +1 -1
  57. package/dist/dialogs/media-picker/media-picker.js +67 -5
  58. package/dist/dialogs/media-picker/media-picker.test.js +72 -1
  59. package/dist/dialogs/media-picker/media-ref.d.ts +15 -0
  60. package/dist/dialogs/media-picker/media-ref.d.ts.map +1 -1
  61. package/dist/dialogs/media-picker/media-ref.js +29 -0
  62. package/dist/dialogs/remove-confirm.d.ts +14 -0
  63. package/dist/dialogs/remove-confirm.d.ts.map +1 -0
  64. package/dist/dialogs/remove-confirm.js +42 -0
  65. package/dist/dialogs/remove-confirm.test.d.ts +2 -0
  66. package/dist/dialogs/remove-confirm.test.d.ts.map +1 -0
  67. package/dist/dialogs/remove-confirm.test.js +118 -0
  68. package/dist/dnd/dnd-react.test.js +11 -2
  69. package/dist/dnd/dnd.test.js +23 -0
  70. package/dist/dnd/engine.d.ts +4 -2
  71. package/dist/dnd/engine.d.ts.map +1 -1
  72. package/dist/dnd/engine.js +6 -0
  73. package/dist/dnd/move-to-dialog.d.ts +4 -3
  74. package/dist/dnd/move-to-dialog.d.ts.map +1 -1
  75. package/dist/dnd/move-to-dialog.js +67 -10
  76. package/dist/dnd/react.d.ts.map +1 -1
  77. package/dist/dnd/react.js +5 -0
  78. package/dist/i18n/diagnostics.d.ts +22 -0
  79. package/dist/i18n/diagnostics.d.ts.map +1 -0
  80. package/dist/i18n/diagnostics.js +153 -0
  81. package/dist/i18n/diagnostics.test.d.ts +2 -0
  82. package/dist/i18n/diagnostics.test.d.ts.map +1 -0
  83. package/dist/i18n/diagnostics.test.js +74 -0
  84. package/dist/i18n/label-catalog.d.ts +20 -0
  85. package/dist/i18n/label-catalog.d.ts.map +1 -0
  86. package/dist/i18n/label-catalog.js +1 -0
  87. package/dist/i18n/locale-name.d.ts +7 -0
  88. package/dist/i18n/locale-name.d.ts.map +1 -0
  89. package/dist/i18n/locale-name.js +31 -0
  90. package/dist/i18n/localize-manifest.d.ts +11 -0
  91. package/dist/i18n/localize-manifest.d.ts.map +1 -0
  92. package/dist/i18n/localize-manifest.js +78 -0
  93. package/dist/i18n/localize-manifest.test.d.ts +2 -0
  94. package/dist/i18n/localize-manifest.test.d.ts.map +1 -0
  95. package/dist/i18n/localize-manifest.test.js +71 -0
  96. package/dist/messages/catalogs.test.d.ts +2 -0
  97. package/dist/messages/catalogs.test.d.ts.map +1 -0
  98. package/dist/messages/catalogs.test.js +80 -0
  99. package/dist/messages/en/app.d.ts +8 -0
  100. package/dist/messages/en/app.d.ts.map +1 -0
  101. package/dist/messages/en/app.js +7 -0
  102. package/dist/messages/en/blocks.d.ts +54 -0
  103. package/dist/messages/en/blocks.d.ts.map +1 -0
  104. package/dist/messages/en/blocks.js +53 -0
  105. package/dist/messages/en/canvas.d.ts +31 -0
  106. package/dist/messages/en/canvas.d.ts.map +1 -0
  107. package/dist/messages/en/canvas.js +30 -0
  108. package/dist/messages/en/clipboard.d.ts +13 -0
  109. package/dist/messages/en/clipboard.d.ts.map +1 -0
  110. package/dist/messages/en/clipboard.js +12 -0
  111. package/dist/messages/en/colorPicker.d.ts +20 -0
  112. package/dist/messages/en/colorPicker.d.ts.map +1 -0
  113. package/dist/messages/en/colorPicker.js +19 -0
  114. package/dist/messages/en/diagnostics.d.ts +40 -0
  115. package/dist/messages/en/diagnostics.d.ts.map +1 -0
  116. package/dist/messages/en/diagnostics.js +39 -0
  117. package/dist/messages/en/dialogs/common.d.ts +6 -0
  118. package/dist/messages/en/dialogs/common.d.ts.map +1 -0
  119. package/dist/messages/en/dialogs/common.js +5 -0
  120. package/dist/messages/en/dialogs/conflict.d.ts +15 -0
  121. package/dist/messages/en/dialogs/conflict.d.ts.map +1 -0
  122. package/dist/messages/en/dialogs/conflict.js +14 -0
  123. package/dist/messages/en/dialogs/delete.d.ts +19 -0
  124. package/dist/messages/en/dialogs/delete.d.ts.map +1 -0
  125. package/dist/messages/en/dialogs/delete.js +18 -0
  126. package/dist/messages/en/dialogs/pageOptions.d.ts +9 -0
  127. package/dist/messages/en/dialogs/pageOptions.d.ts.map +1 -0
  128. package/dist/messages/en/dialogs/pageOptions.js +8 -0
  129. package/dist/messages/en/dialogs/publish.d.ts +15 -0
  130. package/dist/messages/en/dialogs/publish.d.ts.map +1 -0
  131. package/dist/messages/en/dialogs/publish.js +14 -0
  132. package/dist/messages/en/dnd.d.ts +19 -0
  133. package/dist/messages/en/dnd.d.ts.map +1 -0
  134. package/dist/messages/en/dnd.js +18 -0
  135. package/dist/messages/en/editor.d.ts +30 -0
  136. package/dist/messages/en/editor.d.ts.map +1 -0
  137. package/dist/messages/en/editor.js +29 -0
  138. package/dist/messages/en/external.d.ts +6 -0
  139. package/dist/messages/en/external.d.ts.map +1 -0
  140. package/dist/messages/en/external.js +5 -0
  141. package/dist/messages/en/insert.d.ts +25 -0
  142. package/dist/messages/en/insert.d.ts.map +1 -0
  143. package/dist/messages/en/insert.js +24 -0
  144. package/dist/messages/en/inspector.d.ts +176 -0
  145. package/dist/messages/en/inspector.d.ts.map +1 -0
  146. package/dist/messages/en/inspector.js +175 -0
  147. package/dist/messages/en/issues.d.ts +36 -0
  148. package/dist/messages/en/issues.d.ts.map +1 -0
  149. package/dist/messages/en/issues.js +35 -0
  150. package/dist/messages/en/layers.d.ts +29 -0
  151. package/dist/messages/en/layers.d.ts.map +1 -0
  152. package/dist/messages/en/layers.js +28 -0
  153. package/dist/messages/en/leftPanel.d.ts +15 -0
  154. package/dist/messages/en/leftPanel.d.ts.map +1 -0
  155. package/dist/messages/en/leftPanel.js +14 -0
  156. package/dist/messages/en/list.d.ts +9 -0
  157. package/dist/messages/en/list.d.ts.map +1 -0
  158. package/dist/messages/en/list.js +8 -0
  159. package/dist/messages/en/locale.d.ts +4 -0
  160. package/dist/messages/en/locale.d.ts.map +1 -0
  161. package/dist/messages/en/locale.js +3 -0
  162. package/dist/messages/en/media.d.ts +51 -0
  163. package/dist/messages/en/media.d.ts.map +1 -0
  164. package/dist/messages/en/media.js +50 -0
  165. package/dist/messages/en/menu.d.ts +12 -0
  166. package/dist/messages/en/menu.d.ts.map +1 -0
  167. package/dist/messages/en/menu.js +11 -0
  168. package/dist/messages/en/patterns.d.ts +24 -0
  169. package/dist/messages/en/patterns.d.ts.map +1 -0
  170. package/dist/messages/en/patterns.js +23 -0
  171. package/dist/messages/en/preview.d.ts +8 -0
  172. package/dist/messages/en/preview.d.ts.map +1 -0
  173. package/dist/messages/en/preview.js +7 -0
  174. package/dist/messages/en/publish.d.ts +19 -0
  175. package/dist/messages/en/publish.d.ts.map +1 -0
  176. package/dist/messages/en/publish.js +18 -0
  177. package/dist/messages/en/richText.d.ts +21 -0
  178. package/dist/messages/en/richText.d.ts.map +1 -0
  179. package/dist/messages/en/richText.js +20 -0
  180. package/dist/messages/en/sample.d.ts +5 -0
  181. package/dist/messages/en/sample.d.ts.map +1 -0
  182. package/dist/messages/en/sample.js +4 -0
  183. package/dist/messages/en/save.d.ts +15 -0
  184. package/dist/messages/en/save.d.ts.map +1 -0
  185. package/dist/messages/en/save.js +14 -0
  186. package/dist/messages/en/shortcut.d.ts +36 -0
  187. package/dist/messages/en/shortcut.d.ts.map +1 -0
  188. package/dist/messages/en/shortcut.js +35 -0
  189. package/dist/messages/en/statusBar.d.ts +14 -0
  190. package/dist/messages/en/statusBar.d.ts.map +1 -0
  191. package/dist/messages/en/statusBar.js +13 -0
  192. package/dist/messages/en/structure.d.ts +28 -0
  193. package/dist/messages/en/structure.d.ts.map +1 -0
  194. package/dist/messages/en/structure.js +27 -0
  195. package/dist/messages/en/style.d.ts +168 -0
  196. package/dist/messages/en/style.d.ts.map +1 -0
  197. package/dist/messages/en/style.js +167 -0
  198. package/dist/messages/en/styleField.d.ts +301 -0
  199. package/dist/messages/en/styleField.d.ts.map +1 -0
  200. package/dist/messages/en/styleField.js +300 -0
  201. package/dist/messages/en/styleOption.d.ts +128 -0
  202. package/dist/messages/en/styleOption.d.ts.map +1 -0
  203. package/dist/messages/en/styleOption.js +127 -0
  204. package/dist/messages/en/styleSection.d.ts +16 -0
  205. package/dist/messages/en/styleSection.d.ts.map +1 -0
  206. package/dist/messages/en/styleSection.js +15 -0
  207. package/dist/messages/en/toast.d.ts +22 -0
  208. package/dist/messages/en/toast.d.ts.map +1 -0
  209. package/dist/messages/en/toast.js +21 -0
  210. package/dist/messages/en/toolbar.d.ts +47 -0
  211. package/dist/messages/en/toolbar.d.ts.map +1 -0
  212. package/dist/messages/en/toolbar.js +46 -0
  213. package/dist/messages/en/translation.d.ts +7 -0
  214. package/dist/messages/en/translation.d.ts.map +1 -0
  215. package/dist/messages/en/translation.js +6 -0
  216. package/dist/messages/en/ui.d.ts +4 -0
  217. package/dist/messages/en/ui.d.ts.map +1 -0
  218. package/dist/messages/en/ui.js +3 -0
  219. package/dist/messages/en/values.d.ts +45 -0
  220. package/dist/messages/en/values.d.ts.map +1 -0
  221. package/dist/messages/en/values.js +44 -0
  222. package/dist/messages/en.d.ts +1298 -202
  223. package/dist/messages/en.d.ts.map +1 -1
  224. package/dist/messages/en.js +82 -330
  225. package/dist/messages/index.d.ts +12 -0
  226. package/dist/messages/index.d.ts.map +1 -1
  227. package/dist/messages/index.js +28 -1
  228. package/dist/messages/pl/app.d.ts +8 -0
  229. package/dist/messages/pl/app.d.ts.map +1 -0
  230. package/dist/messages/pl/app.js +7 -0
  231. package/dist/messages/pl/blocks.d.ts +54 -0
  232. package/dist/messages/pl/blocks.d.ts.map +1 -0
  233. package/dist/messages/pl/blocks.js +53 -0
  234. package/dist/messages/pl/canvas.d.ts +31 -0
  235. package/dist/messages/pl/canvas.d.ts.map +1 -0
  236. package/dist/messages/pl/canvas.js +30 -0
  237. package/dist/messages/pl/clipboard.d.ts +13 -0
  238. package/dist/messages/pl/clipboard.d.ts.map +1 -0
  239. package/dist/messages/pl/clipboard.js +12 -0
  240. package/dist/messages/pl/colorPicker.d.ts +20 -0
  241. package/dist/messages/pl/colorPicker.d.ts.map +1 -0
  242. package/dist/messages/pl/colorPicker.js +19 -0
  243. package/dist/messages/pl/componentLabels.d.ts +9 -0
  244. package/dist/messages/pl/componentLabels.d.ts.map +1 -0
  245. package/dist/messages/pl/componentLabels.js +308 -0
  246. package/dist/messages/pl/diagnostics.d.ts +39 -0
  247. package/dist/messages/pl/diagnostics.d.ts.map +1 -0
  248. package/dist/messages/pl/diagnostics.js +38 -0
  249. package/dist/messages/pl/dialogs/common.d.ts +6 -0
  250. package/dist/messages/pl/dialogs/common.d.ts.map +1 -0
  251. package/dist/messages/pl/dialogs/common.js +5 -0
  252. package/dist/messages/pl/dialogs/conflict.d.ts +15 -0
  253. package/dist/messages/pl/dialogs/conflict.d.ts.map +1 -0
  254. package/dist/messages/pl/dialogs/conflict.js +14 -0
  255. package/dist/messages/pl/dialogs/delete.d.ts +19 -0
  256. package/dist/messages/pl/dialogs/delete.d.ts.map +1 -0
  257. package/dist/messages/pl/dialogs/delete.js +18 -0
  258. package/dist/messages/pl/dialogs/pageOptions.d.ts +9 -0
  259. package/dist/messages/pl/dialogs/pageOptions.d.ts.map +1 -0
  260. package/dist/messages/pl/dialogs/pageOptions.js +8 -0
  261. package/dist/messages/pl/dialogs/publish.d.ts +15 -0
  262. package/dist/messages/pl/dialogs/publish.d.ts.map +1 -0
  263. package/dist/messages/pl/dialogs/publish.js +14 -0
  264. package/dist/messages/pl/dnd.d.ts +19 -0
  265. package/dist/messages/pl/dnd.d.ts.map +1 -0
  266. package/dist/messages/pl/dnd.js +18 -0
  267. package/dist/messages/pl/editor.d.ts +30 -0
  268. package/dist/messages/pl/editor.d.ts.map +1 -0
  269. package/dist/messages/pl/editor.js +29 -0
  270. package/dist/messages/pl/external.d.ts +6 -0
  271. package/dist/messages/pl/external.d.ts.map +1 -0
  272. package/dist/messages/pl/external.js +5 -0
  273. package/dist/messages/pl/insert.d.ts +25 -0
  274. package/dist/messages/pl/insert.d.ts.map +1 -0
  275. package/dist/messages/pl/insert.js +24 -0
  276. package/dist/messages/pl/inspector.d.ts +176 -0
  277. package/dist/messages/pl/inspector.d.ts.map +1 -0
  278. package/dist/messages/pl/inspector.js +175 -0
  279. package/dist/messages/pl/issues.d.ts +36 -0
  280. package/dist/messages/pl/issues.d.ts.map +1 -0
  281. package/dist/messages/pl/issues.js +35 -0
  282. package/dist/messages/pl/layers.d.ts +29 -0
  283. package/dist/messages/pl/layers.d.ts.map +1 -0
  284. package/dist/messages/pl/layers.js +28 -0
  285. package/dist/messages/pl/leftPanel.d.ts +15 -0
  286. package/dist/messages/pl/leftPanel.d.ts.map +1 -0
  287. package/dist/messages/pl/leftPanel.js +14 -0
  288. package/dist/messages/pl/list.d.ts +9 -0
  289. package/dist/messages/pl/list.d.ts.map +1 -0
  290. package/dist/messages/pl/list.js +8 -0
  291. package/dist/messages/pl/locale.d.ts +4 -0
  292. package/dist/messages/pl/locale.d.ts.map +1 -0
  293. package/dist/messages/pl/locale.js +3 -0
  294. package/dist/messages/pl/media.d.ts +51 -0
  295. package/dist/messages/pl/media.d.ts.map +1 -0
  296. package/dist/messages/pl/media.js +50 -0
  297. package/dist/messages/pl/menu.d.ts +12 -0
  298. package/dist/messages/pl/menu.d.ts.map +1 -0
  299. package/dist/messages/pl/menu.js +11 -0
  300. package/dist/messages/pl/patterns.d.ts +24 -0
  301. package/dist/messages/pl/patterns.d.ts.map +1 -0
  302. package/dist/messages/pl/patterns.js +23 -0
  303. package/dist/messages/pl/preview.d.ts +8 -0
  304. package/dist/messages/pl/preview.d.ts.map +1 -0
  305. package/dist/messages/pl/preview.js +7 -0
  306. package/dist/messages/pl/publish.d.ts +19 -0
  307. package/dist/messages/pl/publish.d.ts.map +1 -0
  308. package/dist/messages/pl/publish.js +18 -0
  309. package/dist/messages/pl/richText.d.ts +21 -0
  310. package/dist/messages/pl/richText.d.ts.map +1 -0
  311. package/dist/messages/pl/richText.js +20 -0
  312. package/dist/messages/pl/sample.d.ts +5 -0
  313. package/dist/messages/pl/sample.d.ts.map +1 -0
  314. package/dist/messages/pl/sample.js +4 -0
  315. package/dist/messages/pl/save.d.ts +15 -0
  316. package/dist/messages/pl/save.d.ts.map +1 -0
  317. package/dist/messages/pl/save.js +14 -0
  318. package/dist/messages/pl/shortcut.d.ts +36 -0
  319. package/dist/messages/pl/shortcut.d.ts.map +1 -0
  320. package/dist/messages/pl/shortcut.js +35 -0
  321. package/dist/messages/pl/statusBar.d.ts +14 -0
  322. package/dist/messages/pl/statusBar.d.ts.map +1 -0
  323. package/dist/messages/pl/statusBar.js +13 -0
  324. package/dist/messages/pl/structure.d.ts +28 -0
  325. package/dist/messages/pl/structure.d.ts.map +1 -0
  326. package/dist/messages/pl/structure.js +27 -0
  327. package/dist/messages/pl/style.d.ts +168 -0
  328. package/dist/messages/pl/style.d.ts.map +1 -0
  329. package/dist/messages/pl/style.js +167 -0
  330. package/dist/messages/pl/styleField.d.ts +301 -0
  331. package/dist/messages/pl/styleField.d.ts.map +1 -0
  332. package/dist/messages/pl/styleField.js +300 -0
  333. package/dist/messages/pl/styleOption.d.ts +128 -0
  334. package/dist/messages/pl/styleOption.d.ts.map +1 -0
  335. package/dist/messages/pl/styleOption.js +127 -0
  336. package/dist/messages/pl/styleSection.d.ts +16 -0
  337. package/dist/messages/pl/styleSection.d.ts.map +1 -0
  338. package/dist/messages/pl/styleSection.js +15 -0
  339. package/dist/messages/pl/toast.d.ts +22 -0
  340. package/dist/messages/pl/toast.d.ts.map +1 -0
  341. package/dist/messages/pl/toast.js +21 -0
  342. package/dist/messages/pl/toolbar.d.ts +47 -0
  343. package/dist/messages/pl/toolbar.d.ts.map +1 -0
  344. package/dist/messages/pl/toolbar.js +46 -0
  345. package/dist/messages/pl/translation.d.ts +7 -0
  346. package/dist/messages/pl/translation.d.ts.map +1 -0
  347. package/dist/messages/pl/translation.js +6 -0
  348. package/dist/messages/pl/ui.d.ts +4 -0
  349. package/dist/messages/pl/ui.d.ts.map +1 -0
  350. package/dist/messages/pl/ui.js +3 -0
  351. package/dist/messages/pl/values.d.ts +45 -0
  352. package/dist/messages/pl/values.d.ts.map +1 -0
  353. package/dist/messages/pl/values.js +44 -0
  354. package/dist/messages/pl.d.ts.map +1 -1
  355. package/dist/messages/pl.js +82 -325
  356. package/dist/messages/plural.test.d.ts +2 -0
  357. package/dist/messages/plural.test.d.ts.map +1 -0
  358. package/dist/messages/plural.test.js +50 -0
  359. package/dist/panels/breadcrumbs/breadcrumbs.d.ts +1 -1
  360. package/dist/panels/breadcrumbs/breadcrumbs.d.ts.map +1 -1
  361. package/dist/panels/breadcrumbs/breadcrumbs.js +10 -3
  362. package/dist/panels/breadcrumbs/breadcrumbs.test.js +9 -2
  363. package/dist/panels/index.d.ts +3 -0
  364. package/dist/panels/index.d.ts.map +1 -1
  365. package/dist/panels/index.js +1 -0
  366. package/dist/panels/insert/catalog.d.ts +21 -1
  367. package/dist/panels/insert/catalog.d.ts.map +1 -1
  368. package/dist/panels/insert/catalog.js +85 -3
  369. package/dist/panels/insert/catalog.order.test.js +106 -1
  370. package/dist/panels/insert/index.d.ts +1 -0
  371. package/dist/panels/insert/index.d.ts.map +1 -1
  372. package/dist/panels/insert/insert-panel.d.ts +14 -4
  373. package/dist/panels/insert/insert-panel.d.ts.map +1 -1
  374. package/dist/panels/insert/insert-panel.js +128 -69
  375. package/dist/panels/insert/insert-panel.test.js +278 -37
  376. package/dist/panels/insert/target.d.ts +5 -1
  377. package/dist/panels/insert/target.d.ts.map +1 -1
  378. package/dist/panels/insert/target.js +11 -1
  379. package/dist/panels/inspector/author-fields.d.ts +21 -0
  380. package/dist/panels/inspector/author-fields.d.ts.map +1 -0
  381. package/dist/panels/inspector/author-fields.js +191 -0
  382. package/dist/panels/inspector/author-fields.test.d.ts +2 -0
  383. package/dist/panels/inspector/author-fields.test.d.ts.map +1 -0
  384. package/dist/panels/inspector/author-fields.test.js +237 -0
  385. package/dist/panels/inspector/controls/external-link.d.ts +24 -0
  386. package/dist/panels/inspector/controls/external-link.d.ts.map +1 -0
  387. package/dist/panels/inspector/controls/external-link.js +43 -0
  388. package/dist/panels/inspector/controls/external-link.test.d.ts +2 -0
  389. package/dist/panels/inspector/controls/external-link.test.d.ts.map +1 -0
  390. package/dist/panels/inspector/controls/external-link.test.js +105 -0
  391. package/dist/panels/inspector/controls/index.d.ts +1 -0
  392. package/dist/panels/inspector/controls/index.d.ts.map +1 -1
  393. package/dist/panels/inspector/controls/index.js +1 -0
  394. package/dist/panels/inspector/controls/media.d.ts +3 -1
  395. package/dist/panels/inspector/controls/media.d.ts.map +1 -1
  396. package/dist/panels/inspector/controls/media.js +8 -3
  397. package/dist/panels/inspector/controls/rich-text.d.ts.map +1 -1
  398. package/dist/panels/inspector/controls/rich-text.js +36 -6
  399. package/dist/panels/inspector/controls/textarea.d.ts +7 -2
  400. package/dist/panels/inspector/controls/textarea.d.ts.map +1 -1
  401. package/dist/panels/inspector/controls/textarea.js +37 -2
  402. package/dist/panels/inspector/default-hint.d.ts +13 -0
  403. package/dist/panels/inspector/default-hint.d.ts.map +1 -0
  404. package/dist/panels/inspector/default-hint.js +30 -0
  405. package/dist/panels/inspector/default-hint.test.d.ts +2 -0
  406. package/dist/panels/inspector/default-hint.test.d.ts.map +1 -0
  407. package/dist/panels/inspector/default-hint.test.js +46 -0
  408. package/dist/panels/inspector/index.d.ts +3 -3
  409. package/dist/panels/inspector/index.d.ts.map +1 -1
  410. package/dist/panels/inspector/index.js +2 -2
  411. package/dist/panels/inspector/inspector.d.ts +20 -2
  412. package/dist/panels/inspector/inspector.d.ts.map +1 -1
  413. package/dist/panels/inspector/inspector.js +246 -26
  414. package/dist/panels/inspector/inspector.test.js +276 -11
  415. package/dist/panels/inspector/props-panel.d.ts +36 -0
  416. package/dist/panels/inspector/props-panel.d.ts.map +1 -1
  417. package/dist/panels/inspector/props-panel.js +99 -17
  418. package/dist/panels/inspector/props-panel.test.d.ts +2 -0
  419. package/dist/panels/inspector/props-panel.test.d.ts.map +1 -0
  420. package/dist/panels/inspector/props-panel.test.js +17 -0
  421. package/dist/panels/inspector/scrub-label.d.ts +14 -0
  422. package/dist/panels/inspector/scrub-label.d.ts.map +1 -0
  423. package/dist/panels/inspector/scrub-label.js +75 -0
  424. package/dist/panels/inspector/scrub-label.test.d.ts +2 -0
  425. package/dist/panels/inspector/scrub-label.test.d.ts.map +1 -0
  426. package/dist/panels/inspector/scrub-label.test.js +132 -0
  427. package/dist/panels/inspector/styles/background-media.d.ts +28 -0
  428. package/dist/panels/inspector/styles/background-media.d.ts.map +1 -0
  429. package/dist/panels/inspector/styles/background-media.js +78 -0
  430. package/dist/panels/inspector/styles/box-model.d.ts +13 -16
  431. package/dist/panels/inspector/styles/box-model.d.ts.map +1 -1
  432. package/dist/panels/inspector/styles/box-model.js +10 -25
  433. package/dist/panels/inspector/styles/color-input.d.ts +3 -0
  434. package/dist/panels/inspector/styles/color-input.d.ts.map +1 -0
  435. package/dist/panels/inspector/styles/color-input.js +72 -0
  436. package/dist/panels/inspector/styles/gradient-fields.d.ts +9 -0
  437. package/dist/panels/inspector/styles/gradient-fields.d.ts.map +1 -0
  438. package/dist/panels/inspector/styles/gradient-fields.js +50 -0
  439. package/dist/panels/inspector/styles/index.d.ts +2 -0
  440. package/dist/panels/inspector/styles/index.d.ts.map +1 -1
  441. package/dist/panels/inspector/styles/index.js +2 -0
  442. package/dist/panels/inspector/styles/model.d.ts +27 -5
  443. package/dist/panels/inspector/styles/model.d.ts.map +1 -1
  444. package/dist/panels/inspector/styles/model.js +101 -3
  445. package/dist/panels/inspector/styles/motion-rows.d.ts +17 -0
  446. package/dist/panels/inspector/styles/motion-rows.d.ts.map +1 -0
  447. package/dist/panels/inspector/styles/motion-rows.js +117 -0
  448. package/dist/panels/inspector/styles/number-input.d.ts +4 -0
  449. package/dist/panels/inspector/styles/number-input.d.ts.map +1 -0
  450. package/dist/panels/inspector/styles/number-input.js +12 -0
  451. package/dist/panels/inspector/styles/option-label.d.ts +7 -0
  452. package/dist/panels/inspector/styles/option-label.d.ts.map +1 -0
  453. package/dist/panels/inspector/styles/option-label.js +9 -0
  454. package/dist/panels/inspector/styles/property-label.d.ts +9 -0
  455. package/dist/panels/inspector/styles/property-label.d.ts.map +1 -0
  456. package/dist/panels/inspector/styles/property-label.js +11 -0
  457. package/dist/panels/inspector/styles/section-state.d.ts +22 -0
  458. package/dist/panels/inspector/styles/section-state.d.ts.map +1 -0
  459. package/dist/panels/inspector/styles/section-state.js +96 -0
  460. package/dist/panels/inspector/styles/section.d.ts +25 -0
  461. package/dist/panels/inspector/styles/section.d.ts.map +1 -0
  462. package/dist/panels/inspector/styles/section.js +43 -0
  463. package/dist/panels/inspector/styles/sections-context.d.ts +13 -0
  464. package/dist/panels/inspector/styles/sections-context.d.ts.map +1 -0
  465. package/dist/panels/inspector/styles/sections-context.js +19 -0
  466. package/dist/panels/inspector/styles/sections-context.test.d.ts +2 -0
  467. package/dist/panels/inspector/styles/sections-context.test.d.ts.map +1 -0
  468. package/dist/panels/inspector/styles/sections-context.test.js +18 -0
  469. package/dist/panels/inspector/styles/sections-toggle.d.ts +6 -0
  470. package/dist/panels/inspector/styles/sections-toggle.d.ts.map +1 -0
  471. package/dist/panels/inspector/styles/sections-toggle.js +18 -0
  472. package/dist/panels/inspector/styles/segments.d.ts +3 -0
  473. package/dist/panels/inspector/styles/segments.d.ts.map +1 -1
  474. package/dist/panels/inspector/styles/segments.js +11 -4
  475. package/dist/panels/inspector/styles/sides-editor.d.ts +1 -1
  476. package/dist/panels/inspector/styles/sides-editor.d.ts.map +1 -1
  477. package/dist/panels/inspector/styles/sides-editor.js +33 -4
  478. package/dist/panels/inspector/styles/style-inspector.d.ts +3 -1
  479. package/dist/panels/inspector/styles/style-inspector.d.ts.map +1 -1
  480. package/dist/panels/inspector/styles/style-inspector.js +610 -42
  481. package/dist/panels/inspector/styles/style-inspector.test.js +694 -14
  482. package/dist/panels/inspector/styles/token-picker.d.ts +1 -1
  483. package/dist/panels/inspector/styles/token-picker.d.ts.map +1 -1
  484. package/dist/panels/inspector/styles/token-picker.js +10 -3
  485. package/dist/panels/inspector/styles/widgets.d.ts +116 -0
  486. package/dist/panels/inspector/styles/widgets.d.ts.map +1 -0
  487. package/dist/panels/inspector/styles/widgets.js +304 -0
  488. package/dist/panels/inspector/styles/widgets.test.d.ts +2 -0
  489. package/dist/panels/inspector/styles/widgets.test.d.ts.map +1 -0
  490. package/dist/panels/inspector/styles/widgets.test.js +247 -0
  491. package/dist/panels/inspector/values/value-editor.d.ts +1 -1
  492. package/dist/panels/inspector/values/value-editor.d.ts.map +1 -1
  493. package/dist/panels/inspector/values/value-editor.js +9 -8
  494. package/dist/panels/inspector/values/values.test.js +9 -3
  495. package/dist/panels/issues/collect.d.ts +2 -0
  496. package/dist/panels/issues/collect.d.ts.map +1 -1
  497. package/dist/panels/issues/collect.js +1 -0
  498. package/dist/panels/issues/index.d.ts +1 -0
  499. package/dist/panels/issues/index.d.ts.map +1 -1
  500. package/dist/panels/issues/index.js +1 -0
  501. package/dist/panels/issues/issues-panel.d.ts +4 -3
  502. package/dist/panels/issues/issues-panel.d.ts.map +1 -1
  503. package/dist/panels/issues/issues-panel.js +22 -35
  504. package/dist/panels/issues/path.d.ts +7 -0
  505. package/dist/panels/issues/path.d.ts.map +1 -0
  506. package/dist/panels/issues/path.js +21 -0
  507. package/dist/panels/layers/flatten.d.ts +16 -2
  508. package/dist/panels/layers/flatten.d.ts.map +1 -1
  509. package/dist/panels/layers/flatten.js +48 -4
  510. package/dist/panels/layers/layers-panel.d.ts +5 -2
  511. package/dist/panels/layers/layers-panel.d.ts.map +1 -1
  512. package/dist/panels/layers/layers-panel.js +177 -35
  513. package/dist/panels/layers/layers-panel.test.js +173 -15
  514. package/dist/panels/left-panel.d.ts +17 -0
  515. package/dist/panels/left-panel.d.ts.map +1 -0
  516. package/dist/panels/left-panel.js +47 -0
  517. package/dist/panels/left-panel.test.d.ts +2 -0
  518. package/dist/panels/left-panel.test.d.ts.map +1 -0
  519. package/dist/panels/left-panel.test.js +77 -0
  520. package/dist/persistence/persistence.test.js +9 -3
  521. package/dist/persistence/react.d.ts.map +1 -1
  522. package/dist/persistence/react.js +2 -2
  523. package/dist/preview/preview.d.ts +8 -0
  524. package/dist/preview/preview.d.ts.map +1 -1
  525. package/dist/preview/preview.js +21 -1
  526. package/dist/preview/preview.test.js +18 -1
  527. package/dist/shortcuts/actions.d.ts +13 -2
  528. package/dist/shortcuts/actions.d.ts.map +1 -1
  529. package/dist/shortcuts/actions.js +70 -15
  530. package/dist/shortcuts/help.d.ts +11 -0
  531. package/dist/shortcuts/help.d.ts.map +1 -0
  532. package/dist/shortcuts/help.js +77 -0
  533. package/dist/shortcuts/index.d.ts +5 -2
  534. package/dist/shortcuts/index.d.ts.map +1 -1
  535. package/dist/shortcuts/index.js +3 -1
  536. package/dist/shortcuts/map.d.ts +1 -1
  537. package/dist/shortcuts/map.d.ts.map +1 -1
  538. package/dist/shortcuts/map.js +14 -8
  539. package/dist/shortcuts/navigation.d.ts +13 -0
  540. package/dist/shortcuts/navigation.d.ts.map +1 -0
  541. package/dist/shortcuts/navigation.js +48 -0
  542. package/dist/shortcuts/shortcuts.d.ts +12 -1
  543. package/dist/shortcuts/shortcuts.d.ts.map +1 -1
  544. package/dist/shortcuts/shortcuts.js +61 -14
  545. package/dist/shortcuts/shortcuts.test.js +206 -5
  546. package/dist/store/create-store.d.ts.map +1 -1
  547. package/dist/store/create-store.js +19 -1
  548. package/dist/store/index.d.ts +4 -1
  549. package/dist/store/index.d.ts.map +1 -1
  550. package/dist/store/index.js +3 -1
  551. package/dist/store/react.d.ts +4 -0
  552. package/dist/store/react.d.ts.map +1 -1
  553. package/dist/store/react.js +7 -0
  554. package/dist/store/store.test.js +24 -0
  555. package/dist/store/structure-lock.d.ts +16 -0
  556. package/dist/store/structure-lock.d.ts.map +1 -0
  557. package/dist/store/structure-lock.js +43 -0
  558. package/dist/store/structure-lock.test.d.ts +2 -0
  559. package/dist/store/structure-lock.test.d.ts.map +1 -0
  560. package/dist/store/structure-lock.test.js +49 -0
  561. package/dist/store/types.d.ts +9 -0
  562. package/dist/store/types.d.ts.map +1 -1
  563. package/dist/store/view.d.ts +20 -0
  564. package/dist/store/view.d.ts.map +1 -0
  565. package/dist/store/view.js +17 -0
  566. package/dist/store/view.test.d.ts +2 -0
  567. package/dist/store/view.test.d.ts.map +1 -0
  568. package/dist/store/view.test.js +103 -0
  569. package/dist/styles/tokens.test.js +88 -9
  570. package/dist/styles.css +4112 -586
  571. package/dist/toolbar/brand.d.ts +2 -2
  572. package/dist/toolbar/brand.d.ts.map +1 -1
  573. package/dist/toolbar/brand.js +4 -4
  574. package/dist/toolbar/breakpoint-control.d.ts +4 -0
  575. package/dist/toolbar/breakpoint-control.d.ts.map +1 -1
  576. package/dist/toolbar/breakpoint-control.js +11 -4
  577. package/dist/toolbar/editable-title.d.ts +4 -1
  578. package/dist/toolbar/editable-title.d.ts.map +1 -1
  579. package/dist/toolbar/editable-title.js +2 -2
  580. package/dist/toolbar/editable-title.test.js +10 -0
  581. package/dist/toolbar/locale-chip.d.ts +10 -0
  582. package/dist/toolbar/locale-chip.d.ts.map +1 -0
  583. package/dist/toolbar/locale-chip.js +27 -0
  584. package/dist/toolbar/locale-switcher.d.ts.map +1 -1
  585. package/dist/toolbar/locale-switcher.js +4 -1
  586. package/dist/toolbar/more-menu.d.ts +26 -4
  587. package/dist/toolbar/more-menu.d.ts.map +1 -1
  588. package/dist/toolbar/more-menu.js +60 -13
  589. package/dist/toolbar/page-chip.d.ts +10 -0
  590. package/dist/toolbar/page-chip.d.ts.map +1 -0
  591. package/dist/toolbar/page-chip.js +12 -0
  592. package/dist/toolbar/page-options-dialog.d.ts +16 -0
  593. package/dist/toolbar/page-options-dialog.d.ts.map +1 -0
  594. package/dist/toolbar/page-options-dialog.js +13 -0
  595. package/dist/toolbar/panel-toggles.d.ts +3 -2
  596. package/dist/toolbar/panel-toggles.d.ts.map +1 -1
  597. package/dist/toolbar/panel-toggles.js +9 -4
  598. package/dist/toolbar/publish-dialog.d.ts +3 -0
  599. package/dist/toolbar/publish-dialog.d.ts.map +1 -1
  600. package/dist/toolbar/publish-dialog.js +34 -7
  601. package/dist/toolbar/publish.test.js +63 -19
  602. package/dist/toolbar/safe-history.d.ts +3 -0
  603. package/dist/toolbar/safe-history.d.ts.map +1 -0
  604. package/dist/toolbar/safe-history.js +5 -0
  605. package/dist/toolbar/sample-picker.d.ts +24 -4
  606. package/dist/toolbar/sample-picker.d.ts.map +1 -1
  607. package/dist/toolbar/sample-picker.js +42 -18
  608. package/dist/toolbar/toolbar-centre.d.ts +3 -11
  609. package/dist/toolbar/toolbar-centre.d.ts.map +1 -1
  610. package/dist/toolbar/toolbar-centre.js +4 -5
  611. package/dist/toolbar/toolbar-left.d.ts +4 -7
  612. package/dist/toolbar/toolbar-left.d.ts.map +1 -1
  613. package/dist/toolbar/toolbar-left.js +13 -11
  614. package/dist/toolbar/toolbar-right.d.ts +21 -6
  615. package/dist/toolbar/toolbar-right.d.ts.map +1 -1
  616. package/dist/toolbar/toolbar-right.js +28 -14
  617. package/dist/toolbar/toolbar.d.ts +23 -17
  618. package/dist/toolbar/toolbar.d.ts.map +1 -1
  619. package/dist/toolbar/toolbar.js +28 -11
  620. package/dist/toolbar/toolbar.test.js +238 -23
  621. package/dist/toolbar/use-overflow-level.d.ts +2 -1
  622. package/dist/toolbar/use-overflow-level.d.ts.map +1 -1
  623. package/dist/toolbar/use-overflow-level.js +9 -3
  624. package/dist/toolbar/zoom-menu.d.ts +5 -1
  625. package/dist/toolbar/zoom-menu.d.ts.map +1 -1
  626. package/dist/toolbar/zoom-menu.js +3 -2
  627. package/dist/ui/icon.d.ts +53 -0
  628. package/dist/ui/icon.d.ts.map +1 -1
  629. package/dist/ui/icon.js +58 -1
  630. package/dist/ui/icon.test.js +101 -3
  631. package/dist/ui/index.d.ts +4 -3
  632. package/dist/ui/index.d.ts.map +1 -1
  633. package/dist/ui/index.js +3 -2
  634. package/dist/ui/primitives.d.ts +97 -14
  635. package/dist/ui/primitives.d.ts.map +1 -1
  636. package/dist/ui/primitives.js +108 -22
  637. package/dist/ui/primitives.test.js +204 -3
  638. package/dist/ui/structure-locked.d.ts +9 -0
  639. package/dist/ui/structure-locked.d.ts.map +1 -0
  640. package/dist/ui/structure-locked.js +28 -0
  641. package/dist/ui/toast.d.ts +3 -1
  642. package/dist/ui/toast.d.ts.map +1 -1
  643. package/dist/ui/toast.js +21 -5
  644. package/dist/ui/toast.test.js +34 -0
  645. package/package.json +6 -4
@@ -7,9 +7,12 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
7
7
  import { axe } from 'vitest-axe';
8
8
  import * as matchers from 'vitest-axe/matchers';
9
9
  import { ManifestProvider } from '../../app/manifest.js';
10
+ import { ClipboardProvider } from '../../clipboard/index.js';
10
11
  import { MessagesProvider } from '../../messages/index.js';
12
+ import { ShortcutProvider } from '../../shortcuts/index.js';
11
13
  import { createEditorStore, EditorStoreProvider } from '../../store/index.js';
12
- import { flattenTree } from './flatten.js';
14
+ import { ToastProvider } from '../../ui/index.js';
15
+ import { filterTree, flattenTree } from './flatten.js';
13
16
  import { LayersPanel } from './layers-panel.js';
14
17
  expect.extend(matchers);
15
18
  globalThis.IS_REACT_ACT_ENVIRONMENT = true;
@@ -69,14 +72,15 @@ afterEach(() => {
69
72
  act(() => root.unmount());
70
73
  document.body.innerHTML = '';
71
74
  });
72
- async function mount(doc = fixture()) {
75
+ async function mount(doc = fixture(), connected = false, canUnlock) {
73
76
  const store = createEditorStore({
77
+ ...(canUnlock === undefined ? {} : { canUnlock }),
74
78
  doc,
75
79
  registry,
76
80
  generateId: createSeededIdGenerator(9),
77
81
  validationDelayMs: null,
78
82
  });
79
- await act(async () => root.render(_jsx(MessagesProvider, { locale: "en", children: _jsx(ManifestProvider, { manifest: toManifest(registry), children: _jsx(EditorStoreProvider, { store: store, children: _jsx(LayersPanel, {}) }) }) })));
83
+ await act(async () => root.render(_jsx(MessagesProvider, { locale: "en", children: _jsx(ManifestProvider, { manifest: toManifest(registry), children: _jsx(EditorStoreProvider, { store: store, children: connected ? (_jsx(ToastProvider, { children: _jsx(ClipboardProvider, { children: _jsx(ShortcutProvider, { children: _jsx(LayersPanel, {}) }) }) })) : (_jsx(LayersPanel, {})) }) }) })));
80
84
  return store;
81
85
  }
82
86
  const tree = () => container.querySelector('[role=tree]');
@@ -121,15 +125,23 @@ describe('flattenTree', () => {
121
125
  describe('LayersPanel', () => {
122
126
  it('is an ARIA tree with names from the manifest and no accessibility violations', async () => {
123
127
  await mount();
124
- expect(tree().getAttribute('aria-label')).toBe('Layers');
128
+ expect(tree().getAttribute('aria-label')).toBe('Page structure');
125
129
  expect(labels()).toEqual(['page', 'Hero', 'Box']);
126
130
  const [, hero] = items();
127
131
  expect(hero?.getAttribute('aria-level')).toBe('2');
132
+ expect(hero?.style.height).toBe('32px');
133
+ expect(hero?.querySelector('[data-row-actions]')).not.toBeNull();
134
+ expect(hero?.querySelector('[data-row-actions]')?.querySelectorAll('button')).toHaveLength(3);
128
135
  expect(hero?.getAttribute('aria-posinset')).toBe('1');
129
136
  expect(hero?.getAttribute('aria-setsize')).toBe('2');
130
137
  expect(hero?.getAttribute('aria-expanded')).toBe('false');
131
138
  expect(await axe(container)).toHaveNoViolations();
132
139
  });
140
+ it('shows a muted type label only on a renamed block', async () => {
141
+ await mount();
142
+ const types = items().map((item) => item.querySelector('.bd-layer-type')?.textContent ?? null);
143
+ expect(types).toEqual([null, 'Box', null]);
144
+ });
133
145
  it('draws an svg icon per row: the named one, or the neutral box, never a letter', async () => {
134
146
  await mount();
135
147
  const icons = items().map((item) => item.querySelector('.bd-layer-icon svg'));
@@ -143,10 +155,59 @@ describe('LayersPanel', () => {
143
155
  expect(icons[2]?.hasAttribute('data-fallback')).toBe(false);
144
156
  expect(items().every((item) => item.querySelector('.bd-layer-icon')?.textContent === '')).toBe(true);
145
157
  });
146
- it('shows badges with accessible names', async () => {
158
+ it('shows a locked node as a pressed lock toggle', async () => {
147
159
  await mount();
148
160
  const [, , locked] = items();
149
- expect(locked?.querySelector('[role=img]')?.getAttribute('aria-label')).toBe('Locked');
161
+ const lock = locked?.querySelector('button[aria-label="Unlock"]');
162
+ expect(lock?.getAttribute('aria-pressed')).toBe('true');
163
+ });
164
+ it('hides a node in the editor through the view store, not the document', async () => {
165
+ const store = await mount();
166
+ const before = store.getState().doc;
167
+ const row = items().find((i) => i.dataset['nodeId'] === 'boxNode001');
168
+ const eye = row?.querySelector('button[aria-label="Hide in editor"]');
169
+ expect(eye?.getAttribute('aria-pressed')).toBe('false');
170
+ await act(async () => eye?.click());
171
+ expect(store.view.getState().hiddenIds).toEqual(['boxNode001']);
172
+ expect(store.getState().doc).toBe(before);
173
+ expect(items()
174
+ .find((i) => i.dataset['nodeId'] === 'boxNode001')
175
+ ?.querySelector('button[aria-label="Show in editor"]')
176
+ ?.getAttribute('aria-pressed')).toBe('true');
177
+ });
178
+ it('locks a node with the document command', async () => {
179
+ const store = await mount();
180
+ const row = items().find((i) => i.dataset['nodeId'] === 'boxNode001');
181
+ await act(async () => row?.querySelector('button[aria-label="Lock"]')?.click());
182
+ expect(store.getState().doc.nodes['boxNode001']?.lock).toEqual({
183
+ structure: true,
184
+ content: true,
185
+ style: true,
186
+ });
187
+ });
188
+ it('unlocks a locked node when the host allows it', async () => {
189
+ const store = await mount(fixture(), false, () => true);
190
+ const row = items().find((i) => i.dataset['nodeId'] === 'boxNode002');
191
+ await act(async () => row?.querySelector('button[aria-label="Unlock"]')?.click());
192
+ expect(store.getState().doc.nodes['boxNode002']?.lock).toBeUndefined();
193
+ expect(container.querySelector('.bd-layers-notice')?.textContent).toBe('');
194
+ });
195
+ it('says so, and keeps the lock, when the host does not allow unlocking', async () => {
196
+ const store = await mount();
197
+ const row = items().find((i) => i.dataset['nodeId'] === 'boxNode002');
198
+ await act(async () => row?.querySelector('button[aria-label="Unlock"]')?.click());
199
+ expect(store.getState().doc.nodes['boxNode002']?.lock).toEqual({ content: true });
200
+ expect(container.querySelector('.bd-layers-notice')?.textContent).toBe('You are not allowed to unlock this block.');
201
+ });
202
+ it('only points to the Structure panel when unlocking is possible', async () => {
203
+ const store = await mount(fixture(), true);
204
+ const row = items().find((i) => i.dataset['nodeId'] === 'boxNode001');
205
+ await act(async () => row?.querySelector('button[aria-label="Lock"]')?.click());
206
+ await pick(store, 'boxNode001');
207
+ await act(async () => tree().focus());
208
+ await press('Delete');
209
+ expect(container.textContent).toContain('This block is locked.');
210
+ expect(container.textContent).not.toContain('Unlock it in the Structure panel');
150
211
  });
151
212
  it('is operable with the keyboard alone', async () => {
152
213
  const store = await mount();
@@ -176,7 +237,7 @@ describe('LayersPanel', () => {
176
237
  await pick(store, 'boxNode002');
177
238
  await act(async () => tree().focus());
178
239
  await press('F2');
179
- const input = container.querySelector('input');
240
+ const input = container.querySelector('[role=tree] input');
180
241
  expect(input.getAttribute('aria-label')).toBe('Layer name');
181
242
  await act(async () => {
182
243
  input.value = 'Footer';
@@ -184,10 +245,10 @@ describe('LayersPanel', () => {
184
245
  });
185
246
  expect(store.getState().doc.nodes['boxNode002']?.name).toBe('Footer');
186
247
  expect(store.getState().undoLabel).toBe('node.setAttr');
187
- expect(container.querySelector('input')).toBeNull();
248
+ expect(container.querySelector('[role=tree] input')).toBeNull();
188
249
  await press('F2');
189
250
  await act(async () => {
190
- const again = container.querySelector('input');
251
+ const again = container.querySelector('[role=tree] input');
191
252
  again.value = 'Nope';
192
253
  again.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
193
254
  });
@@ -204,6 +265,23 @@ describe('LayersPanel', () => {
204
265
  expect(store.getState().doc.nodes['boxNode001']).toBeUndefined();
205
266
  expect(labels()).toEqual(['page', 'Box']);
206
267
  });
268
+ it('keeps a locked block in place: Delete and the menu say why and change nothing', async () => {
269
+ const store = await mount(fixture(), true, () => true);
270
+ const row = items().find((i) => i.dataset['nodeId'] === 'boxNode001');
271
+ await act(async () => row?.querySelector('button[aria-label="Lock"]')?.click());
272
+ const locked = store.getState().doc;
273
+ await pick(store, 'boxNode001');
274
+ await act(async () => tree().focus());
275
+ await press('Delete');
276
+ const message = 'This block is locked. Unlock it in the Structure panel.';
277
+ expect(container.textContent).toContain(message);
278
+ expect(store.getState().doc).toBe(locked);
279
+ // An unlocked sibling still goes.
280
+ await pick(store, 'boxNode002');
281
+ await act(async () => tree().focus());
282
+ await press('Delete');
283
+ expect(store.getState().doc.nodes['boxNode002']).toBeUndefined();
284
+ });
207
285
  it('opens the ancestors of a node selected elsewhere, and marks it selected', async () => {
208
286
  const store = await mount();
209
287
  expect(labels()).toEqual(['page', 'Hero', 'Box']);
@@ -245,14 +323,46 @@ describe('LayersPanel', () => {
245
323
  expect(store.getState().selectedIds).toEqual(['boxNode001']);
246
324
  const menu = document.body.querySelector('[role=menu]');
247
325
  expect(menu?.getAttribute('aria-label')).toBe('Layer actions');
248
- const names = [...(menu?.querySelectorAll('[role=menuitem]') ?? [])].map((i) => i.textContent);
249
- expect(names).toEqual(['Rename', 'Duplicate', 'Wrap in container', 'Unwrap', 'Delete']);
250
- const duplicate = [...(menu?.querySelectorAll('[role=menuitem]') ?? [])].find((i) => i.textContent === 'Duplicate');
326
+ const names = [...(menu?.querySelectorAll('[role=menuitem]') ?? [])].map((i) => i.querySelector('.bd-menu-item-label')?.textContent);
327
+ expect(names).toEqual([
328
+ 'Rename',
329
+ 'Duplicate',
330
+ 'Copy',
331
+ 'Paste',
332
+ 'Wrap in container',
333
+ 'Unwrap',
334
+ 'Hide in editor',
335
+ 'Lock',
336
+ 'Delete',
337
+ ]);
338
+ const duplicate = [...(menu?.querySelectorAll('[role=menuitem]') ?? [])].find((i) => i.querySelector('.bd-menu-item-label')?.textContent === 'Duplicate');
251
339
  await act(async () => {
252
340
  duplicate.click();
253
341
  });
254
342
  expect(store.getState().doc.nodes['root']?.slots?.['default']).toHaveLength(3);
255
343
  });
344
+ it('copies through the shared clipboard and pastes as an undoable command', async () => {
345
+ const store = await mount({ ...fixture(), components: { 'buildr/page': 1, 'buildr/box': 1, 'buildr/text': 1 } }, true);
346
+ const open = async () => act(async () => {
347
+ items()
348
+ .find((i) => i.dataset['nodeId'] === 'boxNode001')
349
+ ?.dispatchEvent(new MouseEvent('contextmenu', { bubbles: true, cancelable: true }));
350
+ });
351
+ const action = (label) => [...document.querySelectorAll('[role=menuitem]')].find((i) => i.querySelector('.bd-menu-item-label')?.textContent === label);
352
+ const before = store.getState().doc;
353
+ await open();
354
+ await act(async () => action('Copy').click());
355
+ expect(store.getState().doc).toBe(before);
356
+ await open();
357
+ expect(await axe(document.querySelector('[role=menu]'))).toHaveNoViolations();
358
+ await act(async () => action('Paste').click());
359
+ expect(store.getState().doc.nodes['root']?.slots?.['default']).toHaveLength(3);
360
+ expect(store.getState().undoLabel).toBe('node.insert');
361
+ await act(async () => {
362
+ store.undo();
363
+ });
364
+ expect(store.getState().doc).toEqual(before);
365
+ });
256
366
  it('opens the same context menu from the hover "more" button, without starting a rename', async () => {
257
367
  const store = await mount();
258
368
  const more = items()[1]?.querySelector('[data-more] button');
@@ -263,7 +373,7 @@ describe('LayersPanel', () => {
263
373
  expect(store.getState().selectedIds).toEqual(['boxNode001']);
264
374
  const menu = document.body.querySelector('[role=menu]');
265
375
  expect(menu?.getAttribute('aria-label')).toBe('Layer actions');
266
- expect(container.querySelector('input')).toBeNull();
376
+ expect(container.querySelector('[role=tree] input')).toBeNull();
267
377
  });
268
378
  it('does not offer changes in a read-only document', async () => {
269
379
  const store = await mount();
@@ -273,7 +383,7 @@ describe('LayersPanel', () => {
273
383
  await press('Delete');
274
384
  await press('F2');
275
385
  expect(store.getState().doc.nodes['boxNode001']).toBeDefined();
276
- expect(container.querySelector('input')).toBeNull();
386
+ expect(container.querySelector('[role=tree] input')).toBeNull();
277
387
  });
278
388
  });
279
389
  describe('a large document', () => {
@@ -304,7 +414,7 @@ describe('a large document', () => {
304
414
  expect(items().length).toBeLessThan(40);
305
415
  expect(elapsed).toBeLessThan(500);
306
416
  const list = container.querySelector('.bd-layers-list');
307
- expect(list.style.height).toBe(`${1001 * 28}px`);
417
+ expect(list.style.height).toBe(`${1001 * 32}px`);
308
418
  });
309
419
  it('scrolls the row of a far selection into view', async () => {
310
420
  const store = await mount(big());
@@ -313,3 +423,51 @@ describe('a large document', () => {
313
423
  expect(present).toContain('n000000900');
314
424
  });
315
425
  });
426
+ describe('structure filter and expand all (PB-157)', () => {
427
+ const field = () => container.querySelector('.bd-layers-filter input');
428
+ const typeFilter = (value) => act(async () => {
429
+ Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set?.call(field(), value);
430
+ field().dispatchEvent(new Event('input', { bubbles: true }));
431
+ });
432
+ const tool = (label) => container.querySelector(`button[aria-label="${label}"]`);
433
+ it('filterTree keeps the ancestors of a match and opens them', () => {
434
+ const doc = fixture();
435
+ const { only, open } = filterTree(doc, (n) => n.id === 'textNodeB1');
436
+ expect([...only].sort()).toEqual(['boxNode001', 'root', 'textNodeB1']);
437
+ expect(open.has('boxNode001')).toBe(true);
438
+ const rows = flattenTree(doc, open, only);
439
+ expect(rows.map((r) => r.id)).toEqual(['root', 'boxNode001', 'textNodeB1']);
440
+ });
441
+ it('shows only the matching blocks with their ancestors, and says when nothing matches', async () => {
442
+ await mount();
443
+ await typeFilter('hero');
444
+ expect(labels()).toEqual(['page', 'Hero']);
445
+ await typeFilter('text');
446
+ expect(labels()).toContain('Hero');
447
+ expect(items().length).toBe(4);
448
+ await typeFilter('zzz');
449
+ expect(items().length).toBe(0);
450
+ expect(container.querySelector('.bd-layers-empty')?.textContent).toBe('No blocks match the filter.');
451
+ await typeFilter('');
452
+ expect(container.querySelector('.bd-layers-empty')).toBeNull();
453
+ });
454
+ it('collapses and expands the whole tree, and is off while filtering', async () => {
455
+ await mount();
456
+ await act(async () => tool('Collapse all').click());
457
+ expect(items().length).toBe(3);
458
+ await act(async () => tool('Expand all').click());
459
+ expect(items().length).toBe(5);
460
+ await typeFilter('a');
461
+ expect(tool('Expand all').disabled).toBe(true);
462
+ expect(tool('Collapse all').disabled).toBe(true);
463
+ });
464
+ it('moves from the filter field into the tree with the down arrow', async () => {
465
+ await mount();
466
+ field().focus();
467
+ await act(async () => {
468
+ field().dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }));
469
+ });
470
+ expect(container.contains(document.activeElement)).toBe(true);
471
+ expect(document.activeElement).not.toBe(field());
472
+ });
473
+ });
@@ -0,0 +1,17 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type LeftPanelTab } from '../app/contracts.ts';
3
+ export interface LeftPanelProps {
4
+ readonly tab: LeftPanelTab;
5
+ readonly onTabChange: (tab: LeftPanelTab) => void;
6
+ readonly onCollapse: () => void;
7
+ /** The Blocks tab (`InsertPanel`). */
8
+ readonly blocks: ReactNode;
9
+ /** The Structure tab (`LayersPanel`). */
10
+ readonly structure: ReactNode;
11
+ }
12
+ /**
13
+ * The left panel: Blocks and Structure tabs (a tablist with arrow-key roving), a collapse button
14
+ * and the active tab's body. Only the active body is mounted.
15
+ */
16
+ export declare function LeftPanel({ tab, onTabChange, onCollapse, blocks, structure }: LeftPanelProps): import("react").JSX.Element;
17
+ //# sourceMappingURL=left-panel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"left-panel.d.ts","sourceRoot":"","sources":["../../src/panels/left-panel.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,SAAS,EAAiB,MAAM,OAAO,CAAC;AAC1E,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAIzE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,CAAC;IAClD,QAAQ,CAAC,UAAU,EAAE,MAAM,IAAI,CAAC;IAChC,sCAAsC;IACtC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,yCAAyC;IACzC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;CAC/B;AAOD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,cAAc,+BAwE5F"}
@@ -0,0 +1,47 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useId, useRef } from 'react';
3
+ import { LEFT_PANEL_TABS } from '../app/contracts.js';
4
+ import { useT } from '../messages/index.js';
5
+ import { Icon, IconButton } from '../ui/index.js';
6
+ const TAB_ICON = {
7
+ blocks: 'layout-grid',
8
+ structure: 'list-tree',
9
+ };
10
+ /**
11
+ * The left panel: Blocks and Structure tabs (a tablist with arrow-key roving), a collapse button
12
+ * and the active tab's body. Only the active body is mounted.
13
+ */
14
+ export function LeftPanel({ tab, onTabChange, onCollapse, blocks, structure }) {
15
+ const t = useT();
16
+ const base = useId();
17
+ const refs = useRef(new Map());
18
+ const tabId = (value) => `${base}-tab-${value}`;
19
+ const panelId = `${base}-panel`;
20
+ const onKeyDown = (event) => {
21
+ const index = LEFT_PANEL_TABS.indexOf(tab);
22
+ const last = LEFT_PANEL_TABS.length - 1;
23
+ let next;
24
+ if (event.key === 'ArrowRight')
25
+ next = index === last ? 0 : index + 1;
26
+ else if (event.key === 'ArrowLeft')
27
+ next = index === 0 ? last : index - 1;
28
+ else if (event.key === 'Home')
29
+ next = 0;
30
+ else if (event.key === 'End')
31
+ next = last;
32
+ else
33
+ return;
34
+ event.preventDefault();
35
+ const value = LEFT_PANEL_TABS[next];
36
+ if (value === undefined)
37
+ return;
38
+ onTabChange(value);
39
+ refs.current.get(value)?.focus();
40
+ };
41
+ return (_jsxs("aside", { className: "bd-left-panel", "aria-label": t('leftPanel.label'), children: [_jsxs("div", { className: "bd-left-panel-head", children: [_jsx("div", { role: "tablist", "aria-label": t('leftPanel.tablistLabel'), className: "bd-tabs-list", onKeyDown: onKeyDown, children: LEFT_PANEL_TABS.map((value) => (_jsxs("button", { ref: (node) => {
42
+ if (node === null)
43
+ refs.current.delete(value);
44
+ else
45
+ refs.current.set(value, node);
46
+ }, type: "button", role: "tab", id: tabId(value), className: "bd-tab", "data-state": tab === value ? 'active' : 'inactive', "aria-selected": tab === value, "aria-controls": tab === value ? panelId : undefined, tabIndex: tab === value ? 0 : -1, onClick: () => onTabChange(value), children: [_jsx(Icon, { name: TAB_ICON[value] }), t(`leftPanel.tab.${value}`)] }, value))) }), _jsx(IconButton, { size: "sm", icon: "chevrons-left", label: t('leftPanel.collapse'), onClick: onCollapse })] }), _jsx("div", { role: "tabpanel", id: panelId, "aria-labelledby": tabId(tab), className: "bd-left-panel-body", "data-tab": tab, children: tab === 'blocks' ? blocks : structure })] }));
47
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=left-panel.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"left-panel.test.d.ts","sourceRoot":"","sources":["../../src/panels/left-panel.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,77 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // @vitest-environment jsdom
3
+ import { act, useState } from 'react';
4
+ import { createRoot } from 'react-dom/client';
5
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
6
+ import { axe } from 'vitest-axe';
7
+ import * as matchers from 'vitest-axe/matchers';
8
+ import { MessagesProvider } from '../messages/index.js';
9
+ import { LeftPanel } from './left-panel.js';
10
+ expect.extend(matchers);
11
+ globalThis.IS_REACT_ACT_ENVIRONMENT = true;
12
+ let container;
13
+ let root;
14
+ beforeEach(() => {
15
+ container = document.createElement('div');
16
+ document.body.append(container);
17
+ root = createRoot(container);
18
+ });
19
+ afterEach(() => {
20
+ act(() => root.unmount());
21
+ document.body.innerHTML = '';
22
+ });
23
+ function Harness({ onCollapse }) {
24
+ const [tab, setTab] = useState('blocks');
25
+ return (_jsx(LeftPanel, { tab: tab, onTabChange: setTab, onCollapse: onCollapse, blocks: _jsx("p", { children: "blocks body" }), structure: _jsx("p", { children: "structure body" }) }));
26
+ }
27
+ async function mount(locale = 'en', onCollapse = () => { }) {
28
+ await act(async () => root.render(_jsx(MessagesProvider, { locale: locale, children: _jsx(Harness, { onCollapse: onCollapse }) })));
29
+ }
30
+ const tabs = () => [...container.querySelectorAll('[role=tab]')];
31
+ const key = (el, k) => act(async () => {
32
+ el.dispatchEvent(new KeyboardEvent('keydown', { key: k, bubbles: true, cancelable: true }));
33
+ });
34
+ describe('LeftPanel', () => {
35
+ it('is a labelled tablist with a tabpanel and no accessibility violations', async () => {
36
+ await mount();
37
+ expect(container.querySelector('[role=tablist]')?.getAttribute('aria-label')).toBe('Left panel');
38
+ expect(tabs().map((t) => t.textContent)).toEqual(['Blocks', 'Structure']);
39
+ expect(tabs().map((t) => t.getAttribute('aria-selected'))).toEqual(['true', 'false']);
40
+ expect(tabs().map((t) => t.tabIndex)).toEqual([0, -1]);
41
+ const panel = container.querySelector('[role=tabpanel]');
42
+ expect(panel.textContent).toBe('blocks body');
43
+ expect(panel.getAttribute('aria-labelledby')).toBe(tabs()[0]?.id);
44
+ expect(tabs()[0]?.getAttribute('aria-controls')).toBe(panel.id);
45
+ expect(await axe(container)).toHaveNoViolations();
46
+ });
47
+ it('switches by click and by arrow keys, wrapping, moving focus', async () => {
48
+ await mount();
49
+ await act(async () => tabs()[1]?.click());
50
+ expect(container.querySelector('[role=tabpanel]')?.textContent).toBe('structure body');
51
+ await key(tabs()[1], 'ArrowRight');
52
+ expect(tabs()[0]?.getAttribute('aria-selected')).toBe('true');
53
+ expect(document.activeElement).toBe(tabs()[0]);
54
+ await key(tabs()[0], 'ArrowLeft');
55
+ expect(tabs()[1]?.getAttribute('aria-selected')).toBe('true');
56
+ await key(tabs()[1], 'Home');
57
+ expect(tabs()[0]?.getAttribute('aria-selected')).toBe('true');
58
+ await key(tabs()[0], 'End');
59
+ expect(tabs()[1]?.getAttribute('aria-selected')).toBe('true');
60
+ });
61
+ it('collapses with the collapse button', async () => {
62
+ const onCollapse = vi.fn();
63
+ await mount('en', onCollapse);
64
+ const button = container.querySelector('button[aria-label="Collapse panel"]');
65
+ await act(async () => button.click());
66
+ expect(onCollapse).toHaveBeenCalledOnce();
67
+ });
68
+ it('uses the Polish labels', async () => {
69
+ await mount('pl');
70
+ expect(tabs().map((t) => t.textContent)).toEqual(['Bloki', 'Struktura']);
71
+ expect(await axe(container)).toHaveNoViolations();
72
+ await act(async () => tabs()[1]?.click());
73
+ expect(container.querySelector('[role=tabpanel]')?.getAttribute('aria-labelledby')).toBe(tabs()[1]?.id);
74
+ expect(container.querySelector('[role=tabpanel] input')).toBeNull();
75
+ expect(await axe(container)).toHaveNoViolations();
76
+ });
77
+ });
@@ -466,18 +466,24 @@ describe('PersistenceProvider', () => {
466
466
  expect(banner()?.textContent).toBe('');
467
467
  expect(controller.state.getState().revision).toBe(2);
468
468
  });
469
- it('asks the author to choose in a conflict', async () => {
469
+ it('asks the author to choose in a conflict, as an alert dialog, and gives focus back', async () => {
470
470
  const fake = fakeAdapter();
471
471
  fake.next = () => ({ ok: false, kind: 'conflict', currentRevision: 9 });
472
472
  const { store, controller } = await mount(fake);
473
+ const opener = document.createElement('button');
474
+ document.body.append(opener);
475
+ opener.focus();
473
476
  edit(store);
474
477
  await advance(2000);
475
- const dialog = document.querySelector('[role=dialog]');
478
+ const dialog = document.querySelector('[role=alertdialog]');
476
479
  expect(dialog?.textContent).toContain('This page was changed elsewhere');
480
+ expect(dialog?.getAttribute('aria-describedby')).not.toBeNull();
481
+ expect(dialog?.querySelector('.bd-dialog-icon[data-tone="warning"]')).not.toBeNull();
477
482
  fake.next = () => ({ ok: true, revision: 10, updatedAt: 't10' });
478
483
  const overwrite = [...(dialog?.querySelectorAll('button') ?? [])].find((b) => b.textContent?.includes('Overwrite'));
479
484
  await act(async () => overwrite?.click());
480
485
  expect(status(controller)).toBe('clean');
481
- expect(document.querySelector('[role=dialog]')).toBeNull();
486
+ expect(document.querySelector('[role=alertdialog]')).toBeNull();
487
+ await vi.waitFor(() => expect(document.activeElement).toBe(opener));
482
488
  });
483
489
  });
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../src/persistence/react.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,SAAS,EAAyB,MAAM,OAAO,CAAC;AAK7E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,wBAAgB,cAAc,IAAI,qBAAqB,CAMtD;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,CAAC,GAAG,CAAC,CAElF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACzC,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC;IAC3C,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;CAC9B,+BA8BA;AAED,wGAAwG;AACxG,wBAAgB,aAAa,IAAI,MAAM,OAAO,CAM7C;AAwDD,8FAA8F;AAC9F,wBAAgB,UAAU,gCAqBzB"}
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../src/persistence/react.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,SAAS,EAAyB,MAAM,OAAO,CAAC;AAK7E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,wBAAgB,cAAc,IAAI,qBAAqB,CAMtD;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,CAAC,GAAG,CAAC,CAElF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACzC,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC;IAC3C,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;CAC9B,+BA8BA;AAED,wGAAwG;AACxG,wBAAgB,aAAa,IAAI,MAAM,OAAO,CAM7C;AA6DD,8FAA8F;AAC9F,wBAAgB,UAAU,gCAqBzB"}
@@ -85,9 +85,9 @@ function ConflictDialog() {
85
85
  const t = useT();
86
86
  const controller = usePersistence();
87
87
  const status = usePersistenceState((state) => state.status);
88
- return (_jsx(Dialog, { open: status === 'conflict', hideClose: true,
88
+ return (_jsx(Dialog, { open: status === 'conflict', hideClose: true, alert: true, icon: "triangle-alert", tone: "warning",
89
89
  // The choice is the only way out: closing without one would leave the editor stuck in conflict.
90
- onOpenChange: () => undefined, title: t('save.conflict.title'), description: t('save.conflict.description'), footer: _jsxs(_Fragment, { children: [_jsx(Button, { onClick: () => void controller.reload(), children: t('save.conflict.reload') }), _jsx(Button, { variant: "danger", onClick: () => void controller.overwrite(), children: t('save.conflict.overwrite') })] }) }));
90
+ onOpenChange: () => undefined, title: t('save.conflict.title'), description: t('save.conflict.description'), footer: _jsxs(_Fragment, { children: [_jsx(Button, { onClick: () => void controller.reload(), children: t('save.conflict.reload') }), _jsx(Button, { variant: "primary", onClick: () => void controller.overwrite(), children: t('save.conflict.overwrite') })] }), children: _jsx("p", { children: t('dialog.conflict.note') }) }));
91
91
  }
92
92
  /** A short status line for the toolbar (PB-083): saved, unsaved, saving, failed, conflict. */
93
93
  export function SaveStatus() {
@@ -1,5 +1,13 @@
1
1
  import { type ReactNode } from 'react';
2
2
  import { type DocumentAdapter, type DocumentRef } from '../persistence/index.ts';
3
+ /**
4
+ * The preview frame's sandbox. `allow-same-origin` is kept only for a preview served from the
5
+ * editor's own origin (the playground's `/preview` reads the draft from `sessionStorage`, which a
6
+ * sandboxed, opaque origin cannot). A preview on another origin has its own storage and needs no
7
+ * access to the editor's, so the flag is left out; with both `allow-scripts` and
8
+ * `allow-same-origin` a same-origin page could otherwise remove its own sandbox.
9
+ */
10
+ export declare function previewSandbox(url: string, base?: string): string;
3
11
  export interface PreviewOverlayProps {
4
12
  readonly url: string;
5
13
  readonly onExit: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../../src/preview/preview.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAoC,MAAM,OAAO,CAAC;AAEzE,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,WAAW,EAAkB,MAAM,yBAAyB,CAAC;AAIjG,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED,0FAA0F;AAC1F,wBAAgB,cAAc,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,mBAAmB,+BA0BlE;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;IACtD,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,2FAA2F;IAC3F,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,SAAS,CAAC;IAChD,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CACrD;AAED,MAAM,WAAW,UAAU;IACzB,qCAAqC;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;IAC7B,0CAA0C;IAC1C,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAC5B,0FAA0F;IAC1F,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,8DAA8D;AAC9D,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,UAAU,CA6BjE"}
1
+ {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../../src/preview/preview.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAoC,MAAM,OAAO,CAAC;AAEzE,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,WAAW,EAAkB,MAAM,yBAAyB,CAAC;AAIjG;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAWjE;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED,0FAA0F;AAC1F,wBAAgB,cAAc,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,mBAAmB,+BA0BlE;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;IACtD,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,2FAA2F;IAC3F,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,SAAS,CAAC;IAChD,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CACrD;AAED,MAAM,WAAW,UAAU;IACzB,qCAAqC;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;IAC7B,0CAA0C;IAC1C,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAC5B,0FAA0F;IAC1F,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,8DAA8D;AAC9D,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,UAAU,CA6BjE"}
@@ -4,6 +4,26 @@ import { useT } from '../messages/index.js';
4
4
  import { usePersistence } from '../persistence/index.js';
5
5
  import { Button } from '../ui/index.js';
6
6
  import { preparePreview } from './prepare.js';
7
+ /**
8
+ * The preview frame's sandbox. `allow-same-origin` is kept only for a preview served from the
9
+ * editor's own origin (the playground's `/preview` reads the draft from `sessionStorage`, which a
10
+ * sandboxed, opaque origin cannot). A preview on another origin has its own storage and needs no
11
+ * access to the editor's, so the flag is left out; with both `allow-scripts` and
12
+ * `allow-same-origin` a same-origin page could otherwise remove its own sandbox.
13
+ */
14
+ export function previewSandbox(url, base) {
15
+ const flags = ['allow-scripts', 'allow-forms', 'allow-popups'];
16
+ try {
17
+ const here = base ?? globalThis.location?.href;
18
+ if (here !== undefined && new URL(url, here).origin === new URL(here).origin) {
19
+ flags.splice(1, 0, 'allow-same-origin');
20
+ }
21
+ }
22
+ catch {
23
+ // An unparseable URL is treated as foreign: no same-origin access.
24
+ }
25
+ return flags.join(' ');
26
+ }
7
27
  /** The page as visitors get it, over the whole editor; Escape or the button leaves it. */
8
28
  export function PreviewOverlay({ url, onExit }) {
9
29
  const t = useT();
@@ -15,7 +35,7 @@ export function PreviewOverlay({ url, onExit }) {
15
35
  window.addEventListener('keydown', onKey);
16
36
  return () => window.removeEventListener('keydown', onKey);
17
37
  }, [onExit]);
18
- return (_jsxs("div", { className: "bd-preview", role: "dialog", "aria-modal": "true", "aria-label": t('preview.title'), children: [_jsxs("div", { className: "bd-preview-bar", children: [_jsx("span", { children: t('preview.title') }), _jsx(Button, { variant: "primary", onClick: onExit, autoFocus: true, children: t('preview.exit') })] }), _jsx("iframe", { className: "bd-preview-frame", title: t('preview.frame'), src: url, sandbox: "allow-scripts allow-same-origin allow-forms allow-popups", referrerPolicy: "no-referrer" })] }));
38
+ return (_jsxs("div", { className: "bd-preview", role: "dialog", "aria-modal": "true", "aria-label": t('preview.title'), children: [_jsxs("div", { className: "bd-preview-bar", children: [_jsx("span", { children: t('preview.title') }), _jsx(Button, { variant: "primary", onClick: onExit, autoFocus: true, children: t('preview.exit') })] }), _jsx("iframe", { className: "bd-preview-frame", title: t('preview.frame'), src: url, sandbox: previewSandbox(url), referrerPolicy: "no-referrer" })] }));
19
39
  }
20
40
  /** Saves, then shows the preview (docs/editor.md#preview). */
21
41
  export function usePreview(options) {
@@ -9,7 +9,7 @@ import { createPersistence, PersistenceProvider } from '../persistence/index.js'
9
9
  import { createEditorStore, EditorStoreProvider } from '../store/index.js';
10
10
  import { ToastProvider } from '../ui/index.js';
11
11
  import { isSafePreviewUrl } from './prepare.js';
12
- import { usePreview } from './preview.js';
12
+ import { previewSandbox, usePreview } from './preview.js';
13
13
  globalThis.IS_REACT_ACT_ENVIRONMENT = true;
14
14
  const item = {
15
15
  type: 'buildr/item',
@@ -127,3 +127,20 @@ describe('preview', () => {
127
127
  expect(container.textContent).toContain('not a web address');
128
128
  });
129
129
  });
130
+ describe('previewSandbox', () => {
131
+ const editor = 'https://editor.example/app';
132
+ it('keeps allow-same-origin only for a preview on the editor origin', () => {
133
+ expect(previewSandbox('/preview?x=1', editor)).toBe('allow-scripts allow-same-origin allow-forms allow-popups');
134
+ expect(previewSandbox('https://editor.example/preview', editor)).toContain('allow-same-origin');
135
+ });
136
+ it('omits it for another origin, another port or an unparseable URL', () => {
137
+ for (const url of [
138
+ 'https://site.example/p',
139
+ 'https://editor.example:8443/p',
140
+ 'http://editor.example/p',
141
+ ]) {
142
+ expect(previewSandbox(url, editor)).toBe('allow-scripts allow-forms allow-popups');
143
+ }
144
+ expect(previewSandbox('http://[bad', editor)).toBe('allow-scripts allow-forms allow-popups');
145
+ });
146
+ });
@@ -1,4 +1,6 @@
1
- import type { EditorStore } from '../store/index.ts';
1
+ import { type NodeId } from '@next-buildr/core';
2
+ import type { RemoveRequest, ShortcutCallbacks } from '../app/contracts.ts';
3
+ import { type EditorStore } from '../store/index.ts';
2
4
  import type { ShortcutRegistry } from './registry.ts';
3
5
  /** What the editor's own shortcuts need from outside: the actions of other modules (PB-085, PB-087). */
4
6
  export interface ExternalActions {
@@ -7,11 +9,20 @@ export interface ExternalActions {
7
9
  readonly paste?: () => boolean | undefined;
8
10
  readonly save?: () => boolean | undefined;
9
11
  }
12
+ /** The UI-only and removal hooks of the host, read on every key press so they may change between renders. */
13
+ export interface HostHooks {
14
+ readonly callbacks?: () => Partial<ShortcutCallbacks> | undefined;
15
+ readonly onRemove?: () => ((request: RemoveRequest) => void) | undefined;
16
+ /** Whether the UI-only keys may run for the key press being handled (`false` for a key aimed outside the editor). */
17
+ readonly uiAllowed?: () => boolean;
18
+ /** Tells the person why a structure-locked block was not removed, moved or duplicated. */
19
+ readonly onLocked?: () => ((ids?: readonly NodeId[]) => void) | undefined;
20
+ }
10
21
  /**
11
22
  * Binds the shortcuts that act on the store (undo, redo, duplicate, delete, move, select, clear)
12
23
  * and the ones other modules provide. Returns the function that unbinds them all. An action that
13
24
  * cannot run (nothing selected, a locked node the command refuses) returns `false`, so the key is
14
25
  * not swallowed.
15
26
  */
16
- export declare function bindEditorActions(registry: ShortcutRegistry, store: EditorStore, external?: ExternalActions): () => void;
27
+ export declare function bindEditorActions(registry: ShortcutRegistry, store: EditorStore, external?: ExternalActions, host?: HostHooks): () => void;
17
28
  //# sourceMappingURL=actions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/shortcuts/actions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,wGAAwG;AACxG,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;CAC3C;AAyCD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,WAAW,EAClB,QAAQ,GAAE,eAAoB,GAC7B,MAAM,IAAI,CAiCZ"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/shortcuts/actions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,KAAK,WAAW,EAAsB,MAAM,mBAAmB,CAAC;AAEzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,wGAAwG;AACxG,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;CAC3C;AAED,6GAA6G;AAC7G,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,iBAAiB,CAAC,GAAG,SAAS,CAAC;IAClE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACzE,qHAAqH;IACrH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;IACnC,0FAA0F;IAC1F,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAC3E;AAyDD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,WAAW,EAClB,QAAQ,GAAE,eAAoB,EAC9B,IAAI,GAAE,SAAc,GACnB,MAAM,IAAI,CA+EZ"}