@blokkli/editor 1.4.0-alpha.1 → 2.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (439) hide show
  1. package/dist/module.d.mts +12 -194
  2. package/dist/module.json +4 -4
  3. package/dist/module.mjs +1847 -1306
  4. package/dist/modules/drupal/adapter/index.d.mts +6 -0
  5. package/dist/modules/drupal/adapter/index.mjs +762 -0
  6. package/dist/modules/drupal/graphql/base/fragment.paragraphsBlokkliEditState.graphql +44 -0
  7. package/dist/modules/drupal/graphql/base/fragment.paragraphsBlokkliMutatedField.graphql +11 -0
  8. package/dist/modules/drupal/graphql/base/fragment.paragraphsBlokkliMutationItem.graphql +9 -0
  9. package/dist/modules/drupal/graphql/base/fragment.paragraphsBlokkliMutationResult.graphql +7 -0
  10. package/dist/modules/drupal/graphql/base/fragment.paragraphsBlokkliViolation.graphql +7 -0
  11. package/dist/modules/drupal/graphql/base/query.pbConfig.graphql +96 -0
  12. package/dist/modules/drupal/graphql/base/query.pbEditState.graphql +15 -0
  13. package/dist/modules/drupal/graphql/features/conversions.graphql +44 -0
  14. package/dist/modules/drupal/graphql/features/import-existing.graphql +34 -0
  15. package/dist/{runtime/adapter/drupal/graphql → modules/drupal/graphql/features}/library.graphql +17 -0
  16. package/dist/modules/drupal/graphql/features/media-library.graphql +28 -0
  17. package/dist/modules/drupal/graphql/features/preview-grant.graphql +13 -0
  18. package/dist/modules/drupal/graphql/features/publish.graphql +15 -0
  19. package/dist/modules/drupal/graphql/features/publishNew.graphql +59 -0
  20. package/dist/modules/drupal/graphql/mutations/add.graphql +25 -0
  21. package/dist/modules/drupal/graphql/mutations/add_clipboard_text.graphql +25 -0
  22. package/dist/modules/drupal/graphql/mutations/add_entity_reference.graphql +31 -0
  23. package/dist/modules/drupal/graphql/mutations/add_entity_reference_multiple.graphql +25 -0
  24. package/dist/modules/drupal/graphql/mutations/add_file.graphql +27 -0
  25. package/dist/modules/drupal/graphql/mutations/add_image.graphql +27 -0
  26. package/dist/modules/drupal/graphql/mutations/add_video_remote.graphql +25 -0
  27. package/dist/modules/drupal/graphql/mutations/bulk_update_behavior_settings.graphql +15 -0
  28. package/dist/modules/drupal/graphql/mutations/duplicate.graphql +33 -0
  29. package/dist/modules/drupal/graphql/mutations/move.graphql +25 -0
  30. package/dist/modules/drupal/graphql/mutations/move_multiple.graphql +25 -0
  31. package/dist/modules/drupal/graphql/mutations/redo.graphql +14 -0
  32. package/dist/modules/drupal/graphql/mutations/remove.graphql +15 -0
  33. package/dist/modules/drupal/graphql/mutations/remove_multiple.graphql +15 -0
  34. package/dist/modules/drupal/graphql/mutations/replace_host_entity_media.graphql +20 -0
  35. package/dist/modules/drupal/graphql/mutations/replace_media.graphql +22 -0
  36. package/dist/modules/drupal/graphql/mutations/revertAllChanges.graphql +14 -0
  37. package/dist/modules/drupal/graphql/mutations/setHistoryIndex.graphql +15 -0
  38. package/dist/modules/drupal/graphql/mutations/setMutationStatus.graphql +16 -0
  39. package/dist/modules/drupal/graphql/mutations/takeOwnership.graphql +14 -0
  40. package/dist/modules/drupal/graphql/mutations/undo.graphql +14 -0
  41. package/dist/modules/drupal/graphql/mutations/update_behavior_setting.graphql +23 -0
  42. package/dist/modules/drupal/graphql/mutations/update_field_value.graphql +22 -0
  43. package/dist/modules/drupal/graphql/mutations/update_host_entity_field_value.graphql +20 -0
  44. package/dist/modules/drupal/index.d.mts +10 -0
  45. package/dist/modules/drupal/index.mjs +170 -0
  46. package/dist/runtime/adapter/index.d.ts +30 -4
  47. package/dist/runtime/blokkliPlugins/AddAction/index.vue +39 -54
  48. package/dist/runtime/blokkliPlugins/AddAction/index.vue.d.ts +26 -0
  49. package/dist/runtime/blokkliPlugins/ContextMenu/Menu/index.vue +38 -64
  50. package/dist/runtime/blokkliPlugins/ContextMenu/Menu/index.vue.d.ts +12 -0
  51. package/dist/runtime/blokkliPlugins/ContextMenu/index.vue +19 -30
  52. package/dist/runtime/blokkliPlugins/ContextMenu/index.vue.d.ts +37 -0
  53. package/dist/runtime/blokkliPlugins/DebugOverlay/index.vue +15 -23
  54. package/dist/runtime/blokkliPlugins/DebugOverlay/index.vue.d.ts +21 -0
  55. package/dist/runtime/blokkliPlugins/DroppableEdit/index.vue +28 -45
  56. package/dist/runtime/blokkliPlugins/DroppableEdit/index.vue.d.ts +41 -0
  57. package/dist/runtime/blokkliPlugins/ItemAction/index.vue +39 -85
  58. package/dist/runtime/blokkliPlugins/ItemAction/index.vue.d.ts +83 -0
  59. package/dist/runtime/blokkliPlugins/ItemDropdown/index.vue +22 -26
  60. package/dist/runtime/blokkliPlugins/ItemDropdown/index.vue.d.ts +17 -0
  61. package/dist/runtime/blokkliPlugins/MenuButton/index.vue +30 -38
  62. package/dist/runtime/blokkliPlugins/MenuButton/index.vue.d.ts +32 -0
  63. package/dist/runtime/blokkliPlugins/Sidebar/Detached/index.vue +146 -211
  64. package/dist/runtime/blokkliPlugins/Sidebar/Detached/index.vue.d.ts +91 -0
  65. package/dist/runtime/blokkliPlugins/Sidebar/index.vue +95 -139
  66. package/dist/runtime/blokkliPlugins/Sidebar/index.vue.d.ts +85 -0
  67. package/dist/runtime/blokkliPlugins/ToolbarButton/index.vue +38 -57
  68. package/dist/runtime/blokkliPlugins/ToolbarButton/index.vue.d.ts +48 -0
  69. package/dist/runtime/blokkliPlugins/TourItem/index.vue +20 -29
  70. package/dist/runtime/blokkliPlugins/TourItem/index.vue.d.ts +20 -0
  71. package/dist/runtime/blokkliPlugins/ViewOption/index.vue +45 -59
  72. package/dist/runtime/blokkliPlugins/ViewOption/index.vue.d.ts +39 -0
  73. package/dist/runtime/components/Blocks/Fragment/index.vue +13 -20
  74. package/dist/runtime/components/Blocks/Fragment/index.vue.d.ts +6 -0
  75. package/dist/runtime/components/Blocks/FromLibrary/index.vue +19 -29
  76. package/dist/runtime/components/Blocks/FromLibrary/index.vue.d.ts +6 -0
  77. package/dist/runtime/components/BlokkliEditable.vue +30 -49
  78. package/dist/runtime/components/BlokkliEditable.vue.d.ts +20 -0
  79. package/dist/runtime/components/BlokkliField.vue +101 -159
  80. package/dist/runtime/components/BlokkliField.vue.d.ts +49 -0
  81. package/dist/runtime/components/BlokkliItem.vue +43 -66
  82. package/dist/runtime/components/BlokkliItem.vue.d.ts +26 -0
  83. package/dist/runtime/components/BlokkliProvider.vue +51 -87
  84. package/dist/runtime/components/BlokkliProvider.vue.d.ts +34 -0
  85. package/dist/runtime/components/Edit/Actions/index.vue +116 -164
  86. package/dist/runtime/components/Edit/Actions/index.vue.d.ts +2 -0
  87. package/dist/runtime/components/Edit/AddListItem/index.vue +45 -66
  88. package/dist/runtime/components/Edit/AddListItem/index.vue.d.ts +28 -0
  89. package/dist/runtime/components/Edit/AnimationCanvas/index.vue +52 -88
  90. package/dist/runtime/components/Edit/AnimationCanvas/index.vue.d.ts +2 -0
  91. package/dist/runtime/components/Edit/AppMenu/index.vue +12 -15
  92. package/dist/runtime/components/Edit/AppMenu/index.vue.d.ts +2 -0
  93. package/dist/runtime/components/Edit/BlockProxy/index.vue +48 -82
  94. package/dist/runtime/components/Edit/BlockProxy/index.vue.d.ts +10 -0
  95. package/dist/runtime/components/Edit/BlokkliErrorBoundary.vue +17 -21
  96. package/dist/runtime/components/Edit/BlokkliErrorBoundary.vue.d.ts +23 -0
  97. package/dist/runtime/components/Edit/Dialog/index.vue +67 -103
  98. package/dist/runtime/components/Edit/Dialog/index.vue.d.ts +44 -0
  99. package/dist/runtime/components/Edit/DragInteractions/index.vue +219 -333
  100. package/dist/runtime/components/Edit/DragInteractions/index.vue.d.ts +2 -0
  101. package/dist/runtime/components/Edit/DraggableList.vue +82 -125
  102. package/dist/runtime/components/Edit/DraggableList.vue.d.ts +27 -0
  103. package/dist/runtime/components/Edit/EditIndicator.vue +34 -46
  104. package/dist/runtime/components/Edit/EditIndicator.vue.d.ts +11 -0
  105. package/dist/runtime/components/Edit/EditProvider.vue +146 -142
  106. package/dist/runtime/components/Edit/EditProvider.vue.d.ts +26 -0
  107. package/dist/runtime/components/Edit/Features/AddList/index.vue +90 -117
  108. package/dist/runtime/components/Edit/Features/AddList/index.vue.d.ts +2 -0
  109. package/dist/runtime/components/Edit/Features/Artboard/Overview/index.vue +43 -63
  110. package/dist/runtime/components/Edit/Features/Artboard/Overview/index.vue.d.ts +6 -0
  111. package/dist/runtime/components/Edit/Features/Artboard/Scrollbar/index.vue +18 -23
  112. package/dist/runtime/components/Edit/Features/Artboard/Scrollbar/index.vue.d.ts +7 -0
  113. package/dist/runtime/components/Edit/Features/Artboard/index.vue +174 -223
  114. package/dist/runtime/components/Edit/Features/Artboard/index.vue.d.ts +2 -0
  115. package/dist/runtime/components/Edit/Features/Assistant/Overlay/ResultMarkup/index.vue +7 -7
  116. package/dist/runtime/components/Edit/Features/Assistant/Overlay/ResultMarkup/index.vue.d.ts +6 -0
  117. package/dist/runtime/components/Edit/Features/Assistant/Overlay/index.vue +41 -54
  118. package/dist/runtime/components/Edit/Features/Assistant/Overlay/index.vue.d.ts +8 -0
  119. package/dist/runtime/components/Edit/Features/Assistant/index.vue +31 -40
  120. package/dist/runtime/components/Edit/Features/Assistant/index.vue.d.ts +2 -0
  121. package/dist/runtime/components/Edit/Features/BlockAddList/index.vue +225 -326
  122. package/dist/runtime/components/Edit/Features/BlockAddList/index.vue.d.ts +2 -0
  123. package/dist/runtime/components/Edit/Features/Clipboard/List/Item/File.vue +36 -44
  124. package/dist/runtime/components/Edit/Features/Clipboard/List/Item/File.vue.d.ts +3 -0
  125. package/dist/runtime/components/Edit/Features/Clipboard/List/Item/Video.vue +33 -35
  126. package/dist/runtime/components/Edit/Features/Clipboard/List/Item/Video.vue.d.ts +3 -0
  127. package/dist/runtime/components/Edit/Features/Clipboard/List/index.vue +13 -21
  128. package/dist/runtime/components/Edit/Features/Clipboard/List/index.vue.d.ts +10 -0
  129. package/dist/runtime/components/Edit/Features/Clipboard/index.vue +227 -298
  130. package/dist/runtime/components/Edit/Features/Clipboard/index.vue.d.ts +2 -0
  131. package/dist/runtime/components/Edit/Features/CommandPalette/Palette/Group/index.vue +24 -34
  132. package/dist/runtime/components/Edit/Features/CommandPalette/Palette/Group/index.vue.d.ts +22 -0
  133. package/dist/runtime/components/Edit/Features/CommandPalette/Palette/index.vue +146 -195
  134. package/dist/runtime/components/Edit/Features/CommandPalette/Palette/index.vue.d.ts +6 -0
  135. package/dist/runtime/components/Edit/Features/CommandPalette/index.vue +21 -26
  136. package/dist/runtime/components/Edit/Features/CommandPalette/index.vue.d.ts +2 -0
  137. package/dist/runtime/components/Edit/Features/Comments/AddForm/index.vue +11 -14
  138. package/dist/runtime/components/Edit/Features/Comments/AddForm/index.vue.d.ts +8 -0
  139. package/dist/runtime/components/Edit/Features/Comments/Comment/index.vue +21 -29
  140. package/dist/runtime/components/Edit/Features/Comments/Comment/index.vue.d.ts +23 -0
  141. package/dist/runtime/components/Edit/Features/Comments/Overlay/Item/index.vue +31 -43
  142. package/dist/runtime/components/Edit/Features/Comments/Overlay/Item/index.vue.d.ts +19 -0
  143. package/dist/runtime/components/Edit/Features/Comments/Overlay/index.vue +70 -100
  144. package/dist/runtime/components/Edit/Features/Comments/Overlay/index.vue.d.ts +18 -0
  145. package/dist/runtime/components/Edit/Features/Comments/index.vue +37 -48
  146. package/dist/runtime/components/Edit/Features/Comments/index.vue.d.ts +2 -0
  147. package/dist/runtime/components/Edit/Features/Conversions/index.vue +40 -56
  148. package/dist/runtime/components/Edit/Features/Conversions/index.vue.d.ts +2 -0
  149. package/dist/runtime/components/Edit/Features/Debug/Rects/index.vue +37 -50
  150. package/dist/runtime/components/Edit/Features/Debug/Rects/index.vue.d.ts +2 -0
  151. package/dist/runtime/components/Edit/Features/Debug/Viewport/index.vue +35 -44
  152. package/dist/runtime/components/Edit/Features/Debug/Viewport/index.vue.d.ts +2 -0
  153. package/dist/runtime/components/Edit/Features/Debug/index.vue +43 -57
  154. package/dist/runtime/components/Edit/Features/Debug/index.vue.d.ts +2 -0
  155. package/dist/runtime/components/Edit/Features/Delete/index.vue +31 -52
  156. package/dist/runtime/components/Edit/Features/Delete/index.vue.d.ts +2 -0
  157. package/dist/runtime/components/Edit/Features/Diff/DiffView/index.vue +75 -114
  158. package/dist/runtime/components/Edit/Features/Diff/DiffView/index.vue.d.ts +2 -0
  159. package/dist/runtime/components/Edit/Features/Diff/index.vue +17 -19
  160. package/dist/runtime/components/Edit/Features/Diff/index.vue.d.ts +2 -0
  161. package/dist/runtime/components/Edit/Features/DraggingOverlay/DragItems/index.vue +193 -337
  162. package/dist/runtime/components/Edit/Features/DraggingOverlay/DragItems/index.vue.d.ts +27 -0
  163. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/fragment.glsl +1 -1
  164. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/index.vue +391 -644
  165. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/index.vue.d.ts +156 -0
  166. package/dist/runtime/components/Edit/Features/DraggingOverlay/index.vue +197 -323
  167. package/dist/runtime/components/Edit/Features/DraggingOverlay/index.vue.d.ts +2 -0
  168. package/dist/runtime/components/Edit/Features/Duplicate/index.vue +49 -71
  169. package/dist/runtime/components/Edit/Features/Duplicate/index.vue.d.ts +2 -0
  170. package/dist/runtime/components/Edit/Features/Edit/index.vue +41 -71
  171. package/dist/runtime/components/Edit/Features/Edit/index.vue.d.ts +2 -0
  172. package/dist/runtime/components/Edit/Features/EditForm/Frame/index.vue +35 -51
  173. package/dist/runtime/components/Edit/Features/EditForm/Frame/index.vue.d.ts +11 -0
  174. package/dist/runtime/components/Edit/Features/EditForm/index.vue +104 -140
  175. package/dist/runtime/components/Edit/Features/EditForm/index.vue.d.ts +2 -0
  176. package/dist/runtime/components/Edit/Features/EditableField/Overlay/Contenteditable/index.vue +18 -25
  177. package/dist/runtime/components/Edit/Features/EditableField/Overlay/Contenteditable/index.vue.d.ts +12 -0
  178. package/dist/runtime/components/Edit/Features/EditableField/Overlay/Frame/index.vue +34 -50
  179. package/dist/runtime/components/Edit/Features/EditableField/Overlay/Frame/index.vue.d.ts +16 -0
  180. package/dist/runtime/components/Edit/Features/EditableField/Overlay/Plaintext/index.vue +40 -51
  181. package/dist/runtime/components/Edit/Features/EditableField/Overlay/Plaintext/index.vue.d.ts +16 -0
  182. package/dist/runtime/components/Edit/Features/EditableField/Overlay/index.vue +147 -209
  183. package/dist/runtime/components/Edit/Features/EditableField/Overlay/index.vue.d.ts +15 -0
  184. package/dist/runtime/components/Edit/Features/EditableField/index.vue +90 -143
  185. package/dist/runtime/components/Edit/Features/EditableField/index.vue.d.ts +2 -0
  186. package/dist/runtime/components/Edit/Features/EditableMask/index.vue +28 -36
  187. package/dist/runtime/components/Edit/Features/EditableMask/index.vue.d.ts +2 -0
  188. package/dist/runtime/components/Edit/Features/EntityTitle/index.vue +49 -58
  189. package/dist/runtime/components/Edit/Features/EntityTitle/index.vue.d.ts +2 -0
  190. package/dist/runtime/components/Edit/Features/Exit/index.vue +16 -20
  191. package/dist/runtime/components/Edit/Features/Exit/index.vue.d.ts +2 -0
  192. package/dist/runtime/components/Edit/Features/FieldAreas/Overlay/index.vue +4 -15
  193. package/dist/runtime/components/Edit/Features/FieldAreas/Overlay/index.vue.d.ts +2 -0
  194. package/dist/runtime/components/Edit/Features/FieldAreas/index.vue +19 -21
  195. package/dist/runtime/components/Edit/Features/FieldAreas/index.vue.d.ts +2 -0
  196. package/dist/runtime/components/Edit/Features/Fragments/Dialog/Item/index.vue +28 -35
  197. package/dist/runtime/components/Edit/Features/Fragments/Dialog/Item/index.vue.d.ts +8 -0
  198. package/dist/runtime/components/Edit/Features/Fragments/Dialog/index.vue +51 -74
  199. package/dist/runtime/components/Edit/Features/Fragments/Dialog/index.vue.d.ts +12 -0
  200. package/dist/runtime/components/Edit/Features/Fragments/index.vue +41 -51
  201. package/dist/runtime/components/Edit/Features/Fragments/index.vue.d.ts +2 -0
  202. package/dist/runtime/components/Edit/Features/Grid/index.vue +17 -20
  203. package/dist/runtime/components/Edit/Features/Grid/index.vue.d.ts +2 -0
  204. package/dist/runtime/components/Edit/Features/Help/Shortcuts/index.vue +24 -35
  205. package/dist/runtime/components/Edit/Features/Help/Shortcuts/index.vue.d.ts +2 -0
  206. package/dist/runtime/components/Edit/Features/Help/index.vue +19 -23
  207. package/dist/runtime/components/Edit/Features/Help/index.vue.d.ts +2 -0
  208. package/dist/runtime/components/Edit/Features/History/List/index.vue +49 -70
  209. package/dist/runtime/components/Edit/Features/History/List/index.vue.d.ts +5 -0
  210. package/dist/runtime/components/Edit/Features/History/index.vue +54 -69
  211. package/dist/runtime/components/Edit/Features/History/index.vue.d.ts +2 -0
  212. package/dist/runtime/components/Edit/Features/ImportExisting/Dialog/index.vue +48 -66
  213. package/dist/runtime/components/Edit/Features/ImportExisting/Dialog/index.vue.d.ts +14 -0
  214. package/dist/runtime/components/Edit/Features/ImportExisting/index.vue +38 -54
  215. package/dist/runtime/components/Edit/Features/ImportExisting/index.vue.d.ts +2 -0
  216. package/dist/runtime/components/Edit/Features/Library/EditReusable/index.vue +90 -128
  217. package/dist/runtime/components/Edit/Features/Library/EditReusable/index.vue.d.ts +13 -0
  218. package/dist/runtime/components/Edit/Features/Library/LibraryDialog/Item/index.vue +29 -38
  219. package/dist/runtime/components/Edit/Features/Library/LibraryDialog/Item/index.vue.d.ts +9 -0
  220. package/dist/runtime/components/Edit/Features/Library/LibraryDialog/index.vue +68 -93
  221. package/dist/runtime/components/Edit/Features/Library/LibraryDialog/index.vue.d.ts +12 -0
  222. package/dist/runtime/components/Edit/Features/Library/ReusableDialog/index.vue +39 -49
  223. package/dist/runtime/components/Edit/Features/Library/ReusableDialog/index.vue.d.ts +12 -0
  224. package/dist/runtime/components/Edit/Features/Library/index.vue +85 -117
  225. package/dist/runtime/components/Edit/Features/Library/index.vue.d.ts +2 -0
  226. package/dist/runtime/components/Edit/Features/MediaLibrary/Library/Item.vue +13 -19
  227. package/dist/runtime/components/Edit/Features/MediaLibrary/Library/Item.vue.d.ts +19 -0
  228. package/dist/runtime/components/Edit/Features/MediaLibrary/Library/index.vue +76 -112
  229. package/dist/runtime/components/Edit/Features/MediaLibrary/Library/index.vue.d.ts +6 -0
  230. package/dist/runtime/components/Edit/Features/MediaLibrary/index.vue +107 -140
  231. package/dist/runtime/components/Edit/Features/MediaLibrary/index.vue.d.ts +2 -0
  232. package/dist/runtime/components/Edit/Features/MultiSelect/Overlay/index.vue +128 -188
  233. package/dist/runtime/components/Edit/Features/MultiSelect/Overlay/index.vue.d.ts +12 -0
  234. package/dist/runtime/components/Edit/Features/MultiSelect/index.vue +42 -57
  235. package/dist/runtime/components/Edit/Features/MultiSelect/index.vue.d.ts +2 -0
  236. package/dist/runtime/components/Edit/Features/Options/Form/Checkbox/index.vue +27 -34
  237. package/dist/runtime/components/Edit/Features/Options/Form/Checkbox/index.vue.d.ts +14 -0
  238. package/dist/runtime/components/Edit/Features/Options/Form/Checkboxes/index.vue +55 -75
  239. package/dist/runtime/components/Edit/Features/Options/Form/Checkboxes/index.vue.d.ts +24 -0
  240. package/dist/runtime/components/Edit/Features/Options/Form/Color/index.vue +18 -21
  241. package/dist/runtime/components/Edit/Features/Options/Form/Color/index.vue.d.ts +12 -0
  242. package/dist/runtime/components/Edit/Features/Options/Form/DateTimeLocal/index.vue +36 -0
  243. package/dist/runtime/components/Edit/Features/Options/Form/DateTimeLocal/index.vue.d.ts +20 -0
  244. package/dist/runtime/components/Edit/Features/Options/Form/Group.vue +7 -9
  245. package/dist/runtime/components/Edit/Features/Options/Form/Group.vue.d.ts +29 -0
  246. package/dist/runtime/components/Edit/Features/Options/Form/Item.vue +87 -93
  247. package/dist/runtime/components/Edit/Features/Options/Form/Item.vue.d.ts +14 -0
  248. package/dist/runtime/components/Edit/Features/Options/Form/Number/index.vue +31 -45
  249. package/dist/runtime/components/Edit/Features/Options/Form/Number/index.vue.d.ts +21 -0
  250. package/dist/runtime/components/Edit/Features/Options/Form/Radios/index.vue +55 -79
  251. package/dist/runtime/components/Edit/Features/Options/Form/Radios/index.vue.d.ts +30 -0
  252. package/dist/runtime/components/Edit/Features/Options/Form/Range/index.vue +23 -33
  253. package/dist/runtime/components/Edit/Features/Options/Form/Range/index.vue.d.ts +18 -0
  254. package/dist/runtime/components/Edit/Features/Options/Form/Text/index.vue +17 -26
  255. package/dist/runtime/components/Edit/Features/Options/Form/Text/index.vue.d.ts +17 -0
  256. package/dist/runtime/components/Edit/Features/Options/Form/index.vue +178 -272
  257. package/dist/runtime/components/Edit/Features/Options/Form/index.vue.d.ts +9 -0
  258. package/dist/runtime/components/Edit/Features/Options/index.vue +38 -69
  259. package/dist/runtime/components/Edit/Features/Options/index.vue.d.ts +2 -0
  260. package/dist/runtime/components/Edit/Features/Ownership/index.vue +27 -34
  261. package/dist/runtime/components/Edit/Features/Ownership/index.vue.d.ts +2 -0
  262. package/dist/runtime/components/Edit/Features/Preview/index.vue +22 -27
  263. package/dist/runtime/components/Edit/Features/Preview/index.vue.d.ts +2 -0
  264. package/dist/runtime/components/Edit/Features/PreviewGrant/QrCode/index.vue +12 -16
  265. package/dist/runtime/components/Edit/Features/PreviewGrant/QrCode/index.vue.d.ts +5 -0
  266. package/dist/runtime/components/Edit/Features/PreviewGrant/index.vue +31 -36
  267. package/dist/runtime/components/Edit/Features/PreviewGrant/index.vue.d.ts +2 -0
  268. package/dist/runtime/components/Edit/Features/ProxyView/index.vue +18 -20
  269. package/dist/runtime/components/Edit/Features/ProxyView/index.vue.d.ts +2 -0
  270. package/dist/runtime/components/Edit/Features/Publish/Dialog/Item.vue +118 -0
  271. package/dist/runtime/components/Edit/Features/Publish/Dialog/Item.vue.d.ts +18 -0
  272. package/dist/runtime/components/Edit/Features/Publish/Dialog/index.vue +251 -0
  273. package/dist/runtime/components/Edit/Features/Publish/Dialog/index.vue.d.ts +19 -0
  274. package/dist/runtime/components/Edit/Features/Publish/Dialog/types.d.ts +7 -0
  275. package/dist/runtime/components/Edit/Features/Publish/index.vue +70 -74
  276. package/dist/runtime/components/Edit/Features/Publish/index.vue.d.ts +2 -0
  277. package/dist/runtime/components/Edit/Features/ResponsivePreview/Frame/index.vue +48 -54
  278. package/dist/runtime/components/Edit/Features/ResponsivePreview/Frame/index.vue.d.ts +27 -0
  279. package/dist/runtime/components/Edit/Features/ResponsivePreview/index.vue +77 -103
  280. package/dist/runtime/components/Edit/Features/ResponsivePreview/index.vue.d.ts +2 -0
  281. package/dist/runtime/components/Edit/Features/Revert/index.vue +27 -32
  282. package/dist/runtime/components/Edit/Features/Revert/index.vue.d.ts +2 -0
  283. package/dist/runtime/components/Edit/Features/Search/Overlay/Results/Content/index.vue +67 -88
  284. package/dist/runtime/components/Edit/Features/Search/Overlay/Results/Content/index.vue.d.ts +17 -0
  285. package/dist/runtime/components/Edit/Features/Search/Overlay/Results/Page/index.vue +89 -139
  286. package/dist/runtime/components/Edit/Features/Search/Overlay/Results/Page/index.vue.d.ts +18 -0
  287. package/dist/runtime/components/Edit/Features/Search/Overlay/index.vue +79 -108
  288. package/dist/runtime/components/Edit/Features/Search/Overlay/index.vue.d.ts +12 -0
  289. package/dist/runtime/components/Edit/Features/Search/index.vue +30 -37
  290. package/dist/runtime/components/Edit/Features/Search/index.vue.d.ts +2 -0
  291. package/dist/runtime/components/Edit/Features/Selection/Overlay/index.vue +67 -103
  292. package/dist/runtime/components/Edit/Features/Selection/Overlay/index.vue.d.ts +9 -0
  293. package/dist/runtime/components/Edit/Features/Selection/OverlayFallback/index.vue +28 -36
  294. package/dist/runtime/components/Edit/Features/Selection/OverlayFallback/index.vue.d.ts +5 -0
  295. package/dist/runtime/components/Edit/Features/Selection/index.vue +131 -217
  296. package/dist/runtime/components/Edit/Features/Selection/index.vue.d.ts +2 -0
  297. package/dist/runtime/components/Edit/Features/Settings/Dialog/FeatureSetting/index.vue +50 -81
  298. package/dist/runtime/components/Edit/Features/Settings/Dialog/FeatureSetting/index.vue.d.ts +9 -0
  299. package/dist/runtime/components/Edit/Features/Settings/Dialog/index.vue +73 -117
  300. package/dist/runtime/components/Edit/Features/Settings/Dialog/index.vue.d.ts +6 -0
  301. package/dist/runtime/components/Edit/Features/Settings/index.vue +41 -53
  302. package/dist/runtime/components/Edit/Features/Settings/index.vue.d.ts +2 -0
  303. package/dist/runtime/components/Edit/Features/Structure/List/Field/index.vue +65 -101
  304. package/dist/runtime/components/Edit/Features/Structure/List/Field/index.vue.d.ts +15 -0
  305. package/dist/runtime/components/Edit/Features/Structure/List/Item/index.vue +71 -99
  306. package/dist/runtime/components/Edit/Features/Structure/List/Item/index.vue.d.ts +12 -0
  307. package/dist/runtime/components/Edit/Features/Structure/List/index.vue +17 -26
  308. package/dist/runtime/components/Edit/Features/Structure/List/index.vue.d.ts +12 -0
  309. package/dist/runtime/components/Edit/Features/Structure/index.vue +31 -40
  310. package/dist/runtime/components/Edit/Features/Structure/index.vue.d.ts +2 -0
  311. package/dist/runtime/components/Edit/Features/Theme/Color/index.vue +32 -53
  312. package/dist/runtime/components/Edit/Features/Theme/Color/index.vue.d.ts +7 -0
  313. package/dist/runtime/components/Edit/Features/Theme/GeneratedCode/index.vue +7 -10
  314. package/dist/runtime/components/Edit/Features/Theme/GeneratedCode/index.vue.d.ts +2 -0
  315. package/dist/runtime/components/Edit/Features/Theme/index.vue +49 -63
  316. package/dist/runtime/components/Edit/Features/Theme/index.vue.d.ts +2 -0
  317. package/dist/runtime/components/Edit/Features/TouchActionBar/Bar/index.vue +9 -10
  318. package/dist/runtime/components/Edit/Features/TouchActionBar/Bar/index.vue.d.ts +12 -0
  319. package/dist/runtime/components/Edit/Features/TouchActionBar/index.vue +16 -19
  320. package/dist/runtime/components/Edit/Features/TouchActionBar/index.vue.d.ts +2 -0
  321. package/dist/runtime/components/Edit/Features/Tour/Overlay/index.vue +119 -174
  322. package/dist/runtime/components/Edit/Features/Tour/Overlay/index.vue.d.ts +6 -0
  323. package/dist/runtime/components/Edit/Features/Tour/Popup/index.vue +10 -12
  324. package/dist/runtime/components/Edit/Features/Tour/Popup/index.vue.d.ts +8 -0
  325. package/dist/runtime/components/Edit/Features/Tour/index.vue +21 -25
  326. package/dist/runtime/components/Edit/Features/Tour/index.vue.d.ts +2 -0
  327. package/dist/runtime/components/Edit/Features/Transform/index.vue +80 -120
  328. package/dist/runtime/components/Edit/Features/Transform/index.vue.d.ts +2 -0
  329. package/dist/runtime/components/Edit/Features/Translations/Banner/index.vue +21 -29
  330. package/dist/runtime/components/Edit/Features/Translations/Banner/index.vue.d.ts +6 -0
  331. package/dist/runtime/components/Edit/Features/Translations/index.vue +96 -139
  332. package/dist/runtime/components/Edit/Features/Translations/index.vue.d.ts +2 -0
  333. package/dist/runtime/components/Edit/Features/Validations/Overlay/Item.vue +21 -35
  334. package/dist/runtime/components/Edit/Features/Validations/Overlay/Item.vue.d.ts +6 -0
  335. package/dist/runtime/components/Edit/Features/Validations/Overlay/index.vue +30 -39
  336. package/dist/runtime/components/Edit/Features/Validations/Overlay/index.vue.d.ts +6 -0
  337. package/dist/runtime/components/Edit/Features/Validations/SidebarItem/index.vue +20 -28
  338. package/dist/runtime/components/Edit/Features/Validations/SidebarItem/index.vue.d.ts +9 -0
  339. package/dist/runtime/components/Edit/Features/Validations/index.vue +27 -33
  340. package/dist/runtime/components/Edit/Features/Validations/index.vue.d.ts +2 -0
  341. package/dist/runtime/components/Edit/Features/index.vue +33 -52
  342. package/dist/runtime/components/Edit/Features/index.vue.d.ts +6 -0
  343. package/dist/runtime/components/Edit/Form/Group/index.vue +23 -0
  344. package/dist/runtime/components/Edit/Form/Group/index.vue.d.ts +20 -0
  345. package/dist/runtime/components/Edit/Form/Item/index.vue +5 -0
  346. package/dist/runtime/components/Edit/Form/Item/index.vue.d.ts +14 -0
  347. package/dist/runtime/components/Edit/Form/Textarea/index.vue +27 -0
  348. package/dist/runtime/components/Edit/Form/Textarea/index.vue.d.ts +16 -0
  349. package/dist/runtime/components/Edit/Form/Toggle/index.vue +21 -0
  350. package/dist/runtime/components/Edit/Form/Toggle/index.vue.d.ts +14 -0
  351. package/dist/runtime/components/Edit/FormOverlay/Header/index.vue +11 -22
  352. package/dist/runtime/components/Edit/FormOverlay/Header/index.vue.d.ts +18 -0
  353. package/dist/runtime/components/Edit/FormOverlay/index.vue +15 -21
  354. package/dist/runtime/components/Edit/FormOverlay/index.vue.d.ts +25 -0
  355. package/dist/runtime/components/Edit/Highlight/index.vue +31 -70
  356. package/dist/runtime/components/Edit/Highlight/index.vue.d.ts +20 -0
  357. package/dist/runtime/components/Edit/Icon/index.vue +11 -14
  358. package/dist/runtime/components/Edit/Icon/index.vue.d.ts +7 -0
  359. package/dist/runtime/components/Edit/InfoBox/index.vue +5 -6
  360. package/dist/runtime/components/Edit/InfoBox/index.vue.d.ts +5 -0
  361. package/dist/runtime/components/Edit/ItemIcon/index.vue +13 -13
  362. package/dist/runtime/components/Edit/ItemIcon/index.vue.d.ts +6 -0
  363. package/dist/runtime/components/Edit/Loading/index.vue +8 -9
  364. package/dist/runtime/components/Edit/Loading/index.vue.d.ts +6 -0
  365. package/dist/runtime/components/Edit/Messages/Item/index.vue +30 -41
  366. package/dist/runtime/components/Edit/Messages/Item/index.vue.d.ts +11 -0
  367. package/dist/runtime/components/Edit/Messages/index.vue +13 -17
  368. package/dist/runtime/components/Edit/Messages/index.vue.d.ts +2 -0
  369. package/dist/runtime/components/Edit/Pagination/index.vue +6 -8
  370. package/dist/runtime/components/Edit/Pagination/index.vue.d.ts +12 -0
  371. package/dist/runtime/components/Edit/PreviewProvider.vue +124 -177
  372. package/dist/runtime/components/Edit/PreviewProvider.vue.d.ts +24 -0
  373. package/dist/runtime/components/Edit/RelativeTime/index.vue +19 -25
  374. package/dist/runtime/components/Edit/RelativeTime/index.vue.d.ts +15 -0
  375. package/dist/runtime/components/Edit/Resizable/index.vue +45 -55
  376. package/dist/runtime/components/Edit/Resizable/index.vue.d.ts +13 -0
  377. package/dist/runtime/components/Edit/ScaleToFit/index.vue +44 -62
  378. package/dist/runtime/components/Edit/ScaleToFit/index.vue.d.ts +15 -0
  379. package/dist/runtime/components/Edit/ScrollBoundary/index.vue +11 -27
  380. package/dist/runtime/components/Edit/ScrollBoundary/index.vue.d.ts +23 -0
  381. package/dist/runtime/components/Edit/ShortcutIndicator/index.vue +47 -59
  382. package/dist/runtime/components/Edit/ShortcutIndicator/index.vue.d.ts +20 -0
  383. package/dist/runtime/components/Edit/Sortli/index.vue +45 -59
  384. package/dist/runtime/components/Edit/Sortli/index.vue.d.ts +14 -0
  385. package/dist/runtime/components/Edit/SystemRequirements/index.vue +29 -43
  386. package/dist/runtime/components/Edit/SystemRequirements/index.vue.d.ts +2 -0
  387. package/dist/runtime/components/Edit/Toolbar/index.vue +26 -41
  388. package/dist/runtime/components/Edit/Toolbar/index.vue.d.ts +6 -0
  389. package/dist/runtime/components/Edit/ViewportBlockingRect/index.vue +29 -51
  390. package/dist/runtime/components/Edit/ViewportBlockingRect/index.vue.d.ts +20 -0
  391. package/dist/runtime/components/Edit/index.d.ts +5 -1
  392. package/dist/runtime/components/Edit/index.js +9 -1
  393. package/dist/runtime/composables/defineBlokkli.d.ts +2 -2
  394. package/dist/runtime/composables/defineBlokkli.js +29 -11
  395. package/dist/runtime/composables/defineBlokkliFragment.d.ts +1 -1
  396. package/dist/runtime/composables/defineBlokkliFragment.js +16 -24
  397. package/dist/runtime/css/output.css +1 -1
  398. package/dist/runtime/helpers/definitionProvider.d.ts +18 -0
  399. package/dist/runtime/helpers/definitionProvider.js +96 -0
  400. package/dist/runtime/helpers/domProvider.d.ts +2 -1
  401. package/dist/runtime/helpers/domProvider.js +6 -3
  402. package/dist/runtime/helpers/editComponents/index.d.ts +2 -0
  403. package/dist/runtime/helpers/editComponents/index.js +10 -0
  404. package/dist/runtime/helpers/featuresProvider.d.ts +2 -1
  405. package/dist/runtime/helpers/featuresProvider.js +19 -10
  406. package/dist/runtime/helpers/frameEventBus.d.ts +1 -1
  407. package/dist/runtime/helpers/imports/index.d.ts +1 -0
  408. package/dist/runtime/helpers/imports/index.js +44 -0
  409. package/dist/runtime/helpers/index.js +5 -8
  410. package/dist/runtime/helpers/runtimeHelpers/index.d.ts +5 -0
  411. package/dist/runtime/helpers/runtimeHelpers/index.js +17 -4
  412. package/dist/runtime/helpers/stateProvider.d.ts +1 -1
  413. package/dist/runtime/helpers/textProvider.d.ts +1 -1
  414. package/dist/runtime/helpers/themeProvider.js +4 -1
  415. package/dist/runtime/helpers/transform.d.ts +1 -1
  416. package/dist/runtime/helpers/typesProvider.d.ts +2 -2
  417. package/dist/runtime/helpers/uiProvider.js +4 -5
  418. package/dist/runtime/helpers/webgl/index.js +1 -1
  419. package/dist/runtime/icons/arrow-right-thin.svg +3 -0
  420. package/dist/runtime/public/_blokkli-assets/check.svg +6 -0
  421. package/dist/runtime/public/_blokkli-assets/loader.svg +1 -0
  422. package/dist/runtime/types/blokkOptions.d.ts +11 -2
  423. package/dist/runtime/types/index.d.ts +34 -14
  424. package/dist/shared/editor.gz_ac6uT.d.mts +431 -0
  425. package/dist/types.d.mts +1 -1
  426. package/package.json +30 -25
  427. package/dist/module.cjs +0 -5
  428. package/dist/module.d.ts +0 -198
  429. package/dist/runtime/adapter/drupal/graphql/base.graphql +0 -944
  430. package/dist/runtime/adapter/drupal/graphqlMiddleware.d.ts +0 -2
  431. package/dist/runtime/adapter/drupal/graphqlMiddleware.js +0 -680
  432. package/dist/runtime/types/generatedModuleTypes.d.ts +0 -49
  433. package/dist/types.d.ts +0 -1
  434. /package/dist/{runtime/adapter/drupal/graphql → modules/drupal/graphql/features}/comments.graphql +0 -0
  435. /package/dist/{runtime/adapter/drupal/graphql → modules/drupal/graphql/features}/fragments.graphql +0 -0
  436. /package/dist/{runtime/adapter/drupal/graphql → modules/drupal/graphql/features}/search.graphql +0 -0
  437. /package/dist/{runtime/adapter/drupal/graphql → modules/drupal/graphql/features}/transform.graphql +0 -0
  438. /package/dist/runtime/{types/generatedModuleTypes.js → components/Edit/Features/Publish/Dialog/types.js} +0 -0
  439. /package/dist/runtime/public/{Inter.var.woff2 → _blokkli-assets/Inter.var.woff2} +0 -0
