@jxsuite/studio 2.4.3 → 4.0.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 (208) hide show
  1. package/README.md +5 -5
  2. package/dist/chunks/Overlay.dev-723bv0df.js +23 -0
  3. package/dist/chunks/cf-settings-45fgyx8y.js +21 -0
  4. package/dist/chunks/{components-z6cnkyy1.js → components-zmx10t62.js} +6 -5
  5. package/dist/chunks/content-source-t88vb2dr.js +49 -0
  6. package/dist/chunks/{convert-to-repeater-k10dvcc7.js → convert-to-repeater-dhw1nrz9.js} +27 -18
  7. package/dist/chunks/entry-commands-6z6bhxg0.js +46 -0
  8. package/dist/chunks/{extension-sections-0ada0xcw.js → extension-sections-3ydgjbdy.js} +32 -23
  9. package/dist/chunks/file-ops-rskmhxyq.js +48 -0
  10. package/dist/chunks/files-0cratsr0.js +92 -0
  11. package/dist/chunks/{format-host-wewba4nq.js → format-host-tgcmfs4p.js} +3 -3
  12. package/dist/chunks/fs-events-hrrg328g.js +21 -0
  13. package/dist/chunks/{git-panel-2dh1aw50.js → git-panel-0yywyk76.js} +21 -15
  14. package/dist/chunks/{jx-validate-jj9rnt4n.js → jx-validate-8q2g05x1.js} +6 -4
  15. package/dist/chunks/layers-panel-z3tqe5cd.js +67 -0
  16. package/dist/chunks/layers-q75tj2mf.js +45 -0
  17. package/dist/chunks/lit-html-j055mkh8.js +22 -0
  18. package/dist/chunks/monaco-buffer-dqw0xxpx.js +25 -0
  19. package/dist/chunks/{monaco-setup-a5wkmbgh.js → monaco-setup-rws7k4br.js} +4 -4
  20. package/dist/chunks/notify-yjm79n4s.js +30 -0
  21. package/dist/chunks/parse-24d0gay3.js +19 -0
  22. package/dist/chunks/platform-ba1j1gbh.js +16 -0
  23. package/dist/chunks/publish-panel-54jvhskq.js +28 -0
  24. package/dist/chunks/quick-search-cgfmjwq5.js +65 -0
  25. package/dist/chunks/references-3qx8fkyp.js +29 -0
  26. package/dist/chunks/right-panel-cqp8bc4v.js +46 -0
  27. package/dist/chunks/sp-overlay.dev-yztmtrs1.js +18 -0
  28. package/dist/chunks/sp-popover.dev-n2etmqdp.js +9 -0
  29. package/dist/chunks/sp-progress-circle.dev-hryhj0es.js +15 -0
  30. package/dist/chunks/sp-tooltip.dev-xcvpnqr0.js +15 -0
  31. package/dist/chunks/{sp-tray.dev-64v4pxw8.js → sp-tray.dev-tkbscm06.js} +5 -5
  32. package/dist/chunks/{studio-f5yyvqxv.js → studio-1hbqnt19.js} +37 -31
  33. package/dist/chunks/studio-2zkz8evn.js +3163 -0
  34. package/dist/chunks/{studio-0b6fs05q.js → studio-4pqqxbrt.js} +23 -15
  35. package/dist/chunks/{studio-kvfx9z2c.js → studio-4rzyrtjz.js} +70 -31
  36. package/dist/chunks/{studio-ef8t53vc.js → studio-5q69gfag.js} +60 -56
  37. package/dist/chunks/{studio-v2c5pmjj.js → studio-5rywrkxz.js} +565 -133
  38. package/dist/chunks/{studio-6kv3apa9.js → studio-68n67094.js} +25 -9
  39. package/dist/chunks/{studio-0rqqhrdy.js → studio-7nte2hj4.js} +2 -2
  40. package/dist/chunks/{studio-hyn3vhwr.js → studio-8swrjbny.js} +31 -18
  41. package/dist/chunks/studio-92ab2jqe.js +282 -0
  42. package/dist/chunks/{studio-sas7mt3k.js → studio-9ab8gqsm.js} +2 -2
  43. package/dist/chunks/{studio-28xc8ws4.js → studio-9c4k4vhv.js} +14 -10
  44. package/dist/chunks/studio-9n4mrmnb.js +184 -0
  45. package/dist/chunks/{studio-tr20m8g8.js → studio-9r6j5ev1.js} +37 -2
  46. package/dist/chunks/{studio-aweyr4v1.js → studio-ahjfdy6e.js} +9 -7
  47. package/dist/chunks/{studio-s519zc99.js → studio-bgxt93ga.js} +3 -3
  48. package/dist/chunks/{studio-26sv44br.js → studio-cb12yz9w.js} +8543 -8784
  49. package/dist/chunks/studio-cft9r4r7.js +119 -0
  50. package/dist/chunks/{studio-rqemfhz6.js → studio-eenfkt4e.js} +6 -6
  51. package/dist/chunks/studio-eesa1myv.js +498 -0
  52. package/dist/chunks/{studio-ay8wcr2b.js → studio-eqq1w638.js} +7 -9
  53. package/dist/chunks/{studio-ke244pam.js → studio-ex8zyp98.js} +51 -25
  54. package/dist/chunks/studio-gv8vvshc.js +118 -0
  55. package/dist/chunks/studio-hbtp0eh1.js +1315 -0
  56. package/dist/chunks/{studio-cz2j1c0g.js → studio-htsf0w6m.js} +75 -123
  57. package/dist/chunks/{studio-pyrw8h0w.js → studio-kjjsjak4.js} +528 -212
  58. package/dist/chunks/{studio-5x5774ak.js → studio-kryvsw6j.js} +3 -3
  59. package/dist/chunks/studio-kyh9avvv.js +28 -0
  60. package/dist/chunks/{studio-jnakhg87.js → studio-kyk2v92a.js} +14 -14
  61. package/dist/chunks/{studio-twsafr1e.js → studio-m3hwn7y1.js} +3 -3
  62. package/dist/chunks/{studio-tzx3xmvx.js → studio-mmv72a27.js} +8 -8
  63. package/dist/chunks/{studio-vhk5fmfv.js → studio-n8b9wqwy.js} +5 -5
  64. package/dist/chunks/{studio-cjm7fdjf.js → studio-p4ngc046.js} +8 -104
  65. package/dist/chunks/{studio-sccge2wf.js → studio-p8j86wag.js} +2 -2
  66. package/dist/chunks/{studio-v1va0vhd.js → studio-pdfjntbk.js} +75 -139
  67. package/dist/chunks/studio-q43a5y9h.js +394 -0
  68. package/dist/chunks/studio-q7v10cg2.js +106 -0
  69. package/dist/chunks/{studio-2w11grav.js → studio-qq6jym04.js} +3 -3
  70. package/dist/chunks/studio-r1r7afxx.js +1066 -0
  71. package/dist/chunks/{studio-3fk1ac9z.js → studio-rdx8jcxy.js} +4 -4
  72. package/dist/chunks/{studio-4mqb9a0j.js → studio-rn9ta2mz.js} +4 -4
  73. package/dist/chunks/studio-sf7zjgv1.js +91 -0
  74. package/dist/chunks/studio-t7qb9db8.js +665 -0
  75. package/dist/chunks/studio-tmc5emrw.js +8 -0
  76. package/dist/chunks/{studio-wdt9y92a.js → studio-txwkm6p9.js} +2 -2
  77. package/dist/chunks/{studio-dgj7gq44.js → studio-v38hmvx1.js} +7 -7
  78. package/dist/chunks/{studio-7ejemhej.js → studio-vadzgkrz.js} +6 -6
  79. package/dist/chunks/studio-wcy8trfx.js +263 -0
  80. package/dist/chunks/{studio-hb7c46jy.js → studio-wx5609xd.js} +21 -15
  81. package/dist/chunks/studio-xrapxwwc.js +1539 -0
  82. package/dist/chunks/{studio-ws6ef6js.js → studio-yxrkyv8a.js} +41 -29
  83. package/dist/chunks/{studio-xm3dbxvn.js → studio-zczps70q.js} +2 -2
  84. package/dist/chunks/workspace-xpres40v.js +89 -0
  85. package/dist/iframe-entry.js +450 -48
  86. package/dist/studio.js +2455 -1761
  87. package/package.json +16 -15
  88. package/src/browse/library-layouts.ts +3 -3
  89. package/src/browse/library-pane.ts +59 -5
  90. package/src/browse/library-preview.ts +19 -3
  91. package/src/canvas/asset-refs.ts +119 -0
  92. package/src/canvas/asset-resolve.ts +256 -0
  93. package/src/canvas/canvas-live-render.ts +23 -15
  94. package/src/canvas/canvas-render.ts +23 -1
  95. package/src/canvas/iframe-entry.ts +1 -0
  96. package/src/canvas/iframe-host.ts +4 -0
  97. package/src/canvas/iframe-patch.ts +47 -21
  98. package/src/canvas/iframe-protocol.ts +9 -0
  99. package/src/canvas/iframe-render.ts +50 -16
  100. package/src/commands/app-commands.ts +4 -0
  101. package/src/commands/command-args.ts +29 -0
  102. package/src/commands/context.ts +15 -1
  103. package/src/commands/defaults.ts +29 -1
  104. package/src/commands/levels.ts +16 -0
  105. package/src/commands/live-context.ts +3 -0
  106. package/src/content/collection-match.ts +267 -0
  107. package/src/content/entry-commands.ts +38 -29
  108. package/src/content/entry-fields.ts +6 -0
  109. package/src/editor/file-drop-action.ts +2 -1
  110. package/src/editor/shortcuts.ts +5 -0
  111. package/src/files/file-ops.ts +10 -42
  112. package/src/files/files.ts +487 -61
  113. package/src/files/fs-events.ts +9 -0
  114. package/src/files/gitignore.ts +432 -0
  115. package/src/files/media-paths.ts +37 -14
  116. package/src/files/media-upload.ts +47 -6
  117. package/src/files/serialize-document.ts +60 -0
  118. package/src/format/convert-file.ts +511 -0
  119. package/src/format/format-choices.ts +199 -0
  120. package/src/grid/grid-idle.ts +45 -0
  121. package/src/grid/grid-view.ts +35 -0
  122. package/src/grid/schema-columns.ts +2 -1
  123. package/src/grid/sources/content-source.ts +24 -3
  124. package/src/media/media-open.ts +58 -0
  125. package/src/media/media-pane.ts +310 -0
  126. package/src/new-project/import-tab.ts +333 -160
  127. package/src/new-project/new-project-modal.ts +27 -34
  128. package/src/packages/ensure-deps.ts +14 -7
  129. package/src/packages/jxsuite-update.ts +11 -11
  130. package/src/page-params.ts +10 -46
  131. package/src/panels/activity-bar.ts +45 -16
  132. package/src/panels/ai-chat/attached-context.ts +6 -1
  133. package/src/panels/ai-chat/chat-view.ts +255 -13
  134. package/src/panels/ai-chat/composer.ts +21 -80
  135. package/src/panels/ai-panel.ts +116 -2
  136. package/src/panels/frontmatter-fields.ts +6 -2
  137. package/src/panels/navigator-panels.ts +7 -6
  138. package/src/panels/properties-panel.ts +8 -2
  139. package/src/panels/seo-modal.ts +5 -6
  140. package/src/panels/settings-menu.ts +799 -0
  141. package/src/panels/signals-panel.ts +2 -1
  142. package/src/panels/toolbar.ts +135 -15
  143. package/src/platforms/cloud.ts +34 -3
  144. package/src/platforms/devserver.ts +72 -34
  145. package/src/preview/preview-overlay.ts +226 -0
  146. package/src/services/ai-ask.ts +247 -0
  147. package/src/services/ai-import-tools.ts +494 -0
  148. package/src/services/ai-models.ts +101 -11
  149. package/src/services/ai-project-tools.ts +20 -26
  150. package/src/services/ai-settings.ts +69 -71
  151. package/src/services/ai-system-prompt.ts +88 -2
  152. package/src/services/ai-turn-signal.ts +70 -0
  153. package/src/services/cf-settings.ts +19 -37
  154. package/src/services/connection.ts +74 -0
  155. package/src/services/context-manager.ts +89 -0
  156. package/src/services/document-assistant.ts +49 -7
  157. package/src/services/idle.ts +6 -1
  158. package/src/services/import-client.ts +33 -6
  159. package/src/services/import-run.ts +158 -0
  160. package/src/services/import-seed.ts +120 -0
  161. package/src/services/jx-validate.ts +58 -6
  162. package/src/services/project-adoption.ts +71 -0
  163. package/src/services/references.ts +0 -0
  164. package/src/services/settings/definitions.ts +181 -0
  165. package/src/services/settings/kernel.ts +335 -0
  166. package/src/services/settings/write-queue.ts +116 -0
  167. package/src/services/tool-executor.ts +34 -2
  168. package/src/settings/contexts-section.ts +45 -3
  169. package/src/settings/dependencies-editor.ts +43 -23
  170. package/src/settings/general-settings.ts +30 -12
  171. package/src/settings/preferences-accounts.ts +6 -19
  172. package/src/settings/preferences-dialog.ts +18 -41
  173. package/src/settings/preferences-keymap.ts +8 -18
  174. package/src/settings/preferences-sections.ts +57 -0
  175. package/src/settings/schema-field-ui.ts +2 -2
  176. package/src/settings/settings-document.ts +65 -9
  177. package/src/shell.ts +6 -14
  178. package/src/studio.ts +65 -7
  179. package/src/tabs/transact.ts +42 -19
  180. package/src/types.ts +164 -8
  181. package/src/ui/ai-credentials-form.ts +52 -27
  182. package/src/ui/ai-model-picker.ts +162 -0
  183. package/src/ui/choice-field.ts +72 -0
  184. package/src/ui/layers.ts +83 -5
  185. package/src/ui/media-picker.ts +6 -11
  186. package/src/utils/studio-utils.ts +43 -31
  187. package/styles/forced-colors.css +7 -0
  188. package/styles/overlays.css +256 -0
  189. package/styles/panels.css +13 -1
  190. package/styles/shell.css +111 -0
  191. package/dist/chunks/Overlay.dev-d2ajy6sj.js +0 -23
  192. package/dist/chunks/cf-settings-g5fbf2zp.js +0 -17
  193. package/dist/chunks/content-source-k9724vcv.js +0 -39
  194. package/dist/chunks/files-yew27sn9.js +0 -69
  195. package/dist/chunks/layers-panel-qnsghwwd.js +0 -59
  196. package/dist/chunks/publish-panel-a0pdft5w.js +0 -21
  197. package/dist/chunks/quick-search-9avyc4pc.js +0 -54
  198. package/dist/chunks/right-panel-kcnhtc5j.js +0 -38
  199. package/dist/chunks/sp-overlay.dev-s18hymn9.js +0 -18
  200. package/dist/chunks/sp-popover.dev-dj9x7e7a.js +0 -9
  201. package/dist/chunks/sp-progress-circle.dev-0zxcyz3r.js +0 -15
  202. package/dist/chunks/sp-tooltip.dev-5c6d1kjz.js +0 -15
  203. package/dist/chunks/studio-a7pzveq1.js +0 -110
  204. package/dist/chunks/studio-c31yb4t6.js +0 -55
  205. package/dist/chunks/studio-ra7ar50f.js +0 -6682
  206. package/src/canvas/content-assets.ts +0 -263
  207. package/src/canvas/site-style-css.ts +0 -121
  208. package/src/services/settings-store.ts +0 -99
