@elytracms/studio 0.0.52 → 0.0.53

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 (308) hide show
  1. package/dist/components/account/account-settings.js +4 -4
  2. package/dist/components/account/credential-panel.js +1 -1
  3. package/dist/components/account/self-account-view-source.js +3 -3
  4. package/dist/components/ai/ai-chat-panel-lazy.js +1 -1
  5. package/dist/components/ai/ai-chat-panel.js +4 -4
  6. package/dist/components/ai/ai-cms-panel.js +1 -1
  7. package/dist/components/ai/proposal-card.js +4 -4
  8. package/dist/components/ai/translate-document-action.js +1 -1
  9. package/dist/components/ai/translate-document-dialog.d.ts +1 -1
  10. package/dist/components/app-views/default-modules.d.ts +3 -3
  11. package/dist/components/app-views/default-modules.js +20 -20
  12. package/dist/components/app-views/sidebar.d.ts +1 -1
  13. package/dist/components/app-views/sidebar.js +2 -2
  14. package/dist/components/app-views/studio-config.d.ts +1 -1
  15. package/dist/components/assets/asset-detail.js +9 -9
  16. package/dist/components/assets/asset-grid.js +7 -7
  17. package/dist/components/assets/asset-thumb.d.ts +1 -1
  18. package/dist/components/assets/asset-thumb.js +2 -2
  19. package/dist/components/assets/assets-collection-view-source.js +3 -3
  20. package/dist/components/assets/assets-module.js +8 -8
  21. package/dist/components/assets/assets-store.d.ts +1 -1
  22. package/dist/components/assets/assets-store.js +1 -1
  23. package/dist/components/builder/blocks-model.js +1 -1
  24. package/dist/components/builder/blocks-panel.d.ts +1 -1
  25. package/dist/components/builder/blocks-panel.js +6 -6
  26. package/dist/components/builder/canvas.js +11 -11
  27. package/dist/components/builder/clipboard-actions.js +2 -2
  28. package/dist/components/builder/composition-field-editor-lazy.d.ts +1 -1
  29. package/dist/components/builder/composition-field-editor-lazy.js +1 -1
  30. package/dist/components/builder/composition-field-editor.d.ts +1 -1
  31. package/dist/components/builder/composition-field-editor.js +9 -9
  32. package/dist/components/builder/insert-context.d.ts +2 -2
  33. package/dist/components/builder/insert-context.js +2 -2
  34. package/dist/components/builder/insert-menu.d.ts +2 -2
  35. package/dist/components/builder/insert-menu.js +1 -1
  36. package/dist/components/builder/layout-inspector.js +1 -1
  37. package/dist/components/builder/page-tree.js +5 -5
  38. package/dist/components/builder/property-inspector.js +3 -3
  39. package/dist/components/builder/reuse-context.d.ts +1 -1
  40. package/dist/components/builder/reuse-context.js +3 -3
  41. package/dist/components/builder/spacing-handles.js +2 -2
  42. package/dist/components/cms/asset-picker.js +4 -4
  43. package/dist/components/cms/bulk-actions.js +1 -1
  44. package/dist/components/cms/bulk-bar.d.ts +1 -1
  45. package/dist/components/cms/bulk-bar.js +3 -3
  46. package/dist/components/cms/cell-edit.js +1 -1
  47. package/dist/components/cms/cell.js +2 -2
  48. package/dist/components/cms/cms-index.js +1 -1
  49. package/dist/components/cms/cms-store.d.ts +2 -2
  50. package/dist/components/cms/cms-store.js +6 -6
  51. package/dist/components/cms/collection-table.js +17 -17
  52. package/dist/components/cms/detail-editor.js +31 -31
  53. package/dist/components/cms/document-diff-view.js +4 -4
  54. package/dist/components/cms/editable-cell.d.ts +1 -1
  55. package/dist/components/cms/editable-cell.js +6 -6
  56. package/dist/components/cms/field-control.js +15 -15
  57. package/dist/components/cms/field-renderer.d.ts +2 -2
  58. package/dist/components/cms/filter-builder.js +3 -3
  59. package/dist/components/cms/import-export.js +1 -1
  60. package/dist/components/cms/issues-pane.js +1 -1
  61. package/dist/components/cms/prop-fields.js +3 -3
  62. package/dist/components/cms/reference-confirm.js +1 -1
  63. package/dist/components/cms/relation-picker.js +1 -1
  64. package/dist/components/cms/rich-text/block-commands.d.ts +1 -1
  65. package/dist/components/cms/rich-text/component-embed.js +2 -2
  66. package/dist/components/cms/rich-text/editor.js +8 -8
  67. package/dist/components/cms/rich-text/embed-inspector.d.ts +1 -1
  68. package/dist/components/cms/rich-text/embed-inspector.js +2 -2
  69. package/dist/components/cms/rich-text/embed-picker.js +1 -1
  70. package/dist/components/cms/rich-text/embed-props.js +1 -1
  71. package/dist/components/cms/rich-text/extensions.d.ts +1 -1
  72. package/dist/components/cms/rich-text/extensions.js +4 -4
  73. package/dist/components/cms/rich-text/index.d.ts +1 -1
  74. package/dist/components/cms/rich-text/index.js +1 -1
  75. package/dist/components/cms/rich-text/insert.d.ts +1 -1
  76. package/dist/components/cms/rich-text/lazy.d.ts +1 -1
  77. package/dist/components/cms/rich-text/lazy.js +1 -1
  78. package/dist/components/cms/rich-text/slash-command.js +1 -1
  79. package/dist/components/cms/rich-text/toolbar.d.ts +1 -1
  80. package/dist/components/cms/rich-text/toolbar.js +4 -4
  81. package/dist/components/cms/use-cell-edit.d.ts +1 -1
  82. package/dist/components/cms/use-cell-edit.js +2 -2
  83. package/dist/components/cms/use-compare-selection.d.ts +1 -1
  84. package/dist/components/cms/use-discard-controller.d.ts +1 -1
  85. package/dist/components/cms/use-discard-controller.js +2 -2
  86. package/dist/components/cms/use-document-versions.d.ts +1 -1
  87. package/dist/components/cms/use-document-versions.js +1 -1
  88. package/dist/components/cms/use-embed-inspector-host.d.ts +1 -1
  89. package/dist/components/cms/use-published-perspective.d.ts +2 -2
  90. package/dist/components/cms/use-published-perspective.js +2 -2
  91. package/dist/components/cms/use-restore-version.js +1 -1
  92. package/dist/components/cms/version-compare-lazy.js +1 -1
  93. package/dist/components/cms/version-compare.js +6 -6
  94. package/dist/components/cms/versions-model.d.ts +1 -1
  95. package/dist/components/cms/versions-pane.js +5 -5
  96. package/dist/components/cms/view-bar.js +2 -2
  97. package/dist/components/collab/collab-context.js +1 -1
  98. package/dist/components/collection-view/cms-collection-view-source.js +2 -2
  99. package/dist/components/components/component-preview.js +3 -3
  100. package/dist/components/components/components-index.js +2 -2
  101. package/dist/components/components/registry-browser.js +2 -2
  102. package/dist/components/components/transfer-dialog.js +5 -5
  103. package/dist/components/components/transfer.js +4 -4
  104. package/dist/components/current-user-menu.js +2 -2
  105. package/dist/components/delivery-health-banner.js +2 -2
  106. package/dist/components/operation-error.js +1 -1
  107. package/dist/components/project-list.js +5 -5
  108. package/dist/components/project-session.js +1 -1
  109. package/dist/components/project-switcher.js +3 -3
  110. package/dist/components/rail-store-status.js +1 -1
  111. package/dist/components/redirects/redirects-collection-view-source.js +3 -3
  112. package/dist/components/redirects/redirects-module.js +6 -6
  113. package/dist/components/section-nav.js +3 -3
  114. package/dist/components/section-surface.js +1 -1
  115. package/dist/components/studio-project-screen.js +7 -7
  116. package/dist/components/studio-shell.js +9 -9
  117. package/dist/components/use-hydration-phase.js +1 -1
  118. package/dist/components/users/users-collection-view-source.js +4 -4
  119. package/dist/components/users/users-module.js +9 -9
  120. package/dist/components/workspace-projects.js +1 -1
  121. package/dist/customization.d.ts +9 -9
  122. package/dist/customization.js +5 -5
  123. package/dist/lib/ai/anthropic-provider.d.ts +1 -1
  124. package/dist/lib/ai/apply-content.d.ts +1 -1
  125. package/dist/lib/ai/apply-content.js +3 -3
  126. package/dist/lib/ai/chat-state.d.ts +2 -2
  127. package/dist/lib/ai/config.d.ts +1 -1
  128. package/dist/lib/ai/create-flow.d.ts +2 -2
  129. package/dist/lib/ai/create-flow.js +3 -3
  130. package/dist/lib/ai/fake-provider.d.ts +1 -1
  131. package/dist/lib/ai/index.d.ts +15 -15
  132. package/dist/lib/ai/index.js +15 -15
  133. package/dist/lib/ai/knowledge.d.ts +1 -1
  134. package/dist/lib/ai/provenance.d.ts +1 -1
  135. package/dist/lib/ai/route-provider.d.ts +1 -1
  136. package/dist/lib/ai/route.d.ts +1 -1
  137. package/dist/lib/ai/shape.d.ts +1 -1
  138. package/dist/lib/ai/translate-document.d.ts +1 -1
  139. package/dist/lib/ai/translate-document.js +3 -3
  140. package/dist/lib/ai-panel.js +1 -1
  141. package/dist/lib/assets/index.d.ts +4 -4
  142. package/dist/lib/assets/index.js +4 -4
  143. package/dist/lib/assets/upload.d.ts +2 -2
  144. package/dist/lib/assets/upload.js +2 -2
  145. package/dist/lib/auth/convex-auth-adapter.d.ts +2 -2
  146. package/dist/lib/auth/convex-auth-adapter.js +1 -1
  147. package/dist/lib/auth/dev-auto-login-adapter.d.ts +1 -1
  148. package/dist/lib/auth/index.d.ts +9 -9
  149. package/dist/lib/auth/index.js +10 -10
  150. package/dist/lib/auth/local-auth-adapter.d.ts +1 -1
  151. package/dist/lib/auth/route-guard.d.ts +1 -1
  152. package/dist/lib/auth-errors.d.ts +1 -1
  153. package/dist/lib/clipboard/index.d.ts +3 -3
  154. package/dist/lib/clipboard/index.js +3 -3
  155. package/dist/lib/cms/published-documents.d.ts +1 -1
  156. package/dist/lib/cms-views/index.d.ts +2 -2
  157. package/dist/lib/cms-views/index.js +2 -2
  158. package/dist/lib/collection-view/collection-view-source.d.ts +4 -4
  159. package/dist/lib/data/collection-content.js +1 -1
  160. package/dist/lib/data/data-store.js +6 -6
  161. package/dist/lib/data/index.d.ts +4 -4
  162. package/dist/lib/data/index.js +4 -4
  163. package/dist/lib/data/sample-capture.js +4 -4
  164. package/dist/lib/data/sources-store.d.ts +1 -1
  165. package/dist/lib/diff-view-preference.js +1 -1
  166. package/dist/lib/dnd/gap-drag.d.ts +1 -1
  167. package/dist/lib/i18n/i18n.d.ts +1 -1
  168. package/dist/lib/i18n/i18n.js +1 -1
  169. package/dist/lib/i18n/index.d.ts +4 -4
  170. package/dist/lib/i18n/index.js +3 -3
  171. package/dist/lib/i18n/messages.en.d.ts +1 -1
  172. package/dist/lib/i18n/messages.en.js +1 -1
  173. package/dist/lib/locale/binding-fallback.d.ts +1 -1
  174. package/dist/lib/locale/binding-fallback.js +2 -2
  175. package/dist/lib/locale/index.d.ts +6 -6
  176. package/dist/lib/locale/index.js +6 -6
  177. package/dist/lib/locale/locale-switcher.js +3 -3
  178. package/dist/lib/locale/use-studio-locale.js +1 -1
  179. package/dist/lib/operations/asset-repository.d.ts +1 -1
  180. package/dist/lib/operations/cms-persistence.d.ts +1 -1
  181. package/dist/lib/operations/cms-persistence.js +1 -1
  182. package/dist/lib/operations/index.d.ts +6 -6
  183. package/dist/lib/operations/index.js +6 -6
  184. package/dist/lib/operations/session-hydration.d.ts +1 -1
  185. package/dist/lib/operations/session-hydration.js +1 -1
  186. package/dist/lib/operations/studio-operations.d.ts +1 -1
  187. package/dist/lib/operations/studio-operations.js +3 -3
  188. package/dist/lib/persistence/convex-adapter.js +2 -2
  189. package/dist/lib/persistence/convex-blob-storage.d.ts +1 -1
  190. package/dist/lib/persistence/convex-blob-storage.js +1 -1
  191. package/dist/lib/persistence/deployment-readiness.d.ts +2 -2
  192. package/dist/lib/persistence/index.d.ts +6 -6
  193. package/dist/lib/persistence/index.js +7 -7
  194. package/dist/lib/persona/labels.js +1 -1
  195. package/dist/lib/query/index.d.ts +2 -2
  196. package/dist/lib/query/index.js +1 -1
  197. package/dist/lib/rail.js +1 -1
  198. package/dist/lib/references/impact.d.ts +1 -1
  199. package/dist/lib/references/impact.js +1 -1
  200. package/dist/lib/references/index.d.ts +3 -3
  201. package/dist/lib/references/index.js +3 -3
  202. package/dist/lib/references/references-store.d.ts +2 -2
  203. package/dist/lib/references/references-store.js +3 -3
  204. package/dist/lib/registry/index.js +2 -2
  205. package/dist/lib/theme.js +1 -1
  206. package/dist/lib/webhooks/config.d.ts +1 -1
  207. package/dist/lib/webhooks/config.js +2 -2
  208. package/dist/lib/webhooks/dispatcher.js +2 -2
  209. package/dist/lib/webhooks/index.d.ts +6 -6
  210. package/dist/lib/webhooks/index.js +4 -4
  211. package/dist/lib/workspace/index.d.ts +7 -7
  212. package/dist/lib/workspace/index.js +3 -3
  213. package/dist/lib/workspace/switcher-source.d.ts +1 -1
  214. package/dist/router/index.d.ts +1 -1
  215. package/dist/router/index.js +1 -1
  216. package/dist/ui/avatar.js +1 -1
  217. package/dist/ui/badge.js +1 -1
  218. package/dist/ui/button.js +1 -1
  219. package/dist/ui/card.js +1 -1
  220. package/dist/ui/collapsible-section.js +2 -2
  221. package/dist/ui/dialog.js +1 -1
  222. package/dist/ui/dropdown-menu.js +1 -1
  223. package/dist/ui/field.js +1 -1
  224. package/dist/ui/index.d.ts +19 -19
  225. package/dist/ui/index.js +19 -19
  226. package/dist/ui/input.js +1 -1
  227. package/dist/ui/inspector.js +1 -1
  228. package/dist/ui/layout.js +1 -1
  229. package/dist/ui/panel.js +2 -2
  230. package/dist/ui/popover.js +1 -1
  231. package/dist/ui/row-item.js +2 -2
  232. package/dist/ui/segmented-control.js +1 -1
  233. package/dist/ui/separator.js +1 -1
  234. package/dist/ui/toolbar.js +2 -2
  235. package/dist/ui/typography.js +1 -1
  236. package/package.json +3 -3
  237. package/dist/components/assets/asset-library.d.ts +0 -14
  238. package/dist/components/assets/asset-library.js +0 -202
  239. package/dist/components/assets/asset-library.js.map +0 -1
  240. package/dist/components/backend-gate.d.ts +0 -19
  241. package/dist/components/backend-gate.js +0 -64
  242. package/dist/components/backend-gate.js.map +0 -1
  243. package/dist/components/builder/composition-scope.d.ts +0 -16
  244. package/dist/components/builder/composition-scope.js +0 -7
  245. package/dist/components/builder/composition-scope.js.map +0 -1
  246. package/dist/components/cms/alias-selector.d.ts +0 -20
  247. package/dist/components/cms/alias-selector.js +0 -34
  248. package/dist/components/cms/alias-selector.js.map +0 -1
  249. package/dist/components/cms/collections-sidebar.d.ts +0 -18
  250. package/dist/components/cms/collections-sidebar.js +0 -36
  251. package/dist/components/cms/collections-sidebar.js.map +0 -1
  252. package/dist/components/cms/new-page-dialog.d.ts +0 -22
  253. package/dist/components/cms/new-page-dialog.js +0 -42
  254. package/dist/components/cms/new-page-dialog.js.map +0 -1
  255. package/dist/components/cms/rich-text/embed-control.d.ts +0 -17
  256. package/dist/components/cms/rich-text/embed-control.js +0 -62
  257. package/dist/components/cms/rich-text/embed-control.js.map +0 -1
  258. package/dist/components/cms/rich-text/image-control.d.ts +0 -16
  259. package/dist/components/cms/rich-text/image-control.js +0 -36
  260. package/dist/components/cms/rich-text/image-control.js.map +0 -1
  261. package/dist/components/components/fixture-runner.d.ts +0 -10
  262. package/dist/components/components/fixture-runner.js +0 -27
  263. package/dist/components/components/fixture-runner.js.map +0 -1
  264. package/dist/components/references/builder-deep-link.d.ts +0 -12
  265. package/dist/components/references/builder-deep-link.js +0 -53
  266. package/dist/components/references/builder-deep-link.js.map +0 -1
  267. package/dist/components/routes/redirect-chain.d.ts +0 -9
  268. package/dist/components/routes/redirect-chain.js +0 -16
  269. package/dist/components/routes/redirect-chain.js.map +0 -1
  270. package/dist/components/routes/redirect-manager.d.ts +0 -13
  271. package/dist/components/routes/redirect-manager.js +0 -24
  272. package/dist/components/routes/redirect-manager.js.map +0 -1
  273. package/dist/components/routes/route-list.d.ts +0 -35
  274. package/dist/components/routes/route-list.js +0 -69
  275. package/dist/components/routes/route-list.js.map +0 -1
  276. package/dist/components/routes/routes-shell.d.ts +0 -14
  277. package/dist/components/routes/routes-shell.js +0 -68
  278. package/dist/components/routes/routes-shell.js.map +0 -1
  279. package/dist/components/sections.d.ts +0 -37
  280. package/dist/components/sections.js +0 -62
  281. package/dist/components/sections.js.map +0 -1
  282. package/dist/components/users/user-search.d.ts +0 -8
  283. package/dist/components/users/user-search.js +0 -13
  284. package/dist/components/users/user-search.js.map +0 -1
  285. package/dist/components/workspace-gate.d.ts +0 -12
  286. package/dist/components/workspace-gate.js +0 -28
  287. package/dist/components/workspace-gate.js.map +0 -1
  288. package/dist/lib/cms-views/views-store.d.ts +0 -70
  289. package/dist/lib/cms-views/views-store.js +0 -129
  290. package/dist/lib/cms-views/views-store.js.map +0 -1
  291. package/dist/lib/operations/graph-commands.d.ts +0 -136
  292. package/dist/lib/operations/graph-commands.js +0 -85
  293. package/dist/lib/operations/graph-commands.js.map +0 -1
  294. package/dist/lib/operations/graph-persistence.d.ts +0 -27
  295. package/dist/lib/operations/graph-persistence.js +0 -35
  296. package/dist/lib/operations/graph-persistence.js.map +0 -1
  297. package/dist/lib/routing/index.d.ts +0 -10
  298. package/dist/lib/routing/index.js +0 -11
  299. package/dist/lib/routing/index.js.map +0 -1
  300. package/dist/lib/routing/routing-analysis.d.ts +0 -26
  301. package/dist/lib/routing/routing-analysis.js +0 -37
  302. package/dist/lib/routing/routing-analysis.js.map +0 -1
  303. package/dist/lib/routing/routing-store.d.ts +0 -50
  304. package/dist/lib/routing/routing-store.js +0 -72
  305. package/dist/lib/routing/routing-store.js.map +0 -1
  306. package/dist/lib/working-graph.d.ts +0 -82
  307. package/dist/lib/working-graph.js +0 -113
  308. package/dist/lib/working-graph.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"backend-gate.js","sourceRoot":"","sources":["../../src/components/backend-gate.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useCallback, useEffect, useMemo, useState } from 'react'\nimport type { ReactNode } from 'react'\nimport { Button, Card, CardContent, CardHeader, CardTitle, Code, Stack, Text } from '@elytracms/studio/ui'\nimport {\n CONVEX_URL_ENV_VAR,\n MODE_ENV_VAR,\n PLAYGROUND_MODE,\n resolveBackendConfig,\n selectPersistenceAdapter,\n} from '@elytracms/studio/lib/persistence'\nimport type { StudioBackendConfig } from '@elytracms/studio/lib/persistence'\nimport { translate } from '@elytracms/studio/lib/i18n'\n\n/**\n * Backend boot gate (EC-153). Convex is the default backend and the in-memory\n * playground is opt-in only — so the two failure shapes are **visible,\n * deterministic error states**, never a silent fallback:\n *\n * 1. *Misconfigured* (no `VITE_CONVEX_URL`, no playground flag): a boot-error\n * screen explaining exactly what to set, rendered before auth or any\n * adapter is constructed.\n * 2. *Backend unreachable at runtime*: the gate probes `adapter.status()` once\n * on the client; a dead deployment renders an error screen with the\n * transport detail and a retry — the studio never swaps storage backends.\n *\n * Playground and healthy-Convex render children untouched. SSR renders the\n * deterministic \"checking\" state (mirrors `SessionLoading`).\n */\nexport function BackendGate({ children }: { children: ReactNode }) {\n const config = useMemo<StudioBackendConfig>(() => resolveBackendConfig(), [])\n const [probe, setProbe] = useState<ProbeState>(() =>\n config.kind === 'convex' ? { phase: 'checking' } : { phase: 'ready' },\n )\n\n const check = useCallback(() => {\n setProbe({ phase: 'checking' })\n void selectPersistenceAdapter()\n .then((adapter) => adapter.status())\n .then((status) =>\n setProbe(\n status.available\n ? { phase: 'ready' }\n : { phase: 'unavailable', detail: status.detail ?? 'No response from the deployment.' },\n ),\n )\n .catch((error: unknown) =>\n setProbe({\n phase: 'unavailable',\n detail: error instanceof Error ? error.message : String(error),\n }),\n )\n }, [])\n\n useEffect(() => {\n if (config.kind === 'convex') check()\n }, [config.kind, check])\n\n if (config.kind === 'misconfigured') return <BackendConfigErrorScreen config={config} />\n if (probe.phase === 'checking') return <BackendChecking />\n if (probe.phase === 'unavailable') {\n return <BackendUnavailableScreen detail={probe.detail} onRetry={check} />\n }\n return <>{children}</>\n}\n\ntype ProbeState =\n | { phase: 'checking' }\n | { phase: 'ready' }\n | { phase: 'unavailable'; detail: string }\n\n/** Deterministic boot state while the backend probe is in flight (also SSR output). */\nfunction BackendChecking() {\n return (\n <BootScreenFrame>\n <Text size=\"sm\" tone=\"muted\">\n {translate('shell.backend.connecting')}\n </Text>\n </BootScreenFrame>\n )\n}\n\n/** Missing/invalid configuration — tells the developer exactly what to set. */\nfunction BackendConfigErrorScreen({\n config,\n}: {\n config: Extract<StudioBackendConfig, { kind: 'misconfigured' }>\n}) {\n return (\n <BootScreenFrame>\n <Card className=\"max-w-xl border-destructive/40\">\n <CardHeader>\n <CardTitle>{translate('shell.backend.notConfigured.title')}</CardTitle>\n </CardHeader>\n <CardContent>\n <Stack gap=\"3\">\n <Text size=\"sm\" tone=\"muted\">\n {config.detail}\n </Text>\n <Stack gap=\"2\">\n <Text size=\"sm\">\n <Code>{CONVEX_URL_ENV_VAR}=https://&lt;deployment&gt;.convex.cloud</Code> — run the\n studio against your Convex deployment (the default; see{' '}\n <Code>docs/backend-setup.md</Code>).\n </Text>\n <Text size=\"sm\">\n <Code>\n {MODE_ENV_VAR}={PLAYGROUND_MODE}\n </Code>{' '}\n — explicitly opt into the local playground: seeded in-memory data, ephemeral, reset\n on every reload.\n </Text>\n </Stack>\n <Text size=\"xs\" tone=\"muted\">\n Set either in <Code>apps/builder/.env.local</Code> and restart the dev server. The\n studio never falls back to in-memory storage on its own.\n </Text>\n </Stack>\n </CardContent>\n </Card>\n </BootScreenFrame>\n )\n}\n\n/** The Convex deployment did not answer — visible degraded state, with retry. */\nfunction BackendUnavailableScreen({ detail, onRetry }: { detail: string; onRetry: () => void }) {\n return (\n <BootScreenFrame>\n <Card className=\"max-w-xl border-destructive/40\">\n <CardHeader>\n <CardTitle>{translate('shell.backend.unavailable.title')}</CardTitle>\n </CardHeader>\n <CardContent>\n <Stack gap=\"3\">\n <Text size=\"sm\" tone=\"muted\">\n {translate('shell.backend.unavailable.body')}\n </Text>\n <Code className=\"block whitespace-pre-wrap break-all text-xs\">{detail}</Code>\n <Text size=\"xs\" tone=\"muted\">\n Check that <Code>npx convex dev</Code> is running (dev) or that the deployment URL in{' '}\n <Code>{CONVEX_URL_ENV_VAR}</Code> is correct, then retry.\n </Text>\n <Button variant=\"outline\" size=\"sm\" onClick={onRetry} className=\"self-start\">\n {translate('shell.backend.retryConnection')}\n </Button>\n </Stack>\n </CardContent>\n </Card>\n </BootScreenFrame>\n )\n}\n\nfunction BootScreenFrame({ children }: { children: ReactNode }) {\n return <div className=\"grid min-h-dvh place-items-center bg-background p-6\">{children}</div>\n}\n"]}