package/dist/module.mjs CHANGED
@@ -1,14 +1,19 @@
1
- import path, { basename, extname } from 'node:path';
2
- import fs, { promises, existsSync } from 'node:fs';
3
- import { defineNuxtModule, createResolver, resolveFiles, addTemplate, addComponent, addBuildPlugin, addImports, addPlugin, updateTemplates } from '@nuxt/kit';
4
- import { defu, createDefu } from 'defu';
5
- import { relative } from 'pathe';
1
+ import { resolveAlias, resolveFiles, createResolver, addComponent, addImports, addTemplate, addTypeTemplate, defineNuxtModule, addPlugin, addBuildPlugin } from '@nuxt/kit';
6
2
  import { createUnplugin } from 'unplugin';
7
3
  import MagicString from 'magic-string';
8
4
  import { walk } from 'estree-walker-ts';
5
+ import { pathToFileURL } from 'node:url';
6
+ import { parseURL, parseQuery } from 'ufo';
7
+ import * as ts from 'typescript';
8
+ import path, { basename } from 'node:path';
9
+ import { dirname, relative } from 'pathe';
10
+ import micromatch from 'micromatch';
11
+ import { hash } from 'ohash';
9
12
  import { BK_VISIBLE_LANGUAGES, BK_HIDDEN_GLOBALLY } from '../dist/runtime/helpers/symbols.js';
13
+ import fs from 'node:fs';
14
+ import { defu, createDefu } from 'defu';
10
15
 
11
- const version = "1.4.0-alpha.1";
16
+ const version = "2.0.0-alpha.2";
12
17
 