@@ -1,28 +1,28 @@
1
+ import {
2
+ distributePageIntoLayout,
3
+ getEffectiveElements,
4
+ getEffectiveHead,
5
+ getEffectiveImports,
6
+ getEffectiveLayoutPath,
7
+ getEffectiveLocales,
8
+ getEffectiveMedia,
9
+ resolveLayoutDoc,
10
+ setLayoutSelection,
11
+ shell
12
+ } from "./studio-hbtp0eh1.js";
1
13
  import {
2
14
  PRIMARY_PANE,
3
15
  activeTab,
4
- allCanvasSurfaces,
5
16
  argsSchema,
6
17
  booleanArg,
7
18
  booleanProperty,
8
19
  boundedNumberArg,
9
20
  cloneSelection,
10
21
  collabState,
11
- computed,
12
- distributePageIntoLayout,
13
- effect,
14
- effectScope,
15
22
  emptyContext,
16
23
  enumArg,
17
24
  enumProperty,
18
25
  focusPane,
19
- getEffectiveElements,
20
- getEffectiveHead,
21
- getEffectiveImports,
22
- getEffectiveLayoutPath,
23
- getEffectiveLocales,
24
- getEffectiveMedia,
25
- isRef as isRef2,
26
26
  isTabActive,
27
27
  localeDirection,
28
28
  mutateInsertNode,
@@ -30,40 +30,46 @@ import {
30
30
  mutateRemoveNode,
31
31
  mutateUpdateProp,
32
32
  mutateUpdateProperty,
33
- notify,
34
33
  numberProperty,
35
- onEffectCleanup,
36
34
  paneById,
37
35
  primarySelection,
38
- reactive,
39
- ref,
40
36
  resolveI18n,
41
- resolveLayoutDoc,
42
- setLayoutSelection,
43
- shell,
44
- stageContaining,
45
37
  stringArg,
46
38
  stringProperty,
47
- surfaceForPane,
48
- toRaw,
49
39
  toggleSelected,
50
40
  transact,
51
41
  transactDoc,
52
- view,
53
42
  workspace
54
- } from "./studio-ra7ar50f.js";
43
+ } from "./studio-2zkz8evn.js";
44
+ import {
45
+ allCanvasSurfaces,
46
+ stageContaining,
47
+ surfaceForPane,
48
+ view
49
+ } from "./studio-wcy8trfx.js";
50
+ import {
51
+ computed,
52
+ effect,
53
+ effectScope,
54
+ isRef as isRef2,
55
+ notify,
56
+ onEffectCleanup,
57
+ reactive,
58
+ ref,
59
+ toRaw
60
+ } from "./studio-xrapxwwc.js";
55
61
  import {
56
62
  classMap,
57
63
  ifDefined,
58
64
  styleMap
59
- } from "./studio-twsafr1e.js";
65
+ } from "./studio-m3hwn7y1.js";
60
66
  import {
61
67
  ref as ref2
62
- } from "./studio-kvfx9z2c.js";
68
+ } from "./studio-4rzyrtjz.js";
63
69
  import {
64
70
  html,
65
71
  nothing
66
- } from "./studio-5x5774ak.js";
72
+ } from "./studio-kryvsw6j.js";
67
73
  import {
68
74
  _defineProperty,
69
75
  combine,
@@ -75,15 +81,23 @@ import {
75
81
  buildComponentInstance,
76
82
  componentRegistry,
77
83
  computeRelativePath
78
- } from "./studio-s519zc99.js";
84
+ } from "./studio-bgxt93ga.js";
79
85
  import {
80
- bodyReturnsValue,
81
86
  childIndex,
82
87
  childList,
83
- displayTagName,
84
88
  getNodeAtPath,
85
- hasStructuredBody,
86
89
  isAncestor,
90
+ leftPanel,
91
+ parentElementPath,
92
+ pathsEqual,
93
+ projectState,
94
+ renderOnly,
95
+ stripEventHandlers
96
+ } from "./studio-p4ngc046.js";
97
+ import {
98
+ bodyReturnsValue,
99
+ displayTagName,
100
+ hasStructuredBody,
87
101
  isExpressionDef,
88
102
  isFunctionDef,
89
103
  isJsonObject,
@@ -95,22 +109,16 @@ import {
95
109
  isServerFnDef,
96
110
  isTagExpression,
97
111
  isTemplateString,
98
- leftPanel,
99
- paramNames,
100
- parentElementPath,
101
- pathsEqual,
102
- projectState,
103
- renderOnly,
104
- stripEventHandlers
105
- } from "./studio-cjm7fdjf.js";
112
+ paramNames
113
+ } from "./studio-q7v10cg2.js";
106
114
  import {
107
115
  formatByName,
108
116
  loadExtensions
109
- } from "./studio-rqemfhz6.js";
117
+ } from "./studio-eenfkt4e.js";
110
118
  import {
111
119
  getPlatform,
112
120
  hasPlatform
113
- } from "./studio-sas7mt3k.js";
121
+ } from "./studio-9ab8gqsm.js";
114
122
  import {
115
123
  bundleUrl
116
124
  } from "./studio-53n8bp04.js";
