mechanica 1.0.25 → 2.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +123 -0
  3. package/bin/mechanica.js +11 -0
  4. package/dist/chunks/ImagePickerDialog-DZyxrbfv.js +468 -0
  5. package/dist/chunks/page-assets-DnDUQegn.js +534 -0
  6. package/dist/chunks/preview-uxnrJ5vY.js +431 -0
  7. package/dist/cli.js +0 -0
  8. package/dist/editor.css +2671 -0
  9. package/dist/editor.js +4851 -6469
  10. package/dist/index.js +230 -0
  11. package/dist/plugin.js +916 -547
  12. package/dist/types/cli/args.d.ts +8 -0
  13. package/dist/types/cli/build.d.ts +10 -0
  14. package/dist/types/cli/cli.d.ts +2 -0
  15. package/dist/types/cli/export.d.ts +40 -0
  16. package/dist/types/cli/headless.d.ts +60 -0
  17. package/dist/types/cli/page-assets.d.ts +65 -0
  18. package/dist/types/cli/push.d.ts +10 -0
  19. package/dist/types/cli/shot.d.ts +36 -0
  20. package/dist/types/cli/thumbs.d.ts +35 -0
  21. package/dist/types/compiler/compile-block.d.ts +45 -0
  22. package/dist/types/core/content.d.ts +7 -0
  23. package/dist/types/core/create-mechanica.d.ts +25 -0
  24. package/dist/types/core/data-registry.d.ts +15 -0
  25. package/dist/types/core/define-block.d.ts +48 -0
  26. package/dist/types/core/define-data.d.ts +26 -0
  27. package/dist/types/core/define-mechanica-app.d.ts +31 -0
  28. package/dist/types/core/field-types.d.ts +34 -0
  29. package/dist/types/core/index.d.ts +17 -0
  30. package/dist/types/core/link.d.ts +32 -0
  31. package/dist/types/core/load-blocks.d.ts +20 -0
  32. package/dist/types/core/preview.d.ts +54 -0
  33. package/dist/types/core/query.d.ts +8 -0
  34. package/dist/types/core/render-blocks.d.ts +15 -0
  35. package/dist/types/core/router.d.ts +42 -0
  36. package/dist/types/core/state.d.ts +30 -0
  37. package/dist/types/core/use-fetch.d.ts +8 -0
  38. package/dist/types/core/use-page-data.d.ts +3 -0
  39. package/dist/types/core/use-pages.d.ts +33 -0
  40. package/dist/types/core/use-pagination.d.ts +32 -0
  41. package/dist/types/editor/editor.d.ts +1 -0
  42. package/dist/types/editor/fields/builtin.d.ts +2 -0
  43. package/dist/types/editor/fields/registry.d.ts +27 -0
  44. package/dist/types/editor/fields/richtext/config.d.ts +17 -0
  45. package/dist/types/editor/fields/richtext/keys.d.ts +10 -0
  46. package/dist/types/editor/fields/richtext/widgets.d.ts +43 -0
  47. package/dist/types/editor/lib/block-meta.d.ts +24 -0
  48. package/dist/types/editor/lib/block-preview.d.ts +23 -0
  49. package/dist/types/editor/lib/bridge.d.ts +38 -0
  50. package/dist/types/editor/lib/content-tree.d.ts +42 -0
  51. package/dist/types/editor/lib/context-menu.d.ts +28 -0
  52. package/dist/types/editor/lib/drag-controller.d.ts +58 -0
  53. package/dist/types/editor/lib/history.d.ts +20 -0
  54. package/dist/types/editor/lib/navigation.d.ts +16 -0
  55. package/dist/types/editor/lib/page-list.d.ts +30 -0
  56. package/dist/types/editor/lib/panel-dock.d.ts +38 -0
  57. package/dist/types/editor/lib/recents.d.ts +8 -0
  58. package/dist/types/editor/lib/save-queue.d.ts +56 -0
  59. package/dist/types/editor/lib/shortcuts.d.ts +17 -0
  60. package/dist/types/editor/lib/store.d.ts +64 -0
  61. package/dist/types/editor/lib/tree-ui.d.ts +11 -0
  62. package/dist/types/editor/lib/types.d.ts +22 -0
  63. package/dist/types/editor/lib/use-block-frames.d.ts +62 -0
  64. package/dist/types/editor/props-panel/humanize.d.ts +2 -0
  65. package/dist/types/editor/props-panel/use-reorder.d.ts +22 -0
  66. package/dist/types/editor/ui/dialog.d.ts +23 -0
  67. package/dist/types/editor/widget-api.d.ts +35 -0
  68. package/dist/types/index.d.ts +1 -0
  69. package/dist/types/svg-plugin.d.ts +2 -0
  70. package/dist/types/vite/collect-blocks.d.ts +28 -0
  71. package/dist/types/vite/collect-widgets.d.ts +12 -0
  72. package/dist/types/vite/dev/assets-store.d.ts +13 -0
  73. package/dist/types/vite/dev/data-store.d.ts +15 -0
  74. package/dist/types/vite/dev/fs-utils.d.ts +6 -0
  75. package/dist/types/vite/dev/middleware.d.ts +19 -0
  76. package/dist/types/vite/dev/page-state.d.ts +24 -0
  77. package/dist/types/vite/dev/pages-store.d.ts +89 -0
  78. package/dist/types/vite/dev/preview.d.ts +16 -0
  79. package/dist/types/vite/dev/query-dev.d.ts +13 -0
  80. package/dist/types/vite/entries.d.ts +43 -0
  81. package/dist/types/vite/index.d.ts +5 -0
  82. package/dist/types/vite/plugin.d.ts +37 -0
  83. package/dist/types/vite/rich-text-codec.d.ts +18 -0
  84. package/dist/widgets.js +35 -0
  85. package/package.json +67 -44
  86. package/src/cli/args.ts +33 -0
  87. package/src/cli/build.ts +41 -0
  88. package/src/cli/cli.ts +60 -0
  89. package/src/cli/export.ts +0 -0
  90. package/src/cli/headless.ts +361 -0
  91. package/src/cli/page-assets.ts +114 -0
  92. package/src/cli/push.ts +64 -0
  93. package/src/cli/shot.ts +237 -0
  94. package/src/cli/thumbs.ts +244 -0
  95. package/src/compiler/compile-block.ts +212 -0
  96. package/src/core/content.ts +24 -0
  97. package/src/core/create-mechanica.ts +107 -0
  98. package/src/core/data-registry.ts +34 -0
  99. package/src/core/define-block.ts +51 -0
  100. package/src/core/define-data.ts +59 -0
  101. package/src/core/define-mechanica-app.ts +54 -0
  102. package/src/core/field-types.ts +22 -0
  103. package/src/core/index.ts +48 -0
  104. package/src/core/link.ts +70 -0
  105. package/src/core/load-blocks.ts +38 -0
  106. package/src/core/preview.ts +221 -0
  107. package/src/core/query.ts +39 -0
  108. package/src/core/render-blocks.ts +42 -0
  109. package/src/core/router.ts +137 -0
  110. package/src/core/state.ts +35 -0
  111. package/src/core/use-fetch.ts +14 -0
  112. package/src/core/use-page-data.ts +10 -0
  113. package/src/core/use-pages.ts +39 -0
  114. package/src/core/use-pagination.ts +75 -0
  115. package/src/editor/EditorApp.vue +350 -0
  116. package/src/editor/components/BlockFrame.vue +18 -0
  117. package/src/editor/components/BlockPalette.vue +248 -0
  118. package/src/editor/components/BlockPreview.vue +127 -0
  119. package/src/editor/components/BlockSettings.vue +21 -0
  120. package/src/editor/components/DataSettings.vue +226 -0
  121. package/src/editor/components/HierarchyTree.vue +568 -0
  122. package/src/editor/components/PageBar.vue +109 -0
  123. package/src/editor/components/PanelToggle.vue +161 -0
  124. package/src/editor/components/VContextMenu.vue +179 -0
  125. package/src/editor/components/VIcon.vue +20 -0
  126. package/src/editor/components/VPopover.vue +129 -0
  127. package/src/editor/components/VSelect.vue +200 -0
  128. package/src/editor/dialogs/ConfirmDialog.vue +48 -0
  129. package/src/editor/dialogs/DataDialog.vue +16 -0
  130. package/src/editor/dialogs/ImagePickerDialog.vue +190 -0
  131. package/src/editor/dialogs/PagesDialog.vue +488 -0
  132. package/src/editor/dialogs/QuickSwitcher.vue +208 -0
  133. package/src/editor/dialogs/RichTextDialog.vue +38 -0
  134. package/src/editor/editor.ts +173 -0
  135. package/src/editor/fields/FieldControl.vue +31 -0
  136. package/src/editor/fields/builtin.ts +29 -0
  137. package/src/editor/fields/editors/BooleanField.vue +12 -0
  138. package/src/editor/fields/editors/ColorField.vue +12 -0
  139. package/src/editor/fields/editors/EnumField.vue +33 -0
  140. package/src/editor/fields/editors/ImageField.vue +132 -0
  141. package/src/editor/fields/editors/MultiselectField.vue +35 -0
  142. package/src/editor/fields/editors/NumberField.vue +12 -0
  143. package/src/editor/fields/editors/RichTextField.vue +59 -0
  144. package/src/editor/fields/editors/SmartLinkField.vue +457 -0
  145. package/src/editor/fields/editors/StringField.vue +15 -0
  146. package/src/editor/fields/editors/TextField.vue +15 -0
  147. package/src/editor/fields/registry.ts +52 -0
  148. package/src/editor/fields/richtext/RichCodeWidget.vue +120 -0
  149. package/src/editor/fields/richtext/RichImageWidget.vue +129 -0
  150. package/src/editor/fields/richtext/RichTableWidget.vue +54 -0
  151. package/src/editor/fields/richtext/RichTextEditor.vue +612 -0
  152. package/src/editor/fields/richtext/WidgetBoundary.vue +45 -0
  153. package/src/editor/fields/richtext/config.ts +77 -0
  154. package/src/editor/fields/richtext/keys.ts +12 -0
  155. package/src/editor/fields/richtext/widgets.ts +117 -0
  156. package/src/editor/icons/arrow-down.svg +1 -0
  157. package/src/editor/icons/arrow-up.svg +1 -0
  158. package/src/editor/icons/bold.svg +1 -0
  159. package/src/editor/icons/book.svg +1 -0
  160. package/src/editor/icons/check.svg +1 -0
  161. package/src/editor/icons/chevron-down.svg +1 -0
  162. package/src/editor/icons/close.svg +1 -0
  163. package/src/editor/icons/code.svg +1 -0
  164. package/src/editor/icons/copy.svg +1 -0
  165. package/src/editor/icons/ellipsis.svg +1 -0
  166. package/src/editor/icons/folder.svg +1 -0
  167. package/src/editor/icons/grip.svg +1 -0
  168. package/src/editor/icons/image.svg +1 -0
  169. package/src/editor/icons/info.svg +1 -0
  170. package/src/editor/icons/italic.svg +1 -0
  171. package/src/editor/icons/menu.svg +1 -0
  172. package/src/editor/icons/named-slots.svg +1 -0
  173. package/src/editor/icons/pencil.svg +1 -0
  174. package/src/editor/icons/plus.svg +1 -0
  175. package/src/editor/icons/redo.svg +1 -0
  176. package/src/editor/icons/search.svg +1 -0
  177. package/src/editor/icons/sliders.svg +1 -0
  178. package/src/editor/icons/slot.svg +1 -0
  179. package/src/editor/icons/strikethrough.svg +1 -0
  180. package/src/editor/icons/table.svg +4 -0
  181. package/src/editor/icons/trash.svg +1 -0
  182. package/src/editor/icons/underline.svg +1 -0
  183. package/src/editor/icons/undo.svg +1 -0
  184. package/src/editor/icons/upload.svg +1 -0
  185. package/src/editor/lib/block-meta.ts +72 -0
  186. package/src/editor/lib/block-preview.ts +78 -0
  187. package/src/editor/lib/bridge.ts +90 -0
  188. package/src/editor/lib/content-tree.ts +186 -0
  189. package/src/editor/lib/context-menu.ts +50 -0
  190. package/src/editor/lib/drag-controller.ts +217 -0
  191. package/src/editor/lib/history.ts +91 -0
  192. package/src/editor/lib/navigation.ts +31 -0
  193. package/src/editor/lib/page-list.ts +62 -0
  194. package/src/editor/lib/panel-dock.ts +97 -0
  195. package/src/editor/lib/recents.ts +31 -0
  196. package/src/editor/lib/save-queue.ts +156 -0
  197. package/src/editor/lib/shortcuts.ts +49 -0
  198. package/src/editor/lib/store.ts +295 -0
  199. package/src/editor/lib/tree-ui.ts +33 -0
  200. package/src/editor/lib/types.ts +24 -0
  201. package/src/editor/lib/use-block-frames.ts +125 -0
  202. package/src/editor/props-panel/ArrayField.vue +106 -0
  203. package/src/editor/props-panel/SchemaField.vue +45 -0
  204. package/src/editor/props-panel/SchemaForm.vue +21 -0
  205. package/src/editor/props-panel/VCollapse.vue +28 -0
  206. package/src/editor/props-panel/humanize.ts +8 -0
  207. package/src/editor/props-panel/use-reorder.ts +90 -0
  208. package/src/editor/styles/_variables.scss +54 -0
  209. package/src/editor/styles/editor.scss +915 -0
  210. package/src/editor/ui/VDialog.vue +95 -0
  211. package/src/editor/ui/VDialogHost.vue +108 -0
  212. package/src/editor/ui/dialog.ts +47 -0
  213. package/src/editor/widget-api.ts +46 -0
  214. package/src/index.ts +1 -0
  215. package/src/svg-plugin.ts +108 -0
  216. package/src/virtual-modules.d.ts +18 -0
  217. package/src/vite/collect-blocks.ts +99 -0
  218. package/src/vite/collect-widgets.ts +54 -0
  219. package/src/vite/dev/assets-store.ts +45 -0
  220. package/src/vite/dev/data-store.ts +61 -0
  221. package/src/vite/dev/fs-utils.ts +41 -0
  222. package/src/vite/dev/middleware.ts +197 -0
  223. package/src/vite/dev/page-state.ts +60 -0
  224. package/src/vite/dev/pages-store.ts +290 -0
  225. package/src/vite/dev/preview.ts +69 -0
  226. package/src/vite/dev/query-dev.ts +27 -0
  227. package/src/vite/entries.ts +124 -0
  228. package/src/vite/index.ts +16 -0
  229. package/src/vite/plugin.ts +442 -0
  230. package/src/vite/rich-text-codec.ts +48 -0
  231. package/src/vue-shim.d.ts +14 -0
  232. package/bin/bin.js +0 -37
  233. package/bin/build.js +0 -63
  234. package/bin/compile.js +0 -478
  235. package/bin/push.js +0 -80
  236. package/dist/editor.d.ts +0 -1
  237. package/dist/editor.js.map +0 -1
  238. package/dist/main.d.ts +0 -214
  239. package/dist/main.js +0 -314
  240. package/dist/main.js.map +0 -1
  241. package/dist/plugin.d.ts +0 -11
  242. package/dist/plugin.js.map +0 -1
  243. package/dist/schemaAliases-t4X-kaIk.js +0 -59
  244. package/dist/schemaAliases-t4X-kaIk.js.map +0 -1
  245. package/dist/style.css +0 -1448
  246. package/dist/updater.d.ts +0 -1
  247. package/dist/updater.js +0 -26
  248. package/dist/updater.js.map +0 -1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 den59k
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,123 @@
1
+ # mechanica
2
+
3
+ Build Vue 3 websites with a visual block editor. Authors write Vue SFC **blocks**, a visual editor arranges them into pages, and the result renders server-side and ships statically or via a backend.
4
+
5
+ Built for **Vite 8 / Vue 3.5 / Bun**.
6
+
7
+ ## Install
8
+
9
+ Works with plain Node ≥ 20.19 (npm/pnpm/yarn) or [Bun](https://bun.sh) — Bun installs run the TypeScript source directly, Node uses the compiled build. The fastest start is the scaffolder:
10
+
11
+ ```bash
12
+ npm create mechanica-app@latest my-site
13
+ # or: bun create mechanica-app my-site
14
+ ```
15
+
16
+ Or add it to an existing Vite + Vue project:
17
+
18
+ ```bash
19
+ npm install mechanica
20
+ ```
21
+
22
+ ## Quick start
23
+
24
+ **`vite.config.ts`**
25
+ ```ts
26
+ import { defineConfig } from 'vite'
27
+ import vue from '@vitejs/plugin-vue'
28
+ import { mechanica } from 'mechanica/plugin'
29
+
30
+ export default defineConfig({
31
+ plugins: [mechanica(), vue()],
32
+ })
33
+ ```
34
+
35
+ **`index.html`** — just a mount point; the plugin injects the entry and editor:
36
+ ```html
37
+ <body><div id="app"></div></body>
38
+ ```
39
+
40
+ **`src/main.ts`** — export an app definition (no `createApp`/`mount` yourself):
41
+ ```ts
42
+ import { defineMechanicaApp } from 'mechanica'
43
+ import App from './App.vue'
44
+
45
+ export default defineMechanicaApp({ root: App })
46
+ ```
47
+
48
+ **`src/App.vue`** — render the page content somewhere:
49
+ ```vue
50
+ <template>
51
+ <Content />
52
+ </template>
53
+ <script setup lang="ts">
54
+ import { Content } from 'mechanica'
55
+ </script>
56
+ ```
57
+
58
+ **`src/blocks/Hero.vue`** — a block. `defineBlock` is a global macro (no import):
59
+ ```vue
60
+ <template>
61
+ <section>
62
+ <h1>{{ props.title }}</h1>
63
+ <p>{{ props.subtitle }}</p>
64
+ </section>
65
+ </template>
66
+ <script setup lang="ts">
67
+ const props = defineBlock({
68
+ name: 'Hero',
69
+ category: 'Content',
70
+ props: {
71
+ title: { type: 'string', default: 'Hello' },
72
+ subtitle: 'text',
73
+ },
74
+ })
75
+ </script>
76
+ ```
77
+
78
+ Run `vite` and open the page — the editor overlay lets you add Hero blocks and edit their props live.
79
+
80
+ ## Authoring API
81
+
82
+ ### `defineBlock(descriptor)` — the one macro
83
+ No import; used inside a block's `<script setup>`. Fields use [compact-json-schema](https://www.npmjs.com/package/compact-json-schema). Built-in field types: `string`, `text`, `number`, `boolean`, `color`, `image`, `file`, `smartLink`, `multiselect`, `richText`, plus `array`/`object`. Object-form fields take editor metadata (`label`, `description`, `default`, `placeholder`).
84
+
85
+ ```ts
86
+ defineBlock({
87
+ name, category, icon, description, order, hidden,
88
+ props: { /* schema */ },
89
+ slots: ['default'], // auto-detected from <slot> if omitted
90
+ })
91
+ ```
92
+
93
+ ### `defineData({ id, scope, props })` — shared data
94
+ An **imported function** (not a macro), used in a standalone module; returns a hook:
95
+ ```ts
96
+ // data/header.ts
97
+ import { defineData } from 'mechanica'
98
+ export const useHeader = defineData({ id: 'header', scope: 'site', props: { logo: 'image' } })
99
+ // in a component: const header = useHeader()
100
+ ```
101
+
102
+ ### Components & composables
103
+ `<Content>`, `<Link :to="..." />` (string path or `smartLink` object), `useRouter`, `useRoute`, `usePages`, `useFetch`, `usePageData`.
104
+
105
+ ### Custom field types
106
+ ```ts
107
+ import { defineFieldType, registerFields } from 'mechanica/editor'
108
+ registerFields([
109
+ defineFieldType({ name: 'video', schema: { type: 'object', properties: { src: 'string' } }, editor: VideoField }),
110
+ ])
111
+ ```
112
+
113
+ ## CLI
114
+
115
+ ```bash
116
+ mechanica build # client + SSR bundles → dist/
117
+ mechanica export # statically render every .mech page → export/
118
+ mechanica shot <blockId | /page/path> # headless screenshot of a block or page
119
+ mechanica thumbs [--blocks] # regenerate page / block thumbnails
120
+ mechanica push --key <apiKey> --host <url> # upload dist/ to a backend
121
+ ```
122
+
123
+ Page content lives in `.mech/pages/**.page.md` — a human-readable, Markdown-centric format equally editable by the visual editor, by hand, and by AI tools (rich text persists as plain Markdown).
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ // Under Bun, run the TS source directly (monorepo dev, Bun-native installs —
3
+ // always live, no build needed). Under Node, use the compiled CLI from dist/.
4
+ const entry = process.versions.bun ? '../src/cli/cli.ts' : '../dist/cli.js'
5
+
6
+ const { run } = await import(entry)
7
+
8
+ run(process.argv.slice(2)).catch((error) => {
9
+ console.error(error)
10
+ process.exit(1)
11
+ })
@@ -0,0 +1,468 @@
1
+ import { Fragment, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, inject, mergeProps, normalizeClass, onMounted, openBlock, ref, renderList, renderSlot, shallowReactive, toDisplayString, unref, withCtx, withModifiers } from "vue";
2
+ //#region \0svg-glob:C:\Users\Den\Desktop\CURVES\mechanica\packages\mechanica\src\editor\icons
3
+ var contents = {
4
+ "arrow-down": `<path d="M12 5v14"/><path d="m19 12-7 7-7-7"/>`,
5
+ "arrow-up": `<path d="M12 19V5"/><path d="m5 12 7-7 7 7"/>`,
6
+ "bold": `<path d="M6 4h7a4 4 0 0 1 0 8H6z"/><path d="M6 12h8a4 4 0 0 1 0 8H6z"/>`,
7
+ "book": `<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/>`,
8
+ "check": `<polyline points="20 6 9 17 4 12"/>`,
9
+ "chevron-down": `<path d="m6 9 6 6 6-6"/>`,
10
+ "close": `<path d="M18 6 6 18"/><path d="m6 6 12 12"/>`,
11
+ "code": `<polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/>`,
12
+ "copy": `<rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/>`,
13
+ "ellipsis": `<circle cx="5" cy="12" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="19" cy="12" r="2"/>`,
14
+ "folder": `<path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>`,
15
+ "grip": `<circle cx="9" cy="5" r="1.6"/><circle cx="9" cy="12" r="1.6"/><circle cx="9" cy="19" r="1.6"/><circle cx="15" cy="5" r="1.6"/><circle cx="15" cy="12" r="1.6"/><circle cx="15" cy="19" r="1.6"/>`,
16
+ "image": `<rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/>`,
17
+ "info": `<circle cx="12" cy="12" r="9"/><line x1="12" y1="11" x2="12" y2="16"/><line x1="12" y1="8" x2="12.01" y2="8"/>`,
18
+ "italic": `<line x1="19" y1="4" x2="10" y2="4"/><line x1="14" y1="20" x2="5" y2="20"/><line x1="15" y1="4" x2="9" y2="20"/>`,
19
+ "menu": `<path d="M3 6h18"/><path d="M3 12h18"/><path d="M3 18h18"/>`,
20
+ "named-slots": `<rect x="4" y="4" width="16" height="16" rx="2.5" stroke-dasharray="3.5 3"/><path d="M12 4.5v15"/>`,
21
+ "pencil": `<path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4Z"/>`,
22
+ "plus": `<path d="M12 5v14"/><path d="M5 12h14"/>`,
23
+ "redo": `<path d="M21 7v6h-6"/><path d="M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6 2.3L21 13"/>`,
24
+ "search": `<circle cx="11" cy="11" r="7"/><path d="m21 21-4.35-4.35"/>`,
25
+ "sliders": `<line x1="21" x2="14" y1="4" y2="4"/><line x1="10" x2="3" y1="4" y2="4"/><line x1="21" x2="12" y1="12" y2="12"/><line x1="8" x2="3" y1="12" y2="12"/><line x1="21" x2="16" y1="20" y2="20"/><line x1="12" x2="3" y1="20" y2="20"/><line x1="14" x2="14" y1="2" y2="6"/><line x1="8" x2="8" y1="10" y2="14"/><line x1="16" x2="16" y1="18" y2="22"/>`,
26
+ "slot": `<rect x="4" y="4" width="16" height="16" rx="2.5" stroke-dasharray="3.5 3"/>`,
27
+ "strikethrough": `<path d="M16 4H9a3 3 0 0 0-2.83 4"/><path d="M14 12a4 4 0 0 1 0 8H6"/><line x1="4" y1="12" x2="20" y2="12"/>`,
28
+ "table": `<rect x="3" y="4" width="18" height="16" rx="2" stroke="currentColor" stroke-width="2"/>
29
+ <path d="M3 9.5H21M9.5 9.5V20M15.5 9.5V20" stroke="currentColor" stroke-width="2"/>`,
30
+ "trash": `<path d="M3 6h18"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><path d="M10 11v6"/><path d="M14 11v6"/>`,
31
+ "underline": `<path d="M6 4v6a6 6 0 0 0 12 0V4"/><line x1="4" y1="21" x2="20" y2="21"/>`,
32
+ "undo": `<path d="M3 7v6h6"/><path d="M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6 2.3L3 13"/>`,
33
+ "upload": `<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" x2="12" y1="3" y2="15"/>`
34
+ };
35
+ var attrs = {
36
+ "arrow-down": {
37
+ "viewBox": "0 0 24 24",
38
+ "fill": "none",
39
+ "stroke": "currentColor",
40
+ "stroke-width": "2",
41
+ "stroke-linecap": "round",
42
+ "stroke-linejoin": "round"
43
+ },
44
+ "arrow-up": {
45
+ "viewBox": "0 0 24 24",
46
+ "fill": "none",
47
+ "stroke": "currentColor",
48
+ "stroke-width": "2",
49
+ "stroke-linecap": "round",
50
+ "stroke-linejoin": "round"
51
+ },
52
+ "bold": {
53
+ "viewBox": "0 0 24 24",
54
+ "fill": "none",
55
+ "stroke": "currentColor",
56
+ "stroke-width": "2.25",
57
+ "stroke-linecap": "round",
58
+ "stroke-linejoin": "round"
59
+ },
60
+ "book": {
61
+ "viewBox": "0 0 24 24",
62
+ "fill": "none",
63
+ "stroke": "currentColor",
64
+ "stroke-width": "2",
65
+ "stroke-linecap": "round",
66
+ "stroke-linejoin": "round"
67
+ },
68
+ "check": {
69
+ "viewBox": "0 0 24 24",
70
+ "fill": "none",
71
+ "stroke": "currentColor",
72
+ "stroke-width": "2.5",
73
+ "stroke-linecap": "round",
74
+ "stroke-linejoin": "round"
75
+ },
76
+ "chevron-down": {
77
+ "viewBox": "0 0 24 24",
78
+ "fill": "none",
79
+ "stroke": "currentColor",
80
+ "stroke-width": "2",
81
+ "stroke-linecap": "round",
82
+ "stroke-linejoin": "round"
83
+ },
84
+ "close": {
85
+ "viewBox": "0 0 24 24",
86
+ "fill": "none",
87
+ "stroke": "currentColor",
88
+ "stroke-width": "2",
89
+ "stroke-linecap": "round",
90
+ "stroke-linejoin": "round"
91
+ },
92
+ "code": {
93
+ "viewBox": "0 0 24 24",
94
+ "fill": "none",
95
+ "stroke": "currentColor",
96
+ "stroke-width": "2",
97
+ "stroke-linecap": "round",
98
+ "stroke-linejoin": "round"
99
+ },
100
+ "copy": {
101
+ "viewBox": "0 0 24 24",
102
+ "fill": "none",
103
+ "stroke": "currentColor",
104
+ "stroke-width": "2",
105
+ "stroke-linecap": "round",
106
+ "stroke-linejoin": "round"
107
+ },
108
+ "ellipsis": {
109
+ "viewBox": "0 0 24 24",
110
+ "fill": "currentColor"
111
+ },
112
+ "folder": {
113
+ "viewBox": "0 0 24 24",
114
+ "fill": "none",
115
+ "stroke": "currentColor",
116
+ "stroke-width": "2",
117
+ "stroke-linecap": "round",
118
+ "stroke-linejoin": "round"
119
+ },
120
+ "grip": {
121
+ "viewBox": "0 0 24 24",
122
+ "fill": "currentColor",
123
+ "stroke": "none"
124
+ },
125
+ "image": {
126
+ "width": "24",
127
+ "height": "24",
128
+ "viewBox": "0 0 24 24",
129
+ "fill": "none",
130
+ "stroke": "currentColor",
131
+ "stroke-width": "2",
132
+ "stroke-linecap": "round",
133
+ "stroke-linejoin": "round"
134
+ },
135
+ "info": {
136
+ "viewBox": "0 0 24 24",
137
+ "fill": "none",
138
+ "stroke": "currentColor",
139
+ "stroke-width": "2",
140
+ "stroke-linecap": "round",
141
+ "stroke-linejoin": "round"
142
+ },
143
+ "italic": {
144
+ "viewBox": "0 0 24 24",
145
+ "fill": "none",
146
+ "stroke": "currentColor",
147
+ "stroke-width": "2",
148
+ "stroke-linecap": "round",
149
+ "stroke-linejoin": "round"
150
+ },
151
+ "menu": {
152
+ "viewBox": "0 0 24 24",
153
+ "fill": "none",
154
+ "stroke": "currentColor",
155
+ "stroke-width": "2",
156
+ "stroke-linecap": "round",
157
+ "stroke-linejoin": "round"
158
+ },
159
+ "named-slots": {
160
+ "viewBox": "0 0 24 24",
161
+ "fill": "none",
162
+ "stroke": "currentColor",
163
+ "stroke-width": "2",
164
+ "stroke-linecap": "round",
165
+ "stroke-linejoin": "round"
166
+ },
167
+ "pencil": {
168
+ "viewBox": "0 0 24 24",
169
+ "fill": "none",
170
+ "stroke": "currentColor",
171
+ "stroke-width": "2",
172
+ "stroke-linecap": "round",
173
+ "stroke-linejoin": "round"
174
+ },
175
+ "plus": {
176
+ "viewBox": "0 0 24 24",
177
+ "fill": "none",
178
+ "stroke": "currentColor",
179
+ "stroke-width": "2",
180
+ "stroke-linecap": "round",
181
+ "stroke-linejoin": "round"
182
+ },
183
+ "redo": {
184
+ "viewBox": "0 0 24 24",
185
+ "fill": "none",
186
+ "stroke": "currentColor",
187
+ "stroke-width": "2",
188
+ "stroke-linecap": "round",
189
+ "stroke-linejoin": "round"
190
+ },
191
+ "search": {
192
+ "viewBox": "0 0 24 24",
193
+ "fill": "none",
194
+ "stroke": "currentColor",
195
+ "stroke-width": "2",
196
+ "stroke-linecap": "round",
197
+ "stroke-linejoin": "round"
198
+ },
199
+ "sliders": {
200
+ "width": "24",
201
+ "height": "24",
202
+ "viewBox": "0 0 24 24",
203
+ "fill": "none",
204
+ "stroke": "currentColor",
205
+ "stroke-width": "2",
206
+ "stroke-linecap": "round",
207
+ "stroke-linejoin": "round"
208
+ },
209
+ "slot": {
210
+ "viewBox": "0 0 24 24",
211
+ "fill": "none",
212
+ "stroke": "currentColor",
213
+ "stroke-width": "2",
214
+ "stroke-linecap": "round",
215
+ "stroke-linejoin": "round"
216
+ },
217
+ "strikethrough": {
218
+ "viewBox": "0 0 24 24",
219
+ "fill": "none",
220
+ "stroke": "currentColor",
221
+ "stroke-width": "2",
222
+ "stroke-linecap": "round",
223
+ "stroke-linejoin": "round"
224
+ },
225
+ "table": {
226
+ "viewBox": "0 0 24 24",
227
+ "fill": "none"
228
+ },
229
+ "trash": {
230
+ "viewBox": "0 0 24 24",
231
+ "fill": "none",
232
+ "stroke": "currentColor",
233
+ "stroke-width": "2",
234
+ "stroke-linecap": "round",
235
+ "stroke-linejoin": "round"
236
+ },
237
+ "underline": {
238
+ "viewBox": "0 0 24 24",
239
+ "fill": "none",
240
+ "stroke": "currentColor",
241
+ "stroke-width": "2",
242
+ "stroke-linecap": "round",
243
+ "stroke-linejoin": "round"
244
+ },
245
+ "undo": {
246
+ "viewBox": "0 0 24 24",
247
+ "fill": "none",
248
+ "stroke": "currentColor",
249
+ "stroke-width": "2",
250
+ "stroke-linecap": "round",
251
+ "stroke-linejoin": "round"
252
+ },
253
+ "upload": {
254
+ "width": "24",
255
+ "height": "24",
256
+ "viewBox": "0 0 24 24",
257
+ "fill": "none",
258
+ "stroke": "currentColor",
259
+ "stroke-width": "2",
260
+ "stroke-linecap": "round",
261
+ "stroke-linejoin": "round"
262
+ }
263
+ };
264
+ //#endregion
265
+ //#region src/editor/components/VIcon.vue?vue&type=script&setup=true&lang.ts
266
+ var _hoisted_1$2 = ["innerHTML"];
267
+ //#endregion
268
+ //#region src/editor/components/VIcon.vue
269
+ var VIcon_default = /* @__PURE__ */ defineComponent({
270
+ __name: "VIcon",
271
+ props: { name: {} },
272
+ setup(__props) {
273
+ return (_ctx, _cache) => {
274
+ return openBlock(), createElementBlock("svg", mergeProps({ class: "vicon" }, unref(attrs)[__props.name], {
275
+ "aria-hidden": "true",
276
+ innerHTML: unref(contents)[__props.name]
277
+ }), null, 16, _hoisted_1$2);
278
+ };
279
+ }
280
+ });
281
+ //#endregion
282
+ //#region \0plugin-vue:export-helper
283
+ var _plugin_vue_export_helper_default = (sfc, props) => {
284
+ const target = sfc.__vccOpts || sfc;
285
+ for (const [key, val] of props) target[key] = val;
286
+ return target;
287
+ };
288
+ //#endregion
289
+ //#region src/editor/ui/dialog.ts
290
+ var dialogKey = Symbol("mech-dialog");
291
+ /** Create the reactive dialog store (provided once by the editor shell). */
292
+ function createDialogStore() {
293
+ const stack = shallowReactive([]);
294
+ let nextId = 0;
295
+ return {
296
+ stack,
297
+ open(component, props) {
298
+ stack.push({
299
+ id: ++nextId,
300
+ component,
301
+ props
302
+ });
303
+ },
304
+ back() {
305
+ stack.pop();
306
+ },
307
+ close() {
308
+ stack.length = 0;
309
+ }
310
+ };
311
+ }
312
+ /** Access the dialog store from any component inside the editor. */
313
+ function useDialog() {
314
+ const store = inject(dialogKey);
315
+ if (!store) throw new Error("[mechanica] useDialog used outside the editor");
316
+ return store;
317
+ }
318
+ //#endregion
319
+ //#region src/editor/ui/VDialog.vue?vue&type=script&setup=true&lang.ts
320
+ var _hoisted_1$1 = { class: "mech-modal__header" };
321
+ var _hoisted_2$1 = { class: "mech-modal__title" };
322
+ var _hoisted_3$1 = { class: "mech-modal__body" };
323
+ var _hoisted_4$1 = {
324
+ key: 0,
325
+ class: "mech-modal__actions"
326
+ };
327
+ //#endregion
328
+ //#region src/editor/ui/VDialog.vue
329
+ var VDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
330
+ __name: "VDialog",
331
+ props: {
332
+ title: {},
333
+ size: { default: "standard" }
334
+ },
335
+ setup(__props) {
336
+ const dialog = useDialog();
337
+ return (_ctx, _cache) => {
338
+ return openBlock(), createElementBlock("div", {
339
+ class: normalizeClass(["mech-modal", `mech-modal--${__props.size}`]),
340
+ role: "dialog",
341
+ "aria-modal": "true",
342
+ "data-mech-ui": ""
343
+ }, [
344
+ createElementVNode("header", _hoisted_1$1, [createElementVNode("h2", _hoisted_2$1, [renderSlot(_ctx.$slots, "header", {}, () => [createTextVNode(toDisplayString(__props.title), 1)], true)]), createElementVNode("button", {
345
+ type: "button",
346
+ class: "mech-modal__close",
347
+ "aria-label": "Close",
348
+ onClick: _cache[0] || (_cache[0] = ($event) => unref(dialog).back())
349
+ }, [createVNode(VIcon_default, { name: "close" })])]),
350
+ createElementVNode("div", _hoisted_3$1, [renderSlot(_ctx.$slots, "default", {}, void 0, true)]),
351
+ _ctx.$slots.actions ? (openBlock(), createElementBlock("footer", _hoisted_4$1, [renderSlot(_ctx.$slots, "actions", {}, void 0, true)])) : createCommentVNode("", true)
352
+ ], 2);
353
+ };
354
+ }
355
+ }), [["__scopeId", "data-v-04d89005"]]);
356
+ //#endregion
357
+ //#region src/editor/dialogs/ImagePickerDialog.vue?vue&type=script&setup=true&lang.ts
358
+ var _hoisted_1 = { class: "mech-image-picker" };
359
+ var _hoisted_2 = { class: "mech-image-picker__upload-text" };
360
+ var _hoisted_3 = {
361
+ key: 0,
362
+ class: "mech-image-picker__grid"
363
+ };
364
+ var _hoisted_4 = ["title", "onClick"];
365
+ var _hoisted_5 = ["src", "alt"];
366
+ var _hoisted_6 = {
367
+ key: 1,
368
+ class: "mech-image-picker__empty"
369
+ };
370
+ //#endregion
371
+ //#region src/editor/dialogs/ImagePickerDialog.vue
372
+ var ImagePickerDialog_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
373
+ __name: "ImagePickerDialog",
374
+ props: { onSelect: { type: Function } },
375
+ setup(__props) {
376
+ const props = __props;
377
+ const dialog = useDialog();
378
+ const uploader = inject("mechFileUploader", null);
379
+ const library = inject("mechImageLibrary", null);
380
+ const images = ref([]);
381
+ const loaded = ref(false);
382
+ const busy = ref(false);
383
+ const dragover = ref(false);
384
+ onMounted(load);
385
+ async function load() {
386
+ try {
387
+ if (library) images.value = await library();
388
+ } catch {} finally {
389
+ loaded.value = true;
390
+ }
391
+ }
392
+ function select(value) {
393
+ props.onSelect(value);
394
+ dialog.back();
395
+ }
396
+ async function upload(file) {
397
+ if (!uploader || busy.value) return;
398
+ busy.value = true;
399
+ try {
400
+ const result = await uploader(file);
401
+ select({
402
+ src: result.src,
403
+ previewSrc: result.previewSrc ?? result.src
404
+ });
405
+ } finally {
406
+ busy.value = false;
407
+ }
408
+ }
409
+ const onPick = (event) => {
410
+ const file = event.target.files?.[0];
411
+ if (file) upload(file);
412
+ };
413
+ const onDrop = (event) => {
414
+ dragover.value = false;
415
+ const file = event.dataTransfer?.files?.[0];
416
+ if (file) upload(file);
417
+ };
418
+ return (_ctx, _cache) => {
419
+ return openBlock(), createBlock(VDialog_default, {
420
+ title: "Choose image",
421
+ size: "wide"
422
+ }, {
423
+ actions: withCtx(() => [createElementVNode("button", {
424
+ type: "button",
425
+ class: "mech-button",
426
+ onClick: _cache[2] || (_cache[2] = ($event) => unref(dialog).back())
427
+ }, "Back")]),
428
+ default: withCtx(() => [createElementVNode("div", _hoisted_1, [
429
+ createElementVNode("label", {
430
+ class: normalizeClass(["mech-image-picker__upload", { "is-dragover": dragover.value }]),
431
+ onDragover: _cache[0] || (_cache[0] = withModifiers(($event) => dragover.value = true, ["prevent"])),
432
+ onDragleave: _cache[1] || (_cache[1] = ($event) => dragover.value = false),
433
+ onDrop: withModifiers(onDrop, ["prevent"])
434
+ }, [
435
+ createElementVNode("input", {
436
+ class: "mech-image-picker__file",
437
+ type: "file",
438
+ accept: "image/*",
439
+ onChange: onPick
440
+ }, null, 32),
441
+ createVNode(VIcon_default, {
442
+ name: "upload",
443
+ class: "mech-image-picker__upload-glyph"
444
+ }),
445
+ createElementVNode("span", _hoisted_2, toDisplayString(busy.value ? "Uploading…" : "Drop an image here, or click to upload"), 1)
446
+ ], 34),
447
+ _cache[3] || (_cache[3] = createElementVNode("div", { class: "mech-image-picker__lib-head" }, "Project images", -1)),
448
+ images.value.length ? (openBlock(), createElementBlock("div", _hoisted_3, [(openBlock(true), createElementBlock(Fragment, null, renderList(images.value, (img) => {
449
+ return openBlock(), createElementBlock("button", {
450
+ key: img.id,
451
+ type: "button",
452
+ class: "mech-image-picker__item",
453
+ title: img.name,
454
+ onClick: ($event) => select({ src: img.src })
455
+ }, [createElementVNode("img", {
456
+ src: img.src,
457
+ alt: img.name,
458
+ loading: "lazy"
459
+ }, null, 8, _hoisted_5)], 8, _hoisted_4);
460
+ }), 128))])) : (openBlock(), createElementBlock("p", _hoisted_6, toDisplayString(loaded.value ? "No images uploaded yet — upload one above." : "Loading…"), 1))
461
+ ])]),
462
+ _: 1
463
+ });
464
+ };
465
+ }
466
+ }), [["__scopeId", "data-v-ce3974a0"]]);
467
+ //#endregion
468
+ export { useDialog as a, dialogKey as i, VDialog_default as n, _plugin_vue_export_helper_default as o, createDialogStore as r, VIcon_default as s, ImagePickerDialog_default as t };