13
18
  function sortObjectKeys(obj) {
14
19
  if (Array.isArray(obj)) {
@@ -23,846 +28,918 @@ function sortObjectKeys(obj) {
23
28
  }
24
29
  return obj;
25
30
  }
26
-
27
- function falsy(value) {
28
- return value !== null && value !== void 0;
31
+ function toValidVariableName(input) {
32
+ let result = input.replace(/\W/g, "_");
33
+ if (/^\d/.test(result)) {
34
+ result = "_" + result;
35
+ }
36
+ if (result === "") {
37
+ result = "_empty";
38
+ }
39
+ return result;
29
40
  }
30
- const fileRegex = /\.vue$/;
31
- function estreeToObject(expression) {
32
- return Object.fromEntries(
33
- expression.properties.map((prop) => {
34
- if (prop.type === "Property" && "name" in prop.key) {
35
- if (prop.value.type === "Literal") {
36
- return [prop.key.name, prop.value.value];
37
- } else if (prop.value.type === "ObjectExpression") {
38
- return [prop.key.name, estreeToObject(prop.value)];
39
- } else if (prop.value.type === "ArrayExpression") {
40
- return [
41
- prop.key.name,
42
- prop.value.elements.map((v) => {
43
- if (v && "value" in v) {
44
- return v.value;
45
- }
46
- }).filter(falsy)
47
- ];
48
- }
49
- }
50
- return null;
51
- }).filter(falsy)
52
- );
41
+ function parseTsObject(tsObjectStr) {
42
+ const source = `(${tsObjectStr})`;
43
+ const result = ts.transpileModule(source, {
44
+ compilerOptions: {
45
+ target: ts.ScriptTarget.ESNext,
46
+ module: ts.ModuleKind.None,
47
+ removeComments: true
48
+ }
49
+ });
50
+ const jsCode = result.outputText.trim();
51
+ const createObj = new Function(`return ${jsCode}`);
52
+ const object = createObj();
53
+ return { object, source: jsCode };
53
54
  }
54
- function buildRuntimeDefinition(definition) {
55
- return {
56
- bundle: definition.bundle
57
- };
55
+ function extractObjectLiteral(fileContents, composables) {
56
+ const composablesMatch = composables.join("|");
57
+ const pattern = `(${composablesMatch})\\(\\s*(\\{[\\s\\S]+?\\})\\s*\\)`;
58
+ const rgx = new RegExp(pattern);
59
+ const matches = rgx.exec(fileContents);
60
+ if (!matches) {
61
+ return;
62
+ }
63
+ return matches?.at(2);
64
+ }
65
+ function falsy(value) {
66
+ return value !== null && value !== void 0;
58
67
  }
59
- const DefinitionPlugin = (nuxt, composableName = "defineBlokkli") => createUnplugin(() => {
60
- return {
61
- name: "transform-file",
62
- enforce: "post",
63
- transform(source, id) {
64
- if (!fileRegex.test(id)) {
65
- return;
66
- }
67
- if (!source.includes(composableName)) {
68
- return;
69
- }
70
- const s = new MagicString(source);
71
- const parsed = this.parse(source, {
72
- sourceType: "module",
73
- ecmaVersion: "latest"
74
- });
75
- walk(parsed, {
76
- enter: (node) => {
77
- if (node.type !== "CallExpression" || node.callee.type !== "Identifier") {
78
- return;
79
- }
80
- const callNode = node;
81
- const name = "name" in callNode.callee && callNode.callee.name;
82
- if (name === composableName) {
83
- const arg = callNode.arguments[0];
84
- const meta = callNode.arguments[0];
85
- if (arg.type === "ObjectExpression") {
86
- const definition = estreeToObject(arg);
87
- const runtimeDefinition = buildRuntimeDefinition(definition);
88
- const start = meta.start;
89
- const end = meta.end;
90
- s.overwrite(start, end, JSON.stringify(runtimeDefinition));
91
- }
92
- }
93
- },
94
- leave: () => {
95
- }
96
- });
97
- if (s.hasChanged()) {
98
- return {
99
- code: s.toString(),
100
- map: nuxt.options.sourcemap.client || nuxt.options.sourcemap.server ? s.generateMap({ hires: true }) : null
101
- };
102
- }
103
- return source;
104
- }
105
- };
106
- });
107
68
 
108
- class BlockExtractor {
109
- definitions = {};
110
- fragmentDefinitions = {};
111
- isBuild = false;
112
- composableName;
113
- fragmentComposableName;
114
- buildDir;
115
- imports;
116
- constructor(isBuild = false, buildDir, imports) {
117
- this.isBuild = isBuild;
118
- this.buildDir = buildDir;
119
- this.imports = imports;
120
- this.composableName = "defineBlokkli";
121
- this.fragmentComposableName = "defineBlokkliFragment";
69
+ class CollectedFile {
70
+ constructor(filePath, fileContents) {
71
+ this.filePath = filePath;
72
+ this.fileContents = fileContents;
122
73
  }
123
- /**
124
- * Add files by path.
125
- */
126
- addFiles(files) {
127
- return Promise.all(files.map((v) => this.handleFile(v)));
74
+ async handleChange(_helper) {
75
+ return Promise.resolve(true);
128
76
  }
129
- async getIcon(componentPath) {
130
- const folder = path.dirname(componentPath);
131
- const iconPath = path.join(folder, "/icon.svg");
132
- try {
133
- await fs.promises.access(iconPath, fs.constants.F_OK);
134
- const data = await fs.promises.readFile(iconPath);
135
- return data.toString();
136
- } catch {
77
+ }
78
+ class Collector {
79
+ constructor(helper) {
80
+ this.helper = helper;
81
+ this.files = /* @__PURE__ */ new Map();
82
+ }
83
+ files;
84
+ needsFileContents = true;
85
+ async addFile(filePath) {
86
+ if (this.needsFileContents) {
87
+ const contents = await this.helper.fileCache.read(filePath);
88
+ const file = this.createCollectedFile(filePath, contents.toString());
89
+ await file.handleChange(this.helper);
90
+ this.files.set(filePath, file);
91
+ } else {
92
+ const file = this.createCollectedFile(filePath);
93
+ await file.handleChange(this.helper);
94
+ this.files.set(filePath, file);
137
95
  }
138
96
  }
139
- async getContextComponent(baseComponentPath, name) {
140
- const folder = path.dirname(baseComponentPath);
141
- const componentPath = path.join(folder, `/${name}.vue`);
142
- try {
143
- await fs.promises.access(componentPath, fs.constants.F_OK);
144
- return componentPath;
145
- } catch {
97
+ async handleAdd(filePath) {
98
+ const applies = await this.applies(filePath);
99
+ if (applies) {
100
+ await this.addFile(filePath);
101
+ return true;
146
102
  }
103
+ return false;
147
104
  }
148
- /**
149
- * Read the file and extract the blokkli component definitions.
150
- *
151
- * Returns a promise containing a boolean that indicated if the given file
152
- * should trigger a rebuild of the query.
153
- */
154
- async handleFile(filePath2) {
155
- const fileSource = await this.readFile(filePath2);
156
- const extracted = this.extractSingle(fileSource, filePath2);
157
- if (!extracted) {
158
- if (this.definitions[filePath2]) {
159
- this.definitions[filePath2] = void 0;
160
- return true;
161
- }
162
- if (this.fragmentDefinitions[filePath2]) {
163
- this.fragmentDefinitions[filePath2] = void 0;
164
- return true;
165
- }
105
+ async handleChange(filePath) {
106
+ const applies = await this.applies(filePath);
107
+ if (!applies) {
108
+ return this.handleUnlink(filePath);
109
+ }
110
+ const file = this.files.get(filePath);
111
+ if (!file) {
166
112
  return false;
167
113
  }
168
- if ("bundle" in extracted.definition) {
169
- const icon = await this.getIcon(filePath2);
170
- const proxyComponent = await this.getContextComponent(filePath2, "proxy");
171
- const diffComponent = await this.getContextComponent(filePath2, "diff");
172
- if (this.definitions[filePath2] && this.definitions[filePath2]?.source === extracted.source) {
173
- return false;
174
- }
175
- const extension = path.extname(filePath2);
176
- const componentFileName = path.basename(filePath2, extension);
177
- this.definitions[filePath2] = {
178
- filePath: filePath2,
179
- definition: extracted.definition,
180
- icon,
181
- proxyComponent,
182
- diffComponent,
183
- chunkName: this.isBuild ? extracted.definition.chunkName || "global" : "global",
184
- componentName: "BlokkliComponent_" + extracted.definition.bundle + "_" + componentFileName,
185
- source: extracted.source,
186
- fileSource,
187
- hasBlokkliField: fileSource.includes("<BlokkliField") || fileSource.includes("<blokkli-field") || fileSource.includes(':is="BlokkliField"')
188
- };
189
- } else if ("name" in extracted.definition) {
190
- if (this.fragmentDefinitions[filePath2] && this.fragmentDefinitions[filePath2]?.source === extracted.source) {
191
- return false;
192
- }
193
- this.fragmentDefinitions[filePath2] = {
194
- filePath: filePath2,
195
- definition: extracted.definition,
196
- chunkName: this.isBuild ? extracted.definition.chunkName || "global" : "global",
197
- componentName: "BlokkliFragmentComponent_" + extracted.definition.name,
198
- source: extracted.source,
199
- fileSource
200
- };
114
+ if (this.needsFileContents) {
115
+ const contents = await this.helper.fileCache.read(filePath);
116
+ file.fileContents = contents.toString();
117
+ return await file.handleChange(this.helper);
201
118
  }
202
119
  return true;
203
120
  }
204
- /**
205
- * Extract the single text method calls.
206
- */
207
- extractSingle(code, filePath) {
208
- const pattern = `(${this.composableName}|${this.fragmentComposableName})\\((\\{.+?\\})\\)`;
209
- const rgx = new RegExp(pattern, "gms");
210
- const source = rgx.exec(code)?.[2];
211
- if (source) {
212
- try {
213
- const definition = eval(`(${source})`);
214
- return { definition, source };
215
- } catch (e) {
216
- console.error(
217
- `Failed to parse component "${filePath}": ${this.composableName} does not contain a valid object literal. No variables and methods are allowed inside ${this.composableName}().`,
218
- e
219
- );
220
- }
121
+ handleUnlink(filePath) {
122
+ if (this.files.has(filePath)) {
123
+ this.files.delete(filePath);
124
+ return true;
221
125
  }
126
+ return false;
222
127
  }
223
- /**
224
- * Read the given file and return its contents.
225
- */
226
- readFile(filePath2) {
227
- return fs.promises.readFile(filePath2).then((v) => {
228
- return v.toString();
229
- });
128
+ handleAddDir() {
129
+ return false;
130
+ }
131
+ handleUnlinkDir(folderPath) {
132
+ const allKeys = [...this.files.keys()];
133
+ const toRemove = allKeys.filter((filePath) => filePath.includes(folderPath));
134
+ if (toRemove.length) {
135
+ toRemove.forEach((key) => this.files.delete(key));
136
+ return true;
137
+ }
138
+ return false;
139
+ }
140
+ async handleWatchEvent(event, filePath) {
141
+ let hasChanged = false;
142
+ if (event === "add") {
143
+ hasChanged = await this.handleAdd(filePath);
144
+ } else if (event === "change") {
145
+ hasChanged = await this.handleChange(filePath);
146
+ } else if (event === "unlink") {
147
+ hasChanged = await this.handleUnlink(filePath);
148
+ } else if (event === "addDir") {
149
+ hasChanged = this.handleAddDir();
150
+ } else if (event === "unlinkDir") {
151
+ hasChanged = this.handleUnlinkDir(filePath);
152
+ }
153
+ return { hasChanged };
230
154
  }
231
- /**
232
- * Generate the template.
233
- */
234
- generateDefinitionTemplate(globalOptions = {}) {
235
- const definitionDeclarations = Object.values(this.definitions).filter(falsy).map((v) => {
236
- return `const ${v.componentName}: DefinitionItem = ${v.source}`;
237
- }, {});
238
- const allDefinitions = Object.values(this.definitions).filter(falsy).reduce((acc, v) => {
239
- const bundle = v.definition.bundle;
240
- const renderFor = v.definition.renderFor;
241
- if (renderFor) {
242
- const renderForList = Array.isArray(renderFor) ? renderFor : [renderFor];
243
- renderForList.forEach((entry) => {
244
- if ("parentBundle" in entry) {
245
- acc.push(
246
- `${bundle}__parent_block_${entry.parentBundle}: ${v.componentName}`
247
- );
248
- } else if ("fieldList" in entry) {
249
- acc.push(
250
- `${bundle}__field_list_type_${entry.fieldList}: ${v.componentName}`
251
- );
252
- } else if ("fieldListType" in entry) {
253
- acc.push(
254
- `${bundle}__field_list_type_${entry.fieldListType}: ${v.componentName}`
255
- );
256
- }
257
- });
258
- } else {
259
- acc.push(`${bundle}: ${v.componentName}`);
260
- }
261
- return acc;
262
- }, []);
263
- const allFragmentDefinitions = Object.values(this.fragmentDefinitions).filter(falsy).map((v) => {
264
- return `${v.definition.name}: ${v.source}`;
265
- });
266
- const icons = Object.values(this.definitions).filter(falsy).reduce((acc, v) => {
267
- if (v.icon) {
268
- acc[v.definition.bundle] = v.icon;
269
- }
270
- return acc;
271
- }, {});
272
- const allFragmentNames = Object.values(this.fragmentDefinitions).filter(falsy).map((v) => `'${v.definition.name}'`).join(" | ");
273
- return `
274
- import type { GlobalOptionsKey, ValidFieldListTypes, BlockBundleWithNested } from './generated-types'
275
- import type { BlockDefinitionInput, BlockDefinitionOptionsInput, FragmentDefinitionInput } from '${this.imports.TYPES}'
276
- export const globalOptions = ${JSON.stringify(globalOptions, null, 2)} as const
277
-
278
- type DefinitionItem = BlockDefinitionInput<BlockDefinitionOptionsInput, GlobalOptionsKey[]>
279
-
280
- ${definitionDeclarations.join("\n")}
281
-
282
- export const icons: Record<string, string> = ${JSON.stringify(icons)}
283
-
284
- export const definitionsMap: Record<string, DefinitionItem> = {
285
- ${allDefinitions.join(",\n")}
286
155
  }
287
156
 
288
- export const fragmentDefinitionsMap: Record<string, FragmentDefinitionInput<BlockDefinitionOptionsInput, GlobalOptionsKey[]>> = {
289
- ${allFragmentDefinitions.join(",\n")}
157
+ const DEFINE_BLOKKLI = "defineBlokkli";
158
+ const DEFINE_BLOKKLI_FRAGMENT = "defineBlokkliFragment";
159
+ function isEditComponent(filePath) {
160
+ return filePath.endsWith("/diff.vue") || filePath.endsWith("/proxy.vue");
290
161
  }
291
-
292
- export type BlokkliFragmentName = ${allFragmentNames || "never"}
293
-
294
- export const definitions: BlockDefinitionInput<any, GlobalOptionsKey[]>[] = Object.values(definitionsMap)
295
- export const fragmentDefinitions: FragmentDefinitionInput<any, GlobalOptionsKey[]>[] = Object.values(fragmentDefinitionsMap)
296
-
297
- /**
298
- * Get the block definition for the given field and parent context.
299
- */
300
- export function getDefinition(bundle: string, fieldListType: ValidFieldListTypes, parentBundle?: BlockBundleWithNested): BlockDefinitionInput<Record<string, any>, GlobalOptionsKey[]>|undefined {
301
- const forFieldListType = bundle + '__field_list_type_' + fieldListType
302
- if (definitionsMap[forFieldListType]) {
303
- return definitionsMap[forFieldListType]
162
+ function isBlock(definition) {
163
+ return "bundle" in definition;
164
+ }
165
+ function getVariations(definition) {
166
+ if (!definition) {
167
+ return [];
304
168
  }
305
- if (parentBundle) {
306
- const forParentBundle = bundle + '__parent_block_' + parentBundle
307
- if (definitionsMap[forParentBundle]) {
308
- return definitionsMap[forParentBundle]
169
+ if (isBlock(definition)) {
170
+ const bundle = definition.bundle;
171
+ if (!definition.renderFor) {
172
+ return ["block:" + bundle];
309
173
  }
174
+ const renderFor = Array.isArray(definition.renderFor) ? definition.renderFor : [definition.renderFor];
175
+ return renderFor.map((v) => {
176
+ if ("parentBundle" in v) {
177
+ return `block:${bundle}__p:${v.parentBundle}`;
178
+ } else if ("fieldList" in v) {
179
+ return `block:${bundle}__f:${v.fieldList}`;
180
+ } else {
181
+ return `block:${bundle}__f:${v.fieldListType}`;
182
+ }
183
+ }).sort();
310
184
  }
311
-
312
- return definitionsMap[bundle]
185
+ return [`fragment:${definition.name}`];
313
186
  }
314
-
315
- /**
316
- * Get the definition of the default block component.
317
- */
318
- export function getDefaultDefinition(bundle: string): BlockDefinitionInput<Record<string, any>, GlobalOptionsKey[]>|undefined {
319
- return definitionsMap[bundle]
187
+ function getIdentifier(definition) {
188
+ const type = isBlock(definition) ? "b" : "f";
189
+ const name = isBlock(definition) ? definition.bundle : definition.name;
190
+ return toValidVariableName(
191
+ type + "_" + hash(name + getVariations(definition).join("__"))
192
+ );
320
193
  }
321
- export const getFragmentDefinition = (name: string): FragmentDefinitionInput<Record<string, any>, GlobalOptionsKey[]>|undefined => fragmentDefinitionsMap[name]
322
- `;
194
+ class CollectedBlockFile extends CollectedFile {
195
+ folder = "";
196
+ iconPath = null;
197
+ iconContents = null;
198
+ diffComponentPath = null;
199
+ proxyComponentPath = null;
200
+ type = null;
201
+ definition = null;
202
+ definitionSource = null;
203
+ hasBlokkliField = false;
204
+ identifier = "";
205
+ chunkName = "global";
206
+ variations = [];
207
+ objectLiteralString = "";
208
+ hasSiblingFile(name, helper) {
209
+ const siblingFilePath = path.join(this.folder, "/" + name);
210
+ if (helper.fileCache.fileExists(siblingFilePath)) {
211
+ return siblingFilePath;
212
+ }
213
+ return null;
323
214
  }
324
- /**
325
- * Generate the template for the block item options used for runtime (e.g. not during editing).
326
- */
327
- generateRuntimeOptionsTemplate(globalOptions = {}) {
328
- const bundles = Object.values(this.definitions).filter(falsy).reduce((acc, definition2) => {
329
- if (definition2.definition.renderFor) {
330
- return acc;
215
+ async handleChange(helper) {
216
+ this.folder = dirname(this.filePath);
217
+ const diffComponentPath = this.hasSiblingFile("diff.vue", helper);
218
+ const proxyComponentPath = this.hasSiblingFile("proxy.vue", helper);
219
+ const objectLiteralString = extractObjectLiteral(this.fileContents, [
220
+ DEFINE_BLOKKLI,
221
+ DEFINE_BLOKKLI_FRAGMENT
222
+ ]);
223
+ if (objectLiteralString === this.objectLiteralString && diffComponentPath === this.diffComponentPath && proxyComponentPath === this.proxyComponentPath) {
224
+ return false;
225
+ }
226
+ this.objectLiteralString = objectLiteralString || "";
227
+ this.diffComponentPath = diffComponentPath;
228
+ this.proxyComponentPath = proxyComponentPath;
229
+ try {
230
+ if (this.objectLiteralString) {
231
+ const result = parseTsObject(
232
+ this.objectLiteralString
233
+ );
234
+ this.definition = result.object;
235
+ this.definitionSource = result.source;
331
236
  }
332
- const bundle = definition2.definition.bundle;
333
- const optionDefinitions = Object.entries(
334
- definition2.definition.options || {}
237
+ } catch (e) {
238
+ console.error(
239
+ `Failed to parse component "${this.filePath}": The composabe does not contain a valid object literal. No variables and methods are allowed inside the composable.`,
240
+ e
335
241
  );
336
- const options = {};
337
- if (definition2.definition.globalOptions) {
338
- definition2.definition.globalOptions.forEach((name) => {
339
- const option = globalOptions[name];
340
- options[name] = [option.type, option.default];
341
- });
242
+ return false;
243
+ }
244
+ this.hasBlokkliField = this.fileContents.includes("<BlokkliField") || this.fileContents.includes("<blokkli-field") || this.fileContents.includes(':is="BlokkliField"');
245
+ this.chunkName = this.definition?.chunkName || "global";
246
+ this.identifier = this.definition ? getIdentifier(this.definition) : "";
247
+ if (!this.definition) {
248
+ this.type = null;
249
+ } else if (isBlock(this.definition)) {
250
+ if (this.definition.renderFor) {
251
+ this.type = "context";
252
+ } else {
253
+ this.type = "main";
342
254
  }
343
- optionDefinitions.forEach(([name, option]) => {
344
- options[name] = [option.type, option.default];
345
- });
346
- if (Object.values(options).length) {
347
- acc[bundle] = options;
255
+ } else {
256
+ this.type = "fragment";
257
+ }
258
+ if (this.type === "main") {
259
+ this.iconPath = this.hasSiblingFile("icon.svg", helper);
260
+ if (this.iconPath) {
261
+ this.iconContents = await helper.fileCache.read(this.iconPath);
348
262
  }
349
- return acc;
350
- }, {});
351
- function getOptionTypes(definition2) {
352
- const definedOptions = definition2.options || {};
353
- const blockGlobalOptions = definition2.globalOptions || [];
354
- blockGlobalOptions.forEach((key) => {
355
- if (globalOptions[key]) {
356
- definedOptions[key] = globalOptions[key];
357
- }
358
- });
359
- return Object.entries(definedOptions || {}).map(([key, option]) => {
360
- if (option.type === "text") {
361
- return `${key}: string`;
362
- } else if (option.type === "checkbox") {
363
- return `${key}: boolean`;
364
- } else if (option.type === "checkboxes") {
365
- const possibleValues = Object.keys(option.options).map((v) => `'${v}'`).join(" | ") || "string";
366
- return `${key}: Array<${possibleValues}>`;
367
- } else if (option.type === "radios") {
368
- const possibleValues = Object.keys(option.options).map((v) => `'${v}'`).join(" | ") || "string";
369
- return `${key}: ${possibleValues}`;
370
- } else if (option.type === "color") {
371
- return key + ": `#${string}`";
372
- } else if (option.type === "range" || option.type === "number") {
373
- return `${key}: number`;
263
+ } else {
264
+ this.iconPath = null;
265
+ this.iconContents = null;
266
+ }
267
+ this.variations = getVariations(this.definition);
268
+ return true;
269
+ }
270
+ }
271
+ class BlockCollector extends Collector {
272
+ patterns;
273
+ constructor(helper) {
274
+ super(helper);
275
+ this.patterns = (helper.options.pattern || []).map((pattern) => {
276
+ if (pattern.startsWith("/")) {
277
+ return pattern;
278
+ } else if (pattern.startsWith(".")) {
279
+ return helper.resolvers.src.resolve(pattern);
280
+ }
281
+ return resolveAlias(pattern);
282
+ });
283
+ }
284
+ async init() {
285
+ const files = await resolveFiles(
286
+ this.helper.nuxt.options.srcDir,
287
+ this.patterns
288
+ );
289
+ const promises = [];
290
+ for (const filePath of files) {
291
+ const applies = await this.applies(filePath);
292
+ if (applies) {
293
+ promises.push(this.addFile(filePath));
294
+ }
295
+ }
296
+ await Promise.all(promises);
297
+ }
298
+ runHooks() {
299
+ return this.helper.nuxt.hooks.callHook("blokkli:alter-blocks", {
300
+ blocks: [...this.files.values()]
301
+ });
302
+ }
303
+ createCollectedFile(filePath, fileContents = "") {
304
+ return new CollectedBlockFile(filePath, fileContents);
305
+ }
306
+ findBlockForFolderFile(iconPath) {
307
+ for (const file of this.files.values()) {
308
+ if (file.iconPath === iconPath || file.proxyComponentPath === iconPath || file.diffComponentPath === iconPath) {
309
+ return file.filePath;
310
+ }
311
+ }
312
+ return null;
313
+ }
314
+ async handleAdd(filePath) {
315
+ if (isEditComponent(filePath)) {
316
+ const folder = dirname(filePath);
317
+ for (const file of this.files.values()) {
318
+ if (file.folder === folder) {
319
+ return super.handleChange(file.filePath);
374
320
  }
375
- });
321
+ }
376
322
  }
377
- const runtimeMappedOptionTypes = Object.values(this.definitions).filter(falsy).map((definition2) => {
378
- if (definition2.definition.renderFor) {
379
- return null;
323
+ return super.handleAdd(filePath);
324
+ }
325
+ async handleUnlink(filePath) {
326
+ if (isEditComponent(filePath)) {
327
+ const folder = dirname(filePath);
328
+ for (const file of this.files.values()) {
329
+ if (file.folder === folder) {
330
+ return super.handleChange(file.filePath);
331
+ }
380
332
  }
381
- const bundle = definition2.definition.bundle;
382
- const options = getOptionTypes(definition2.definition).join("\n ");
383
- if (!options) {
384
- return ` ${bundle}: {}`;
333
+ }
334
+ return super.handleUnlink(filePath);
335
+ }
336
+ async handleChange(filePath) {
337
+ if (filePath.includes("icon.svg")) {
338
+ const matchingBlockFilePath = this.findBlockForFolderFile(filePath);
339
+ if (matchingBlockFilePath) {
340
+ return this.handleChange(matchingBlockFilePath);
385
341
  }
386
- return ` ${bundle}: {
387
- ${options}
388
- }`;
389
- }).filter(falsy).join(",\n");
390
- return `
391
- import type { BlockOptionDefinition } from '${this.imports.TYPES_BLOKK_OPTIONS}'
392
-
393
- export type RuntimeBlockOptionArray = {
394
- [T in BlockOptionDefinition as T['type']]: [T['type'], T['default']]
395
- }[BlockOptionDefinition['type']]
396
-
397
- export type RuntimeBlockOptions = {
398
- ${runtimeMappedOptionTypes}
342
+ return false;
343
+ }
344
+ return super.handleChange(filePath);
345
+ }
346
+ async applies(filePath) {
347
+ if (!filePath.endsWith(".vue")) {
348
+ return false;
349
+ }
350
+ if (!micromatch.isMatch(filePath, this.patterns)) {
351
+ return false;
352
+ }
353
+ if (isEditComponent(filePath)) {
354
+ return true;
355
+ }
356
+ const content = await this.helper.fileCache.read(filePath);
357
+ return content.includes(DEFINE_BLOKKLI) || content.includes(DEFINE_BLOKKLI_FRAGMENT);
358
+ }
359
+ getDependencyTypes() {
360
+ return ["block-content", "block-path"];
361
+ }
399
362
  }
400
363
 
401
- export const BLOCK_OPTIONS: Record<string, Record<string, RuntimeBlockOptionArray>> = ${JSON.stringify(bundles, null, 2)}
402
- `;
364
+ function isVue(id, opts = {}) {
365
+ const { search } = parseURL(decodeURIComponent(pathToFileURL(id).href));
366
+ if (id.endsWith(".vue") && !search) {
367
+ return true;
403
368
  }
404
- generateEditComponents() {
405
- const buildContextComponents = (name) => {
406
- const proxyComponents = Object.values(this.definitions).reduce((acc, v) => {
407
- if (v?.[name]) {
408
- acc[v.definition.bundle] = v[name];
409
- }
410
- return acc;
411
- }, {});
412
- const imports = Object.entries(proxyComponents).map(([bundle, proxyComponentPath]) => {
413
- return `import ${name}_${bundle} from '${this.toBuildRelativePath(proxyComponentPath)}'`;
414
- }).join("\n");
415
- const maps = Object.keys(proxyComponents).map((bundle) => {
416
- return `'${bundle}': ${name}_${bundle}`;
417
- }).join(", \n");
418
- return {
419
- imports,
420
- maps
421
- };
422
- };
423
- const proxy = buildContextComponents("proxyComponent");
424
- const diff = buildContextComponents("diffComponent");
425
- return `
426
- ${proxy.imports}
427
- ${diff.imports}
428
-
429
- const PROXY_COMPONENTS: Record<string, any> = {
430
- ${proxy.maps}
369
+ if (!search) {
370
+ return false;
371
+ }
372
+ const query = parseQuery(search);
373
+ if (query.nuxt_component) {
374
+ return false;
375
+ }
376
+ if (query.macro && (search === "?macro=true" || !opts.type || opts.type.includes("script"))) {
377
+ return true;
378
+ }
379
+ const type = "setup" in query ? "script" : query.type;
380
+ if (!("vue" in query) || opts.type && !opts.type.includes(type)) {
381
+ return false;
382
+ }
383
+ return true;
431
384
  }
432
-
433
- const DIFF_COMPONENTS: Record<string, any> = {
434
- ${diff.maps}
385
+ function generateRuntimeArg(definition) {
386
+ const name = isBlock(definition) ? definition.bundle : definition.name;
387
+ return `${name}::${getIdentifier(definition)}`;
435
388
  }
389
+ const RuntimeDefinitionPlugin = (nuxt, composableName) => {
390
+ const cache = /* @__PURE__ */ new Map();
391
+ function extract(source) {
392
+ const fromCache = cache.get(source);
393
+ if (fromCache) {
394
+ return fromCache;
395
+ }
396
+ const definition = parseTsObject(source);
397
+ if (definition.object) {
398
+ cache.set(source, definition.object);
399
+ return definition.object;
400
+ }
401
+ return null;
402
+ }
403
+ return createUnplugin(() => {
404
+ return {
405
+ name: "blokkli:runtime-definition",
406
+ enforce: "post",
407
+ transformInclude(id) {
408
+ return isVue(id);
409
+ },
410
+ transform(source) {
411
+ if (!source.includes(composableName)) {
412
+ return;
413
+ }
414
+ const s = new MagicString(source);
415
+ const parsed = this.parse(source, {
416
+ sourceType: "module",
417
+ ecmaVersion: "latest"
418
+ });
419
+ walk(parsed, {
420
+ enter: (node) => {
421
+ if (node.type !== "CallExpression" || node.callee.type !== "Identifier") {
422
+ return;
423
+ }
424
+ const callNode = node;
425
+ const name = "name" in callNode.callee && callNode.callee.name;
426
+ if (name === composableName) {
427
+ const arg = callNode.arguments[0];
428
+ if (!arg) {
429
+ return;
430
+ }
431
+ const meta = callNode.arguments[0];
432
+ if (arg.type === "ObjectExpression") {
433
+ const start = meta.start;
434
+ const end = meta.end;
435
+ const objectSource = s.slice(start, end);
436
+ const object = extract(objectSource);
437
+ if (object) {
438
+ const arg2 = generateRuntimeArg(object);
439
+ s.overwrite(start, end, `"${arg2}"`);
440
+ }
441
+ }
442
+ }
443
+ },
444
+ leave: () => {
445
+ }
446
+ });
447
+ if (s.hasChanged()) {
448
+ return {
449
+ code: s.toString(),
450
+ map: nuxt.options.sourcemap.client || nuxt.options.sourcemap.server ? s.generateMap({ hires: true }) : null
451
+ };
452
+ }
453
+ }
454
+ };
455
+ });
456
+ };
436
457
 
437
- export function getBlokkliItemProxyComponent(bundle: string): any {
438
- return PROXY_COMPONENTS[bundle]
458
+ class IconCollector extends Collector {
459
+ needsFileContents = false;
460
+ srcFromModule;
461
+ constructor(helper) {
462
+ super(helper);
463
+ this.srcFromModule = helper.resolvers.module.resolve("./runtime/icons");
464
+ }
465
+ async init() {
466
+ const srcFromModule = this.helper.resolvers.module.resolve("./runtime/icons");
467
+ const filesModule = await resolveFiles(srcFromModule, "*.svg");
468
+ const filesApp = await resolveFiles(
469
+ this.helper.paths.srcDir,
470
+ "**/icon-blokkli-*.svg"
471
+ );
472
+ const allFiles = [...filesModule, ...filesApp];
473
+ await Promise.all(allFiles.map((filePath) => this.addFile(filePath)));
474
+ }
475
+ runHooks() {
476
+ return this.helper.nuxt.hooks.callHook("blokkli:alter-icons", {
477
+ icons: [...this.files.values()]
478
+ });
479
+ }
480
+ applies(filePath) {
481
+ return Promise.resolve(
482
+ filePath.startsWith(this.srcFromModule) || micromatch.isMatch(filePath, "icon-blokkli-*.svg")
483
+ );
484
+ }
485
+ getDependencyTypes() {
486
+ return ["icons"];
487
+ }
488
+ createCollectedFile(filePath, fileContents = "") {
489
+ return new CollectedFile(filePath, fileContents);
490
+ }
439
491
  }
440
492
 
441
- export function getBlokkliItemDiffComponent(bundle: string): any {
442
- return DIFF_COMPONENTS[bundle]
443
- }
444
- `;
493
+ class FileCache {
494
+ cache = /* @__PURE__ */ new Map();
495
+ existingFiles = /* @__PURE__ */ new Set();
496
+ /**
497
+ * Read a file from disk.
498
+ */
499
+ async read(filePath) {
500
+ const existing = this.cache.get(filePath);
501
+ if (existing) {
502
+ return existing;
503
+ }
504
+ const buffer = await fs.promises.readFile(filePath);
505
+ const content = buffer.toString();
506
+ this.cache.set(filePath, content);
507
+ return content;
445
508
  }
446
509
  /**
447
- * Generate the options schema.
510
+ * Delete a file.
448
511
  */
449
- generateOptionsSchema(globalOptions = {}) {
450
- const schema = Object.values(this.definitions).filter(falsy).reduce((acc, v) => {
451
- const existing = acc[v.definition.bundle] || {};
452
- acc[v.definition.bundle] = defu(existing, v.definition.options || {});
453
- const globalOptionKeys = v.definition.globalOptions || [];
454
- globalOptionKeys.forEach((name) => {
455
- if (globalOptions[name]) {
456
- acc[v.definition.bundle][name] = globalOptions[name];
457
- }
458
- });
459
- return acc;
460
- }, {});
461
- const sorted = sortObjectKeys(schema);
462
- return JSON.stringify(sorted, null, 2);
512
+ delete(filePath) {
513
+ this.cache.delete(filePath);
463
514
  }
464
- getBundlesWithGlobalOptions(key) {
465
- return Object.values(this.definitions).map((definition2) => {
466
- const globalOptions = definition2?.definition.globalOptions;
467
- if (definition2 && globalOptions && globalOptions.includes(key)) {
468
- return definition2.definition.bundle;
469
- }
470
- }).filter(falsy);
515
+ /**
516
+ * Check if a file exists.
517
+ */
518
+ fileExists(filePath) {
519
+ if (this.existingFiles.has(filePath)) {
520
+ return true;
521
+ }
522
+ const exists = fs.existsSync(filePath);
523
+ if (exists) {
524
+ this.existingFiles.add(filePath);
525
+ }
526
+ return exists;
471
527
  }
472
528
  /**
473
- * Generate the default global options values template.
529
+ * Handles the builder watch event.
474
530
  */
475
- generateDefaultGlobalOptions(globalOptions = {}) {
476
- const defaults = Object.entries(globalOptions).reduce(
477
- (acc, [key, option]) => {
478
- if (option.default !== void 0 && option.default !== null) {
479
- acc[key] = {
480
- default: option.default,
481
- type: option.type
482
- };
483
- }
484
- return acc;
485
- },
486
- {}
487
- );
488
- return `import type { BlockOptionDefinition } from '${this.imports.TYPES_BLOKK_OPTIONS}'
489
-
490
- type GlobalOptionsDefaults = {
491
- type: BlockOptionDefinition['type']
492
- default: any
493
- }
494
-
495
- export const bundlesWithVisibleLanguage: string[] = ${JSON.stringify(this.getBundlesWithGlobalOptions(BK_VISIBLE_LANGUAGES))}
496
- export const bundlesWithHiddenGlobally: string[] = ${JSON.stringify(this.getBundlesWithGlobalOptions(BK_HIDDEN_GLOBALLY))}
497
-
498
- export const globalOptionsDefaults: Record<string, GlobalOptionsDefaults> = ${JSON.stringify(
499
- defaults,
500
- null,
501
- 2
502
- )} as const`;
503
- }
504
- generateTypesTemplate(globalOptions, chunkNames, fieldListTypes, getBundlePropsType) {
505
- const allDefintions = Object.values(
506
- this.definitions
507
- ).map((v) => v?.definition).filter(falsy);
508
- const validChunkNames = chunkNames.map((v) => {
509
- return `'${v}'`;
510
- }).join(" | ");
511
- const validFieldListTypes = fieldListTypes.map((v) => {
512
- return `'${v}'`;
513
- }).join(" | ");
514
- const validGlobalOptions = Object.keys(globalOptions).map((v) => {
515
- return `'${v}'`;
516
- }).join(" | ");
517
- const blockBundlesWithNested = Object.values(this.definitions).filter(falsy).filter((v) => v.hasBlokkliField).map((v) => {
518
- return `'${v.definition.bundle}'`;
519
- }).join(" | ");
520
- const validBlockBundles = allDefintions.filter((v) => v.bundle !== "from_library").map((v) => {
521
- return `'${v.bundle}'`;
522
- }).join(" | ");
523
- function getOptionTypes(definition2) {
524
- const definedOptions = definition2.options || {};
525
- const blockGlobalOptions = definition2.globalOptions || [];
526
- blockGlobalOptions.forEach((key) => {
527
- if (globalOptions[key]) {
528
- definedOptions[key] = globalOptions[key];
529
- }
530
- });
531
- const options = Object.entries(definedOptions || {}).map(([key, option]) => {
532
- if (option.type === "text") {
533
- return `${key}: string | undefined`;
534
- } else if (option.type === "checkbox") {
535
- return `${key}: '1' | '0' | undefined`;
536
- } else if (option.type === "radios" || option.type === "checkboxes") {
537
- return `${key}: string | undefined`;
538
- } else if (option.type === "color") {
539
- return `${key}: string | undefined`;
540
- } else if (option.type === "range" || option.type === "number") {
541
- return `${key}: number | string | undefined`;
542
- }
543
- }).join("\n ");
544
- return `{
545
- ${options}
546
- }`;
547
- }
548
- const propTypeImports = {};
549
- const typedFieldListItems = [];
550
- const definitions = Object.entries(this.definitions);
551
- const mappedGetBundlePropsType = (bundle, definition2) => {
552
- if (bundle === "from_library" || bundle === "blokkli_fragment") {
553
- return {
554
- typeName: "Props",
555
- from: definition2.filePath
556
- };
557
- } else if (getBundlePropsType) {
558
- return getBundlePropsType(bundle, definition2);
559
- }
560
- return null;
561
- };
562
- for (let i = 0; i < definitions.length; i++) {
563
- const [_, definition2] = definitions[i];
564
- if (!definition2) {
565
- continue;
566
- }
567
- if (definition2.definition.renderFor) {
568
- continue;
569
- }
570
- const bundle = definition2.definition.bundle;
571
- const options = getOptionTypes(definition2.definition);
572
- const generatedTypeName = `FieldListItem_${bundle}`;
573
- const lines = [` bundle: '${bundle}'`, `options: ${options}`];
574
- const bundlePropsType = mappedGetBundlePropsType(bundle, definition2);
575
- if (bundlePropsType) {
576
- const { typeName, from } = bundlePropsType;
577
- if (!propTypeImports[from]) {
578
- propTypeImports[from] = [];
531
+ async handleWatchEvent(event, filePath) {
532
+ if (event === "add") {
533
+ this.existingFiles.add(filePath);
534
+ this.cache.delete(filePath);
535
+ } else if (event === "change") {
536
+ this.existingFiles.add(filePath);
537
+ this.cache.delete(filePath);
538
+ } else if (event === "unlink") {
539
+ this.existingFiles.delete(filePath);
540
+ this.cache.delete(filePath);
541
+ } else if (event === "unlinkDir") {
542
+ const filePaths = [...this.existingFiles.keys()];
543
+ filePaths.forEach((v) => {
544
+ if (v.startsWith(filePath)) {
545
+ this.existingFiles.delete(v);
546
+ this.cache.delete(v);
579
547
  }
580
- propTypeImports[from].push({ bundle, typeName });
581
- lines.push(`props: Bundle_${bundle}_Props`);
582
- }
583
- const typeDefinition = `
584
- type ${generatedTypeName} = {
585
- ${lines.join("\n ")}
586
- }`;
587
- typedFieldListItems.push({
588
- typeName: generatedTypeName,
589
- typeDefinition
590
548
  });
591
549
  }
592
- const propTypeImportStatements = Object.entries(propTypeImports).map(([from, items]) => {
593
- const imports = items.map((v) => {
594
- return `${v.typeName} as Bundle_${v.bundle}_Props`;
595
- }).join(",\n ");
596
- const importPath = this.toBuildRelativePath(from);
597
- return `import type {
598
- ${imports}
599
- } from '${importPath}'`;
600
- }).join("\n");
601
- return `
602
- ${propTypeImportStatements}
603
- import type { FieldListItem } from "${this.imports.TYPES}"
604
-
605
- export type ValidFieldListTypes = ${validFieldListTypes}
606
-
607
- export type BlockBundle = ${validBlockBundles || `''`}
608
-
609
- export type BlockBundleWithNested = ${blockBundlesWithNested || `''`}
610
-
611
- export type ValidChunkNames = ${validChunkNames}
612
-
613
- export type GlobalOptionsKey = ${validGlobalOptions || "never"}
614
-
615
- export type ValidGlobalConfigKeys = Array<GlobalOptionsKey>
616
-
617
- ${typedFieldListItems.map((v) => v.typeDefinition).join("\n\n")}
618
-
619
- export type FieldListItemTyped = Omit<FieldListItem, 'props'> & (${typedFieldListItems.map((v) => v.typeName).join(" | ")})
620
- export type FieldListItemTypedArray = Array<FieldListItemTyped>
621
- `;
622
550
  }
623
- generateChunkGroupTemplate(chunkName) {
624
- return this.generateChunkGroup(
625
- chunkName,
626
- chunkName,
627
- { ...this.definitions, ...this.fragmentDefinitions },
628
- true
551
+ }
552
+
553
+ function onlyUnique(value, index, self) {
554
+ return self.indexOf(value) === index;
555
+ }
556
+ class ModuleHelper {
557
+ constructor(nuxt, moduleUrl, providedOptions) {
558
+ this.nuxt = nuxt;
559
+ this.isDev = nuxt.options.dev;
560
+ this.isModuleBuild = false;
561
+ this.fileCache = new FileCache();
562
+ this.resolvers = {
563
+ module: createResolver(moduleUrl),
564
+ build: createResolver(nuxt.options.buildDir),
565
+ src: createResolver(nuxt.options.srcDir),
566
+ app: createResolver(nuxt.options.dir.app)
567
+ };
568
+ this.paths = {
569
+ blokkliBuildDir: this.resolvers.build.resolve("blokkli"),
570
+ srcDir: nuxt.options.srcDir,
571
+ editAdapter: ""
572
+ };
573
+ this.relativePaths = {
574
+ TYPES: relative(
575
+ this.paths.blokkliBuildDir,
576
+ this.resolvers.module.resolve("./runtime/types/index.ts")
577
+ ),
578
+ CONSTANTS: relative(
579
+ this.paths.blokkliBuildDir,
580
+ this.resolvers.module.resolve("./runtime/constants/index.ts")
581
+ ),
582
+ ADAPTER: relative(
583
+ this.paths.blokkliBuildDir,
584
+ this.resolvers.module.resolve("./runtime/adapter/index.ts")
585
+ ),
586
+ TYPES_THEME: relative(
587
+ this.paths.blokkliBuildDir,
588
+ this.resolvers.module.resolve("./runtime/types/theme.ts")
589
+ ),
590
+ TYPES_BLOKK_OPTIONS: relative(
591
+ this.paths.blokkliBuildDir,
592
+ this.resolvers.module.resolve("./runtime/types/blokkOptions.ts")
593
+ )
594
+ };
595
+ const pattern = providedOptions.pattern || [];
596
+ pattern.push(
597
+ this.resolvers.module.resolve(
598
+ "./runtime/components/Blocks/FromLibrary/*.vue"
599
+ )
600
+ );
601
+ pattern.push(
602
+ this.resolvers.module.resolve(
603
+ "./runtime/components/Blocks/Fragment/*.vue"
604
+ )
629
605
  );
606
+ const fieldListTypes = providedOptions.fieldListTypes || [];
607
+ if (!fieldListTypes.includes("default")) {
608
+ fieldListTypes.push("default");
609
+ }
610
+ const chunkNames = providedOptions.chunkNames || [];
611
+ if (!chunkNames.includes("global")) {
612
+ chunkNames.push("global");
613
+ }
614
+ this.options = {
615
+ ...providedOptions,
616
+ pattern,
617
+ fieldListTypes: fieldListTypes.filter(onlyUnique),
618
+ chunkNames: chunkNames.filter(onlyUnique)
619
+ };
620
+ this.paths.editAdapter = this.findEditAdapterPath();
630
621
  }
622
+ relativePaths;
623
+ paths;
624
+ resolvers;
625
+ fileCache;
626
+ options;
627
+ isDev;
628
+ isModuleBuild;
631
629
  /**
632
- * Generate the template.
630
+ * Transform the path relative to the module's build directory.
631
+ *
632
+ * @param path - The absolute path.
633
+ *
634
+ * @returns The path relative to the module's build directory.
633
635
  */
634
- generateImportsTemplate(chunkNames) {
635
- const chunkImports = chunkNames.filter((v) => v !== "global").map((chunkName) => {
636
- return `${chunkName}: () => import('./chunk-${chunkName}')`;
637
- });
638
- const nonGlobalChunkMapping = Object.values(this.definitions).reduce((acc, v) => {
639
- if (v && v.chunkName !== "global") {
640
- acc["block_" + v.definition.bundle] = v.chunkName;
641
- }
642
- return acc;
643
- }, {});
644
- const nonGlobalFragmentChunkMapping = Object.values(
645
- this.fragmentDefinitions
646
- ).reduce((acc, v) => {
647
- if (v && v.chunkName !== "global") {
648
- acc["fragment_" + v.definition.name] = v.chunkName;
649
- }
650
- return acc;
651
- }, {});
652
- return `
653
- import { defineAsyncComponent } from '#imports'
654
- ${this.generateChunkGroup("global", "global", this.definitions)}
655
- ${this.generateChunkGroup(
656
- "global",
657
- "globalFragments",
658
- this.fragmentDefinitions
659
- )}
660
-
661
- const chunks: Record<string, () => Promise<any>> = {
662
- ${chunkImports.join(",\n ")}
663
- }
664
-
665
- const chunkMapping: Record<string, string> = ${JSON.stringify(
666
- nonGlobalChunkMapping,
667
- null,
668
- 2
669
- )}
670
-
671
- const fragmentChunkMapping: Record<string, string> = ${JSON.stringify(
672
- nonGlobalFragmentChunkMapping,
673
- null,
674
- 2
675
- )}
676
-
677
- function componentOrFunction(component: any) {
678
- if (typeof component === 'object') {
679
- return component
680
- }
681
-
682
- return defineAsyncComponent(() => component())
683
- }
684
-
685
- export function getBlokkliItemComponent(bundle: string, fieldListType?: string, parentBundle?: string): any {
686
- const forFieldListType = 'block_' + bundle + '__field_list_type_' + fieldListType
687
- if (global[forFieldListType]) {
688
- return componentOrFunction(global[forFieldListType])
636
+ toModuleBuildRelative(path) {
637
+ return relative(this.paths.blokkliBuildDir, path);
689
638
  }
690
- if (parentBundle) {
691
- const forParentBundle = 'block_' + bundle + '__parent_block_' + parentBundle
692
- if (global[forParentBundle]) {
693
- return componentOrFunction(global[forParentBundle])
639
+ findEditAdapterPath() {
640
+ const filePath = this.resolvers.app.resolve("blokkli.editAdapter.ts");
641
+ if (this.fileCache.fileExists(filePath)) {
642
+ return filePath;
643
+ }
644
+ if (this.options.editAdapterPath && this.fileCache.fileExists(this.options.editAdapterPath)) {
645
+ return this.options.editAdapterPath;
694
646
  }
647
+ throw new Error(`Missing bl\xF6kkli edit adapter at "${filePath}"`);
695
648
  }
696
- const key = 'block_' + bundle
697
- if (global[key]) {
698
- return componentOrFunction(global[key])
649
+ getChunkNames() {
650
+ return this.options.chunkNames || ["global"];
699
651
  }
700
- const chunkName = chunkMapping[key]
701
- if (chunkName) {
702
- return defineAsyncComponent(() => chunks[chunkName]().then(chunk => {
703
- return chunk.default[key]
704
- }))
652
+ addComponent(name) {
653
+ addComponent({
654
+ filePath: this.resolvers.module.resolve("./runtime/components/" + name),
655
+ name,
656
+ global: true
657
+ });
705
658
  }
706
- }
707
-
708
- export function getBlokkliFragmentComponent(name: string): any {
709
- const key = 'fragment_' + name
710
- if (globalFragments[key]) {
711
- return componentOrFunction(globalFragments[key])
659
+ addComposable(name) {
660
+ addImports({
661
+ name,
662
+ from: this.resolvers.module.resolve("./runtime/composables/" + name)
663
+ });
712
664
  }
713
- const chunkName = fragmentChunkMapping[key]
714
- if (chunkName) {
715
- return defineAsyncComponent(() => chunks[chunkName]().then(chunk => {
716
- return chunk.default[key]
717
- }))
665
+ addAlias(name, path) {
666
+ this.nuxt.options.alias[name] = path;
667
+ this.nuxt.options.nitro.typescript ||= {};
668
+ this.nuxt.options.nitro.typescript.tsConfig ||= {};
669
+ this.nuxt.options.nitro.typescript.tsConfig.compilerOptions ||= {};
670
+ this.nuxt.options.nitro.typescript.tsConfig.compilerOptions.paths ||= {};
671
+ this.nuxt.options.nitro.typescript.tsConfig.compilerOptions.paths[name] = [
672
+ path
673
+ ];
674
+ this.nuxt.options.nitro.typescript.tsConfig.compilerOptions.paths[name + "/*"] = [path + "/*"];
675
+ this.nuxt.options.typescript.tsConfig ||= {};
676
+ this.nuxt.options.typescript.tsConfig.compilerOptions ||= {};
677
+ this.nuxt.options.typescript.tsConfig.compilerOptions.paths ||= {};
678
+ this.nuxt.options.typescript.tsConfig.compilerOptions.paths[name] = [path];
679
+ this.nuxt.options.typescript.tsConfig.compilerOptions.paths[name + "/*"] = [
680
+ path + "/*"
681
+ ];
718
682
  }
719
683
  }
720
- `;
684
+
685
+ const WRITE = false;
686
+ class ModuleContext {
687
+ constructor(helper, icons, features, blocks, theme) {
688
+ this.helper = helper;
689
+ this.icons = icons;
690
+ this.features = features;
691
+ this.blocks = blocks;
692
+ this.theme = theme;
721
693
  }
722
- toBuildRelativePath(path2) {
723
- if (!path2.startsWith("/")) {
724
- return path2;
694
+ templates = [];
695
+ templateContents = /* @__PURE__ */ new Map();
696
+ getTemplateContents(type, name) {
697
+ const contents = this.templateContents.get(type + name);
698
+ if (contents === void 0) {
699
+ throw new Error(
700
+ `Failed to get contents for template "${name}" of type ${type}`
701
+ );
725
702
  }
726
- return relative(this.buildDir, path2);
703
+ return contents;
727
704
  }
728
- /**
729
- * Generate the template.
730
- */
731
- generateChunkGroup(chunkName, exportName, inputDefinitions, addExport) {
732
- const definitions = Object.values(inputDefinitions).filter((v) => {
733
- return v?.chunkName === chunkName;
734
- }).filter(falsy);
735
- const imports = definitions.map((v) => {
736
- if (this.isBuild) {
737
- return `import ${v.componentName} from '${this.toBuildRelativePath(v.filePath)}'`;
705
+ setTemplateContents(type, name, contents) {
706
+ this.templateContents.set(type + name, contents.trim());
707
+ }
708
+ async generateTemplates(dependencies) {
709
+ for (const template of this.templates) {
710
+ if (dependencies?.length) {
711
+ const shouldUpdate = dependencies.some(
712
+ (v) => template.options.dependencies.includes(v)
713
+ );
714
+ if (!shouldUpdate) {
715
+ continue;
716
+ }
717
+ }
718
+ if (template.type === "code") {
719
+ this.setTemplateContents(
720
+ "code",
721
+ template.name,
722
+ await template.buildCode(this)
723
+ );
724
+ this.setTemplateContents(
725
+ "types",
726
+ template.name,
727
+ await template.buildTypes(this)
728
+ );
738
729
  } else {
739
- return `const ${v.componentName} = () => import('${this.toBuildRelativePath(v.filePath)}')`;
730
+ this.setTemplateContents(
731
+ "file",
732
+ template.fileName,
733
+ await template.build(this)
734
+ );
740
735
  }
741
- });
742
- const map = definitions.reduce((acc, v) => {
743
- if ("bundle" in v.definition) {
744
- const bundle = v.definition.bundle;
745
- const renderFor = v.definition.renderFor;
746
- if (!renderFor) {
747
- acc.push(`block_${v.definition.bundle}: ${v.componentName}`);
748
- } else {
749
- const renderForList = Array.isArray(renderFor) ? renderFor : [renderFor];
750
- renderForList.forEach((entry) => {
751
- if ("parentBundle" in entry) {
752
- acc.push(
753
- `block_${bundle}__parent_block_${entry.parentBundle}: ${v.componentName}`
754
- );
755
- } else if ("fieldList" in entry) {
756
- acc.push(
757
- `block_${bundle}__field_list_type_${entry.fieldList}: ${v.componentName}`
758
- );
759
- } else if ("fieldListType" in entry) {
760
- acc.push(
761
- `block_${bundle}__field_list_type_${entry.fieldListType}: ${v.componentName}`
762
- );
736
+ }
737
+ }
738
+ addTemplate(template) {
739
+ this.templates.push(template);
740
+ if (template.type === "code") {
741
+ addTemplate({
742
+ filename: `blokkli/${template.name}.js`,
743
+ write: template.options.write || WRITE,
744
+ getContents: () => this.getTemplateContents("code", template.name)
745
+ });
746
+ addTypeTemplate({
747
+ filename: `blokkli/${template.name}.d.ts`,
748
+ write: true,
749
+ // Type files are always written.
750
+ getContents: () => {
751
+ const lines = this.getTemplateContents("types", template.name).trim().split("\n");
752
+ const imports = [];
753
+ const declarations = [];
754
+ for (const line of lines) {
755
+ if (line.startsWith("import ") && line.includes(" from ")) {
756
+ imports.push(line);
757
+ } else {
758
+ declarations.push(line);
763
759
  }
764
- });
760
+ }
761
+ return `${imports.join("\n")}
762
+
763
+ declare module '#blokkli-build/${template.name}' {
764
+ ${declarations.join("\n ")}
765
+ }`;
765
766
  }
767
+ });
768
+ } else {
769
+ const filename = template.fileName.startsWith("/") ? template.fileName : `blokkli/${template.fileName}`;
770
+ if (filename.endsWith(".d.ts")) {
771
+ addTypeTemplate({
772
+ filename,
773
+ write: true,
774
+ getContents: () => this.getTemplateContents("file", template.fileName)
775
+ });
766
776
  } else {
767
- acc.push(`fragment_${v.definition.name}: ${v.componentName}`);
777
+ addTemplate({
778
+ filename,
779
+ write: true,
780
+ getContents: () => this.getTemplateContents("file", template.fileName)
781
+ });
768
782
  }
769
- return acc;
770
- }, []);
771
- let content = `
772
- ${imports.join("\n")}
773
-
774
- const ${exportName}: Record<string, any> = {
775
- ${map.join(",\n ")}
776
- }
777
- `;
778
- if (addExport) {
779
- content += `export default ${exportName}`;
780
783
  }
781
- return content;
782
784
  }
783
785
  }
784
786
 
785
- class Extractor {
786
- definitions = {};
787
- isBuild = false;
788
- composableName;
789
- constructor(isBuild = false) {
790
- this.isBuild = isBuild;
791
- this.composableName = "defineBlokkliFeature";
792
- }
793
- /**
794
- * Add files by path.
795
- */
796
- addFiles(files) {
797
- return Promise.all(files.map((v) => this.handleFile(v)));
798
- }
799
- /**
800
- * Read the file and extract the blokkli component definitions.
801
- *
802
- * Returns a promise containing a boolean that indicated if the given file
803
- * should trigger a rebuild of the query.
804
- */
805
- async handleFile(filePath2) {
806
- const fileSource = await this.readFile(filePath2);
807
- const extracted = this.extractSingle(fileSource, filePath2);
808
- if (!extracted) {
809
- if (this.definitions[filePath2]) {
810
- this.definitions[filePath2] = void 0;
811
- return true;
812
- }
813
- return false;
814
- }
815
- const { definition: definition2, source: source2 } = extracted;
816
- if (!this.definitions[filePath2]) {
817
- const regex = /\/Features\/([^/]+)\//;
818
- const componentName = filePath2.match(regex)?.[1] || "";
819
- this.definitions[filePath2] = {
820
- id: definition2.id,
821
- componentName,
822
- componentPath: filePath2,
823
- filePath: filePath2,
824
- definition: definition2,
825
- source: source2
826
- };
827
- return true;
787
+ function defineCodeTemplate(name, buildCode, buildTypes, options) {
788
+ return {
789
+ type: "code",
790
+ name,
791
+ buildCode,
792
+ buildTypes,
793
+ options: {
794
+ dependencies: options?.dependencies || [],
795
+ write: !!options?.write
828
796
  }
829
- if (this.definitions[filePath2]?.definition === definition2) {
830
- return false;
797
+ };
798
+ }
799
+ function defineFileTemplate(fileName, build) {
800
+ return {
801
+ type: "file",
802
+ fileName,
803
+ build,
804
+ options: {
805
+ dependencies: [],
806
+ write: true
831
807
  }
832
- this.definitions[filePath2].definition = definition2;
833
- return true;
808
+ };
809
+ }
810
+ function withHelper(cb) {
811
+ return cb;
812
+ }
813
+
814
+ function toObject(name, map, noExport) {
815
+ const lines = [...map.entries()].map(([key, value]) => {
816
+ return `'${key}': ${value}`;
817
+ }).sort().join(",\n ");
818
+ if (noExport) {
819
+ return `
820
+ const ${name} = {
821
+ ${lines}
822
+ }
823
+ `;
834
824
  }
835
- /**
836
- * Extract the single text method calls.
837
- */
838
- extractSingle(code, filePath) {
839
- const pattern = this.composableName + "\\((\\{.+?\\})\\)";
840
- const rgx = new RegExp(pattern, "gms");
841
- const source = rgx.exec(code)?.[1];
842
- if (source) {
843
- try {
844
- const definition = eval(`(${source})`);
845
- return { definition, source };
846
- } catch (e) {
847
- console.error(
848
- `Failed to parse component "${filePath}": ${this.composableName} does not contain a valid object literal. No variables and methods are allowed inside ${this.composableName}().`,
849
- e
850
- );
851
- }
825
+ return `
826
+ export const ${name} = {
827
+ ${lines}
828
+ }
829
+ `;
830
+ }
831
+ function toImports(map) {
832
+ return [...map.entries()].map(([key, path]) => {
833
+ return `import ${key} from '${path}'`;
834
+ }).sort().join("\n");
835
+ }
836
+
837
+ const icons = defineCodeTemplate(
838
+ "icons",
839
+ (ctx) => {
840
+ const imports = /* @__PURE__ */ new Map();
841
+ const icons = /* @__PURE__ */ new Map();
842
+ const files = ctx.icons.files.values();
843
+ for (const file of files) {
844
+ const name = basename(file.filePath, ".svg").toLowerCase();
845
+ const importName = "icon_" + toValidVariableName(name);
846
+ imports.set(importName, `${file.filePath}?raw`);
847
+ icons.set(name, importName);
852
848
  }
849
+ return `${toImports(imports)}
850
+
851
+ ${toObject("icons", icons)}
852
+ `;
853
+ },
854
+ (ctx) => {
855
+ const allIconNames = [...ctx.icons.files.values()].map((file) => {
856
+ return basename(file.filePath, ".svg").toLowerCase();
857
+ }).sort().map((name) => `"${name}"`).join("\n | ");
858
+ return `
859
+ export type BlokkliIcon =
860
+ | ${allIconNames}
861
+ export const icons: Record<BlokkliIcon, string>
862
+ `;
863
+ },
864
+ {
865
+ dependencies: ["icons"]
853
866
  }
854
- /**
855
- * Read the given file and return its contents.
856
- */
857
- readFile(filePath2) {
858
- return fs.promises.readFile(filePath2).then((v) => {
859
- return v.toString();
860
- });
861
- }
862
- getFeatures() {
863
- return Object.values(this.definitions).filter(falsy);
867
+ );
868
+
869
+ const features = defineCodeTemplate(
870
+ "features",
871
+ (ctx) => {
872
+ const features = ctx.features.getEnabledFeatures().sort((a, b) => b.id.localeCompare(a.id));
873
+ const featuresComponents = /* @__PURE__ */ new Map();
874
+ const definitions = [];
875
+ const declarations = [];
876
+ const imports = /* @__PURE__ */ new Map();
877
+ for (const feature of features) {
878
+ const componentVarName = toValidVariableName(`component_${feature.id}`);
879
+ const declarationVarName = toValidVariableName(`feature_${feature.id}`);
880
+ declarations.push(
881
+ `const ${declarationVarName} = ${feature.definitionSource}`
882
+ );
883
+ definitions.push(declarationVarName);
884
+ imports.set(componentVarName, feature.componentPath);
885
+ featuresComponents.set(feature.id, componentVarName);
886
+ }
887
+ const availableFeaturesAtBuild = features.map((v) => v.id);
888
+ return `${toImports(imports)}
889
+
890
+ export const availableFeaturesAtBuild = ${JSON.stringify(
891
+ availableFeaturesAtBuild.sort()
892
+ )}
893
+
894
+ ${toObject("featureComponents", featuresComponents)}
895
+
896
+ ${declarations.join("\n\n")}
897
+
898
+ export const featureDefinitions = [
899
+ ${definitions.join(",\n ")}
900
+ ]
901
+ `;
902
+ },
903
+ (ctx) => {
904
+ const features = ctx.features.getEnabledFeatures().map((v) => v.id);
905
+ const availableFeaturesAtBuild = features;
906
+ return `
907
+ import type { BlokkliAdapter } from '${ctx.helper.relativePaths.ADAPTER}'
908
+ import type { Viewport } from '${ctx.helper.relativePaths.CONSTANTS}'
909
+ import type { Component } from 'vue'
910
+
911
+ type AdapterMethods = keyof BlokkliAdapter<any>
912
+
913
+ export type ValidFeatureKey = ${availableFeaturesAtBuild.map((v) => '"' + v + '"').join(" | ")}
914
+
915
+ export declare const featureComponents: Record<ValidFeatureKey, Component>
916
+ export declare const featureDefinitions: FeatureDefinition[]
917
+ export declare const availableFeaturesAtBuild: ValidFeatureKey[]
918
+ `;
919
+ },
920
+ {
921
+ dependencies: ["features"]
864
922
  }
865
- }
923
+ );
924
+
925
+ const featuresJson = defineFileTemplate("features-data.json", async (ctx) => {
926
+ const features = [...ctx.features.files.values()];
927
+ const featuresData = await Promise.all(
928
+ features.map(async (v) => {
929
+ const docsPath = v.filePath.replace("index.vue", "docs.md");
930
+ let docs = "";
931
+ if (ctx.helper.fileCache.fileExists(docsPath)) {
932
+ docs = await ctx.helper.fileCache.read(docsPath);
933
+ }
934
+ return {
935
+ ...v,
936
+ repoRelativePath: v.filePath.replace(/.*\/src/, "/src"),
937
+ docs
938
+ };
939
+ })
940
+ );
941
+ return JSON.stringify(featuresData, null, 2);
942
+ });
866
943
 
867
944
  const addCommentToItem$2 = {
868
945
  source: "Comment",
@@ -6222,12 +6299,66 @@ const it = {
6222
6299
  validationsTourText: validationsTourText
6223
6300
  };
6224
6301
 
6225
- const translations = {
6302
+ const translations$1 = {
6226
6303
  de,
6227
6304
  fr,
6228
6305
  it
6229
6306
  };
6230
6307
 
6308
+ const translations = defineCodeTemplate(
6309
+ "translations",
6310
+ (ctx) => {
6311
+ const translations = {};
6312
+ Object.keys(translations$1).forEach((language) => {
6313
+ translations[language] = {};
6314
+ Object.keys(translations$1[language]).forEach((key) => {
6315
+ translations[language][key] = translations$1[language][key].translation;
6316
+ });
6317
+ });
6318
+ const merged = defu(ctx.helper.options.translations, translations);
6319
+ return `export const translations = ${JSON.stringify(merged, null, 2)}`;
6320
+ },
6321
+ () => {
6322
+ return `
6323
+ export declare const translations: Record<string, Record<string, string>>
6324
+ `;
6325
+ }
6326
+ );
6327
+
6328
+ const editAdapter = defineCodeTemplate(
6329
+ "edit-adapter",
6330
+ (ctx) => {
6331
+ const pathRelative = ctx.helper.toModuleBuildRelative(
6332
+ ctx.helper.paths.editAdapter
6333
+ );
6334
+ return `
6335
+ import adapter from '${pathRelative}'
6336
+
6337
+ export default adapter
6338
+ `;
6339
+ },
6340
+ (ctx) => {
6341
+ return `
6342
+ import type { BlokkliAdapterFactory } from '${ctx.helper.relativePaths.ADAPTER}'
6343
+
6344
+ declare const adapter: BlokkliAdapterFactory<any>
6345
+
6346
+ export default adapter
6347
+ `;
6348
+ }
6349
+ );
6350
+
6351
+ const styles = defineFileTemplate("styles.css", (ctx) => {
6352
+ const cssFilePath = ctx.helper.resolvers.module.resolve(
6353
+ "./runtime/css/output.css"
6354
+ );
6355
+ return `
6356
+ @import url("${relative(ctx.helper.paths.blokkliBuildDir, cssFilePath)}");
6357
+
6358
+ ${ctx.theme.css}
6359
+ `;
6360
+ });
6361
+
6231
6362
  const accent$3 = {
6232
6363
  "50": [
6233
6364
  237,
@@ -6992,27 +7123,871 @@ const nuxt = {
6992
7123
  lime: lime
6993
7124
  };
6994
7125
 
6995
- const themes = {
6996
- fire,
6997
- arctic,
6998
- gruvbox,
6999
- nuxt
7000
- };
7001
- const getTheme = (v) => {
7002
- if (typeof v === "string") {
7003
- if (v === "arctic") {
7004
- return themes.arctic;
7005
- } else if (v === "gruvbox") {
7006
- return themes.gruvbox;
7007
- } else if (v === "fire") {
7008
- return themes.fire;
7009
- } else if (v === "nuxt") {
7010
- return themes.nuxt;
7126
+ const themes = {
7127
+ fire,
7128
+ arctic,
7129
+ gruvbox,
7130
+ nuxt
7131
+ };
7132
+ const getTheme = (v) => {
7133
+ if (typeof v === "string") {
7134
+ if (v === "arctic") {
7135
+ return themes.arctic;
7136
+ } else if (v === "gruvbox") {
7137
+ return themes.gruvbox;
7138
+ } else if (v === "fire") {
7139
+ return themes.fire;
7140
+ } else if (v === "nuxt") {
7141
+ return themes.nuxt;
7142
+ }
7143
+ throw new Error(`Invalid theme name: ${v}`);
7144
+ }
7145
+ return v || {};
7146
+ };
7147
+
7148
+ const config = defineCodeTemplate(
7149
+ "config",
7150
+ (ctx) => {
7151
+ const settingsOverride = ctx.helper.options.settingsOverride || {};
7152
+ return `
7153
+ export const hasCustomTheme = ${JSON.stringify(ctx.theme.hasCustomTheme)}
7154
+
7155
+ export const themes = ${JSON.stringify(themes, null, 2)}
7156
+
7157
+ export const theme = ${JSON.stringify(ctx.theme.fullTheme, null, 2)}
7158
+
7159
+ export const settingsOverride = ${JSON.stringify(settingsOverride)}
7160
+
7161
+ export const blokkliVersion = ${JSON.stringify(version)}
7162
+
7163
+ export const storageDefaults = ${JSON.stringify(
7164
+ ctx.helper.options.storageDefaults || {}
7165
+ )}
7166
+ export const defaultLanguage = ${JSON.stringify(
7167
+ ctx.helper.options.defaultLanguage || "en"
7168
+ )}
7169
+ export const forceDefaultLanguage = ${JSON.stringify(
7170
+ !!ctx.helper.options.forceDefaultLanguage
7171
+ )}
7172
+ `;
7173
+ },
7174
+ (ctx) => {
7175
+ return `
7176
+ import type { Theme } from '${ctx.helper.relativePaths.TYPES_THEME}'
7177
+ import type { ModuleOptionsSettings } from '#blokkli-build/module-types'
7178
+
7179
+ /**
7180
+ * Whether the app uses a custom theme.
7181
+ */
7182
+ export declare const hasCustomTheme: boolean
7183
+
7184
+ /**
7185
+ * All available themes.
7186
+ */
7187
+ export declare const themes: Record<string, Theme>
7188
+
7189
+ /**
7190
+ * The default theme.
7191
+ */
7192
+ export declare const theme: Theme
7193
+
7194
+ /**
7195
+ * Overrides for settings.
7196
+ */
7197
+ export declare const settingsOverride: ModuleOptionsSettings
7198
+
7199
+ /**
7200
+ * The version of the @blokkli/editor package.
7201
+ */
7202
+ export declare const blokkliVersion: string
7203
+
7204
+ /**
7205
+ * Default storage settings.
7206
+ */
7207
+ export declare const storageDefaults: Record<string, string|boolean|string[]>
7208
+
7209
+ /**
7210
+ * The default/fallback language.
7211
+ */
7212
+ export declare const defaultLanguage: string
7213
+
7214
+ /**
7215
+ * Whether to always force the default language, even on translation pages.
7216
+ */
7217
+ export declare const forceDefaultLanguage: boolean
7218
+ `;
7219
+ }
7220
+ );
7221
+
7222
+ const definitions = defineCodeTemplate(
7223
+ "definitions",
7224
+ (ctx) => {
7225
+ const blocks = [];
7226
+ const fragments = [];
7227
+ const icons = /* @__PURE__ */ new Map();
7228
+ const definitions = [];
7229
+ const files = [...ctx.blocks.files.values()].sort(
7230
+ (a, b) => b.identifier.localeCompare(a.identifier)
7231
+ );
7232
+ let key = "";
7233
+ files.forEach((file) => {
7234
+ if (!file.definition || !file.definitionSource) {
7235
+ return;
7236
+ }
7237
+ const identifier = file.identifier;
7238
+ key += identifier;
7239
+ if (isBlock(file.definition)) {
7240
+ definitions.push(`const ${identifier} = ${file.definitionSource}`);
7241
+ blocks.push(identifier);
7242
+ if (file.iconContents) {
7243
+ icons.set(file.definition.bundle, JSON.stringify(file.iconContents));
7244
+ }
7245
+ } else {
7246
+ definitions.push(`const ${identifier} = ${file.definitionSource}`);
7247
+ fragments.push(identifier);
7248
+ }
7249
+ });
7250
+ const renderKey = hash(key);
7251
+ return `
7252
+ ${definitions.join("\n\n")}
7253
+
7254
+ const blocks = [
7255
+ ${blocks.join(",\n ")}
7256
+ ]
7257
+
7258
+ const fragments = [
7259
+ ${fragments.join(",\n ")}
7260
+ ]
7261
+
7262
+ ${toObject("icons", icons, true)}
7263
+
7264
+
7265
+ const globalOptions = ${JSON.stringify(ctx.helper.options.globalOptions || {})}
7266
+
7267
+ const renderKey = "${renderKey}"
7268
+
7269
+ const definitions = {
7270
+ blocks,
7271
+ fragments,
7272
+ icons,
7273
+ globalOptions,
7274
+ renderKey
7275
+ }
7276
+
7277
+ export default definitions
7278
+ `;
7279
+ },
7280
+ (ctx) => {
7281
+ const fragmentNames = [];
7282
+ for (const file of ctx.blocks.files.values()) {
7283
+ if (!file.definition) {
7284
+ continue;
7285
+ }
7286
+ if (isBlock(file.definition)) {
7287
+ continue;
7288
+ }
7289
+ fragmentNames.push(`'${file.definition.name}'`);
7290
+ }
7291
+ return `
7292
+ import type { GlobalOptionsKey, ValidFieldListTypes, BlockBundleWithNested, ValidGlobalConfigKeys } from '#blokkli-build/generated-types'
7293
+ import type { BlockDefinitionInput, BlockDefinitionOptionsInput, FragmentDefinitionInput } from '${ctx.helper.relativePaths.TYPES}'
7294
+
7295
+ export type BlockDefinition = BlockDefinitionInput<BlockDefinitionOptionsInput, GlobalOptionsKey[]>
7296
+ export type FragmentDefinition = FragmentDefinitionInput<Record<string, any>, GlobalOptionsKey[]>
7297
+
7298
+ export type BlokkliFragmentName = ${fragmentNames.join(" | ") || "never"}
7299
+
7300
+ const globalOptions = ${JSON.stringify(ctx.helper.options.globalOptions || {})} as const
7301
+
7302
+ export type GlobalOptionsType = typeof globalOptions
7303
+
7304
+ export type Definitions = {
7305
+ blocks: BlockDefinition[]
7306
+ fragments: FragmentDefinition[]
7307
+ icons: Record<string, string>
7308
+ globalOptions: BlockDefinitionOptionsInput
7309
+ renderKey: string
7310
+ }
7311
+
7312
+ const definitions: Definitions
7313
+
7314
+ export default definitions
7315
+ `;
7316
+ },
7317
+ {
7318
+ dependencies: ["block-content", "block-path"]
7319
+ }
7320
+ );
7321
+
7322
+ const moduleTypes = defineCodeTemplate(
7323
+ "module-types",
7324
+ () => {
7325
+ return `export {}`;
7326
+ },
7327
+ (ctx) => {
7328
+ const features = ctx.features.getEnabledFeatures();
7329
+ const settings = [];
7330
+ features.forEach((feature) => {
7331
+ if (feature.definition.settings) {
7332
+ Object.entries(feature.definition.settings).sort((a, b) => a[0].localeCompare(b[0])).forEach(([key, setting]) => {
7333
+ const settingsKey = `feature:${feature.id}:${key}`;
7334
+ settings.push(`/** ${setting.label} */`);
7335
+ if (setting.type === "radios") {
7336
+ const type = Object.keys(setting.options).map((v) => `'${v}'`).join(" | ");
7337
+ settings.push(
7338
+ `'${settingsKey}'?: { disable?: boolean, default?: ${type} }
7339
+ `
7340
+ );
7341
+ } else if (setting.type === "checkbox") {
7342
+ settings.push(
7343
+ `'${settingsKey}'?: { disable?: boolean, default?: boolean }
7344
+ `
7345
+ );
7346
+ } else if (setting.type === "slider") {
7347
+ settings.push(
7348
+ `'${settingsKey}'?: { disable?: boolean, default?: number }
7349
+ `
7350
+ );
7351
+ } else {
7352
+ settings.push(`'${settingsKey}'?: { disable?: boolean }
7353
+ `);
7354
+ }
7355
+ });
7356
+ }
7357
+ });
7358
+ return `
7359
+ export type ModuleOptionsSettings = {
7360
+ ${settings.join("\n ")}
7361
+ }
7362
+ `;
7363
+ },
7364
+ {
7365
+ dependencies: ["features"]
7366
+ }
7367
+ );
7368
+
7369
+ const runtimeOptions = defineCodeTemplate(
7370
+ "runtime-options",
7371
+ (ctx) => {
7372
+ const globalOptions = ctx.helper.options.globalOptions || {};
7373
+ const files = [...ctx.blocks.files.values()];
7374
+ const items = files.map((v) => {
7375
+ if (v.definition && v.identifier) {
7376
+ if (isBlock(v.definition)) {
7377
+ return {
7378
+ varName: v.identifier,
7379
+ definition: v.definition,
7380
+ variations: v.variations
7381
+ };
7382
+ }
7383
+ return {
7384
+ varName: v.identifier,
7385
+ definition: v.definition,
7386
+ variations: v.variations
7387
+ };
7388
+ }
7389
+ return null;
7390
+ }).filter(falsy);
7391
+ const declarations = [];
7392
+ const OPTIONS = /* @__PURE__ */ new Map();
7393
+ for (const item of items) {
7394
+ const optionDefinitions = Object.entries(item.definition.options || {});
7395
+ const options = {};
7396
+ if (item.definition.globalOptions) {
7397
+ item.definition.globalOptions.forEach((name) => {
7398
+ const option = globalOptions[name];
7399
+ if (option) {
7400
+ options[name] = [option.type, option.default];
7401
+ }
7402
+ });
7403
+ }
7404
+ optionDefinitions.forEach(([name, option]) => {
7405
+ options[name] = [option.type, option.default];
7406
+ });
7407
+ const hasOptions = Object.keys(options).length > 0;
7408
+ if (hasOptions) {
7409
+ declarations.push(`const ${item.varName} = ${JSON.stringify(options)}`);
7410
+ OPTIONS.set(item.varName, item.varName);
7411
+ }
7412
+ item.variations.forEach((variation) => {
7413
+ if (hasOptions) {
7414
+ OPTIONS.set(variation, item.varName);
7415
+ }
7416
+ });
7417
+ }
7418
+ return `
7419
+ ${declarations.join("\n")}
7420
+
7421
+ ${toObject("OPTIONS", OPTIONS)}
7422
+ `;
7423
+ },
7424
+ (ctx) => {
7425
+ const globalOptions = ctx.helper.options.globalOptions || {};
7426
+ const blocks = [...ctx.blocks.files.values()].map((v) => {
7427
+ if (v.definition && isBlock(v.definition)) {
7428
+ return v.definition;
7429
+ }
7430
+ return null;
7431
+ }).filter(falsy);
7432
+ function getOptionTypes(definition) {
7433
+ const definedOptions = definition.options || {};
7434
+ const blockGlobalOptions = definition.globalOptions || [];
7435
+ blockGlobalOptions.forEach((key) => {
7436
+ if (globalOptions[key]) {
7437
+ definedOptions[key] = globalOptions[key];
7438
+ }
7439
+ });
7440
+ return Object.entries(definedOptions || {}).map(([key, option]) => {
7441
+ if (option.type === "text" || option.type === "datetime-local") {
7442
+ return `${key}: string`;
7443
+ } else if (option.type === "checkbox") {
7444
+ return `${key}: boolean`;
7445
+ } else if (option.type === "checkboxes") {
7446
+ const possibleValues = Object.keys(option.options).map((v) => `'${v}'`).join(" | ") || "string";
7447
+ return `${key}: Array<${possibleValues}>`;
7448
+ } else if (option.type === "radios") {
7449
+ const possibleValues = Object.keys(option.options).map((v) => `'${v}'`).join(" | ") || "string";
7450
+ return `${key}: ${possibleValues}`;
7451
+ } else if (option.type === "color") {
7452
+ return key + ": `#${string}`";
7453
+ } else if (option.type === "range" || option.type === "number") {
7454
+ return `${key}: number`;
7455
+ }
7456
+ });
7457
+ }
7458
+ const runtimeMappedOptionTypes = blocks.map((definition) => {
7459
+ if (definition.renderFor) {
7460
+ return null;
7461
+ }
7462
+ const bundle = definition.bundle;
7463
+ const options = getOptionTypes(definition).join("\n ");
7464
+ if (!options) {
7465
+ return ` ${bundle}: {}`;
7466
+ }
7467
+ return ` ${bundle}: {
7468
+ ${options}
7469
+ }`;
7470
+ }).filter(falsy).join(",\n");
7471
+ return `
7472
+ import type { BlockOptionDefinition } from '${ctx.helper.relativePaths.TYPES_BLOKK_OPTIONS}'
7473
+
7474
+ export type RuntimeBlockOptionArray = {
7475
+ [T in BlockOptionDefinition as T['type']]: [T['type'], T['default']]
7476
+ }[BlockOptionDefinition['type']]
7477
+
7478
+ export type RuntimeBlockOptions = {
7479
+ ${runtimeMappedOptionTypes}
7480
+ }
7481
+
7482
+ export declare const OPTIONS: Record<string, Record<string, RuntimeBlockOptionArray>>
7483
+ `;
7484
+ },
7485
+ {
7486
+ dependencies: ["block-content", "block-path"]
7487
+ }
7488
+ );
7489
+
7490
+ const editComponents = defineCodeTemplate(
7491
+ "edit-components",
7492
+ (ctx) => {
7493
+ const imports = {};
7494
+ const proxyComponents = /* @__PURE__ */ new Map();
7495
+ const diffComponents = /* @__PURE__ */ new Map();
7496
+ for (const file of ctx.blocks.files.values()) {
7497
+ if (!file.definition || !isBlock(file.definition)) {
7498
+ continue;
7499
+ }
7500
+ const { bundle } = file.definition;
7501
+ if (file.proxyComponentPath) {
7502
+ const importName = "proxy_" + bundle;
7503
+ imports[importName] = file.proxyComponentPath;
7504
+ proxyComponents.set(bundle, importName);
7505
+ } else if (file.diffComponentPath) {
7506
+ const importName = "diff_" + file.definition.bundle;
7507
+ imports[importName] = file.diffComponentPath;
7508
+ diffComponents.set(bundle, importName);
7509
+ }
7510
+ }
7511
+ const importLines = Object.entries(imports).map(([variableName, path]) => {
7512
+ return `import ${variableName} from '${path}'`;
7513
+ }).join("\n");
7514
+ return `
7515
+ ${importLines}
7516
+
7517
+ ${toObject("PROXY_COMPONENTS", proxyComponents)}
7518
+
7519
+ ${toObject("DIFF_COMPONENTS", diffComponents)}
7520
+ `;
7521
+ },
7522
+ () => {
7523
+ return `
7524
+ export declare const PROXY_COMPONENTS: Record<string, any>
7525
+ export declare const DIFF_COMPONENTS: Record<string, any>
7526
+ `;
7527
+ },
7528
+ {
7529
+ dependencies: ["block-path"]
7530
+ }
7531
+ );
7532
+
7533
+ function toStringUnion(strings) {
7534
+ return strings.sort().map((v) => `'${v}'`).join(" | ") || "never";
7535
+ }
7536
+ function getOptionTypes(definition, globalOptions) {
7537
+ const definedOptions = { ...definition.options || {} };
7538
+ const blockGlobalOptions = definition.globalOptions || [];
7539
+ blockGlobalOptions.forEach((key) => {
7540
+ if (globalOptions[key]) {
7541
+ definedOptions[key] = globalOptions[key];
7542
+ }
7543
+ });
7544
+ const options = Object.entries(definedOptions || {}).map(([key, option]) => {
7545
+ if (option.type === "checkbox") {
7546
+ return `${key}: '1' | '0' | undefined`;
7547
+ } else if (option.type === "text" || option.type === "radios" || option.type === "checkboxes" || option.type === "color" || option.type === "datetime-local") {
7548
+ return `${key}: string | undefined`;
7549
+ } else if (option.type === "range" || option.type === "number") {
7550
+ return `${key}: number | string | undefined`;
7551
+ }
7552
+ }).join("\n ");
7553
+ return `{
7554
+ ${options}
7555
+ }`;
7556
+ }
7557
+ const generatedTypes = defineCodeTemplate(
7558
+ "generated-types",
7559
+ () => {
7560
+ return `export {}`;
7561
+ },
7562
+ (ctx) => {
7563
+ const mappedGetBundlePropsType = (bundle, file) => {
7564
+ if (bundle === "from_library" || bundle === "blokkli_fragment") {
7565
+ return {
7566
+ typeName: "Props",
7567
+ from: file.filePath
7568
+ };
7569
+ } else if (ctx.helper.options.getBundlePropsType) {
7570
+ return ctx.helper.options.getBundlePropsType(bundle, file);
7571
+ }
7572
+ return null;
7573
+ };
7574
+ const chunkNames = ctx.helper.options.chunkNames || ["global"];
7575
+ const fieldListTypes = ctx.helper.options.fieldListTypes || ["default"];
7576
+ const globalOptions = ctx.helper.options.globalOptions || {};
7577
+ const validGlobalOptions = Object.keys(globalOptions);
7578
+ const blockBundlesWithNested = [];
7579
+ const validBlockBundles = [];
7580
+ const propTypeImports = {};
7581
+ const propTypes = {};
7582
+ const typedFieldListItems = [];
7583
+ for (const file of ctx.blocks.files.values()) {
7584
+ if (!file.definition || !isBlock(file.definition)) {
7585
+ continue;
7586
+ }
7587
+ if (file.hasBlokkliField) {
7588
+ blockBundlesWithNested.push(file.definition.bundle);
7589
+ }
7590
+ if (file.definition.bundle !== "from_library") {
7591
+ validBlockBundles.push(file.definition.bundle);
7592
+ }
7593
+ if (!file.definition.renderFor) {
7594
+ const bundle = file.definition.bundle;
7595
+ const options = getOptionTypes(file.definition, globalOptions);
7596
+ const generatedTypeName = `FieldListItem_${bundle}`;
7597
+ const lines = [` bundle: '${bundle}'`, `options: ${options}`];
7598
+ const bundlePropsType = mappedGetBundlePropsType(bundle, file);
7599
+ if (bundlePropsType) {
7600
+ const { typeName, from } = bundlePropsType;
7601
+ if (!propTypeImports[from]) {
7602
+ propTypeImports[from] = [];
7603
+ }
7604
+ propTypeImports[from].push({ bundle, typeName });
7605
+ const tsTypeName = `Bundle_${bundle}_Props`;
7606
+ lines.push(`props: ${tsTypeName}`);
7607
+ propTypes[bundle] = tsTypeName;
7608
+ }
7609
+ const typeDefinition = `
7610
+ type ${generatedTypeName} = {
7611
+ ${lines.join("\n ")}
7612
+ }`;
7613
+ typedFieldListItems.push({
7614
+ typeName: generatedTypeName,
7615
+ typeDefinition
7616
+ });
7617
+ }
7618
+ }
7619
+ const propTypeImportStatements = Object.entries(propTypeImports).map(([from, items]) => {
7620
+ const imports = items.map((v) => {
7621
+ return `${v.typeName} as Bundle_${v.bundle}_Props`;
7622
+ }).join(", ");
7623
+ const importPath = relative(ctx.helper.paths.blokkliBuildDir, from);
7624
+ return `import type { ${imports} } from '${importPath}'`;
7625
+ }).join("\n");
7626
+ const BundleProps = Object.entries(propTypes).map(([key, type]) => {
7627
+ return `'${key}': ${type}`;
7628
+ }).join("\n ");
7629
+ return `
7630
+ ${propTypeImportStatements}
7631
+ import type { FieldListItem } from "${ctx.helper.relativePaths.TYPES}"
7632
+
7633
+ export type ValidFieldListTypes = ${toStringUnion(fieldListTypes)}
7634
+
7635
+ export type BlockBundle = ${toStringUnion(validBlockBundles)}
7636
+
7637
+ export type BlockBundleWithNested = ${toStringUnion(blockBundlesWithNested)}
7638
+
7639
+ export type ValidChunkNames = ${toStringUnion(chunkNames)}
7640
+
7641
+ export type BundleProps = {
7642
+ ${BundleProps}
7643
+ }
7644
+
7645
+ export type GlobalOptionsKey = ${toStringUnion(validGlobalOptions)}
7646
+
7647
+ export type ValidGlobalConfigKeys = Array<GlobalOptionsKey>
7648
+
7649
+ ${typedFieldListItems.map((v) => v.typeDefinition).join("\n\n")}
7650
+
7651
+ export type FieldListItemTyped = Omit<FieldListItem, 'props'> & (${typedFieldListItems.map((v) => v.typeName).sort().join(" | ")})
7652
+ export type FieldListItemTypedArray = Array<FieldListItemTyped>
7653
+ `;
7654
+ },
7655
+ {
7656
+ dependencies: ["block-path"]
7657
+ }
7658
+ );
7659
+
7660
+ const defaultGlobalOptions = defineCodeTemplate(
7661
+ "default-global-options",
7662
+ (ctx) => {
7663
+ const globalOptions = ctx.helper.options.globalOptions || {};
7664
+ const defaults = Object.entries(globalOptions).reduce(
7665
+ (acc, [key, option]) => {
7666
+ if (option.default !== void 0 && option.default !== null) {
7667
+ acc[key] = {
7668
+ default: option.default,
7669
+ type: option.type
7670
+ };
7671
+ }
7672
+ return acc;
7673
+ },
7674
+ {}
7675
+ );
7676
+ const bundlesWithVisibleLanguage = [];
7677
+ const bundlesWithHiddenGlobally = [];
7678
+ for (const file of ctx.blocks.files.values()) {
7679
+ if (!file.definition || !isBlock(file.definition)) {
7680
+ continue;
7681
+ }
7682
+ const usedGlobalOptions = file.definition.globalOptions || [];
7683
+ if (usedGlobalOptions.includes(BK_VISIBLE_LANGUAGES)) {
7684
+ bundlesWithVisibleLanguage.push(file.definition.bundle);
7685
+ }
7686
+ if (usedGlobalOptions.includes(BK_HIDDEN_GLOBALLY)) {
7687
+ bundlesWithHiddenGlobally.push(file.definition.bundle);
7688
+ }
7689
+ }
7690
+ return `
7691
+ export const bundlesWithVisibleLanguage = ${JSON.stringify(bundlesWithVisibleLanguage.sort())}
7692
+ export const bundlesWithHiddenGlobally = ${JSON.stringify(bundlesWithHiddenGlobally.sort())}
7693
+
7694
+ export const globalOptionsDefaults = ${JSON.stringify(defaults, null, 2)}`;
7695
+ },
7696
+ (ctx) => {
7697
+ return `
7698
+ import type { BlockOptionDefinition } from '${ctx.helper.relativePaths.TYPES_BLOKK_OPTIONS}'
7699
+
7700
+ type GlobalOptionsDefaults = {
7701
+ type: BlockOptionDefinition['type']
7702
+ default: any
7703
+ }
7704
+
7705
+ export declare const bundlesWithVisibleLanguage: string[]
7706
+ export declare const bundlesWithHiddenGlobally: string[]
7707
+
7708
+ export declare const globalOptionsDefaults: Record<string, GlobalOptionsDefaults>
7709
+ `;
7710
+ },
7711
+ {
7712
+ dependencies: ["block-path"]
7713
+ }
7714
+ );
7715
+
7716
+ const imports = defineCodeTemplate(
7717
+ "imports",
7718
+ (ctx) => {
7719
+ const chunkMapping = {};
7720
+ for (const file of ctx.blocks.files.values()) {
7721
+ if (!file.definition) {
7722
+ continue;
7723
+ }
7724
+ file.variations.forEach((variation) => {
7725
+ chunkMapping[variation] = file.chunkName;
7726
+ });
7727
+ }
7728
+ const lines = Object.entries(chunkMapping).map(
7729
+ ([variation, importName]) => {
7730
+ return `'${variation}': '${importName}'`;
7731
+ }
7732
+ );
7733
+ const chunks = ctx.helper.getChunkNames().map((chunkName) => {
7734
+ if (chunkName === "global") {
7735
+ return null;
7736
+ }
7737
+ return `${chunkName}: () => import('#blokkli-build/chunk-${chunkName}.js').then(v => v['${chunkName}'])`;
7738
+ }).filter(falsy).sort().join(",\n ");
7739
+ return `
7740
+ import { global } from '#blokkli-build/chunk-global.js'
7741
+
7742
+ export const chunks = {
7743
+ global,
7744
+ ${chunks}
7745
+ }
7746
+
7747
+ export const chunkMapping = {
7748
+ ${lines.sort().join(",\n ")}
7749
+ }
7750
+ `;
7751
+ },
7752
+ () => {
7753
+ return `
7754
+ import type { Component } from 'vue'
7755
+
7756
+ export type ChunkGroup = Record<string, Component | { loadComponent: () => Promise<Component> } >
7757
+ export type ChunkGroupEntry = ChunkGroup | (() => Promise<ChunkGroup>)
7758
+
7759
+ /**
7760
+ * Mapping of block/fragment variation ID to a chunk group.
7761
+ *
7762
+ * The variation is only present if its chunkName is not 'global'.
7763
+ */
7764
+ export declare const chunkMapping: Record<string, string>
7765
+
7766
+ /**
7767
+ * All available chunks.
7768
+ */
7769
+ export declare const chunks: Record<string, ChunkGroupEntry>
7770
+ `;
7771
+ },
7772
+ {
7773
+ dependencies: ["block-path", "block-content"]
7774
+ }
7775
+ );
7776
+
7777
+ const optionsSchema = withHelper((helper) => {
7778
+ let fileName = "options-schema.json";
7779
+ const outputPath = helper.options.schemaOptionsPath;
7780
+ if (outputPath) {
7781
+ const resolved = resolveAlias(outputPath);
7782
+ fileName = helper.resolvers.src.resolve(resolved);
7783
+ }
7784
+ return defineFileTemplate(fileName, (ctx) => {
7785
+ const globalOptions = ctx.helper.options.globalOptions || {};
7786
+ const blocks = [...ctx.blocks.files.values()];
7787
+ const schema = blocks.reduce((acc, v) => {
7788
+ if (v.definition && isBlock(v.definition)) {
7789
+ const bundle = v.definition.bundle;
7790
+ const existing = acc[v.definition.bundle] || {};
7791
+ acc[v.definition.bundle] = defu(existing, v.definition.options || {});
7792
+ const globalOptionKeys = v.definition.globalOptions || [];
7793
+ globalOptionKeys.forEach((name) => {
7794
+ if (globalOptions[name]) {
7795
+ acc[bundle][name] = globalOptions[name];
7796
+ }
7797
+ });
7798
+ }
7799
+ return acc;
7800
+ }, {});
7801
+ const sorted = sortObjectKeys(schema);
7802
+ return JSON.stringify(sorted, null, 2);
7803
+ });
7804
+ });
7805
+
7806
+ const chunkGroup = withHelper((helper) => {
7807
+ return helper.getChunkNames().map((chunkName) => {
7808
+ return defineCodeTemplate(
7809
+ "chunk-" + chunkName,
7810
+ (ctx) => {
7811
+ const imports = [];
7812
+ const map = {};
7813
+ for (const file of ctx.blocks.files.values()) {
7814
+ if (!file.definition) {
7815
+ continue;
7816
+ }
7817
+ if (!fs.existsSync(file.filePath)) {
7818
+ continue;
7819
+ }
7820
+ if (file.chunkName !== chunkName) {
7821
+ continue;
7822
+ }
7823
+ if (helper.isDev) {
7824
+ imports.push(
7825
+ `const ${file.identifier} = () => import('${file.filePath}').then(v => v.default)`
7826
+ );
7827
+ file.variations.forEach((variation) => {
7828
+ map[variation] = `{ loadComponent: ${file.identifier} }`;
7829
+ });
7830
+ } else {
7831
+ imports.push(`import ${file.identifier} from '${file.filePath}'`);
7832
+ file.variations.forEach((variation) => {
7833
+ map[variation] = file.identifier;
7834
+ });
7835
+ }
7836
+ }
7837
+ const lines = Object.entries(map).map(([variation, importName]) => {
7838
+ return `'${variation}': ${importName}`;
7839
+ });
7840
+ return `
7841
+ ${imports.sort().join("\n")}
7842
+
7843
+ export const ${chunkName} = {
7844
+ ${lines.sort().join(",\n ")}
7845
+ }
7846
+ `;
7847
+ },
7848
+ () => {
7849
+ return `
7850
+ import type { Component } from 'vue'
7851
+ export declare const ${chunkName}: Record<string, { loadComponent: () => Promise<Component> } | Component>
7852
+ `;
7853
+ },
7854
+ {
7855
+ dependencies: ["block-path", "block-content"]
7856
+ }
7857
+ );
7858
+ });
7859
+ });
7860
+
7861
+ const TEMPLATES = [
7862
+ icons,
7863
+ features,
7864
+ featuresJson,
7865
+ translations,
7866
+ editAdapter,
7867
+ styles,
7868
+ config,
7869
+ definitions,
7870
+ moduleTypes,
7871
+ runtimeOptions,
7872
+ editComponents,
7873
+ generatedTypes,
7874
+ defaultGlobalOptions,
7875
+ imports,
7876
+ optionsSchema,
7877
+ chunkGroup
7878
+ ];
7879
+
7880
+ class CollectedFeatureFile extends CollectedFile {
7881
+ definition = null;
7882
+ composableName = "defineBlokkliFeature";
7883
+ enabled = true;
7884
+ objectLiteral = void 0;
7885
+ getDefinition() {
7886
+ return this.definition;
7887
+ }
7888
+ async handleChange() {
7889
+ const objectLiteral = extractObjectLiteral(this.fileContents, [
7890
+ this.composableName
7891
+ ]);
7892
+ if (this.objectLiteral === objectLiteral) {
7893
+ return false;
7011
7894
  }
7012
- throw new Error(`Invalid theme name: ${v}`);
7895
+ this.objectLiteral = objectLiteral;
7896
+ if (!this.objectLiteral) {
7897
+ return false;
7898
+ }
7899
+ try {
7900
+ const { object: definition, source } = parseTsObject(
7901
+ this.objectLiteral
7902
+ );
7903
+ const regex = /\/Features\/([^/]+)\//;
7904
+ const componentName = this.filePath.match(regex)?.[1] || "";
7905
+ this.definition = {
7906
+ id: definition.id,
7907
+ componentName,
7908
+ componentPath: this.filePath,
7909
+ definition,
7910
+ definitionSource: source
7911
+ };
7912
+ } catch (e) {
7913
+ console.error(
7914
+ `Failed to parse component "${this.filePath}": ${this.composableName} does not contain a valid object literal. No variables and methods are allowed inside ${this.composableName}().`,
7915
+ e
7916
+ );
7917
+ }
7918
+ return Promise.resolve(true);
7013
7919
  }
7014
- return v || {};
7015
- };
7920
+ isEnabled() {
7921
+ return this.enabled;
7922
+ }
7923
+ /**
7924
+ * Disable the feature.
7925
+ */
7926
+ disable() {
7927
+ this.enabled = false;
7928
+ }
7929
+ }
7930
+ class FeatureCollector extends Collector {
7931
+ needsFileContents = true;
7932
+ disabledFeatures = /* @__PURE__ */ new Set();
7933
+ srcFromModule;
7934
+ constructor(helper) {
7935
+ super(helper);
7936
+ this.srcFromModule = helper.resolvers.module.resolve(
7937
+ "./runtime/components/Edit/Features"
7938
+ );
7939
+ }
7940
+ getEnabledFeatures() {
7941
+ return [...this.files.values()].filter((v) => v.isEnabled()).map((v) => v.getDefinition()).filter(falsy).filter((v) => !this.disabledFeatures.has(v.id));
7942
+ }
7943
+ async init() {
7944
+ const builtinFeatures = await resolveFiles(
7945
+ this.srcFromModule,
7946
+ ["*/index.vue"],
7947
+ {
7948
+ followSymbolicLinks: false
7949
+ }
7950
+ );
7951
+ const customFeatures = this.helper.options.featureImports ? await resolveFiles(
7952
+ this.helper.paths.srcDir,
7953
+ this.helper.options.featureImports,
7954
+ {
7955
+ followSymbolicLinks: false
7956
+ }
7957
+ ) : [];
7958
+ await Promise.all(
7959
+ [...builtinFeatures, ...customFeatures].map((v) => this.addFile(v))
7960
+ );
7961
+ const features = [...this.files.values()];
7962
+ if (!this.helper.options.enableThemeEditor) {
7963
+ const themeFeature = features.find(
7964
+ (v) => v.getDefinition()?.id === "theme"
7965
+ );
7966
+ if (themeFeature) {
7967
+ themeFeature.disable();
7968
+ }
7969
+ }
7970
+ }
7971
+ runHooks() {
7972
+ return this.helper.nuxt.hooks.callHook("blokkli:alter-features", {
7973
+ features: [...this.files.values()]
7974
+ });
7975
+ }
7976
+ createCollectedFile(filePath, fileContents = "") {
7977
+ return new CollectedFeatureFile(filePath, fileContents);
7978
+ }
7979
+ applies(filePath) {
7980
+ return Promise.resolve(
7981
+ filePath.startsWith(this.srcFromModule) || micromatch.isMatch(filePath, "icon-blokkli-*.svg")
7982
+ );
7983
+ }
7984
+ getDependencyTypes() {
7985
+ return ["features"];
7986
+ }
7987
+ disableFeature(id) {
7988
+ this.disabledFeatures.add(id);
7989
+ }
7990
+ }
7016
7991
 
7017
7992
  function hexToRgb(hex) {
7018
7993
  if (hex.startsWith("#")) {
@@ -7026,21 +8001,6 @@ function hexToRgb(hex) {
7026
8001
  const b = Number.parseInt(hex.slice(4, 6), 16);
7027
8002
  return [r, g, b];
7028
8003
  }
7029
- function onlyUnique(value, index, self) {
7030
- return self.indexOf(value) === index;
7031
- }
7032
- const fileExists = (path, extensions = ["js", "ts"]) => {
7033
- if (!path) {
7034
- return null;
7035
- } else if (existsSync(path)) {
7036
- return path;
7037
- }
7038
- const extension = extensions.find(
7039
- (extension2) => existsSync(`${path}.${extension2}`)
7040
- );
7041
- return extension ? `${path}.${extension}` : null;
7042
- };
7043
- const POSSIBLE_EXTENSIONS = [".js", ".ts", ".vue", ".mjs"];
7044
8004
  const buildThemeData = (themeOption) => {
7045
8005
  const hasCustomTheme = !!themeOption;
7046
8006
  const mergeTheme = createDefu((obj, key, value) => {
@@ -7077,17 +8037,28 @@ const buildThemeData = (themeOption) => {
7077
8037
  );
7078
8038
  return { themeCss, fullTheme, hasCustomTheme };
7079
8039
  };
8040
+ class ThemeData {
8041
+ css;
8042
+ fullTheme;
8043
+ hasCustomTheme;
8044
+ constructor(helper) {
8045
+ const data = buildThemeData(helper.options.theme);
8046
+ this.css = data.themeCss;
8047
+ this.fullTheme = data.fullTheme;
8048
+ this.hasCustomTheme = data.hasCustomTheme;
8049
+ }
8050
+ }
8051
+
7080
8052
  const module = defineNuxtModule({
7081
8053
  meta: {
7082
8054
  name: "blokkli",
7083
8055
  configKey: "blokkli",
7084
8056
  version,
7085
8057
  compatibility: {
7086
- nuxt: "^3.12.0"
8058
+ nuxt: "^3.15.0"
7087
8059
  }
7088
8060
  },
7089
8061
  defaults: {
7090
- pattern: ["components/Blokkli/**/*.{js,ts,vue}"],
7091
8062
  globalOptions: {
7092
8063
  [BK_VISIBLE_LANGUAGES]: {
7093
8064
  type: "checkboxes",
@@ -7101,494 +8072,85 @@ const module = defineNuxtModule({
7101
8072
  default: false
7102
8073
  }
7103
8074
  },
7104
- chunkNames: ["global"],
7105
- itemEntityType: "block"
8075
+ chunkNames: ["global"]
7106
8076
  },
7107
8077
  async setup(moduleOptions, nuxt) {
7108
- const srcDir = nuxt.options.srcDir;
7109
- const srcResolver = createResolver(srcDir);
7110
- const moduleDir = import.meta.url;
7111
- const resolver = createResolver(moduleDir);
7112
- const buildResolver = createResolver(nuxt.options.buildDir);
7113
- const blokkliBuildDir = buildResolver.resolve("blokkli");
7114
- const IMPORTS = {
7115
- TYPES: relative(
7116
- blokkliBuildDir,
7117
- resolver.resolve("./runtime/types/index.ts")
7118
- ),
7119
- CONSTANTS: relative(
7120
- blokkliBuildDir,
7121
- resolver.resolve("./runtime/constants/index.ts")
7122
- ),
7123
- ADAPTER: relative(
7124
- blokkliBuildDir,
7125
- resolver.resolve("./runtime/adapter/index.ts")
7126
- ),
7127
- TYPES_THEME: relative(
7128
- blokkliBuildDir,
7129
- resolver.resolve("./runtime/types/theme.ts")
7130
- ),
7131
- TYPES_GENERATED_MODULE_TYPED: relative(
7132
- blokkliBuildDir,
7133
- resolver.resolve("./runtime/types/generatedModuleTypes.ts")
7134
- ),
7135
- TYPES_BLOKK_OPTIONS: relative(
7136
- blokkliBuildDir,
7137
- resolver.resolve("./runtime/types/blokkOptions.ts")
7138
- )
7139
- };
7140
- const featureFolder = resolver.resolve("./runtime/components/Edit/Features");
7141
- const featureExtractor = new Extractor(!nuxt.options.dev);
7142
- const builtinFeatures = await resolveFiles(featureFolder, ["*/index.vue"], {
7143
- followSymbolicLinks: false
7144
- });
7145
- const customFeatures = moduleOptions.featureImports ? await resolveFiles(srcDir, moduleOptions.featureImports, {
7146
- followSymbolicLinks: false
7147
- }) : [];
7148
- await featureExtractor.addFiles([...builtinFeatures, ...customFeatures]);
7149
- const extractedFeatures = featureExtractor.getFeatures();
7150
- const features = extractedFeatures.filter((v) => {
7151
- return v.id !== "theme" || moduleOptions.enableThemeEditor;
7152
- });
7153
- const featuresContext = {
7154
- features
7155
- };
7156
- if (moduleOptions.alterFeatures) {
7157
- featuresContext.features = await Promise.resolve(
7158
- moduleOptions.alterFeatures(featuresContext)
7159
- );
7160
- }
7161
- const allFeatureIds = [
7162
- ...extractedFeatures.map((v) => v.id),
7163
- ...featuresContext.features.map((v) => v.id)
7164
- ].filter(onlyUnique);
7165
- const featureComponents = addTemplate({
7166
- write: true,
7167
- filename: "blokkli/features.ts",
7168
- getContents: () => {
7169
- const features2 = featuresContext.features.map((v) => {
7170
- const importName = `Feature_${v.componentName}`;
7171
- return {
7172
- id: v.id,
7173
- componentName: v.componentPath,
7174
- importName,
7175
- importStatement: `import ${importName} from '${relative(blokkliBuildDir, v.componentPath)}'`,
7176
- definition: v.definition
7177
- };
7178
- });
7179
- const imports = features2.map((v) => {
7180
- return v.importStatement;
7181
- }).join("\n");
7182
- const availableFeaturesAtBuild = featuresContext.features.map(
7183
- (v) => v.id
7184
- );
7185
- const featuresArray = features2.map((v) => {
7186
- return `{
7187
- id: "${v.id}",
7188
- dependencies: ${JSON.stringify(v.definition.dependencies || [])},
7189
- viewports: ${JSON.stringify(v.definition.viewports || [])},
7190
- component: ${v.importName},
7191
- requiredAdapterMethods: ${JSON.stringify(
7192
- v.definition.requiredAdapterMethods || []
7193
- )},
7194
- label: ${JSON.stringify(v.definition.label || "")},
7195
- beta: ${JSON.stringify(!!v.definition.beta)},
7196
- description: "${v.definition.description || ""}"
7197
- }`;
7198
- }).join(",\n");
7199
- return `${imports}
7200
- import type { BlokkliAdapter } from '${IMPORTS.ADAPTER}'
7201
- import type { Viewport } from '${IMPORTS.CONSTANTS}'
7202
- type AdapterMethods = keyof BlokkliAdapter<any>
7203
-
7204
- export const availableFeaturesAtBuild = ${JSON.stringify(
7205
- availableFeaturesAtBuild
7206
- )} as const
7207
-
7208
- export type ValidFeatureKey = ${allFeatureIds.map((v) => '"' + v + '"').join(" | ")}
7209
-
7210
- type FeatureComponent = {
7211
- id: ValidFeatureKey
7212
- component: any
7213
- requiredAdapterMethods: AdapterMethods[]
7214
- dependencies: ValidFeatureKey[]
7215
- description: string
7216
- label: string
7217
- beta: boolean
7218
- viewports: Viewport[]
7219
- }
7220
-
7221
- export const featureComponents: FeatureComponent[] = [
7222
- ${featuresArray}
7223
- ]
7224
- `;
7225
- },
7226
- options: {
7227
- blokkli: true
7228
- }
7229
- });
7230
- nuxt.options.alias["#blokkli-build/features"] = featureComponents.dst;
7231
- addTemplate({
7232
- write: true,
7233
- filename: "blokkli/features.json",
7234
- getContents: async () => {
7235
- const featuresData = await Promise.all(
7236
- featuresContext.features.map(async (v) => {
7237
- const docsPath = v.filePath.replace("index.vue", "docs.md");
7238
- let docs = "";
7239
- if (fileExists(docsPath)) {
7240
- docs = await promises.readFile(docsPath).then((v2) => v2.toString());
7241
- }
7242
- return {
7243
- ...v,
7244
- repoRelativePath: v.filePath.replace(/.*\/src/, "/src"),
7245
- docs
7246
- };
7247
- })
7248
- );
7249
- return JSON.stringify(featuresData, null, 2);
7250
- },
7251
- options: {
7252
- blokkli: true
7253
- }
7254
- });
7255
- function getChunkNames() {
7256
- const chunkNames = [...moduleOptions.chunkNames || []];
7257
- if (!chunkNames.includes("global")) {
7258
- chunkNames.push("global");
7259
- }
7260
- return chunkNames.filter(onlyUnique);
7261
- }
7262
- function getFieldListTypes() {
7263
- const types = [...moduleOptions.fieldListTypes || []];
7264
- if (!types.includes("default")) {
7265
- types.push("default");
8078
+ const blokkliModules = moduleOptions.modules || [];
8079
+ for (const module of blokkliModules) {
8080
+ if (module.init.alterOptions) {
8081
+ module.init.alterOptions(moduleOptions);
7266
8082
  }
7267
- return types.filter(onlyUnique);
7268
- }
7269
- const importPattern = moduleOptions.pattern || [];
7270
- const featureIsEnabled = (id) => featuresContext.features.some((v) => v.id === id);
7271
- if (featureIsEnabled("library")) {
7272
- importPattern.push(
7273
- resolver.resolve("./runtime/components/Blocks/FromLibrary/*.vue")
7274
- );
7275
- }
7276
- if (featureIsEnabled("fragments")) {
7277
- importPattern.push(
7278
- resolver.resolve("./runtime/components/Blocks/Fragment/*.vue")
7279
- );
7280
8083
  }
7281
- const files = await resolveFiles(srcDir, importPattern, {
7282
- followSymbolicLinks: false
7283
- });
7284
- const blockExtractor = new BlockExtractor(
7285
- !nuxt.options.dev,
7286
- blokkliBuildDir,
7287
- IMPORTS
8084
+ const helper = new ModuleHelper(nuxt, import.meta.url, moduleOptions);
8085
+ const theme = new ThemeData(helper);
8086
+ const iconCollector = new IconCollector(helper);
8087
+ const featureCollector = new FeatureCollector(helper);
8088
+ const blockCollector = new BlockCollector(helper);
8089
+ const collectors = [
8090
+ iconCollector,
8091
+ featureCollector,
8092
+ blockCollector
8093
+ ];
8094
+ await Promise.all(collectors.map((v) => v.init()));
8095
+ await Promise.all(collectors.map((v) => v.runHooks()));
8096
+ const context = new ModuleContext(
8097
+ helper,
8098
+ iconCollector,
8099
+ featureCollector,
8100
+ blockCollector,
8101
+ theme
7288
8102
  );
7289
- await blockExtractor.addFiles(files);
7290
- const templateDefinitions = addTemplate({
7291
- write: true,
7292
- filename: "blokkli/definitions.ts",
7293
- getContents: () => {
7294
- return blockExtractor.generateDefinitionTemplate(
7295
- moduleOptions.globalOptions
7296
- );
7297
- },
7298
- options: {
7299
- blokkli: true
7300
- }
7301
- });
7302
- nuxt.options.alias["#blokkli-build/definitions"] = templateDefinitions.dst;
7303
- const templateRuntimeOptions = addTemplate({
7304
- write: true,
7305
- filename: "blokkli/runtime-options.ts",
7306
- getContents: () => {
7307
- return blockExtractor.generateRuntimeOptionsTemplate(
7308
- moduleOptions.globalOptions
7309
- );
7310
- },
7311
- options: {
7312
- blokkli: true
7313
- }
7314
- });
7315
- nuxt.options.alias["#blokkli-build/runtime-options"] = templateRuntimeOptions.dst;
7316
- const templateEditComponents = addTemplate({
7317
- write: true,
7318
- filename: "blokkli/edit-components.ts",
7319
- getContents: () => {
7320
- return blockExtractor.generateEditComponents();
7321
- },
7322
- options: {
7323
- blokkli: true
7324
- }
7325
- });
7326
- nuxt.options.alias["#blokkli-build/edit-components"] = templateEditComponents.dst;
7327
- const templateTranslations = addTemplate({
7328
- write: true,
7329
- filename: "blokkli/translations.ts",
7330
- getContents: () => {
7331
- const translations$1 = {};
7332
- Object.keys(translations).forEach((language) => {
7333
- translations$1[language] = {};
7334
- Object.keys(translations[language]).forEach((key) => {
7335
- translations$1[language][key] = translations[language][key].translation;
7336
- });
8103
+ const app = {
8104
+ helper,
8105
+ context
8106
+ };
8107
+ for (const module of blokkliModules) {
8108
+ await module.init.setup(app, module.options);
8109
+ }
8110
+ TEMPLATES.forEach((v) => {
8111
+ if (typeof v === "function") {
8112
+ const result = v(helper);
8113
+ const templates = Array.isArray(result) ? result : [result];
8114
+ templates.forEach((template) => {
8115
+ context.addTemplate(template);
7337
8116
  });
7338
- const merged = defu(moduleOptions.translations, translations$1);
7339
- return `export const translations = ${JSON.stringify(merged, null, 2)}`;
7340
- },
7341
- options: {
7342
- blokkli: true
8117
+ } else {
8118
+ context.addTemplate(v);
7343
8119
  }
7344
8120
  });
7345
- nuxt.options.alias["#blokkli-build/translations"] = templateTranslations.dst;
8121
+ await context.generateTemplates();
8122
+ helper.addAlias("#blokkli-build", helper.paths.blokkliBuildDir);
8123
+ const moduleDir = import.meta.url;
8124
+ const resolver = createResolver(moduleDir);
7346
8125
  nuxt.options.runtimeConfig.public.blokkli = {
7347
8126
  itemEntityType: moduleOptions.itemEntityType || "",
7348
8127
  defaultLanguage: moduleOptions.defaultLanguage || "en"
7349
8128
  };
7350
- const resolvedPath = "~/app/blokkli.editAdapter".replace(/^(~~|@@)/, nuxt.options.rootDir).replace(/^(~|@)/, nuxt.options.srcDir);
7351
- const adapterTemplate = (() => {
7352
- const resolvedFilename = `blokkli/editAdapter.ts`;
7353
- const maybeUserFile = fileExists(resolvedPath, ["ts"]);
7354
- if (!maybeUserFile) {
7355
- throw new Error(
7356
- "Missing blokkli adapter file in ~/app/blokkli.editAdapter.ts"
7357
- );
7358
- }
7359
- return addTemplate({
7360
- filename: resolvedFilename,
7361
- write: true,
7362
- getContents: () => `
7363
- import type { BlokkliAdapterFactory } from '${IMPORTS.ADAPTER}'
7364
- import adapter from '${relative(blokkliBuildDir, resolvedPath)}'
7365
-
7366
- export default adapter as BlokkliAdapterFactory<any>
7367
- `
7368
- });
7369
- })();
7370
- nuxt.options.alias["#blokkli-build/compiled-edit-adapter"] = adapterTemplate.dst;
7371
8129
  nuxt.options.build.transpile.push(resolver.resolve("runtime"));
7372
- addComponent({
7373
- filePath: resolver.resolve("./runtime/components/BlokkliField"),
7374
- name: "BlokkliField",
7375
- global: true
7376
- });
7377
- addComponent({
7378
- filePath: resolver.resolve("./runtime/components/BlokkliEditable"),
7379
- name: "BlokkliEditable",
7380
- global: true
7381
- });
7382
- addComponent({
7383
- filePath: resolver.resolve("./runtime/components/BlokkliProvider"),
7384
- name: "BlokkliProvider",
7385
- global: true
7386
- });
7387
- addComponent({
7388
- filePath: resolver.resolve("./runtime/components/BlokkliItem"),
7389
- name: "BlokkliItem",
7390
- global: true
7391
- });
7392
- addBuildPlugin(DefinitionPlugin(nuxt));
7393
- addImports({
7394
- name: "defineBlokkli",
7395
- from: resolver.resolve("./runtime/composables/defineBlokkli"),
7396
- as: "defineBlokkli"
7397
- });
7398
- addImports({
7399
- name: "defineBlokkliFragment",
7400
- from: resolver.resolve("./runtime/composables/defineBlokkliFragment"),
7401
- as: "defineBlokkliFragment"
7402
- });
7403
- addImports({
7404
- name: "defineBlokkliFeature",
7405
- from: resolver.resolve("./runtime/composables/defineBlokkliFeature"),
7406
- as: "defineBlokkliFeature"
7407
- });
7408
- addImports({
7409
- name: "useBlokkli",
7410
- from: resolver.resolve("./runtime/composables/useBlokkli"),
7411
- as: "useBlokkli"
7412
- });
7413
- nuxt.options.alias["#blokkli-build/styles"] = resolver.resolve(
7414
- "./runtime/css/output.css"
7415
- );
7416
- const templateGeneratedTypes = addTemplate({
7417
- write: true,
7418
- filename: "blokkli/generated-types.ts",
7419
- getContents: () => {
7420
- return blockExtractor.generateTypesTemplate(
7421
- moduleOptions.globalOptions || {},
7422
- getChunkNames(),
7423
- getFieldListTypes(),
7424
- moduleOptions.getBundlePropsType
7425
- );
7426
- },
7427
- options: {
7428
- blokkli: true
7429
- }
7430
- });
7431
- nuxt.options.alias["#blokkli-build/generated-types"] = templateGeneratedTypes.dst;
7432
- const { themeCss, fullTheme, hasCustomTheme } = buildThemeData(
7433
- moduleOptions.theme
7434
- );
7435
- const templateThemeCss = addTemplate({
7436
- write: true,
7437
- filename: "blokkli/theme.css",
7438
- getContents: () => {
7439
- return themeCss;
7440
- },
7441
- options: {
7442
- blokkli: true
7443
- }
7444
- });
7445
- nuxt.options.alias["#blokkli-build/theme"] = templateThemeCss.dst;
7446
- const templateConfig = addTemplate({
7447
- write: true,
7448
- filename: "blokkli/config.ts",
7449
- getContents: () => {
7450
- const settingsOverride = moduleOptions.settingsOverride || {};
7451
- return `import type { Theme } from '${IMPORTS.TYPES_THEME}'
7452
- import type { ModuleOptionsSettings } from '${IMPORTS.TYPES_GENERATED_MODULE_TYPED}'
7453
-
7454
- export const hasCustomTheme = ${JSON.stringify(hasCustomTheme)}
7455
- export const themes: Record<string, Theme> = ${JSON.stringify(themes, null, 2)}
7456
- export const theme: Theme = ${JSON.stringify(fullTheme, null, 2)}
7457
-
7458
- export const settingsOverride: ModuleOptionsSettings = ${JSON.stringify(
7459
- settingsOverride
7460
- )}
7461
-
7462
- export const blokkliVersion = ${JSON.stringify(version)}
7463
-
7464
- export const storageDefaults: Record<string, string|boolean|string[]> = ${JSON.stringify(
7465
- moduleOptions.storageDefaults || {}
7466
- )}
7467
- export const defaultLanguage: string = ${JSON.stringify(
7468
- moduleOptions.defaultLanguage || "en"
7469
- )}
7470
- export const forceDefaultLanguage: boolean = ${JSON.stringify(
7471
- !!moduleOptions.forceDefaultLanguage
7472
- )}
7473
- `;
7474
- },
7475
- options: {
7476
- blokkli: true
7477
- }
7478
- });
7479
- nuxt.options.alias["#blokkli-build/config"] = templateConfig.dst;
7480
- const templateDefaultGlobalOptions = addTemplate({
7481
- write: true,
7482
- filename: "blokkli/default-global-options.ts",
7483
- getContents: () => {
7484
- return blockExtractor.generateDefaultGlobalOptions(
7485
- moduleOptions.globalOptions || {}
7486
- );
7487
- },
7488
- options: {
7489
- blokkli: true
7490
- }
7491
- });
7492
- nuxt.options.alias["#blokkli-build/default-global-options"] = templateDefaultGlobalOptions.dst;
7493
- let optionsSchemaTemplate = null;
7494
- const generateOptionsSchema = async () => {
7495
- const outputPath = moduleOptions.schemaOptionsPath;
7496
- if (outputPath) {
7497
- const resolvedPath2 = await srcResolver.resolvePath(outputPath);
7498
- const content = blockExtractor.generateOptionsSchema(
7499
- moduleOptions.globalOptions || {}
7500
- );
7501
- return promises.writeFile(resolvedPath2, content);
7502
- }
7503
- if (optionsSchemaTemplate) {
7504
- return;
7505
- }
7506
- optionsSchemaTemplate = addTemplate({
7507
- write: true,
7508
- filename: "blokkli/options-schema.json",
7509
- getContents: () => {
7510
- return blockExtractor.generateOptionsSchema(
7511
- moduleOptions.globalOptions || {}
7512
- );
7513
- },
7514
- options: {
7515
- blokkli: true
7516
- }
7517
- });
7518
- };
7519
- await generateOptionsSchema();
7520
- getChunkNames().forEach((chunkName) => {
7521
- if (chunkName !== "global" && !nuxt.options.dev) {
7522
- addTemplate({
7523
- write: true,
7524
- filename: `blokkli/chunk-${chunkName}.ts`,
7525
- getContents: () => {
7526
- return blockExtractor.generateChunkGroupTemplate(chunkName);
7527
- },
7528
- options: {
7529
- blokkli: true
7530
- }
7531
- });
7532
- }
7533
- });
7534
- const templateImports = addTemplate({
7535
- write: true,
7536
- filename: "blokkli/imports.ts",
7537
- getContents: () => {
7538
- return blockExtractor.generateImportsTemplate(
7539
- nuxt.options.dev ? ["global"] : getChunkNames()
7540
- );
7541
- },
7542
- options: {
7543
- blokkli: true
7544
- }
7545
- });
7546
- const templateIcons = addTemplate({
7547
- write: true,
7548
- filename: "blokkli/icons.ts",
7549
- getContents: async () => {
7550
- const pathModule = resolver.resolve("./runtime/icons");
7551
- const filesModule = await resolveFiles(pathModule, "*.svg");
7552
- const filesApp = await resolveFiles(
7553
- srcDir,
7554
- "components/**/icon-blokkli-*.svg"
7555
- );
7556
- const icons = await Promise.all(
7557
- [...filesModule, ...filesApp].map((filePath) => {
7558
- return promises.readFile(filePath).then((data) => {
7559
- const name = basename(filePath, ".svg").toLowerCase();
7560
- return {
7561
- markup: data.toString(),
7562
- name
7563
- };
7564
- });
7565
- })
7566
- );
7567
- const iconMap = icons.reduce((acc, v) => {
7568
- acc[v.name] = v.markup;
7569
- return acc;
7570
- }, {});
7571
- return `export const icons = ${JSON.stringify(iconMap)} as const
7572
- export type BlokkliIcon = keyof typeof icons`;
7573
- },
7574
- options: {
7575
- blokkli: true
7576
- }
7577
- });
7578
- nuxt.options.alias["#blokkli-build/icons"] = templateIcons.dst;
7579
- nuxt.options.alias["#blokkli-build/imports"] = templateImports.dst;
7580
- nuxt.options.alias["#blokkli/types"] = resolver.resolve("runtime/types");
7581
- nuxt.options.alias["#blokkli/constants"] = resolver.resolve("runtime/constants");
7582
- nuxt.options.alias["#blokkli/plugins"] = resolver.resolve(
7583
- "runtime/blokkliPlugins"
8130
+ helper.addComponent("BlokkliField");
8131
+ helper.addComponent("BlokkliEditable");
8132
+ helper.addComponent("BlokkliProvider");
8133
+ helper.addComponent("BlokkliItem");
8134
+ helper.addComposable("defineBlokkli");
8135
+ helper.addComposable("defineBlokkliFragment");
8136
+ helper.addComposable("defineBlokkliFeature");
8137
+ helper.addComposable("useBlokkli");
8138
+ helper.addAlias("#blokkli-build", helper.paths.blokkliBuildDir);
8139
+ helper.addAlias("#blokkli/types", resolver.resolve("runtime/types"));
8140
+ helper.addAlias("#blokkli/constants", resolver.resolve("runtime/constants"));
8141
+ helper.addAlias(
8142
+ "#blokkli/plugins",
8143
+ resolver.resolve("runtime/blokkliPlugins")
7584
8144
  );
7585
- nuxt.options.alias["#blokkli/components"] = resolver.resolve(
7586
- "runtime/components/Edit"
8145
+ helper.addAlias(
8146
+ "#blokkli/components",
8147
+ resolver.resolve("runtime/components/Edit")
7587
8148
  );
7588
- nuxt.options.alias["#blokkli/helpers"] = resolver.resolve("runtime/helpers");
7589
- nuxt.options.alias["#blokkli/adapter"] = resolver.resolve("runtime/adapter");
7590
- nuxt.options.alias["#blokkli/runtime-helpers"] = resolver.resolve(
7591
- "runtime/helpers/runtimeHelpers"
8149
+ helper.addAlias("#blokkli/helpers", resolver.resolve("runtime/helpers"));
8150
+ helper.addAlias("#blokkli/adapter", resolver.resolve("runtime/adapter"));
8151
+ helper.addAlias(
8152
+ "#blokkli/runtime-helpers",
8153
+ resolver.resolve("runtime/helpers/runtimeHelpers")
7592
8154
  );
7593
8155
  nuxt.hook("nitro:config", (nitroConfig) => {
7594
8156
  nitroConfig.publicAssets ||= [];
@@ -7601,43 +8163,22 @@ export type BlokkliIcon = keyof typeof icons`;
7601
8163
  addPlugin({
7602
8164
  src: resolver.resolve("runtime/plugins/blokkliEditable")
7603
8165
  });
7604
- const applies = (path) => {
7605
- const filePath = srcResolver.resolve(path);
7606
- if (!POSSIBLE_EXTENSIONS.includes(extname(filePath))) {
7607
- return Promise.resolve(void 0);
7608
- }
7609
- return resolveFiles(srcDir, importPattern, {
7610
- followSymbolicLinks: false
7611
- }).then((files2) => {
7612
- return files2.find((v) => v === filePath);
7613
- });
7614
- };
8166
+ addBuildPlugin(RuntimeDefinitionPlugin(nuxt, "defineBlokkli"));
8167
+ addBuildPlugin(RuntimeDefinitionPlugin(nuxt, "defineBlokkliFragment"));
7615
8168
  if (nuxt.options.dev) {
7616
- nuxt.hook("vite:serverCreated", (viteServer) => {
7617
- nuxt.hook("builder:watch", async (_event, path) => {
7618
- const filePath = await applies(path);
7619
- if (!filePath) {
7620
- return;
7621
- }
7622
- const hasChanged = await blockExtractor.handleFile(filePath);
7623
- if (!hasChanged) {
7624
- return;
7625
- }
7626
- await updateTemplates({
7627
- filter: (template) => {
7628
- return template.options && template.options.blokkli;
7629
- }
7630
- });
7631
- await generateOptionsSchema();
7632
- const modules = viteServer.moduleGraph.getModulesByFile(
7633
- templateDefinitions.dst
7634
- );
7635
- if (modules) {
7636
- modules.forEach((v) => {
7637
- viteServer.reloadModule(v);
7638
- });
8169
+ nuxt.hook("builder:watch", async (event, providedFilePath) => {
8170
+ const filePath = providedFilePath.startsWith("/") ? providedFilePath : helper.resolvers.src.resolve(providedFilePath);
8171
+ helper.fileCache.handleWatchEvent(event, filePath);
8172
+ const dependenciesToUpdate = [];
8173
+ for (const collector of collectors) {
8174
+ const result = await collector.handleWatchEvent(event, filePath);
8175
+ if (result.hasChanged) {
8176
+ dependenciesToUpdate.push(...collector.getDependencyTypes());
7639
8177
  }
7640
- });
8178
+ }
8179
+ if (dependenciesToUpdate.length) {
8180
+ await context.generateTemplates(dependenciesToUpdate);
8181
+ }
7641
8182
  });
7642
8183
  }
7643
8184
  }