@@ -193,23 +201,18 @@ function tabOfContainer(container) {
193
201
  return tabOfPane(paneOfContainer(container));
194
202
  }
195
203
 
196
- // src/page-params.ts
204
+ // ../site/src/routes.ts
197
205
  var PARAM_SEGMENT = /\[\.\.\.(\w+)\]|\[(\w+)\]/g;
198
- function dynamicRouteParams(documentPath) {
199
- if (!documentPath) {
200
- return [];
201
- }
202
- const params = [];
203
- for (const match of documentPath.matchAll(PARAM_SEGMENT)) {
204
- params.push(match[1] ?? match[2]);
205
- }
206
- return params;
206
+ function pageRelativePath(documentPath) {
207
+ return documentPath.split("\\").join("/").replace(/^\.\//, "").replace(/^\//, "").replace(/^pages\//, "");
207
208
  }
208
- function documentUrlPattern(documentPath) {
209
- if (!documentPath) {
210
- return "/";
209
+ function fileToRoute(relativePath) {
210
+ let urlPath = pageRelativePath(relativePath);
211
+ const lastSegment = urlPath.slice(urlPath.lastIndexOf("/") + 1);
212
+ const dot = lastSegment.lastIndexOf(".");
213
+ if (dot > 0) {
214
+ urlPath = urlPath.slice(0, urlPath.length - (lastSegment.length - dot));
211
215
  }
212
- let urlPath = documentPath.replace(/^\.\//, "").replace(/^pages\//, "").replace(/\.[^/.]+$/, "");
213
216
  if (urlPath.endsWith("/index")) {
214
217
  urlPath = urlPath.slice(0, -6) || "/";
215
218
  } else if (urlPath === "index") {
@@ -218,8 +221,35 @@ function documentUrlPattern(documentPath) {
218
221
  if (!urlPath.startsWith("/")) {
219
222
  urlPath = `/${urlPath}`;
220
223
  }
221
- return urlPath.replaceAll(PARAM_SEGMENT, (_match, spread, named) => spread ? "*" : `:${named}`);
224
+ const params = [];
225
+ let isDynamic = false;
226
+ let isCatchAll = false;
227
+ const urlPattern = urlPath.replaceAll(PARAM_SEGMENT, (_match, spread, named) => {
228
+ isDynamic = true;
229
+ if (spread) {
230
+ isCatchAll = true;
231
+ params.push(spread);
232
+ return "*";
233
+ }
234
+ params.push(named);
235
+ return `:${named}`;
236
+ });
237
+ return { isCatchAll, isDynamic, params, urlPattern };
238
+ }
239
+ function documentUrlPattern(documentPath) {
240
+ if (!documentPath) {
241
+ return "/";
242
+ }
243
+ return fileToRoute(documentPath).urlPattern;
244
+ }
245
+ function dynamicRouteParams(documentPath) {
246
+ if (!documentPath) {
247
+ return [];
248
+ }
249
+ return fileToRoute(documentPath).params;
222
250
  }
251
+
252
+ // src/page-params.ts
223
253
  function pagePathsDef(doc) {
224
254
  const fromDoc = doc.document?.$paths;
225
255
  const fromFrontmatter = doc.frontmatter?.$paths;
@@ -2632,6 +2662,194 @@ function evaluateOperand(operand, state, event, iterCtx) {
2632
2662
  return resolveOperand(operand, state, event, iterCtx);
2633
2663
  }
2634
2664
 
2665
+ // ../schema/src/asset-paths.ts
2666
+ function normalizeDir(value) {
2667
+ const forward = value.replaceAll("\\", "/");
2668
+ return forward.length > 1 && forward.endsWith("/") ? forward.slice(0, -1) : forward;
2669
+ }
2670
+ function normalizeAssetPrefix(prefix) {
2671
+ const forward = normalizeDir(prefix);
2672
+ return forward.startsWith("/") ? forward : `/${forward}`;
2673
+ }
2674
+ function bySpecificity(mounts, key) {
2675
+ return [...mounts].toSorted((a, b) => b[key].length - a[key].length);
2676
+ }
2677
+ function isUnder(path, dir) {
2678
+ return path === dir || path.startsWith(`${dir}/`);
2679
+ }
2680
+ function assetUrlFor(mounts, absolutePath) {
2681
+ const path = normalizeDir(absolutePath);
2682
+ for (const mount of bySpecificity(mounts, "dir")) {
2683
+ const dir = normalizeDir(mount.dir);
2684
+ if (!isUnder(path, dir) || path === dir) {
2685
+ continue;
2686
+ }
2687
+ const rest = path.slice(dir.length + 1);
2688
+ const encoded = rest.split("/").map((segment) => encodeURIComponent(segment)).join("/");
2689
+ return `${normalizeAssetPrefix(mount.urlPrefix)}/${encoded}`;
2690
+ }
2691
+ return null;
2692
+ }
2693
+ function resolveAssetUrl(mounts, url) {
2694
+ const pathname = url.split("#")[0].split("?")[0];
2695
+ if (!pathname.startsWith("/")) {
2696
+ return null;
2697
+ }
2698
+ let decoded;
2699
+ try {
2700
+ decoded = decodeURIComponent(pathname);
2701
+ } catch {
2702
+ return null;
2703
+ }
2704
+ if (/%2e|%2f/i.test(decoded)) {
2705
+ return null;
2706
+ }
2707
+ for (const mount of bySpecificity(mounts, "urlPrefix")) {
2708
+ const prefix = normalizeAssetPrefix(mount.urlPrefix);
2709
+ if (!decoded.startsWith(`${prefix}/`)) {
2710
+ continue;
2711
+ }
2712
+ const rest = decoded.slice(prefix.length + 1);
2713
+ const segments = rest.split("/");
2714
+ if (segments.some((s) => s === "" || s === "." || s === "..")) {
2715
+ return null;
2716
+ }
2717
+ return `${normalizeDir(mount.dir)}/${segments.join("/")}`;
2718
+ }
2719
+ return null;
2720
+ }
2721
+ var URL_TERMINATOR = String.raw`"'\s<>()\\`;
2722
+ var PUBLIC_DIR = "public";
2723
+ var BUILD_LANES = ["mounts", "public"];
2724
+ function splitRefSuffix(value) {
2725
+ const cut = value.search(/[#?]/);
2726
+ return cut === -1 ? { path: value, suffix: "" } : { path: value.slice(0, cut), suffix: value.slice(cut) };
2727
+ }
2728
+ function isNonRelativeRef(value) {
2729
+ return value === "" || value.startsWith("/") || value.startsWith("#") || value.includes("${") || /^[a-z][\w+.-]*:/i.test(value);
2730
+ }
2731
+ function normalizeProjectPath(path) {
2732
+ return path.replaceAll("\\", "/").replace(/^\.\//, "").replace(/^\/+/, "").replace(/\/+$/, "");
2733
+ }
2734
+ function dirOfPath(path) {
2735
+ const normalized = normalizeProjectPath(path);
2736
+ const slash = normalized.lastIndexOf("/");
2737
+ return slash === -1 ? "" : normalized.slice(0, slash);
2738
+ }
2739
+ function joinProjectPath(dir, ref3) {
2740
+ const base = dir === "" || dir === "." ? [] : normalizeProjectPath(dir).split("/");
2741
+ const out = base.filter((segment) => segment !== "" && segment !== ".");
2742
+ for (const segment of ref3.replaceAll("\\", "/").split("/")) {
2743
+ if (segment === "" || segment === ".") {
2744
+ continue;
2745
+ }
2746
+ if (segment === "..") {
2747
+ if (out.length === 0) {
2748
+ return null;
2749
+ }
2750
+ out.pop();
2751
+ continue;
2752
+ }
2753
+ out.push(segment);
2754
+ }
2755
+ return out.join("/");
2756
+ }
2757
+ function projectPathsForSiteUrl(url, mounts, lanes) {
2758
+ const { path } = splitRefSuffix(url);
2759
+ if (!path.startsWith("/")) {
2760
+ return [];
2761
+ }
2762
+ let decoded;
2763
+ try {
2764
+ decoded = decodeURIComponent(path);
2765
+ } catch {
2766
+ return [];
2767
+ }
2768
+ if (/%2e|%2f/i.test(decoded)) {
2769
+ return [];
2770
+ }
2771
+ const rest = decoded.replace(/^\/+/, "");
2772
+ if (rest === "" || rest.split("/").some((segment) => segment === "." || segment === "..")) {
2773
+ return [];
2774
+ }
2775
+ const out = [];
2776
+ for (const lane of lanes) {
2777
+ if (lane === "mounts") {
2778
+ const mounted = resolveAssetUrl(mounts, path);
2779
+ if (mounted !== null && !mounted.startsWith("/") && !/^[A-Za-z]:/.test(mounted)) {
2780
+ out.push(normalizeProjectPath(mounted));
2781
+ }
2782
+ continue;
2783
+ }
2784
+ out.push(lane === "root" ? rest : `${PUBLIC_DIR}/${rest}`);
2785
+ }
2786
+ return [...new Set(out)];
2787
+ }
2788
+ function projectPathForRef(value, documentDir, mounts, lanes) {
2789
+ const { path } = splitRefSuffix(value);
2790
+ if (path === "") {
2791
+ return null;
2792
+ }
2793
+ if (isNonRelativeRef(value)) {
2794
+ return path.startsWith("/") ? projectPathsForSiteUrl(path, mounts, lanes)[0] ?? null : null;
2795
+ }
2796
+ if (path.endsWith("/")) {
2797
+ return null;
2798
+ }
2799
+ let decoded;
2800
+ try {
2801
+ decoded = decodeURIComponent(path);
2802
+ } catch {
2803
+ return null;
2804
+ }
2805
+ const joined = joinProjectPath(documentDir, decoded);
2806
+ if (joined === null || joined === "" || joined === normalizeProjectPath(documentDir)) {
2807
+ return null;
2808
+ }
2809
+ return joined;
2810
+ }
2811
+ function encodeProjectPath(path) {
2812
+ return path.split("/").map((segment) => encodeURIComponent(segment)).join("/");
2813
+ }
2814
+ function parseSrcset(value) {
2815
+ const out = [];
2816
+ let i = 0;
2817
+ while (i < value.length) {
2818
+ while (i < value.length && (/\s/.test(value[i]) || value[i] === ",")) {
2819
+ i += 1;
2820
+ }
2821
+ if (i >= value.length) {
2822
+ break;
2823
+ }
2824
+ const start = i;
2825
+ while (i < value.length && !/\s/.test(value[i])) {
2826
+ i += 1;
2827
+ }
2828
+ let url = value.slice(start, i);
2829
+ if (url.endsWith(",")) {
2830
+ out.push({ descriptor: "", url: url.replace(/,+$/, "") });
2831
+ continue;
2832
+ }
2833
+ while (i < value.length && /\s/.test(value[i])) {
2834
+ i += 1;
2835
+ }
2836
+ const descStart = i;
2837
+ while (i < value.length && value[i] !== ",") {
2838
+ i += 1;
2839
+ }
2840
+ const descriptor = value.slice(descStart, i).trim();
2841
+ i += 1;
2842
+ url = url.replace(/,+$/, "");
2843
+ if (url !== "") {
2844
+ out.push({ descriptor, url });
2845
+ }
2846
+ }
2847
+ return out;
2848
+ }
2849
+ function formatSrcset(candidates) {
2850
+ return candidates.map(({ url, descriptor }) => descriptor ? `${url} ${descriptor}` : url).join(", ");
2851
+ }
2852
+
2635
2853
  // ../runtime/src/statements.ts
2636
2854
  function statementKind(statement) {
2637
2855
  if ("operator" in statement) {
@@ -2816,6 +3034,52 @@ function canvasAttrName(el, key) {
2816
3034
  }
2817
3035
  return key;
2818
3036
  }
3037
+ var _canvasAssetResolver = null;
3038
+ function setCanvasAssetResolver(fn) {
3039
+ _canvasAssetResolver = fn;
3040
+ }
3041
+ var ASSET_KEYS = new Set(["src", "poster", "data"]);
3042
+ var SRCSET_KEYS = new Set(["srcset", "imagesrcset"]);
3043
+ var HREF_ASSET_TAGS = new Set(["LINK"]);
3044
+ function isAssetKey(tagName, key) {
3045
+ return ASSET_KEYS.has(key) || key === "href" && HREF_ASSET_TAGS.has(tagName);
3046
+ }
3047
+ function canvasAssetValue(tagName, key, value) {
3048
+ if (!_canvasAssetResolver || value === "") {
3049
+ return value;
3050
+ }
3051
+ const name = key.toLowerCase();
3052
+ if (SRCSET_KEYS.has(name)) {
3053
+ const candidates = parseSrcset(value);
3054
+ let changed = false;
3055
+ const next = candidates.map((candidate) => {
3056
+ const resolved = _canvasAssetResolver?.(candidate.url, name) ?? null;
3057
+ if (resolved === null || resolved === candidate.url) {
3058
+ return candidate;
3059
+ }
3060
+ changed = true;
3061
+ return { descriptor: candidate.descriptor, url: resolved };
3062
+ });
3063
+ return changed ? formatSrcset(next) : value;
3064
+ }
3065
+ if (!isAssetKey(tagName, name)) {
3066
+ return value;
3067
+ }
3068
+ return _canvasAssetResolver(value, name) ?? value;
3069
+ }
3070
+ var CSS_URL_RE = /\burl\(\s*(?<q>["']?)(?<u>[^"')]*)\k<q>\s*\)/g;
3071
+ function canvasStyleUrls(value) {
3072
+ if (!_canvasAssetResolver || !value.includes("url(")) {
3073
+ return value;
3074
+ }
3075
+ return value.replaceAll(CSS_URL_RE, (whole, quote, url) => {
3076
+ const resolved = url === "" ? null : _canvasAssetResolver?.(url, "url()") ?? null;
3077
+ return resolved === null ? whole : `url(${quote}${resolved}${quote})`;
3078
+ });
3079
+ }
3080
+ function canvasStyleValue(value) {
3081
+ return transposeCanvasUnits(canvasStyleUrls(value));
3082
+ }
2819
3083
  var _stampPropBindings = false;
2820
3084
  var PURE_STATE_TEMPLATE = /^\s*\$\{\s*state\.(\w+)\s*\}\s*$/;
2821
3085
  function boundPropKey(key, val, state) {
@@ -2986,6 +3250,32 @@ function evaluateTemplate(str, state) {
2986
3250
  const fn = new Function("state", "$map", "item", "index", `return \`${str}\``);
2987
3251
  return fn(state, $map, $map?.item, $map?.index);
2988
3252
  }
3253
+ function isSingleExpression(str) {
3254
+ if (!str.startsWith("${") || !str.endsWith("}")) {
3255
+ return false;
3256
+ }
3257
+ let depth = 0;
3258
+ for (let i = 1;i < str.length; i += 1) {
3259
+ const c = str[i];
3260
+ if (c === "{") {
3261
+ depth += 1;
3262
+ } else if (c === "}") {
3263
+ depth -= 1;
3264
+ if (depth === 0) {
3265
+ return i === str.length - 1;
3266
+ }
3267
+ }
3268
+ }
3269
+ return false;
3270
+ }
3271
+ function evaluateAttrTemplate(str, state) {
3272
+ if (!isSingleExpression(str)) {
3273
+ return evaluateTemplate(str, state);
3274
+ }
3275
+ const $map = state?.$map;
3276
+ const fn = new Function("state", "$map", "item", "index", `return (${str.slice(2, -1)})`);
3277
+ return fn(state, $map, $map?.item, $map?.index);
3278
+ }
2989
3279
  var _moduleCache = new Map;
2990
3280
  async function resolveFunction(def, state, key, base) {
2991
3281
  if (def.body && def.$src) {
@@ -3089,6 +3379,17 @@ var RESERVED_KEYS = new Set([
3089
3379
  "observedAttributes"
3090
3380
  ]);
3091
3381
  var warnedRefChildren = new Set;
3382
+ var SVG_NS = "http://www.w3.org/2000/svg";
3383
+ var MATHML_NS = "http://www.w3.org/1998/Math/MathML";
3384
+ function elementNamespace(tagName, inherited) {
3385
+ if (tagName === "svg") {
3386
+ return SVG_NS;
3387
+ }
3388
+ if (tagName === "math") {
3389
+ return MATHML_NS;
3390
+ }
3391
+ return inherited ?? null;
3392
+ }
3092
3393
  function renderNode(def, state, options) {
3093
3394
  const path = options?._path ?? [];
3094
3395
  if (typeof def === "string" || typeof def === "number" || typeof def === "boolean") {
@@ -3131,7 +3432,9 @@ function renderNode(def, state, options) {
3131
3432
  if (def.$switch) {
3132
3433
  return renderSwitch(def, localState, options);
3133
3434
  }
3134
- const el = document.createElement(tagName);
3435
+ const ns = elementNamespace(tagName, options?._ns);
3436
+ const childNs = tagName === "foreignObject" ? null : ns;
3437
+ const el = ns ? document.createElementNS(ns, tagName) : document.createElement(tagName);
3135
3438
  if (options?.onNodeCreated) {
3136
3439
  options.onNodeCreated(el, path, def, localState);
3137
3440
  }
@@ -3140,12 +3443,12 @@ function renderNode(def, state, options) {
3140
3443
  applyAttributes(el, def.attributes ?? {}, localState);
3141
3444
  const kids = def.children;
3142
3445
  if (isMappedArray(kids)) {
3143
- const arrOpts = options ? { ...options, _path: [...path, "children"] } : undefined;
3446
+ const arrOpts = options || childNs ? { ...options, _ns: childNs, _path: [...path, "children"] } : undefined;
3144
3447
  renderMappedArrayInto(el, kids, localState, arrOpts);
3145
3448
  } else if (Array.isArray(kids)) {
3146
3449
  for (let i = 0;i < kids.length; i++) {
3147
3450
  const child = kids[i];
3148
- const childOpts = options ? { ...options, _path: [...path, "children", i] } : undefined;
3451
+ const childOpts = options || childNs ? { ...options, _ns: childNs, _path: [...path, "children", i] } : undefined;
3149
3452
  if (isMappedArray(child)) {
3150
3453
  renderMappedArrayInto(el, child, localState, childOpts);
3151
3454
  } else {
@@ -3204,6 +3507,15 @@ function bindProperty(el, key, val, state) {
3204
3507
  if (boundProp) {
3205
3508
  el.dataset.jxBoundProp = boundProp;
3206
3509
  }
3510
+ const asAsset = (resolved) => typeof resolved === "string" ? canvasAssetValue(el.tagName, key, resolved) : resolved;
3511
+ const write = (resolved) => {
3512
+ const node = el;
3513
+ if (key === "className" && !(node instanceof HTMLElement)) {
3514
+ node.setAttribute("class", resolved == null ? "" : String(resolved));
3515
+ return;
3516
+ }
3517
+ target[key] = resolved;
3518
+ };
3207
3519
  if (isRefObj(val)) {
3208
3520
  const refVal = val;
3209
3521
  if (key === "id") {
@@ -3211,17 +3523,17 @@ function bindProperty(el, key, val, state) {
3211
3523
  return;
3212
3524
  }
3213
3525
  effect(() => {
3214
- target[key] = resolveRef(refVal.$ref, state);
3526
+ write(asAsset(resolveRef(refVal.$ref, state)));
3215
3527
  });
3216
3528
  return;
3217
3529
  }
3218
3530
  if (isTemplateString(val)) {
3219
3531
  effect(() => {
3220
- target[key] = evaluateTemplate(val, state);
3532
+ write(asAsset(evaluateTemplate(val, state)));
3221
3533
  });
3222
3534
  return;
3223
3535
  }
3224
- target[key] = val;
3536
+ write(asAsset(val));
3225
3537
  }
3226
3538
  function applyStyle(el, styleDef, mediaQueries = {}, state = {}) {
3227
3539
  const nested = {};
@@ -3256,19 +3568,19 @@ function applyStyle(el, styleDef, mediaQueries = {}, state = {}) {
3256
3568
  if (prop.startsWith("--")) {
3257
3569
  if (isTemplateString(val)) {
3258
3570
  effect(() => {
3259
- el.style.setProperty(prop, transposeCanvasUnits(evaluateTemplate(val, state)));
3571
+ el.style.setProperty(prop, canvasStyleValue(evaluateTemplate(val, state)));
3260
3572
  });
3261
3573
  } else {
3262
- el.style.setProperty(prop, transposeCanvasUnits(scalar));
3574
+ el.style.setProperty(prop, canvasStyleValue(scalar));
3263
3575
  }
3264
3576
  } else if (isTemplateString(val)) {
3265
3577
  effect(() => {
3266
- el.style[prop] = transposeCanvasUnits(evaluateTemplate(val, state));
3578
+ el.style[prop] = canvasStyleValue(evaluateTemplate(val, state));
3267
3579
  });
3268
3580
  } else if (mediaOverriddenProps.has(prop)) {
3269
3581
  baseDecls[prop] = scalar;
3270
3582
  } else {
3271
- el.style[prop] = transposeCanvasUnits(scalar);
3583
+ el.style[prop] = canvasStyleValue(scalar);
3272
3584
  }
3273
3585
  }
3274
3586
  const hasNested = Object.keys(nested).length > 0;
@@ -3327,7 +3639,7 @@ function applyStyle(el, styleDef, mediaQueries = {}, state = {}) {
3327
3639
  if (key === "@--") {
3328
3640
  continue;
3329
3641
  }
3330
- const query = key.startsWith("@--") ? mediaQueries[key.slice(1)] ?? key.slice(1) : key.startsWith("@(") ? key.slice(1) : null;
3642
+ const query = resolveAtQuery(key, mediaQueries);
3331
3643
  const atRule = query === null ? key : `@media ${query}`;
3332
3644
  const scope = `[data-jx="${uid}"]`;
3333
3645
  const scheme = query === null ? null : pureSchemeOf(query);
@@ -3350,15 +3662,35 @@ function applyStyle(el, styleDef, mediaQueries = {}, state = {}) {
3350
3662
  elementStyleTags.set(el, tag);
3351
3663
  }
3352
3664
  var elementStyleTags = new WeakMap;
3665
+ var ENUMERATED_ATTRS = new Set(["contenteditable", "draggable", "spellcheck"]);
3666
+ function booleanAttrValue(name, value) {
3667
+ const lower = name.toLowerCase();
3668
+ if (lower.startsWith("aria-") || ENUMERATED_ATTRS.has(lower)) {
3669
+ return String(value);
3670
+ }
3671
+ return value ? "" : null;
3672
+ }
3353
3673
  function applyAttributes(el, attrs, state) {
3354
3674
  for (const [k, v] of Object.entries(attrs)) {
3355
3675
  const attr = canvasAttrName(el, k);
3676
+ const write = (resolved) => {
3677
+ if (typeof resolved === "boolean") {
3678
+ const text = booleanAttrValue(attr, resolved);
3679
+ if (text === null) {
3680
+ el.removeAttribute(attr);
3681
+ } else {
3682
+ el.setAttribute(attr, text);
3683
+ }
3684
+ return;
3685
+ }
3686
+ el.setAttribute(attr, canvasAssetValue(el.tagName, k, String(resolved ?? "")));
3687
+ };
3356
3688
  if (isRefObj(v)) {
3357
- effect(() => el.setAttribute(attr, String(resolveRef(v.$ref, state) ?? "")));
3689
+ effect(() => write(resolveRef(v.$ref, state)));
3358
3690
  } else if (isTemplateString(v)) {
3359
- effect(() => el.setAttribute(attr, String(evaluateTemplate(v, state))));
3691
+ effect(() => write(evaluateAttrTemplate(v, state)));
3360
3692
  } else {
3361
- el.setAttribute(attr, String(v));
3693
+ write(v);
3362
3694
  }
3363
3695
  }
3364
3696
  }
@@ -4031,7 +4363,18 @@ function camelToKebab(s) {
4031
4363
  return s.replaceAll(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);
4032
4364
  }
4033
4365
  function toCSSText(rules) {
4034
- return Object.entries(rules).filter(([k, v]) => !isNestedSelector(k) && (v === null || typeof v !== "object")).map(([p, v]) => `${camelToKebab(p)}: ${transposeCanvasUnits(String(v))}`).join("; ");
4366
+ return Object.entries(rules).filter(([k, v]) => !isNestedSelector(k) && (v === null || typeof v !== "object")).map(([p, v]) => `${camelToKebab(p)}: ${canvasStyleValue(String(v))}`).join("; ");
4367
+ }
4368
+ var MEDIA_TYPES = new Set(["all", "print", "screen", "speech"]);
4369
+ function resolveAtQuery(atKey, mediaQueries) {
4370
+ if (atKey.startsWith("@--")) {
4371
+ return mediaQueries[atKey.slice(1)] ?? atKey.slice(1);
4372
+ }
4373
+ if (atKey.startsWith("@(")) {
4374
+ const inner = atKey.slice(2, -1).trim();
4375
+ return MEDIA_TYPES.has(inner.toLowerCase()) ? inner : atKey.slice(1);
4376
+ }
4377
+ return null;
4035
4378
  }
4036
4379
  var COLOR_SCHEME_ATTR = "data-color-scheme";
4037
4380
  function pureSchemeOf(query) {
@@ -4179,6 +4522,9 @@ async function defineElement(source, baseUrl) {
4179
4522
  }
4180
4523
  applyStyle(this, def.style ?? {}, state["$media"] ?? {}, state);
4181
4524
  applyAttributes(this, def.attributes ?? {}, state);
4525
+ if (!Array.isArray(def.children) && def.textContent !== undefined) {
4526
+ bindProperty(this, "textContent", def.textContent, state);
4527
+ }
4182
4528
  const children = Array.isArray(def.children) ? def.children : [];
4183
4529
  for (const childDef of children) {
4184
4530
  this.append(renderNode(childDef, state));
@@ -4225,19 +4571,21 @@ function renderCustomElementWithProps(def, state, options, path) {
4225
4571
  if (refusePrivateProp(key, "$props")) {
4226
4572
  continue;
4227
4573
  }
4574
+ const write = (resolved) => {
4575
+ el[key] = typeof resolved === "string" ? canvasAssetValue(el.tagName, key, resolved) : resolved;
4576
+ };
4228
4577
  if (isRefObj(val)) {
4229
4578
  const refVal = val;
4230
- const resolved = resolveRef(refVal.$ref, state);
4231
- el[key] = resolved;
4579
+ write(resolveRef(refVal.$ref, state));
4232
4580
  effect(() => {
4233
- el[key] = resolveRef(refVal.$ref, state);
4581
+ write(resolveRef(refVal.$ref, state));
4234
4582
  });
4235
4583
  } else if (isTemplateString(val)) {
4236
4584
  effect(() => {
4237
- el[key] = evaluateTemplate(val, state);
4585
+ write(evaluateTemplate(val, state));
4238
4586
  });
4239
4587
  } else {
4240
- el[key] = val;
4588
+ write(val);
4241
4589
  }
4242
4590
  }
4243
4591
  applyStyle(el, def.style ?? {}, state["$media"] ?? {}, state);
@@ -4980,101 +5328,94 @@ function substitutePreviewProps(renderDoc, props) {
4980
5328
  return { ...renderDoc, state };
4981
5329
  }
4982
5330
 
4983
- // ../schema/src/asset-paths.ts
4984
- function normalizeDir(value) {
4985
- const forward = value.replaceAll("\\", "/");
4986
- return forward.length > 1 && forward.endsWith("/") ? forward.slice(0, -1) : forward;
4987
- }
4988
- function normalizeAssetPrefix(prefix) {
4989
- const forward = normalizeDir(prefix);
4990
- return forward.startsWith("/") ? forward : `/${forward}`;
4991
- }
4992
- function bySpecificity(mounts, key) {
4993
- return [...mounts].toSorted((a, b) => b[key].length - a[key].length);
4994
- }
4995
- function isUnder(path, dir) {
4996
- return path === dir || path.startsWith(`${dir}/`);
4997
- }
4998
- function assetUrlFor(mounts, absolutePath) {
4999
- const path = normalizeDir(absolutePath);
5000
- for (const mount of bySpecificity(mounts, "dir")) {
5001
- const dir = normalizeDir(mount.dir);
5002
- if (!isUnder(path, dir) || path === dir) {
5003
- continue;
5004
- }
5005
- const rest = path.slice(dir.length + 1);
5006
- const encoded = rest.split("/").map((segment) => encodeURIComponent(segment)).join("/");
5007
- return `${normalizeAssetPrefix(mount.urlPrefix)}/${encoded}`;
5008
- }
5009
- return null;
5010
- }
5011
- var URL_TERMINATOR = String.raw`"'\s<>()\\`;
5012
-
5013
- // src/canvas/content-assets.ts
5014
- var ASSET_KEYS = ["src", "poster"];
5331
+ // src/canvas/asset-resolve.ts
5015
5332
  var SAFE_TYPE_NAME = /^[\w.~-]+$/;
5016
5333
  var SECTION_KEY = "content";
5017
- function isNonRelativeRef(value) {
5018
- return value === "" || value.startsWith("/") || value.startsWith("#") || value.includes("${") || /^[a-z][\w+.-]*:/i.test(value);
5019
- }
5020
- function normalizeSource(source) {
5021
- return source.replaceAll("\\", "/").replace(/^\.\//, "").replace(/\/+$/, "");
5022
- }
5023
- function resolveRelativePath(dir, ref3) {
5024
- const segments = dir === "" || dir === "." ? [] : dir.replaceAll("\\", "/").split("/");
5025
- const out = segments.filter((s) => s !== "" && s !== ".");
5026
- for (const segment of ref3.replaceAll("\\", "/").split("/")) {
5027
- if (segment === "" || segment === ".") {
5028
- continue;
5029
- }
5030
- if (segment === "..") {
5031
- if (out.length === 0) {
5032
- return null;
5033
- }
5034
- out.pop();
5035
- continue;
5036
- }
5037
- out.push(segment);
5038
- }
5039
- return out.join("/");
5040
- }
5041
- function dirOf(path) {
5042
- const normalized = path.replaceAll("\\", "/");
5043
- const slash = normalized.lastIndexOf("/");
5044
- return slash === -1 ? "" : normalized.slice(0, slash);
5045
- }
5046
- function contentMountFor(documentPath, content) {
5334
+ var LOCALE_PLACEHOLDER = "{locale}";
5335
+ function contentMountFor(documentPath, content, locales = []) {
5047
5336
  if (!documentPath || !content) {
5048
5337
  return null;
5049
5338
  }
5050
5339
  const path = documentPath.replaceAll("\\", "/").replace(/^\.\//, "");
5051
5340
  let best = null;
5341
+ const consider = (dir, urlPrefix) => {
5342
+ if (path.startsWith(`${dir}/`) && (!best || dir.length > best.dir.length)) {
5343
+ best = { dir, urlPrefix };
5344
+ }
5345
+ };
5052
5346
  for (const [name, def] of Object.entries(content)) {
5053
5347
  if (!def?.source || !SAFE_TYPE_NAME.test(name)) {
5054
5348
  continue;
5055
5349
  }
5056
5350
  const dir = normalizeSource(def.source);
5057
- if (dir === "" || dir.startsWith("..") || /\.[a-z0-9]+$/i.test(dir)) {
5351
+ if (dir === "" || dir.startsWith("..")) {
5058
5352
  continue;
5059
5353
  }
5060
- if (path.startsWith(`${dir}/`) && (!best || dir.length > best.dir.length)) {
5061
- best = { dir, urlPrefix: `/${SECTION_KEY}/${name}` };
5354
+ if (dir.includes(LOCALE_PLACEHOLDER)) {
5355
+ const mount = localeMountFor(path, dir, name, locales);
5356
+ if (mount) {
5357
+ consider(mount.dir, mount.urlPrefix);
5358
+ }
5359
+ continue;
5360
+ }
5361
+ if (/\.[a-z0-9]+$/i.test(dir)) {
5362
+ continue;
5062
5363
  }
5364
+ consider(dir, `/${SECTION_KEY}/${name}`);
5063
5365
  }
5064
5366
  return best;
5065
5367
  }
5368
+ function localeMountFor(path, source, name, locales) {
5369
+ const cut = source.indexOf(LOCALE_PLACEHOLDER);
5370
+ const head = source.slice(0, cut);
5371
+ const tail = source.slice(cut + LOCALE_PLACEHOLDER.length);
5372
+ if (!path.startsWith(head)) {
5373
+ return null;
5374
+ }
5375
+ const segment = path.slice(head.length).split("/")[0] ?? "";
5376
+ if (segment === "" || !SAFE_TYPE_NAME.test(segment)) {
5377
+ return null;
5378
+ }
5379
+ const canonical = locales.find((tag) => tag.toLowerCase() === segment.toLowerCase());
5380
+ if (canonical === undefined || !SAFE_TYPE_NAME.test(canonical)) {
5381
+ return null;
5382
+ }
5383
+ const dir = `${head}${segment}${tail}`.replace(/\/+$/, "");
5384
+ return { dir, urlPrefix: `/${SECTION_KEY}/${name}/${canonical}` };
5385
+ }
5386
+ function normalizeSource(source) {
5387
+ return source.replaceAll("\\", "/").replace(/^\.\//, "").replace(/\/+$/, "");
5388
+ }
5389
+ function resolveAssetRef(value, ctx) {
5390
+ if (!ctx || value === "") {
5391
+ return null;
5392
+ }
5393
+ if (ctx.space === "repo") {
5394
+ if (!ctx.fileBaseUrl) {
5395
+ return null;
5396
+ }
5397
+ const path = projectPathForRef(value, ctx.documentDir, ctx.mounts, ctx.lanes);
5398
+ if (path === null) {
5399
+ return null;
5400
+ }
5401
+ const { suffix } = splitRefSuffix(value);
5402
+ return `${ctx.fileBaseUrl}${encodeProjectPath(path)}${suffix}`;
5403
+ }
5404
+ const [mount] = ctx.mounts;
5405
+ return mount ? mountedRefFor(value, ctx.documentDir, mount) : null;
5406
+ }
5066
5407
  function mountedRefFor(value, entryDir, mount) {
5067
5408
  if (isNonRelativeRef(value)) {
5068
5409
  return null;
5069
5410
  }
5070
- const bare = value.split("#")[0].split("?")[0];
5411
+ const { path: bare, suffix } = splitRefSuffix(value);
5071
5412
  let decoded;
5072
5413
  try {
5073
5414
  decoded = decodeURIComponent(bare);
5074
5415
  } catch {
5075
5416
  return null;
5076
5417
  }
5077
- const target = resolveRelativePath(entryDir, decoded);
5418
+ const target = joinProjectPath(entryDir, decoded);
5078
5419
  if (target === null) {
5079
5420
  return null;
5080
5421
  }
@@ -5082,76 +5423,39 @@ function mountedRefFor(value, entryDir, mount) {
5082
5423
  if (!url) {
5083
5424
  return null;
5084
5425
  }
5085
- return `${url}${value.slice(bare.length)}`;
5086
- }
5087
- function rewriteNode(node, entryDir, mount) {
5088
- const record = node;
5089
- let patch = null;
5090
- for (const key of ASSET_KEYS) {
5091
- const value = record[key];
5092
- if (typeof value === "string") {
5093
- const rewritten = mountedRefFor(value, entryDir, mount);
5094
- if (rewritten) {
5095
- patch ??= {};
5096
- patch[key] = rewritten;
5097
- }
5098
- }
5099
- }
5100
- const attributes = record.attributes;
5101
- if (attributes) {
5102
- let nextAttrs = null;
5103
- for (const key of ASSET_KEYS) {
5104
- const value = attributes[key];
5105
- if (typeof value === "string") {
5106
- const rewritten = mountedRefFor(value, entryDir, mount);
5107
- if (rewritten) {
5108
- nextAttrs ??= { ...attributes };
5109
- nextAttrs[key] = rewritten;
5110
- }
5111
- }
5112
- }
5113
- if (nextAttrs) {
5114
- patch ??= {};
5115
- patch.attributes = nextAttrs;
5116
- }
5117
- }
5118
- const children = record.children;
5119
- if (Array.isArray(children)) {
5120
- let nextChildren = null;
5121
- for (const [i, child] of children.entries()) {
5122
- if (!child || typeof child !== "object") {
5123
- continue;
5124
- }
5125
- const rewrittenChild = rewriteNode(child, entryDir, mount);
5126
- if (rewrittenChild !== child) {
5127
- nextChildren ??= [...children];
5128
- nextChildren[i] = rewrittenChild;
5129
- }
5130
- }
5131
- if (nextChildren) {
5132
- patch ??= {};
5133
- patch.children = nextChildren;
5134
- }
5135
- }
5136
- return patch ? { ...node, ...patch } : node;
5426
+ return `${url}${suffix}`;
5137
5427
  }
5138
- function rewriteContentAssets(doc, documentPath, content) {
5139
- const mount = contentMountFor(documentPath, content);
5140
- if (!mount) {
5141
- return doc;
5428
+
5429
+ // src/canvas/asset-refs.ts
5430
+ function projectLocales() {
5431
+ return resolveI18n(projectState?.projectConfig ?? {}).i18n?.locales ?? [];
5432
+ }
5433
+ function assetContextFor(documentPath, over) {
5434
+ const space = over?.space ?? "site";
5435
+ const mount = contentMountFor(documentPath, projectState?.projectConfig?.content, projectLocales());
5436
+ if (space === "site" && !mount) {
5437
+ return null;
5142
5438
  }
5143
- return rewriteNode(doc, dirOf(documentPath.replaceAll("\\", "/").replace(/^\.\//, "")), mount);
5439
+ return {
5440
+ documentDir: dirOfPath(documentPath ?? ""),
5441
+ ...over?.fileBaseUrl === undefined ? {} : { fileBaseUrl: over.fileBaseUrl },
5442
+ lanes: BUILD_LANES,
5443
+ mounts: mount ? [mount] : [],
5444
+ space
5445
+ };
5144
5446
  }
5145
5447
  function previewAssetSrc(value) {
5146
5448
  if (!value) {
5147
5449
  return value;
5148
5450
  }
5149
- const documentPath = activeTab.value?.documentPath;
5150
- const mount = contentMountFor(documentPath, projectState?.projectConfig?.content);
5151
- if (!mount) {
5152
- return value;
5153
- }
5154
- return mountedRefFor(value, dirOf(documentPath), mount) ?? value;
5451
+ const ctx = assetContextFor(activeTab.value?.documentPath, hostAssetDeclarations());
5452
+ return loopbackAssetSrc(resolveAssetRef(value, ctx) ?? value);
5453
+ }
5454
+ function hostAssetDeclarations() {
5455
+ return {
5456
+ fileBaseUrl: documentBase(projectState?.projectRoot),
5457
+ ...hasPlatform() ? { space: getPlatform().assetSpace } : {}
5458
+ };
5155
5459
  }
5156
5460
 
5157
5461
  // src/canvas/canvas-live-render.ts
@@ -5221,7 +5525,12 @@ async function resolveCanvasDocument(doc, tab) {
5221
5525
  }
5222
5526
  }
5223
5527
  }
5224
- const docBase = S.documentPath ? new URL(S.documentPath, documentBase(projectState?.projectRoot)).href : undefined;
5528
+ const fileBase = documentBase(projectState?.projectRoot);
5529
+ const docBase = S.documentPath ? new URL(S.documentPath, fileBase).href : undefined;
5530
+ const assets = assetContextFor(S.documentPath, {
5531
+ fileBaseUrl: fileBase,
5532
+ ...hasPlatform() ? { space: getPlatform().assetSpace } : {}
5533
+ });
5225
5534
  if (isPage && tab) {
5226
5535
  const { previewParams } = tab.session.ui;
5227
5536
  if (previewParams && Object.keys(previewParams).length > 0) {
@@ -5236,7 +5545,6 @@ async function resolveCanvasDocument(doc, tab) {
5236
5545
  renderDoc = substitutePreviewProps(renderDoc, previewProps);
5237
5546
  }
5238
5547
  }
5239
- renderDoc = rewriteContentAssets(renderDoc, S.documentPath, projectState?.projectConfig?.content);
5240
5548
  const arrayPaths = new Set;
5241
5549
  if (canvasMode === "design" || canvasMode === "edit") {
5242
5550
  (function findArrayPaths(node, path) {
@@ -5320,6 +5628,7 @@ async function resolveCanvasDocument(doc, tab) {
5320
5628
  renderDoc.$head = head;
5321
5629
  }
5322
5630
  return {
5631
+ assets,
5323
5632
  docBase,
5324
5633
  mapperCtx: {
5325
5634
  arrayPaths: [...arrayPaths],
@@ -7375,6 +7684,7 @@ function preparePassRender(gen, doc, tabId, viewTab, paneId) {
7375
7684
  const formatElements = formatByName(renderTab?.doc.sourceFormat)?.studio?.elements;
7376
7685
  const editableTags = formatElements ? formatEditableVerdicts(formatElements) : undefined;
7377
7686
  return {
7687
+ assets: resolved.assets,
7378
7688
  doc: cloneableDoc,
7379
7689
  docBase: resolved.docBase ?? `${canvasBaseOrigin()}/`,
7380
7690
  mapperCtx: resolved.mapperCtx,
@@ -7421,6 +7731,7 @@ function mountStylebookCanvas(gen, generated, canvasEl, widthPx) {
7421
7731
  const cloneableDoc = JSON.parse(JSON.stringify(generated.doc));
7422
7732
  const cloneableShadow = JSON.parse(JSON.stringify(generated.doc));
7423
7733
  const message = {
7734
+ assets: null,
7424
7735
  colorScheme: schemeWireFor(tabOfContainer(canvasEl)),
7425
7736
  doc: cloneableDoc,
7426
7737
  docBase: `${canvasBaseOrigin()}/`,
@@ -7613,7 +7924,7 @@ function openPageAction(label = "Open a page…") {
7613
7924
  return {
7614
7925
  label,
7615
7926
  run: () => {
7616
- import("./quick-search-9avyc4pc.js").then((m) => {
7927
+ import("./quick-search-cgfmjwq5.js").then((m) => {
7617
7928
  m.openQuickSearch();
7618
7929
  });
7619
7930
  }
@@ -7677,6 +7988,7 @@ var PLACEMENTS = [
7677
7988
  "blockbar",
7678
7989
  "blockbar/format",
7679
7990
  "outline/row",
7991
+ "settings/menu",
7680
7992
  "palette",
7681
7993
  "never"
7682
7994
  ];
@@ -7703,6 +8015,10 @@ var PLACEMENT_MATRIX = {
7703
8015
  note: "the bar's inline-format cluster — a range inside the selection is still the selection"
7704
8016
  },
7705
8017
  "outline/row": { admits: ["selection"], note: "row actions act on the row's node" },
8018
+ "settings/menu": {
8019
+ admits: ["application", "project"],
8020
+ note: "the rail foot's gear menu — the settings family. It is a MENU, not a pinned slot, so it " + "may host two levels for the reason commandbar/overflow does: a menu prints each row's own " + "name, chord and gate, and draws a divider where the level changes. The rail's PINNED " + "groups stay single-level, in PANEL_PLACEMENT_MATRIX"
8021
+ },
7706
8022
  palette: {
7707
8023
  admits: ["application", "project", "document", "selection"],
7708
8024
  note: "the level-agnostic surface; it groups rows by level"
@@ -7883,7 +8199,7 @@ function railPanelSet() {
7883
8199
  return RAIL_GROUP_LEVELS.flatMap(({ level }) => railable.filter((panel) => panel.level === level));
7884
8200
  }
7885
8201
 
7886
- export { KEY_SCOPES, CATEGORIES, checkRecordPlacements, intlHelpersClause, PURE_METHOD_OPS, BLESSED_OPERATORS, BLESSED_GLOBALS, isMutating, evaluateExpression, rectOf, loopbackAssetSrc, getPreviewNavigateHandler, activeCanvasSurface, tabOfPane, derivationOfPane, surfacesShowingTab, canvasModeOfTab, canvasModeOfPane, activeMediaOfPane, paneOfContainer, tabOfContainer, dynamicRouteParams, documentUrlPattern, pagePathsDef, invalidateParamValues, loadParamValues, isComponentDoc, componentPropEntries, contentMountFor, previewAssetSrc, SPAN_FULL_RENDER, SPAN_MOUNT_CANVAS, SPAN_PATCH_BATCH, canvasPerf, recordEscalation, timeSpan, timeSpanAsync, mediaDisplayName, defaultDef, parentCursorToIframe, serializeJxPath, elements_meta_default, getInlineActions, isInlineElement, isEditing, bubbleInlinePath, stageZoom, canvasPanelTemplate, observeCenterUntilStable, applyTransform, applyEditZoom, setEditZoom, requestEditZoom, fitToScreen, getFit, setFit, markExplicitZoom, setUserZoom, fitOnCanvasEntry, resetZoom, panToElement, canvasBaseViewsFor, canvasBaseViewOf, previewStateOf, setCanvasView, registerCanvasViewCommands, updateActivePanelHeaders, setDragGhost, moveDragGhost, clearDragGhost, disableNativeDragPreview, attachInstruction, extractInstruction, hasElement, enableElement, disableElement, removePackageElements, removeElementRef, setSkipServerFunctions, runScoped, buildScope, renderNode, pureSchemeOf, renderComponentPreview, registerLayersDnD, registerComponentsDnD, registerElementsDnD, applyDropInstruction, sawIframeDragOver, allowAutoRequestsOnNextRender, requestCanvasEval, flushCanvasEdits, liveDragHostAt, beginDragSession, currentDragSession, hostDragGeometry, canvasIdleBlockers, canvasPointAt, revealCanvasPath, adoptCanvasPreviewMode, postDragMessage, endDragSession, clearDropIndicator, setNativeDragEnterHandler, setInsertZoneClickHandler, setFileDropHandler, setCanvasSlashHandler, setCanvasContextMenuHandler, setStylebookHitHandler, isCaretActive, setToolbarRefresh, setCanvasPointerDownHandler, setIframePatchEscalation, postPatchToHosts, dragHostTab, releaseCanvasHosts, mountIframeCanvas, mountStylebookCanvas, postColorSchemeToLiveHosts, postLocaleToLiveHosts, postSiteStyleToLiveHosts, postStyleUpdateToStylebookHosts, panToStylebookTag, getEditSnapshot, setKeymapSource, postApplyFormat, postOpenSlash, commitActiveEditSession, getEditBarAnchorRect, clickAnythingTo, staleSelectionMessage, openPageAction, renderEmptyState, panelContext, registerPanel, getPanel, listPanels, isPanelVisible, railGroups, railPanelSet };
8202
+ export { LEVELS, KEY_SCOPES, CATEGORIES, checkRecordPlacements, intlHelpersClause, PURE_METHOD_OPS, BLESSED_OPERATORS, BLESSED_GLOBALS, isMutating, evaluateExpression, rectOf, loopbackAssetSrc, getPreviewNavigateHandler, activeCanvasSurface, tabOfPane, derivationOfPane, surfacesShowingTab, canvasModeOfTab, canvasModeOfPane, activeMediaOfPane, paneOfContainer, tabOfContainer, documentUrlPattern, dynamicRouteParams, pagePathsDef, invalidateParamValues, loadParamValues, isComponentDoc, componentPropEntries, PUBLIC_DIR, normalizeProjectPath, encodeProjectPath, contentMountFor, resolveAssetRef, projectLocales, assetContextFor, previewAssetSrc, hostAssetDeclarations, SPAN_FULL_RENDER, SPAN_MOUNT_CANVAS, SPAN_PATCH_BATCH, canvasPerf, recordEscalation, timeSpan, timeSpanAsync, mediaDisplayName, defaultDef, parentCursorToIframe, serializeJxPath, elements_meta_default, getInlineActions, isInlineElement, isEditing, bubbleInlinePath, stageZoom, canvasPanelTemplate, observeCenterUntilStable, applyTransform, applyEditZoom, setEditZoom, requestEditZoom, fitToScreen, getFit, setFit, markExplicitZoom, setUserZoom, fitOnCanvasEntry, resetZoom, panToElement, canvasBaseViewsFor, canvasBaseViewOf, previewStateOf, setCanvasView, registerCanvasViewCommands, updateActivePanelHeaders, setDragGhost, moveDragGhost, clearDragGhost, disableNativeDragPreview, attachInstruction, extractInstruction, hasElement, enableElement, disableElement, removePackageElements, removeElementRef, setSkipServerFunctions, runScoped, setCanvasAssetResolver, buildScope, renderNode, pureSchemeOf, renderComponentPreview, registerLayersDnD, registerComponentsDnD, registerElementsDnD, applyDropInstruction, sawIframeDragOver, allowAutoRequestsOnNextRender, requestCanvasEval, flushCanvasEdits, liveDragHostAt, beginDragSession, currentDragSession, hostDragGeometry, canvasIdleBlockers, canvasPointAt, revealCanvasPath, adoptCanvasPreviewMode, postDragMessage, endDragSession, clearDropIndicator, setNativeDragEnterHandler, setInsertZoneClickHandler, setFileDropHandler, setCanvasSlashHandler, setCanvasContextMenuHandler, setStylebookHitHandler, isCaretActive, setToolbarRefresh, setCanvasPointerDownHandler, setIframePatchEscalation, postPatchToHosts, dragHostTab, releaseCanvasHosts, mountIframeCanvas, mountStylebookCanvas, postColorSchemeToLiveHosts, postLocaleToLiveHosts, postSiteStyleToLiveHosts, postStyleUpdateToStylebookHosts, panToStylebookTag, getEditSnapshot, setKeymapSource, postApplyFormat, postOpenSlash, commitActiveEditSession, getEditBarAnchorRect, clickAnythingTo, staleSelectionMessage, openPageAction, renderEmptyState, panelContext, registerPanel, getPanel, listPanels, isPanelVisible, railGroups, railPanelSet };
7887
8203
 
7888
- //# debugId=CD43D5D53F29ABBB64756E2164756E21
7889
- //# sourceMappingURL=studio-pyrw8h0w.js.map
8204
+ //# debugId=124567CCB82F091564756E2164756E21
8205
+ //# sourceMappingURL=studio-kjjsjak4.js.map