@@ -1,16 +0,0 @@
1
- /**
2
- * Marks the builder as a SCOPED composition-field editor (EC-188) rather than the
3
- * project page builder. Page-graph-only chrome checks this to stay hidden: a
4
- * composition field's synthetic root IS the active page root, but it is a builder
5
- * artifact, not a routable page — so page-level controls don't belong here.
6
- *
7
- * Default `active: false` → the standalone page builder is unaffected. Lives in
8
- * its own module so page-chrome can read it without importing
9
- * `composition-field-editor`, which would form an import cycle through the shared
10
- * `property-inspector`.
11
- */
12
- export interface CompositionScope {
13
- active: boolean;
14
- }
15
- export declare const CompositionScopeProvider: import("react").Provider<CompositionScope>;
16
- export declare function useCompositionScope(): CompositionScope;
@@ -1,7 +0,0 @@
1
- import { createContext, useContext } from 'react';
2
- const CompositionScopeContext = createContext({ active: false });
3
- export const CompositionScopeProvider = CompositionScopeContext.Provider;
4
- export function useCompositionScope() {
5
- return useContext(CompositionScopeContext);
6
- }
7
- //# sourceMappingURL=composition-scope.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"composition-scope.js","sourceRoot":"","sources":["../../../src/components/builder/composition-scope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAiBjD,MAAM,uBAAuB,GAAG,aAAa,CAAmB,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;AAElF,MAAM,CAAC,MAAM,wBAAwB,GAAG,uBAAuB,CAAC,QAAQ,CAAA;AAExE,MAAM,UAAU,mBAAmB;IACjC,OAAO,UAAU,CAAC,uBAAuB,CAAC,CAAA;AAC5C,CAAC","sourcesContent":["import { createContext, useContext } from 'react'\n\n/**\n * Marks the builder as a SCOPED composition-field editor (EC-188) rather than the\n * project page builder. Page-graph-only chrome checks this to stay hidden: a\n * composition field's synthetic root IS the active page root, but it is a builder\n * artifact, not a routable page — so page-level controls don't belong here.\n *\n * Default `active: false` → the standalone page builder is unaffected. Lives in\n * its own module so page-chrome can read it without importing\n * `composition-field-editor`, which would form an import cycle through the shared\n * `property-inspector`.\n */\nexport interface CompositionScope {\n active: boolean\n}\n\nconst CompositionScopeContext = createContext<CompositionScope>({ active: false })\n\nexport const CompositionScopeProvider = CompositionScopeContext.Provider\n\nexport function useCompositionScope(): CompositionScope {\n return useContext(CompositionScopeContext)\n}\n"]}
@@ -1,20 +0,0 @@
1
- import type { CmsDocument, CollectionDef } from '@elytracms/core/cms-core';
2
- /**
3
- * EC-284 — assign this document to one of its collection's declared alias slots
4
- * (`main`, `mobile`, `footer`, `legal`…), so code resolves it by
5
- * `(collection, alias)` instead of a literal id. A segmented control: each
6
- * declared slot is a button; the one already taken by a *sibling* document is
7
- * disabled (with a hint), so duplicates aren't created by accident (any that slip
8
- * through — e.g. a config change — surface as `duplicate-alias` drift in the list
9
- * review lane). Clicking the active slot clears the assignment.
10
- *
11
- * Renders nothing for a collection that declares no slots.
12
- */
13
- export declare function AliasSelector({ collection, doc, siblings, readOnly, onChange, }: {
14
- collection: CollectionDef;
15
- doc: CmsDocument;
16
- /** The other documents in this collection (to show which slots are taken). */
17
- siblings: readonly CmsDocument[];
18
- readOnly?: boolean;
19
- onChange: (alias: string | undefined) => void;
20
- }): import("react").JSX.Element | null;
@@ -1,34 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { declaredAliases } from '@elytracms/core/cms-core';
3
- import { Row, Text } from '@elytracms/studio/ui';
4
- import { cn } from '@elytracms/studio/lib/utils';
5
- /**
6
- * EC-284 — assign this document to one of its collection's declared alias slots
7
- * (`main`, `mobile`, `footer`, `legal`…), so code resolves it by
8
- * `(collection, alias)` instead of a literal id. A segmented control: each
9
- * declared slot is a button; the one already taken by a *sibling* document is
10
- * disabled (with a hint), so duplicates aren't created by accident (any that slip
11
- * through — e.g. a config change — surface as `duplicate-alias` drift in the list
12
- * review lane). Clicking the active slot clears the assignment.
13
- *
14
- * Renders nothing for a collection that declares no slots.
15
- */
16
- export function AliasSelector({ collection, doc, siblings, readOnly, onChange, }) {
17
- const slots = declaredAliases(collection);
18
- if (slots.length === 0)
19
- return null;
20
- const takenBySibling = new Set();
21
- for (const sibling of siblings) {
22
- if (sibling.id !== doc.id && sibling.alias !== undefined)
23
- takenBySibling.add(sibling.alias);
24
- }
25
- const current = doc.alias;
26
- return (_jsxs(Row, { gap: "2", align: "center", "data-testid": "alias-selector", children: [_jsx(Text, { size: "xs", tone: "muted", children: "Slot" }), _jsx(Row, { gap: "px", className: "rounded-md bg-muted/60 p-0.5", children: slots.map((slot) => {
27
- const active = current === slot;
28
- const taken = takenBySibling.has(slot);
29
- return (_jsx("button", { type: "button", "aria-pressed": active, disabled: readOnly || (taken && !active), title: taken && !active ? 'Already assigned to another document' : undefined, onClick: () => onChange(active ? undefined : slot), className: cn('rounded px-2 py-0.5 text-xs font-medium capitalize transition-colors disabled:opacity-40', active
30
- ? 'bg-background text-foreground shadow-sm'
31
- : 'text-muted-foreground hover:text-foreground'), children: slot }, slot));
32
- }) })] }));
33
- }
34
- //# sourceMappingURL=alias-selector.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"alias-selector.js","sourceRoot":"","sources":["../../../src/components/cms/alias-selector.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAE1D,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAA;AAChD,OAAO,EAAE,EAAE,EAAE,MAAM,6BAA6B,CAAA;AAEhD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAAC,EAC5B,UAAU,EACV,GAAG,EACH,QAAQ,EACR,QAAQ,EACR,QAAQ,GAQT;IACC,MAAM,KAAK,GAAG,eAAe,CAAC,UAAU,CAAC,CAAA;IACzC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IAEnC,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAA;IACxC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,OAAO,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;YAAE,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IAC7F,CAAC;IACD,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAA;IAEzB,OAAO,CACL,MAAC,GAAG,IAAC,GAAG,EAAC,GAAG,EAAC,KAAK,EAAC,QAAQ,iBAAa,gBAAgB,aACtD,KAAC,IAAI,IAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,OAAO,qBAErB,EACP,KAAC,GAAG,IAAC,GAAG,EAAC,IAAI,EAAC,SAAS,EAAC,8BAA8B,YACnD,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;oBAClB,MAAM,MAAM,GAAG,OAAO,KAAK,IAAI,CAAA;oBAC/B,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;oBACtC,OAAO,CACL,iBAEE,IAAI,EAAC,QAAQ,kBACC,MAAM,EACpB,QAAQ,EAAE,QAAQ,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,EACxC,KAAK,EAAE,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,sCAAsC,CAAC,CAAC,CAAC,SAAS,EAC5E,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,EAClD,SAAS,EAAE,EAAE,CACX,0FAA0F,EAC1F,MAAM;4BACJ,CAAC,CAAC,yCAAyC;4BAC3C,CAAC,CAAC,6CAA6C,CAClD,YAEA,IAAI,IAbA,IAAI,CAcF,CACV,CAAA;gBACH,CAAC,CAAC,GACE,IACF,CACP,CAAA;AACH,CAAC","sourcesContent":["import { declaredAliases } from '@elytracms/core/cms-core'\nimport type { CmsDocument, CollectionDef } from '@elytracms/core/cms-core'\nimport { Row, Text } from '@elytracms/studio/ui'\nimport { cn } from '@elytracms/studio/lib/utils'\n\n/**\n * EC-284 — assign this document to one of its collection's declared alias slots\n * (`main`, `mobile`, `footer`, `legal`…), so code resolves it by\n * `(collection, alias)` instead of a literal id. A segmented control: each\n * declared slot is a button; the one already taken by a *sibling* document is\n * disabled (with a hint), so duplicates aren't created by accident (any that slip\n * through — e.g. a config change — surface as `duplicate-alias` drift in the list\n * review lane). Clicking the active slot clears the assignment.\n *\n * Renders nothing for a collection that declares no slots.\n */\nexport function AliasSelector({\n collection,\n doc,\n siblings,\n readOnly,\n onChange,\n}: {\n collection: CollectionDef\n doc: CmsDocument\n /** The other documents in this collection (to show which slots are taken). */\n siblings: readonly CmsDocument[]\n readOnly?: boolean\n onChange: (alias: string | undefined) => void\n}) {\n const slots = declaredAliases(collection)\n if (slots.length === 0) return null\n\n const takenBySibling = new Set<string>()\n for (const sibling of siblings) {\n if (sibling.id !== doc.id && sibling.alias !== undefined) takenBySibling.add(sibling.alias)\n }\n const current = doc.alias\n\n return (\n <Row gap=\"2\" align=\"center\" data-testid=\"alias-selector\">\n <Text size=\"xs\" tone=\"muted\">\n Slot\n </Text>\n <Row gap=\"px\" className=\"rounded-md bg-muted/60 p-0.5\">\n {slots.map((slot) => {\n const active = current === slot\n const taken = takenBySibling.has(slot)\n return (\n <button\n key={slot}\n type=\"button\"\n aria-pressed={active}\n disabled={readOnly || (taken && !active)}\n title={taken && !active ? 'Already assigned to another document' : undefined}\n onClick={() => onChange(active ? undefined : slot)}\n className={cn(\n 'rounded px-2 py-0.5 text-xs font-medium capitalize transition-colors disabled:opacity-40',\n active\n ? 'bg-background text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground',\n )}\n >\n {slot}\n </button>\n )\n })}\n </Row>\n </Row>\n )\n}\n"]}
@@ -1,18 +0,0 @@
1
- /**
2
- * EC-239 focus lens: a focused CMS module shows only `focus` collections, in that
3
- * order (config order is honoured); ids not present are dropped. Unset → all.
4
- */
5
- export declare function focusCollectionList<T extends {
6
- id: string;
7
- }>(all: readonly T[], focus?: readonly string[]): T[];
8
- /**
9
- * Left sidebar listing the project's collections (brief §8.4). The active
10
- * collection arrives as a prop from the splat resolver (EC-223 Stage 6) — the
11
- * `collectionId` is no longer a route param, so it can't be read from the router.
12
- */
13
- export declare function CollectionsSidebar({ projectId, activeCollectionId, focusCollections, }: {
14
- projectId: string;
15
- activeCollectionId?: string;
16
- /** EC-239: restrict the list to these collection ids (a focused CMS module lens). */
17
- focusCollections?: readonly string[];
18
- }): import("react").JSX.Element;
@@ -1,36 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Link, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router';
3
- import { Database, FileCog, Image } from 'lucide-react';
4
- import { isSingleton } from '@elytracms/core/cms-core';
5
- import { Code, Row, Spacer, Text } from '@elytracms/studio/ui';
6
- import { cn } from '@elytracms/studio/lib/utils';
7
- import { useCms } from './cms-store';
8
- /**
9
- * EC-239 focus lens: a focused CMS module shows only `focus` collections, in that
10
- * order (config order is honoured); ids not present are dropped. Unset → all.
11
- */
12
- export function focusCollectionList(all, focus) {
13
- if (!focus)
14
- return [...all];
15
- const byId = new Map(all.map((collection) => [collection.id, collection]));
16
- return focus.map((id) => byId.get(id)).filter((collection) => collection !== undefined);
17
- }
18
- /**
19
- * Left sidebar listing the project's collections (brief §8.4). The active
20
- * collection arrives as a prop from the splat resolver (EC-223 Stage 6) — the
21
- * `collectionId` is no longer a route param, so it can't be read from the router.
22
- */
23
- export function CollectionsSidebar({ projectId, activeCollectionId, focusCollections, }) {
24
- const cms = useCms();
25
- const collections = focusCollectionList(cms.collections, focusCollections);
26
- return (_jsxs("div", { className: "flex h-full min-h-0 flex-col", children: [_jsxs(Row, { gap: "2", className: "h-10 shrink-0 border-b border-border px-3", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "Collections" }), _jsx(Spacer, {}), _jsx(Text, { size: "xs", tone: "subtle", mono: true, children: collections.length })] }), _jsx("div", { className: "min-h-0 flex-1 overflow-auto p-2", children: collections.map((collection) => {
27
- const active = collection.id === activeCollectionId;
28
- // EC-217: a singleton reads as one fixed document, not a list — a
29
- // distinct icon and no row count (which would always be a noisy "1").
30
- const singleton = isSingleton(collection);
31
- const Icon = singleton ? FileCog : collection.kind === 'asset' ? Image : Database;
32
- const count = cms.documentsOf(collection.id).length;
33
- return (_jsxs(Link, { to: STUDIO_PROJECT_ROUTE, params: { projectId, _splat: studioPath.cmsCollection(collection.id) }, "aria-current": active ? 'page' : undefined, className: cn('flex items-center gap-2 rounded-md px-2.5 py-1.5 text-sm transition-colors', active ? 'bg-accent text-accent-foreground' : 'text-muted-foreground hover:bg-muted hover:text-foreground'), children: [_jsx(Icon, { className: "size-4 shrink-0" }), _jsx("span", { className: "min-w-0 flex-1 truncate font-medium text-foreground", children: collection.form?.label ?? collection.id }), singleton ? null : _jsx(Code, { tone: "muted", children: count })] }, collection.id));
34
- }) })] }));
35
- }
36
- //# sourceMappingURL=collections-sidebar.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"collections-sidebar.js","sourceRoot":"","sources":["../../../src/components/cms/collections-sidebar.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Link, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router'\nimport { Database, FileCog, Image } from 'lucide-react'\nimport { isSingleton } from '@elytracms/core/cms-core'\nimport { Code, Row, Spacer, Text } from '@elytracms/studio/ui'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { useCms } from './cms-store'\n\n/**\n * EC-239 focus lens: a focused CMS module shows only `focus` collections, in that\n * order (config order is honoured); ids not present are dropped. Unset → all.\n */\nexport function focusCollectionList<T extends { id: string }>(\n all: readonly T[],\n focus?: readonly string[],\n): T[] {\n if (!focus) return [...all]\n const byId = new Map(all.map((collection) => [collection.id, collection]))\n return focus.map((id) => byId.get(id)).filter((collection): collection is T => collection !== undefined)\n}\n\n/**\n * Left sidebar listing the project's collections (brief §8.4). The active\n * collection arrives as a prop from the splat resolver (EC-223 Stage 6) — the\n * `collectionId` is no longer a route param, so it can't be read from the router.\n */\nexport function CollectionsSidebar({\n projectId,\n activeCollectionId,\n focusCollections,\n}: {\n projectId: string\n activeCollectionId?: string\n /** EC-239: restrict the list to these collection ids (a focused CMS module lens). */\n focusCollections?: readonly string[]\n}) {\n const cms = useCms()\n const collections = focusCollectionList(cms.collections, focusCollections)\n\n return (\n <div className=\"flex h-full min-h-0 flex-col\">\n <Row gap=\"2\" className=\"h-10 shrink-0 border-b border-border px-3\">\n <Text size=\"sm\" weight=\"semibold\">\n Collections\n </Text>\n <Spacer />\n <Text size=\"xs\" tone=\"subtle\" mono>\n {collections.length}\n </Text>\n </Row>\n <div className=\"min-h-0 flex-1 overflow-auto p-2\">\n {collections.map((collection) => {\n const active = collection.id === activeCollectionId\n // EC-217: a singleton reads as one fixed document, not a list — a\n // distinct icon and no row count (which would always be a noisy \"1\").\n const singleton = isSingleton(collection)\n const Icon = singleton ? FileCog : collection.kind === 'asset' ? Image : Database\n const count = cms.documentsOf(collection.id).length\n return (\n <Link\n key={collection.id}\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.cmsCollection(collection.id) }}\n aria-current={active ? 'page' : undefined}\n className={cn(\n 'flex items-center gap-2 rounded-md px-2.5 py-1.5 text-sm transition-colors',\n active ? 'bg-accent text-accent-foreground' : 'text-muted-foreground hover:bg-muted hover:text-foreground',\n )}\n >\n <Icon className=\"size-4 shrink-0\" />\n <span className=\"min-w-0 flex-1 truncate font-medium text-foreground\">\n {collection.form?.label ?? collection.id}\n </span>\n {singleton ? null : <Code tone=\"muted\">{count}</Code>}\n </Link>\n )\n })}\n </div>\n </div>\n )\n}\n"]}
@@ -1,22 +0,0 @@
1
- /**
2
- * Create a page in ONE action (EC-192). Pages are documents in the `page`
3
- * collection (EC-187): this dialog mints the page document (stable slug id,
4
- * `cms.createPage`) and opens the new page's editor.
5
- *
6
- * EC-207 ("routes as code"): creating a page no longer persists an addressing
7
- * route to the backend — routes are authored in `elytra.config.ts` and read
8
- * from the resolved config, never written to or read from the DB. The page's
9
- * URL is bound by a route in the consuming repo's `cms/routes.ts`, so this
10
- * dialog only creates the page document.
11
- */
12
- export declare function NewPageDialog({ projectId, open, onOpenChange, }: {
13
- projectId: string;
14
- /**
15
- * Configured locales. EC-207 dropped the per-page address/language inputs
16
- * (routes are config-sourced), so this is currently unused — kept on the prop
17
- * contract for the page-collection caller and a future config-aware preview.
18
- */
19
- locales?: readonly string[];
20
- open: boolean;
21
- onOpenChange: (open: boolean) => void;
22
- }): import("react").JSX.Element;
@@ -1,42 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { STUDIO_PROJECT_ROUTE, studioPath, useNavigate } from '@elytracms/studio/router';
3
- import { useState } from 'react';
4
- import { Button, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, Field, Input, Stack, } from '@elytracms/studio/ui';
5
- import { useCms } from './cms-store';
6
- /**
7
- * Create a page in ONE action (EC-192). Pages are documents in the `page`
8
- * collection (EC-187): this dialog mints the page document (stable slug id,
9
- * `cms.createPage`) and opens the new page's editor.
10
- *
11
- * EC-207 ("routes as code"): creating a page no longer persists an addressing
12
- * route to the backend — routes are authored in `elytra.config.ts` and read
13
- * from the resolved config, never written to or read from the DB. The page's
14
- * URL is bound by a route in the consuming repo's `cms/routes.ts`, so this
15
- * dialog only creates the page document.
16
- */
17
- export function NewPageDialog({ projectId, open, onOpenChange, }) {
18
- const cms = useCms();
19
- const navigate = useNavigate();
20
- const [name, setName] = useState('');
21
- function reset() {
22
- setName('');
23
- }
24
- function handleOpenChange(next) {
25
- if (!next)
26
- reset();
27
- onOpenChange(next);
28
- }
29
- function submit(event) {
30
- event.preventDefault();
31
- if (name.trim() === '')
32
- return;
33
- const ref = cms.createPage({ name: name.trim() });
34
- handleOpenChange(false);
35
- void navigate({
36
- to: STUDIO_PROJECT_ROUTE,
37
- params: { projectId, _splat: studioPath.cmsDocument('page', ref.id) },
38
- });
39
- }
40
- return (_jsx(Dialog, { open: open, onOpenChange: handleOpenChange, children: _jsxs(DialogContent, { children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "New page" }), _jsx(DialogDescription, { children: "Give the page a name. You can design it next; its address is set in elytra.config.ts." })] }), _jsxs("form", { onSubmit: submit, children: [_jsx(Stack, { gap: "3", children: _jsx(Field, { label: "Name", htmlFor: "new-page-name", required: true, children: _jsx(Input, { id: "new-page-name", value: name, onChange: (event) => setName(event.target.value), placeholder: "About us", autoFocus: true, required: true }) }) }), _jsxs(DialogFooter, { className: "mt-4", children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => handleOpenChange(false), children: "Cancel" }), _jsx(Button, { type: "submit", size: "sm", disabled: name.trim() === '', "data-testid": "create-page", children: "Create page" })] })] })] }) }));
41
- }
42
- //# sourceMappingURL=new-page-dialog.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"new-page-dialog.js","sourceRoot":"","sources":["../../../src/components/cms/new-page-dialog.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,oBAAoB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AACxF,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEhC,OAAO,EACL,MAAM,EACN,MAAM,EACN,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,KAAK,EACL,KAAK,EACL,KAAK,GACN,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAAC,EAC5B,SAAS,EACT,IAAI,EACJ,YAAY,GAWb;IACC,MAAM,GAAG,GAAG,MAAM,EAAE,CAAA;IACpB,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAC9B,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;IAEpC,SAAS,KAAK;QACZ,OAAO,CAAC,EAAE,CAAC,CAAA;IACb,CAAC;IAED,SAAS,gBAAgB,CAAC,IAAa;QACrC,IAAI,CAAC,IAAI;YAAE,KAAK,EAAE,CAAA;QAClB,YAAY,CAAC,IAAI,CAAC,CAAA;IACpB,CAAC;IAED,SAAS,MAAM,CAAC,KAAgB;QAC9B,KAAK,CAAC,cAAc,EAAE,CAAA;QACtB,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,OAAM;QAC9B,MAAM,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;QACjD,gBAAgB,CAAC,KAAK,CAAC,CAAA;QACvB,KAAK,QAAQ,CAAC;YACZ,EAAE,EAAE,oBAAoB;YACxB,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE;SACtE,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,CACL,KAAC,MAAM,IAAC,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,gBAAgB,YAChD,MAAC,aAAa,eACZ,MAAC,YAAY,eACX,KAAC,WAAW,2BAAuB,EACnC,KAAC,iBAAiB,wGAEE,IACP,EACf,gBAAM,QAAQ,EAAE,MAAM,aACpB,KAAC,KAAK,IAAC,GAAG,EAAC,GAAG,YACZ,KAAC,KAAK,IAAC,KAAK,EAAC,MAAM,EAAC,OAAO,EAAC,eAAe,EAAC,QAAQ,kBAClD,KAAC,KAAK,IACJ,EAAE,EAAC,eAAe,EAClB,KAAK,EAAE,IAAI,EACX,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAChD,WAAW,EAAC,UAAU,EACtB,SAAS,QACT,QAAQ,SACR,GACI,GACF,EACR,MAAC,YAAY,IAAC,SAAS,EAAC,MAAM,aAC5B,KAAC,MAAM,IAAC,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAC,OAAO,EAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,uBAE7E,EACT,KAAC,MAAM,IACL,IAAI,EAAC,QAAQ,EACb,IAAI,EAAC,IAAI,EACT,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,iBAChB,aAAa,4BAGlB,IACI,IACV,IACO,GACT,CACV,CAAA;AACH,CAAC","sourcesContent":["import { STUDIO_PROJECT_ROUTE, studioPath, useNavigate } from '@elytracms/studio/router'\nimport { useState } from 'react'\nimport type { FormEvent } from 'react'\nimport {\n Button,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Field,\n Input,\n Stack,\n} from '@elytracms/studio/ui'\nimport { useCms } from './cms-store'\n\n/**\n * Create a page in ONE action (EC-192). Pages are documents in the `page`\n * collection (EC-187): this dialog mints the page document (stable slug id,\n * `cms.createPage`) and opens the new page's editor.\n *\n * EC-207 (\"routes as code\"): creating a page no longer persists an addressing\n * route to the backend — routes are authored in `elytra.config.ts` and read\n * from the resolved config, never written to or read from the DB. The page's\n * URL is bound by a route in the consuming repo's `cms/routes.ts`, so this\n * dialog only creates the page document.\n */\nexport function NewPageDialog({\n projectId,\n open,\n onOpenChange,\n}: {\n projectId: string\n /**\n * Configured locales. EC-207 dropped the per-page address/language inputs\n * (routes are config-sourced), so this is currently unused — kept on the prop\n * contract for the page-collection caller and a future config-aware preview.\n */\n locales?: readonly string[]\n open: boolean\n onOpenChange: (open: boolean) => void\n}) {\n const cms = useCms()\n const navigate = useNavigate()\n const [name, setName] = useState('')\n\n function reset() {\n setName('')\n }\n\n function handleOpenChange(next: boolean) {\n if (!next) reset()\n onOpenChange(next)\n }\n\n function submit(event: FormEvent) {\n event.preventDefault()\n if (name.trim() === '') return\n const ref = cms.createPage({ name: name.trim() })\n handleOpenChange(false)\n void navigate({\n to: STUDIO_PROJECT_ROUTE,\n params: { projectId, _splat: studioPath.cmsDocument('page', ref.id) },\n })\n }\n\n return (\n <Dialog open={open} onOpenChange={handleOpenChange}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>New page</DialogTitle>\n <DialogDescription>\n Give the page a name. You can design it next; its address is set in elytra.config.ts.\n </DialogDescription>\n </DialogHeader>\n <form onSubmit={submit}>\n <Stack gap=\"3\">\n <Field label=\"Name\" htmlFor=\"new-page-name\" required>\n <Input\n id=\"new-page-name\"\n value={name}\n onChange={(event) => setName(event.target.value)}\n placeholder=\"About us\"\n autoFocus\n required\n />\n </Field>\n </Stack>\n <DialogFooter className=\"mt-4\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => handleOpenChange(false)}>\n Cancel\n </Button>\n <Button\n type=\"submit\"\n size=\"sm\"\n disabled={name.trim() === ''}\n data-testid=\"create-page\"\n >\n Create page\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n )\n}\n"]}
@@ -1,17 +0,0 @@
1
- import type { Editor } from '@tiptap/react';
2
- interface EmbedControlProps {
3
- editor: Editor;
4
- /** The field's embed `allow` list (component ids). Empty/absent ⇒ any non-primitive. */
5
- allow?: string[];
6
- }
7
- /**
8
- * Insert a registry component into prose as a `componentEmbed` (EC-189/EC-314): the
9
- * third place constrained composition lives. The pick-list is the field's `allow`
10
- * list (or every non-primitive component when open), matching the `blocks` field and
11
- * the `validateRichTextEmbeds` leash. The inserted node holds a fresh `ComponentNode`
12
- * built from manifest prop defaults; its props are edited from the embed's own
13
- * inspector (deferred) — insertion + round-trip land here. Hidden when nothing is
14
- * embeddable.
15
- */
16
- export declare function EmbedControl({ editor, allow }: EmbedControlProps): import("react").JSX.Element | null;
17
- export {};
@@ -1,62 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useMemo, useState } from 'react';
3
- import { Blocks } from 'lucide-react';
4
- import { COMPONENT_EMBED_NODE_TYPE } from '@elytracms/core/rich-text';
5
- import { staticProp } from '@elytracms/core/project-graph';
6
- import { isPrimitive } from '@elytracms/core/component-registry';
7
- import { getStudioRegistry } from '@elytracms/studio/lib/registry';
8
- import { Dialog, DialogContent, DialogHeader, DialogTitle, Input, Stack, Text, } from '@elytracms/studio/ui';
9
- import { translate } from '@elytracms/studio/lib/i18n';
10
- import { cn } from '@elytracms/studio/lib/utils';
11
- import { ToolbarButton } from './toolbar-button';
12
- /**
13
- * Insert a registry component into prose as a `componentEmbed` (EC-189/EC-314): the
14
- * third place constrained composition lives. The pick-list is the field's `allow`
15
- * list (or every non-primitive component when open), matching the `blocks` field and
16
- * the `validateRichTextEmbeds` leash. The inserted node holds a fresh `ComponentNode`
17
- * built from manifest prop defaults; its props are edited from the embed's own
18
- * inspector (deferred) — insertion + round-trip land here. Hidden when nothing is
19
- * embeddable.
20
- */
21
- export function EmbedControl({ editor, allow }) {
22
- const [open, setOpen] = useState(false);
23
- const [query, setQuery] = useState('');
24
- const embeddable = useMemo(() => {
25
- const all = getStudioRegistry().registry.list();
26
- const permitted = allow && allow.length > 0 ? all.filter((m) => allow.includes(m.id)) : all.filter((m) => !isPrimitive(m.id));
27
- return permitted.filter((m) => m.clientRenderable !== false);
28
- }, [allow]);
29
- const results = useMemo(() => {
30
- const q = query.trim().toLowerCase();
31
- if (!q)
32
- return embeddable;
33
- return embeddable.filter((m) => (m.title ?? m.id).toLowerCase().includes(q) || m.id.toLowerCase().includes(q));
34
- }, [embeddable, query]);
35
- if (embeddable.length === 0)
36
- return null;
37
- function insert(manifest) {
38
- editor
39
- .chain()
40
- .focus()
41
- .insertContent({ type: COMPONENT_EMBED_NODE_TYPE, attrs: { node: embedNode(manifest) } })
42
- .run();
43
- setOpen(false);
44
- setQuery('');
45
- }
46
- return (_jsxs(_Fragment, { children: [_jsx(ToolbarButton, { label: translate('richText.embed.add'), onClick: () => setOpen(true), children: _jsx(Blocks, { className: "size-3.5" }) }), _jsx(Dialog, { open: open, onOpenChange: setOpen, children: _jsxs(DialogContent, { className: "max-w-md", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: translate('richText.embed.add') }) }), _jsxs(Stack, { gap: "2", children: [_jsx(Input, { autoFocus: true, value: query, placeholder: translate('richText.link.documentSearch'), onChange: (e) => setQuery(e.target.value) }), _jsx(Stack, { gap: "none", className: "max-h-72 overflow-y-auto", children: results.length === 0 ? (_jsx(Text, { as: "span", size: "xs", tone: "muted", className: "px-1 py-2", children: translate('richText.embed.empty') })) : (results.map((manifest) => (_jsxs("button", { type: "button", onClick: () => insert(manifest), className: cn('flex w-full items-center gap-2.5 rounded-md px-2 py-2 text-left', 'hover:bg-muted focus-visible:bg-muted outline-none'), children: [_jsx(Blocks, { className: "size-4 shrink-0 text-muted-foreground" }), _jsxs("span", { className: "flex min-w-0 flex-1 flex-col", children: [_jsx("span", { className: "truncate text-sm font-medium", children: manifest.title ?? manifest.id }), _jsx("span", { className: "truncate text-xs text-muted-foreground", children: manifest.id })] })] }, manifest.id)))) })] })] }) })] }));
47
- }
48
- /** A fresh ComponentNode from a manifest's prop defaults (mirrors builder node-factory). */
49
- function embedNode(manifest) {
50
- const props = {};
51
- for (const [name, spec] of Object.entries(manifest.props)) {
52
- if (spec.default !== undefined)
53
- props[name] = staticProp(spec.default);
54
- }
55
- return { id: newEmbedId(), componentId: manifest.id, props };
56
- }
57
- /** A unique id for an embedded node (studio runs in the browser; crypto is present). */
58
- function newEmbedId() {
59
- const uuid = globalThis.crypto?.randomUUID?.();
60
- return uuid ? `embed-${uuid}` : `embed-${Math.random().toString(36).slice(2)}`;
61
- }
62
- //# sourceMappingURL=embed-control.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"embed-control.js","sourceRoot":"","sources":["../../../../src/components/cms/rich-text/embed-control.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo, useState } from 'react'\nimport { Blocks } from 'lucide-react'\nimport type { Editor } from '@tiptap/react'\nimport { COMPONENT_EMBED_NODE_TYPE } from '@elytracms/core/rich-text'\nimport { staticProp } from '@elytracms/core/project-graph'\nimport type { ComponentNode, JsonValue } from '@elytracms/core/project-graph'\nimport { isPrimitive } from '@elytracms/core/component-registry'\nimport type { ComponentManifest } from '@elytracms/core/component-registry'\nimport { getStudioRegistry } from '@elytracms/studio/lib/registry'\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n Input,\n Stack,\n Text,\n} from '@elytracms/studio/ui'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { ToolbarButton } from './toolbar-button'\n\ninterface EmbedControlProps {\n editor: Editor\n /** The field's embed `allow` list (component ids). Empty/absent ⇒ any non-primitive. */\n allow?: string[]\n}\n\n/**\n * Insert a registry component into prose as a `componentEmbed` (EC-189/EC-314): the\n * third place constrained composition lives. The pick-list is the field's `allow`\n * list (or every non-primitive component when open), matching the `blocks` field and\n * the `validateRichTextEmbeds` leash. The inserted node holds a fresh `ComponentNode`\n * built from manifest prop defaults; its props are edited from the embed's own\n * inspector (deferred) — insertion + round-trip land here. Hidden when nothing is\n * embeddable.\n */\nexport function EmbedControl({ editor, allow }: EmbedControlProps) {\n const [open, setOpen] = useState(false)\n const [query, setQuery] = useState('')\n\n const embeddable = useMemo(() => {\n const all = getStudioRegistry().registry.list()\n const permitted =\n allow && allow.length > 0 ? all.filter((m) => allow.includes(m.id)) : all.filter((m) => !isPrimitive(m.id))\n return permitted.filter((m) => m.clientRenderable !== false)\n }, [allow])\n\n const results = useMemo(() => {\n const q = query.trim().toLowerCase()\n if (!q) return embeddable\n return embeddable.filter(\n (m) => (m.title ?? m.id).toLowerCase().includes(q) || m.id.toLowerCase().includes(q),\n )\n }, [embeddable, query])\n\n if (embeddable.length === 0) return null\n\n function insert(manifest: ComponentManifest) {\n editor\n .chain()\n .focus()\n .insertContent({ type: COMPONENT_EMBED_NODE_TYPE, attrs: { node: embedNode(manifest) } })\n .run()\n setOpen(false)\n setQuery('')\n }\n\n return (\n <>\n <ToolbarButton label={translate('richText.embed.add')} onClick={() => setOpen(true)}>\n <Blocks className=\"size-3.5\" />\n </ToolbarButton>\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogContent className=\"max-w-md\">\n <DialogHeader>\n <DialogTitle>{translate('richText.embed.add')}</DialogTitle>\n </DialogHeader>\n <Stack gap=\"2\">\n <Input\n autoFocus\n value={query}\n placeholder={translate('richText.link.documentSearch')}\n onChange={(e) => setQuery(e.target.value)}\n />\n <Stack gap=\"none\" className=\"max-h-72 overflow-y-auto\">\n {results.length === 0 ? (\n <Text as=\"span\" size=\"xs\" tone=\"muted\" className=\"px-1 py-2\">\n {translate('richText.embed.empty')}\n </Text>\n ) : (\n results.map((manifest) => (\n <button\n key={manifest.id}\n type=\"button\"\n onClick={() => insert(manifest)}\n className={cn(\n 'flex w-full items-center gap-2.5 rounded-md px-2 py-2 text-left',\n 'hover:bg-muted focus-visible:bg-muted outline-none',\n )}\n >\n <Blocks className=\"size-4 shrink-0 text-muted-foreground\" />\n <span className=\"flex min-w-0 flex-1 flex-col\">\n <span className=\"truncate text-sm font-medium\">{manifest.title ?? manifest.id}</span>\n <span className=\"truncate text-xs text-muted-foreground\">{manifest.id}</span>\n </span>\n </button>\n ))\n )}\n </Stack>\n </Stack>\n </DialogContent>\n </Dialog>\n </>\n )\n}\n\n/** A fresh ComponentNode from a manifest's prop defaults (mirrors builder node-factory). */\nfunction embedNode(manifest: ComponentManifest): ComponentNode {\n const props: ComponentNode['props'] = {}\n for (const [name, spec] of Object.entries(manifest.props)) {\n if (spec.default !== undefined) props[name] = staticProp(spec.default as JsonValue)\n }\n return { id: newEmbedId(), componentId: manifest.id, props }\n}\n\n/** A unique id for an embedded node (studio runs in the browser; crypto is present). */\nfunction newEmbedId(): string {\n const uuid = globalThis.crypto?.randomUUID?.()\n return uuid ? `embed-${uuid}` : `embed-${Math.random().toString(36).slice(2)}`\n}\n"]}
@@ -1,16 +0,0 @@
1
- import type { Editor } from '@tiptap/react';
2
- import type { AssetsStore } from '../../assets/assets-store';
3
- interface ImageControlProps {
4
- editor: Editor;
5
- assets: AssetsStore | null;
6
- }
7
- /**
8
- * Insert an editorial image (EC-314/EC-301): pick an asset from the project library
9
- * and drop an `image` node carrying the canonical asset envelope at `attrs.ref`
10
- * (`{ type: 'asset', id }`) — so the reference-extractor indexes it as an asset use
11
- * and delivery resolves it to the live URL. `attrs.src` snapshots the current URL for
12
- * the editor preview and as delivery's external fallback. Rendered only when an asset
13
- * backend is present.
14
- */
15
- export declare function ImageControl({ editor, assets }: ImageControlProps): import("react").JSX.Element | null;
16
- export {};
@@ -1,36 +0,0 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState } from 'react';
3
- import { ImagePlus } from 'lucide-react';
4
- import { assetNode } from '@elytracms/core/cms-core';
5
- import { translate } from '@elytracms/studio/lib/i18n';
6
- import { AssetPicker } from '../asset-picker';
7
- import { ToolbarButton } from './toolbar-button';
8
- /**
9
- * Insert an editorial image (EC-314/EC-301): pick an asset from the project library
10
- * and drop an `image` node carrying the canonical asset envelope at `attrs.ref`
11
- * (`{ type: 'asset', id }`) — so the reference-extractor indexes it as an asset use
12
- * and delivery resolves it to the live URL. `attrs.src` snapshots the current URL for
13
- * the editor preview and as delivery's external fallback. Rendered only when an asset
14
- * backend is present.
15
- */
16
- export function ImageControl({ editor, assets }) {
17
- const [open, setOpen] = useState(false);
18
- if (!assets)
19
- return null;
20
- function insert(assetId) {
21
- setOpen(false);
22
- if (!assetId)
23
- return;
24
- const record = assets.assets.find((a) => a.id === assetId);
25
- editor
26
- .chain()
27
- .focus()
28
- .insertContent({
29
- type: 'image',
30
- attrs: { src: record?.url ?? '', alt: record?.alt ?? '', ref: assetNode(assetId) },
31
- })
32
- .run();
33
- }
34
- return (_jsxs(_Fragment, { children: [_jsx(ToolbarButton, { label: translate('richText.image.add'), onClick: () => setOpen(true), children: _jsx(ImagePlus, { className: "size-3.5" }) }), _jsx(AssetPicker, { open: open, onOpenChange: setOpen, value: null, onChange: insert, accept: "image/*" })] }));
35
- }
36
- //# sourceMappingURL=image-control.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"image-control.js","sourceRoot":"","sources":["../../../../src/components/cms/rich-text/image-control.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAExC,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;AAEtD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAOhD;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,EAAqB;IAChE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAEvC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IAExB,SAAS,MAAM,CAAC,OAAsB;QACpC,OAAO,CAAC,KAAK,CAAC,CAAA;QACd,IAAI,CAAC,OAAO;YAAE,OAAM;QACpB,MAAM,MAAM,GAAG,MAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,CAAA;QAC3D,MAAM;aACH,KAAK,EAAE;aACP,KAAK,EAAE;aACP,aAAa,CAAC;YACb,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE;SACnF,CAAC;aACD,GAAG,EAAE,CAAA;IACV,CAAC;IAED,OAAO,CACL,8BACE,KAAC,aAAa,IAAC,KAAK,EAAE,SAAS,CAAC,oBAAoB,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,YACjF,KAAC,SAAS,IAAC,SAAS,EAAC,UAAU,GAAG,GACpB,EAChB,KAAC,WAAW,IAAC,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAC,SAAS,GAAG,IACjG,CACJ,CAAA;AACH,CAAC","sourcesContent":["import { useState } from 'react'\nimport { ImagePlus } from 'lucide-react'\nimport type { Editor } from '@tiptap/react'\nimport { assetNode } from '@elytracms/core/cms-core'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport type { AssetsStore } from '../../assets/assets-store'\nimport { AssetPicker } from '../asset-picker'\nimport { ToolbarButton } from './toolbar-button'\n\ninterface ImageControlProps {\n editor: Editor\n assets: AssetsStore | null\n}\n\n/**\n * Insert an editorial image (EC-314/EC-301): pick an asset from the project library\n * and drop an `image` node carrying the canonical asset envelope at `attrs.ref`\n * (`{ type: 'asset', id }`) — so the reference-extractor indexes it as an asset use\n * and delivery resolves it to the live URL. `attrs.src` snapshots the current URL for\n * the editor preview and as delivery's external fallback. Rendered only when an asset\n * backend is present.\n */\nexport function ImageControl({ editor, assets }: ImageControlProps) {\n const [open, setOpen] = useState(false)\n\n if (!assets) return null\n\n function insert(assetId: string | null) {\n setOpen(false)\n if (!assetId) return\n const record = assets!.assets.find((a) => a.id === assetId)\n editor\n .chain()\n .focus()\n .insertContent({\n type: 'image',\n attrs: { src: record?.url ?? '', alt: record?.alt ?? '', ref: assetNode(assetId) },\n })\n .run()\n }\n\n return (\n <>\n <ToolbarButton label={translate('richText.image.add')} onClick={() => setOpen(true)}>\n <ImagePlus className=\"size-3.5\" />\n </ToolbarButton>\n <AssetPicker open={open} onOpenChange={setOpen} value={null} onChange={insert} accept=\"image/*\" />\n </>\n )\n}\n"]}
@@ -1,10 +0,0 @@
1
- import type { ComponentManifest } from '@elytracms/core/component-registry';
2
- /**
3
- * Visual fixture runner (brief §7.2, §8.3, §11, EC-054). Renders each of a
4
- * component's preview states through the runtime renderer + registry — the same
5
- * render path the Builder and export use — so output is deterministic and
6
- * agent-verifiable. Incompatible components surface the renderer's fallback.
7
- */
8
- export declare function FixtureRunner({ manifest }: {
9
- manifest: ComponentManifest;
10
- }): import("react").JSX.Element;
@@ -1,27 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useMemo, useState } from 'react';
3
- import { renderNode } from '@elytracms/core/runtime-renderer';
4
- import { getStudioRegistry, previewContext } from '@elytracms/studio/lib/registry';
5
- import { previewSpecs } from '@elytracms/studio/lib/registry/preview';
6
- import { Panel, PanelHeader, Row, Spacer, Text } from '@elytracms/studio/ui';
7
- import { translate } from '@elytracms/studio/lib/i18n';
8
- import { cn } from '@elytracms/studio/lib/utils';
9
- /**
10
- * Visual fixture runner (brief §7.2, §8.3, §11, EC-054). Renders each of a
11
- * component's preview states through the runtime renderer + registry — the same
12
- * render path the Builder and export use — so output is deterministic and
13
- * agent-verifiable. Incompatible components surface the renderer's fallback.
14
- */
15
- export function FixtureRunner({ manifest }) {
16
- const studio = getStudioRegistry();
17
- const specs = useMemo(() => previewSpecs(manifest), [manifest]);
18
- const [index, setIndex] = useState(0);
19
- const ctx = useMemo(() => previewContext(studio), [studio]);
20
- const active = specs[Math.min(index, specs.length - 1)];
21
- return (_jsxs(Panel, { children: [_jsxs(PanelHeader, { children: [_jsx(Text, { size: "sm", weight: "semibold", children: translate('components.fixtureRunner.preview') }), _jsx(Spacer, {}), _jsx(Text, { size: "xs", tone: "muted", mono: true, children: translate(specs.length === 1
22
- ? 'components.fixtureRunner.stateCount.one'
23
- : 'components.fixtureRunner.stateCount.other', { count: specs.length }) })] }), specs.length > 1 ? (_jsx(Row, { gap: "1", wrap: true, className: "border-b border-border px-3 py-2", role: "group", "aria-label": translate('components.fixtureRunner.statesAria'), children: specs.map((spec, i) => (_jsx("button", { type: "button", "aria-pressed": i === index, onClick: () => setIndex(i), className: cn('rounded-md px-2.5 py-1 text-xs font-medium transition-colors', i === index
24
- ? 'bg-accent text-accent-foreground'
25
- : 'text-muted-foreground hover:bg-muted hover:text-foreground'), children: spec.name }, spec.name))) })) : null, _jsx("div", { className: "canvas-grid p-6", "data-fixture-state": active?.name, children: _jsx("div", { className: "mx-auto max-w-xl rounded-lg border border-border bg-background p-6 shadow-sm", children: active ? renderNode(active.node, ctx) : null }) })] }));
26
- }
27
- //# sourceMappingURL=fixture-runner.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fixture-runner.js","sourceRoot":"","sources":["../../../src/components/components/fixture-runner.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAA;AAE7D,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAClF,OAAO,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAA;AACrE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAA;AAC5E,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;AACtD,OAAO,EAAE,EAAE,EAAE,MAAM,6BAA6B,CAAA;AAEhD;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,EAAE,QAAQ,EAAmC;IACzE,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAA;IAClC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC/D,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAA;IACrC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IAC3D,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAA;IAEvD,OAAO,CACL,MAAC,KAAK,eACJ,MAAC,WAAW,eACV,KAAC,IAAI,IAAC,IAAI,EAAC,IAAI,EAAC,MAAM,EAAC,UAAU,YAC9B,SAAS,CAAC,kCAAkC,CAAC,GACzC,EACP,KAAC,MAAM,KAAG,EACV,KAAC,IAAI,IAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAC,IAAI,kBAC9B,SAAS,CACR,KAAK,CAAC,MAAM,KAAK,CAAC;4BAChB,CAAC,CAAC,yCAAyC;4BAC3C,CAAC,CAAC,2CAA2C,EAC/C,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,CACxB,GACI,IACK,EAEb,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAClB,KAAC,GAAG,IACF,GAAG,EAAC,GAAG,EACP,IAAI,QACJ,SAAS,EAAC,kCAAkC,EAC5C,IAAI,EAAC,OAAO,gBACA,SAAS,CAAC,qCAAqC,CAAC,YAE3D,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CACtB,iBAEE,IAAI,EAAC,QAAQ,kBACC,CAAC,KAAK,KAAK,EACzB,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAC1B,SAAS,EAAE,EAAE,CACX,8DAA8D,EAC9D,CAAC,KAAK,KAAK;wBACT,CAAC,CAAC,kCAAkC;wBACpC,CAAC,CAAC,4DAA4D,CACjE,YAEA,IAAI,CAAC,IAAI,IAXL,IAAI,CAAC,IAAI,CAYP,CACV,CAAC,GACE,CACP,CAAC,CAAC,CAAC,IAAI,EAER,cAAK,SAAS,EAAC,iBAAiB,wBAAqB,MAAM,EAAE,IAAI,YAC/D,cAAK,SAAS,EAAC,8EAA8E,YAC1F,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GACzC,GACF,IACA,CACT,CAAA;AACH,CAAC","sourcesContent":["import { useMemo, useState } from 'react'\nimport { renderNode } from '@elytracms/core/runtime-renderer'\nimport type { ComponentManifest } from '@elytracms/core/component-registry'\nimport { getStudioRegistry, previewContext } from '@elytracms/studio/lib/registry'\nimport { previewSpecs } from '@elytracms/studio/lib/registry/preview'\nimport { Panel, PanelHeader, Row, Spacer, Text } from '@elytracms/studio/ui'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { cn } from '@elytracms/studio/lib/utils'\n\n/**\n * Visual fixture runner (brief §7.2, §8.3, §11, EC-054). Renders each of a\n * component's preview states through the runtime renderer + registry — the same\n * render path the Builder and export use — so output is deterministic and\n * agent-verifiable. Incompatible components surface the renderer's fallback.\n */\nexport function FixtureRunner({ manifest }: { manifest: ComponentManifest }) {\n const studio = getStudioRegistry()\n const specs = useMemo(() => previewSpecs(manifest), [manifest])\n const [index, setIndex] = useState(0)\n const ctx = useMemo(() => previewContext(studio), [studio])\n const active = specs[Math.min(index, specs.length - 1)]\n\n return (\n <Panel>\n <PanelHeader>\n <Text size=\"sm\" weight=\"semibold\">\n {translate('components.fixtureRunner.preview')}\n </Text>\n <Spacer />\n <Text size=\"xs\" tone=\"muted\" mono>\n {translate(\n specs.length === 1\n ? 'components.fixtureRunner.stateCount.one'\n : 'components.fixtureRunner.stateCount.other',\n { count: specs.length },\n )}\n </Text>\n </PanelHeader>\n\n {specs.length > 1 ? (\n <Row\n gap=\"1\"\n wrap\n className=\"border-b border-border px-3 py-2\"\n role=\"group\"\n aria-label={translate('components.fixtureRunner.statesAria')}\n >\n {specs.map((spec, i) => (\n <button\n key={spec.name}\n type=\"button\"\n aria-pressed={i === index}\n onClick={() => setIndex(i)}\n className={cn(\n 'rounded-md px-2.5 py-1 text-xs font-medium transition-colors',\n i === index\n ? 'bg-accent text-accent-foreground'\n : 'text-muted-foreground hover:bg-muted hover:text-foreground',\n )}\n >\n {spec.name}\n </button>\n ))}\n </Row>\n ) : null}\n\n <div className=\"canvas-grid p-6\" data-fixture-state={active?.name}>\n <div className=\"mx-auto max-w-xl rounded-lg border border-border bg-background p-6 shadow-sm\">\n {active ? renderNode(active.node, ctx) : null}\n </div>\n </div>\n </Panel>\n )\n}\n"]}
@@ -1,12 +0,0 @@
1
- /**
2
- * Param-driven builder selection (EC-172). Reference-panel entries deep-link
3
- * to `/$projectId/builder?page=<pageId>&node=<nodeId>`; this headless
4
- * component applies those params to the builder store — switching the active
5
- * page, selecting the node (falling back to the page root when the node has
6
- * drifted away), and scrolling the canvas wrapper (`data-ec-node-id`) into
7
- * view. Pure selection state: nothing here mutates the graph.
8
- */
9
- export declare function BuilderDeepLink({ pageId, nodeId }: {
10
- pageId?: string;
11
- nodeId?: string;
12
- }): null;
@@ -1,53 +0,0 @@
1
- import { useEffect, useRef } from 'react';
2
- import { getNode } from '@elytracms/core/project-graph';
3
- import { useBuilder } from '../builder/builder-store';
4
- /**
5
- * Param-driven builder selection (EC-172). Reference-panel entries deep-link
6
- * to `/$projectId/builder?page=<pageId>&node=<nodeId>`; this headless
7
- * component applies those params to the builder store — switching the active
8
- * page, selecting the node (falling back to the page root when the node has
9
- * drifted away), and scrolling the canvas wrapper (`data-ec-node-id`) into
10
- * view. Pure selection state: nothing here mutates the graph.
11
- */
12
- export function BuilderDeepLink({ pageId, nodeId }) {
13
- const builder = useBuilder();
14
- const { dispatch } = builder;
15
- const graphRef = useRef(builder.present);
16
- graphRef.current = builder.present;
17
- useEffect(() => {
18
- if (pageId === undefined && nodeId === undefined)
19
- return;
20
- const graph = graphRef.current;
21
- const page = (pageId !== undefined ? graph.pages.find((p) => p.id === pageId) : undefined) ??
22
- (nodeId !== undefined
23
- ? graph.pages.find((p) => getNode(p.root, nodeId) !== undefined)
24
- : undefined);
25
- if (!page)
26
- return;
27
- const selectedId = nodeId !== undefined && getNode(page.root, nodeId) ? nodeId : page.root.id;
28
- dispatch({ type: 'select', id: selectedId, pageId: page.id });
29
- // The canvas marks every rendered node with `data-ec-node-id`; scroll the
30
- // selection into view once the page has rendered (bounded retries — the
31
- // canvas may need a frame or two after a page switch).
32
- let cancelled = false;
33
- let attempts = 0;
34
- const tryScroll = () => {
35
- if (cancelled)
36
- return;
37
- const element = document.querySelector(`[data-ec-node-id="${CSS.escape(selectedId)}"]`);
38
- if (element) {
39
- element.scrollIntoView({ block: 'center', behavior: 'smooth' });
40
- }
41
- else if (attempts < 10) {
42
- attempts += 1;
43
- window.setTimeout(tryScroll, 60);
44
- }
45
- };
46
- window.setTimeout(tryScroll, 60);
47
- return () => {
48
- cancelled = true;
49
- };
50
- }, [pageId, nodeId, dispatch]);
51
- return null;
52
- }
53
- //# sourceMappingURL=builder-deep-link.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"builder-deep-link.js","sourceRoot":"","sources":["../../../src/components/references/builder-deep-link.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAA;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AAErD;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,EAAE,MAAM,EAAE,MAAM,EAAwC;IACtF,MAAM,OAAO,GAAG,UAAU,EAAE,CAAA;IAC5B,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAA;IAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IACxC,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAA;IAElC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS;YAAE,OAAM;QACxD,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAA;QAC9B,MAAM,IAAI,GACR,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC7E,CAAC,MAAM,KAAK,SAAS;gBACnB,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,SAAS,CAAC;gBAChE,CAAC,CAAC,SAAS,CAAC,CAAA;QAChB,IAAI,CAAC,IAAI;YAAE,OAAM;QACjB,MAAM,UAAU,GAAG,MAAM,KAAK,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAA;QAC7F,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;QAE7D,0EAA0E;QAC1E,wEAAwE;QACxE,uDAAuD;QACvD,IAAI,SAAS,GAAG,KAAK,CAAA;QACrB,IAAI,QAAQ,GAAG,CAAC,CAAA;QAChB,MAAM,SAAS,GAAG,GAAG,EAAE;YACrB,IAAI,SAAS;gBAAE,OAAM;YACrB,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,qBAAqB,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;YACvF,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,cAAc,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAA;YACjE,CAAC;iBAAM,IAAI,QAAQ,GAAG,EAAE,EAAE,CAAC;gBACzB,QAAQ,IAAI,CAAC,CAAA;gBACb,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;YAClC,CAAC;QACH,CAAC,CAAA;QACD,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;QAChC,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAA;QAClB,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAA;IAE9B,OAAO,IAAI,CAAA;AACb,CAAC","sourcesContent":["import { useEffect, useRef } from 'react'\nimport { getNode } from '@elytracms/core/project-graph'\nimport { useBuilder } from '../builder/builder-store'\n\n/**\n * Param-driven builder selection (EC-172). Reference-panel entries deep-link\n * to `/$projectId/builder?page=<pageId>&node=<nodeId>`; this headless\n * component applies those params to the builder store — switching the active\n * page, selecting the node (falling back to the page root when the node has\n * drifted away), and scrolling the canvas wrapper (`data-ec-node-id`) into\n * view. Pure selection state: nothing here mutates the graph.\n */\nexport function BuilderDeepLink({ pageId, nodeId }: { pageId?: string; nodeId?: string }) {\n const builder = useBuilder()\n const { dispatch } = builder\n const graphRef = useRef(builder.present)\n graphRef.current = builder.present\n\n useEffect(() => {\n if (pageId === undefined && nodeId === undefined) return\n const graph = graphRef.current\n const page =\n (pageId !== undefined ? graph.pages.find((p) => p.id === pageId) : undefined) ??\n (nodeId !== undefined\n ? graph.pages.find((p) => getNode(p.root, nodeId) !== undefined)\n : undefined)\n if (!page) return\n const selectedId = nodeId !== undefined && getNode(page.root, nodeId) ? nodeId : page.root.id\n dispatch({ type: 'select', id: selectedId, pageId: page.id })\n\n // The canvas marks every rendered node with `data-ec-node-id`; scroll the\n // selection into view once the page has rendered (bounded retries — the\n // canvas may need a frame or two after a page switch).\n let cancelled = false\n let attempts = 0\n const tryScroll = () => {\n if (cancelled) return\n const element = document.querySelector(`[data-ec-node-id=\"${CSS.escape(selectedId)}\"]`)\n if (element) {\n element.scrollIntoView({ block: 'center', behavior: 'smooth' })\n } else if (attempts < 10) {\n attempts += 1\n window.setTimeout(tryScroll, 60)\n }\n }\n window.setTimeout(tryScroll, 60)\n return () => {\n cancelled = true\n }\n }, [pageId, nodeId, dispatch])\n\n return null\n}\n"]}
@@ -1,9 +0,0 @@
1
- import type { RedirectResolution } from '@elytracms/core/cms-core';
2
- /**
3
- * Visualizes a redirect chain from the engine's {@link RedirectResolution}:
4
- * every hop in order, with the loop entry point highlighted when the chain
5
- * closes a loop (EC-170).
6
- */
7
- export declare function RedirectChain({ resolution }: {
8
- resolution: RedirectResolution;
9
- }): import("react").JSX.Element;