@jxsuite/studio 0.21.4 → 0.22.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.
package/dist/studio.js CHANGED
@@ -254721,6 +254721,8 @@ function mutateUpdateAttribute(tab, path, attr, value) {
254721
254721
  delete node.attributes;
254722
254722
  }
254723
254723
  function mutateUpdateMediaStyle(tab, path, mediaName, prop, value) {
254724
+ if (!mediaName)
254725
+ return mutateUpdateStyle(tab, path, prop, value);
254724
254726
  const node = getNodeAtPath(tab.doc.document, path);
254725
254727
  if (!node.style)
254726
254728
  node.style = {};
@@ -263034,6 +263036,12 @@ function collapsePropsToAttrMap(propsObj) {
263034
263036
  if (key.startsWith(":") && CSS_PSEUDO_NAMES2.has(key.slice(1))) {
263035
263037
  mdAttrKey = key.slice(1);
263036
263038
  }
263039
+ if (key === "@") {
263040
+ if (value2 && typeof value2 === "object" && !Array.isArray(value2)) {
263041
+ walk2(value2, prefix);
263042
+ }
263043
+ continue;
263044
+ }
263037
263045
  if (key.startsWith("@--")) {
263038
263046
  mdAttrKey = key.slice(1);
263039
263047
  }
@@ -263060,9 +263068,11 @@ async function codeService(action, payload) {
263060
263068
  }
263061
263069
  var pluginSchemaCache = new Map;
263062
263070
  async function fetchPluginSchema(def3, state) {
263063
- if (!def3.$src || !def3.$prototype)
263071
+ const importedPath = def3.$prototype ? projectState?.projectConfig?.imports?.[def3.$prototype] : null;
263072
+ const src = def3.$src || importedPath;
263073
+ if (!src || !def3.$prototype)
263064
263074
  return null;
263065
- const cacheKey = `${def3.$src}::${def3.$prototype}`;
263075
+ const cacheKey = `${src}::${def3.$prototype}`;
263066
263076
  if (pluginSchemaCache.has(cacheKey))
263067
263077
  return pluginSchemaCache.get(cacheKey);
263068
263078
  try {
@@ -263071,8 +263081,8 @@ async function fetchPluginSchema(def3, state) {
263071
263081
  pluginSchemaCache.set(cacheKey, null);
263072
263082
  return null;
263073
263083
  }
263074
- const base2 = state.documentPath ? `${location.origin}/${state.documentPath}` : undefined;
263075
- const schema4 = await platform3.fetchPluginSchema(def3.$src, def3.$prototype, base2);
263084
+ const base2 = !importedPath && state.documentPath ? `${location.origin}/${state.documentPath}` : undefined;
263085
+ const schema4 = await platform3.fetchPluginSchema(src, def3.$prototype, base2);
263076
263086
  pluginSchemaCache.set(cacheKey, schema4);
263077
263087
  return schema4;
263078
263088
  } catch {
@@ -264427,10 +264437,6 @@ var _serverFnConfig = { skip: false };
264427
264437
  function setSkipServerFunctions(v) {
264428
264438
  _serverFnConfig.skip = v;
264429
264439
  }
264430
- var _contentConfig = { skip: false };
264431
- function setSkipContentResolution(v) {
264432
- _contentConfig.skip = v;
264433
- }
264434
264440
  async function buildScope(doc, parentScope = {}, base2 = location.href) {
264435
264441
  const raw = {};
264436
264442
  for (const [key, val] of Object.entries(parentScope)) {
@@ -264805,7 +264811,8 @@ function renderMappedArray(def3, state, options) {
264805
264811
  applyProperties(container, def3, state);
264806
264812
  applyStyle2(container, def3.style ?? {}, state["$media"] ?? {}, state);
264807
264813
  applyAttributes(container, def3.attributes ?? {}, state);
264808
- const { items: itemsSrc, map: mapDef, filter: filterRef, sort: sortRef } = def3.children;
264814
+ const { items: _items, of: _of, map: mapDef, filter: filterRef, sort: sortRef } = def3.children;
264815
+ const itemsSrc = _items ?? _of;
264809
264816
  effect(() => {
264810
264817
  container.innerHTML = "";
264811
264818
  let items;
@@ -265033,39 +265040,6 @@ async function resolvePrototype(def3, state, key, base2) {
265033
265040
  return new Blob(def3.parts ?? [], { type: def3.type ?? "text/plain" });
265034
265041
  case "ReadableStream":
265035
265042
  return null;
265036
- case "ContentCollection":
265037
- case "ContentEntry": {
265038
- if (_contentConfig.skip) {
265039
- return ref(def3.$prototype === "ContentCollection" ? [{ id: "", data: {} }] : null);
265040
- }
265041
- const s2 = ref(def3.$prototype === "ContentCollection" ? [] : null);
265042
- effect(() => {
265043
- let id = def3.id;
265044
- if (id && typeof id === "object" && id.$ref?.startsWith("#/$params/")) {
265045
- const paramName = id.$ref.replace("#/$params/", "");
265046
- id = state?.$params?.[paramName];
265047
- } else if (typeof id === "string" && id.includes("${")) {
265048
- id = evaluateTemplate(id, state);
265049
- }
265050
- if (def3.$prototype === "ContentEntry" && !id)
265051
- return;
265052
- fetch("/__studio/content", {
265053
- method: "POST",
265054
- headers: { "Content-Type": "application/json" },
265055
- body: JSON.stringify({
265056
- $prototype: def3.$prototype,
265057
- contentType: def3.contentType,
265058
- id,
265059
- filter: def3.filter,
265060
- sort: def3.sort,
265061
- limit: def3.limit
265062
- })
265063
- }).then((r) => r.ok ? r.json() : null).then((d2) => {
265064
- s2.value = d2;
265065
- }).catch(() => {});
265066
- });
265067
- return s2;
265068
- }
265069
265043
  default:
265070
265044
  console.warn(`Jx: unknown $prototype "${def3.$prototype}" for "${key}". Did you mean to add '$src'?`);
265071
265045
  return ref(null);
@@ -265149,6 +265123,10 @@ async function resolveClassJson(def3, state, key, base2) {
265149
265123
  return resolveViaDevProxy(def3, state, key, base2);
265150
265124
  }
265151
265125
  if (classDef.$implementation) {
265126
+ const schemaStr = JSON.stringify(classDef);
265127
+ if (schemaStr.includes('"#/$context/')) {
265128
+ return resolveViaDevProxy(def3, state, key, base2);
265129
+ }
265152
265130
  const schemaUrl = base2 ? new URL(src, base2).href : new URL(src, location.href).href;
265153
265131
  const implSrc = new URL(classDef.$implementation, schemaUrl).href;
265154
265132
  const exportName = def3.$export ?? classDef.title ?? def3.$prototype;
@@ -265690,7 +265668,6 @@ async function renderCanvasLive(gen, doc, canvasEl) {
265690
265668
  _failedElementsDocPath = S.documentPath ?? null;
265691
265669
  }
265692
265670
  setSkipServerFunctions(canvasMode !== "preview");
265693
- setSkipContentResolution(canvasMode !== "preview");
265694
265671
  let renderDoc = canvasMode === "preview" ? structuredClone(toRaw(doc)) : prepareForEditMode(stripEventHandlers(doc));
265695
265672
  let layoutWrapped = false;
265696
265673
  activeLayoutPath = null;
@@ -265741,7 +265718,7 @@ async function renderCanvasLive(gen, doc, canvasEl) {
265741
265718
  const docPrefix = root2 ? `${root2}/` : "";
265742
265719
  const docBase = S.documentPath ? `${location.origin}/${docPrefix}${S.documentPath}` : undefined;
265743
265720
  let effectiveElements = getEffectiveElements(renderDoc.$elements);
265744
- if (S.mode === "content" && componentRegistry.length > 0) {
265721
+ if ((S.mode === "content" || layoutWrapped) && componentRegistry.length > 0) {
265745
265722
  const existingRefs = new Set(effectiveElements.map((e) => typeof e === "string" ? e : e?.$ref));
265746
265723
  const collectTags = (node2) => {
265747
265724
  const tags2 = new Set;
@@ -265862,6 +265839,8 @@ async function renderCanvasLive(gen, doc, canvasEl) {
265862
265839
  if (!entry?.tagName)
265863
265840
  continue;
265864
265841
  const tag3 = entry.tagName.toLowerCase();
265842
+ if (tag3 === "script" && !entry.attributes?.src)
265843
+ continue;
265865
265844
  const attrs = { ...entry.attributes };
265866
265845
  for (const key of ["href", "src"]) {
265867
265846
  const val = attrs[key];
@@ -266340,6 +266319,24 @@ function renderSignalsTemplate(S, ctx) {
266340
266319
  const type = e.target.value;
266341
266320
  if (!type)
266342
266321
  return;
266322
+ if (type.startsWith("import:")) {
266323
+ const protoName = type.slice(7);
266324
+ const src = projectState?.projectConfig?.imports?.[protoName];
266325
+ let n3 = "$" + protoName.charAt(0).toLowerCase() + protoName.slice(1);
266326
+ let i3 = 1;
266327
+ const base2 = n3;
266328
+ while (S.document.state && S.document.state[n3]) {
266329
+ n3 = base2 + i3++;
266330
+ }
266331
+ transactDoc(activeTab.value, (t) => mutateAddDef(t, n3, { $prototype: protoName }));
266332
+ expandedSignal = n3;
266333
+ if (src) {
266334
+ fetchPluginSchema({ $prototype: protoName, $src: src }, S).then(() => ctx.renderLeftPanel());
266335
+ } else {
266336
+ ctx.renderLeftPanel();
266337
+ }
266338
+ return;
266339
+ }
266343
266340
  const template = DEF_TEMPLATES[type];
266344
266341
  if (!template)
266345
266342
  return;
@@ -266367,6 +266364,7 @@ function renderSignalsTemplate(S, ctx) {
266367
266364
  <sp-menu-item value="map">Map</sp-menu-item>
266368
266365
  <sp-menu-item value="formData">FormData</sp-menu-item>
266369
266366
  <sp-menu-item value="external">External Module…</sp-menu-item>
266367
+ ${projectState?.projectConfig?.imports ? html3`<sp-menu-divider></sp-menu-divider>${Object.keys(projectState.projectConfig.imports).map((k) => html3`<sp-menu-item value="import:${k}">${k}</sp-menu-item>`)}` : nothing}
266370
266368
  <sp-menu-divider></sp-menu-divider>
266371
266369
  <sp-menu-item value="function">Function</sp-menu-item>
266372
266370
  </sp-picker>
@@ -266554,9 +266552,6 @@ function renderDataSourceFields(S, name, def3, textareaRow, pickerRow, ctx) {
266554
266552
  ${signalFieldRow("Default", String(def3.default || ""), (v) => transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { default: v })))}
266555
266553
  `;
266556
266554
  }
266557
- if (proto2 === "ContentEntry" || proto2 === "ContentCollection") {
266558
- return renderContentPrototypeFields(name, def3, proto2);
266559
- }
266560
266555
  if (proto2 === "Set" || proto2 === "Map" || proto2 === "FormData") {
266561
266556
  const fieldName = proto2 === "FormData" ? "fields" : "default";
266562
266557
  const fieldLabel = proto2 === "FormData" ? "Fields" : "Default";
@@ -266569,85 +266564,6 @@ function renderDataSourceFields(S, name, def3, textareaRow, pickerRow, ctx) {
266569
266564
  }
266570
266565
  return renderExternalPrototypeEditorTemplate(S, name, def3, ctx);
266571
266566
  }
266572
- function renderContentPrototypeFields(name, def3, proto2) {
266573
- const contentTypes = projectState?.projectConfig?.contentTypes;
266574
- const typeNames = contentTypes ? Object.keys(contentTypes) : [];
266575
- const currentType = def3.contentType || "";
266576
- const schema4 = currentType && contentTypes?.[currentType]?.schema || undefined;
266577
- const contentTypeField = typeNames.length ? html3`
266578
- <div class="signal-field-row">
266579
- <label class="signal-field-label">Content Type</label>
266580
- <sp-picker
266581
- size="s"
266582
- value=${currentType}
266583
- style="width:100%"
266584
- @change=${(e) => {
266585
- const v = e.target.value;
266586
- transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { contentType: v }));
266587
- }}
266588
- >
266589
- ${typeNames.map((t) => html3`<sp-menu-item value=${t}>${t}</sp-menu-item>`)}
266590
- </sp-picker>
266591
- </div>
266592
- ` : signalFieldRow("Content Type", currentType, (v) => transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { contentType: v })));
266593
- let entryFields = nothing;
266594
- if (proto2 === "ContentEntry") {
266595
- const idVal = def3.id;
266596
- const idStr = idVal && typeof idVal === "object" && idVal.$ref ? idVal.$ref : typeof idVal === "string" ? idVal : "";
266597
- entryFields = signalFieldRow("ID", idStr, (v) => {
266598
- const val = v.startsWith("#/") ? { $ref: v } : v;
266599
- transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { id: val }));
266600
- });
266601
- } else {
266602
- const filterStr = def3.filter ? JSON.stringify(def3.filter) : "";
266603
- const sortStr = def3.sort ? `${def3.sort.field || ""} ${def3.sort.order || ""}`.trim() : "";
266604
- const limitStr = def3.limit != null ? String(def3.limit) : "";
266605
- entryFields = html3`
266606
- ${signalFieldRow("Filter", filterStr, (v) => {
266607
- try {
266608
- const parsed = v ? JSON.parse(v) : undefined;
266609
- transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { filter: parsed }));
266610
- } catch {}
266611
- })}
266612
- ${signalFieldRow("Sort", sortStr, (v) => {
266613
- if (!v) {
266614
- transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { sort: undefined }));
266615
- return;
266616
- }
266617
- const [field, order2] = v.split(" ");
266618
- transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { sort: { field, order: order2 || "asc" } }));
266619
- })}
266620
- ${signalFieldRow("Limit", limitStr, (v) => {
266621
- const num = v ? parseInt(v, 10) : undefined;
266622
- transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { limit: num }));
266623
- })}
266624
- `;
266625
- }
266626
- let schemaFields = nothing;
266627
- if (schema4?.properties) {
266628
- const fields = Object.entries(schema4.properties);
266629
- const required = new Set(schema4.required || []);
266630
- schemaFields = html3`
266631
- <div style="margin-top:8px;padding:6px 0;border-top:1px solid var(--border-dim)">
266632
- <div style="font-size:11px;color:var(--fg-dim);margin-bottom:4px;font-weight:500">
266633
- Fields (${currentType})
266634
- </div>
266635
- ${fields.map(([field, fieldDef]) => html3`
266636
- <div style="font-size:11px;padding:2px 0;display:flex;gap:4px;align-items:center">
266637
- <code style="color:var(--fg-default)">${field}</code>
266638
- <span style="color:var(--fg-dim)">${fieldDef.type || ""}</span>
266639
- ${required.has(field) ? html3`<span style="color:var(--color-accent,#f36f32);font-size:9px">req</span>` : nothing}
266640
- </div>
266641
- `)}
266642
- </div>
266643
- `;
266644
- }
266645
- return html3`
266646
- ${contentTypeField}
266647
- ${signalFieldRow("Prototype", proto2, (v) => transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { $prototype: v })))}
266648
- ${entryFields} ${schemaFields}
266649
- `;
266650
- }
266651
266567
  function renderFunctionFields(S, name, def3, textareaRow, ctx) {
266652
266568
  const descriptionField = signalFieldRow("Description", def3.description || "", (v) => transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { description: v || undefined })));
266653
266569
  const bodyField = def3.$src ? html3`
@@ -266894,15 +266810,86 @@ function renderEmitsEditorTemplate(S, name, def3) {
266894
266810
  </button>
266895
266811
  `;
266896
266812
  }
266897
- function renderSchemaFieldsTemplate(schema4, def3, name, _S) {
266813
+ function resolveSchemaEnum(enumDef, parentDef) {
266814
+ if (Array.isArray(enumDef))
266815
+ return enumDef;
266816
+ if (enumDef && typeof enumDef === "object") {
266817
+ const ref3 = enumDef.$ref;
266818
+ if (ref3 === "#/$context/contentTypes") {
266819
+ return Object.keys(projectState?.projectConfig?.contentTypes ?? {});
266820
+ }
266821
+ if (typeof ref3 === "string" && ref3.startsWith("#/$context/contentTypes/{@")) {
266822
+ const match2 = ref3.match(/#\/\$context\/contentTypes\/\{@(\w+)\}\/schema\/properties/);
266823
+ if (match2 && parentDef) {
266824
+ const paramName = match2[1];
266825
+ const typeName = parentDef[paramName];
266826
+ if (typeName) {
266827
+ const ct = projectState?.projectConfig?.contentTypes?.[typeName];
266828
+ const schema4 = ct?.schema;
266829
+ const props = schema4?.properties;
266830
+ if (props)
266831
+ return Object.keys(props);
266832
+ }
266833
+ }
266834
+ return;
266835
+ }
266836
+ }
266837
+ if (enumDef === "$contentTypes") {
266838
+ return Object.keys(projectState?.projectConfig?.contentTypes ?? {});
266839
+ }
266840
+ return;
266841
+ }
266842
+ function renderInlineField(key, schema4, value2, onChange, parentDef) {
266843
+ const enumValues = resolveSchemaEnum(schema4.enum, parentDef);
266844
+ if (enumValues) {
266845
+ return html3`<sp-picker
266846
+ size="s"
266847
+ label=${key}
266848
+ value=${value2 !== undefined ? String(value2) : "__none__"}
266849
+ @change=${(e) => onChange(e.target.value === "__none__" ? undefined : e.target.value)}
266850
+ >
266851
+ <sp-menu-item value="__none__">—</sp-menu-item>
266852
+ ${enumValues.map((v) => html3`<sp-menu-item value=${v}>${v}</sp-menu-item>`)}
266853
+ </sp-picker>`;
266854
+ }
266855
+ if (schema4.type === "boolean") {
266856
+ return html3`<sp-switch
266857
+ size="s"
266858
+ ?checked=${!!value2}
266859
+ @change=${(e) => onChange(e.target.checked)}
266860
+ >${key}</sp-switch
266861
+ >`;
266862
+ }
266863
+ if (schema4.type === "integer" || schema4.type === "number") {
266864
+ return html3`<sp-number-field
266865
+ size="s"
266866
+ label=${key}
266867
+ .value=${value2 !== undefined ? value2 : nothing}
266868
+ step=${schema4.type === "integer" ? "1" : nothing}
266869
+ @change=${(e) => {
266870
+ const parsed = schema4.type === "integer" ? parseInt(e.target.value, 10) : parseFloat(e.target.value);
266871
+ onChange(isNaN(parsed) ? undefined : parsed);
266872
+ }}
266873
+ ></sp-number-field>`;
266874
+ }
266875
+ return html3`<sp-textfield
266876
+ size="s"
266877
+ label=${key}
266878
+ placeholder=${key}
266879
+ .value=${value2 ?? ""}
266880
+ @input=${(e) => onChange(e.target.value || undefined)}
266881
+ ></sp-textfield>`;
266882
+ }
266883
+ function renderSchemaFieldsTemplate(schema4, def3, name, _S, ctx = null) {
266898
266884
  if (!schema4?.properties)
266899
266885
  return nothing;
266900
266886
  const required = new Set(schema4.required ?? []);
266901
- return Object.entries(schema4.properties).filter(([prop]) => !STUDIO_RESERVED_KEYS.has(prop)).map(([prop, ps]) => {
266887
+ const propertyFields = Object.entries(schema4.properties).filter(([prop]) => !STUDIO_RESERVED_KEYS.has(prop)).map(([prop, ps]) => {
266902
266888
  const currentValue = def3[prop];
266903
266889
  const labelText = prop + (required.has(prop) ? " *" : "");
266904
266890
  let control;
266905
- if (ps.enum) {
266891
+ const enumValues = resolveSchemaEnum(ps.enum, def3);
266892
+ if (enumValues) {
266906
266893
  control = html3`
266907
266894
  <sp-picker
266908
266895
  size="s"
@@ -266912,7 +266899,7 @@ function renderSchemaFieldsTemplate(schema4, def3, name, _S) {
266912
266899
  }))}
266913
266900
  >
266914
266901
  ${!required.has(prop) ? html3`<sp-menu-item value="__none__">—</sp-menu-item>` : nothing}
266915
- ${ps.enum.map((val) => html3`<sp-menu-item value=${val}>${val}</sp-menu-item>`)}
266902
+ ${enumValues.map((val) => html3`<sp-menu-item value=${val}>${val}</sp-menu-item>`)}
266916
266903
  </sp-picker>
266917
266904
  `;
266918
266905
  } else if (ps.type === "boolean") {
@@ -266930,7 +266917,7 @@ function renderSchemaFieldsTemplate(schema4, def3, name, _S) {
266930
266917
  max=${ifDefined(ps.maximum)}
266931
266918
  step=${ps.type === "integer" ? "1" : nothing}
266932
266919
  .value=${currentValue !== undefined ? currentValue : nothing}
266933
- placeholder=${ps.default !== undefined ? String(ps.default) : nothing}
266920
+ placeholder=${ps.default != null ? String(ps.default) : nothing}
266934
266921
  @change=${(e) => {
266935
266922
  clearTimeout(debounce);
266936
266923
  debounce = setTimeout(() => {
@@ -266979,6 +266966,51 @@ function renderSchemaFieldsTemplate(schema4, def3, name, _S) {
266979
266966
  ></sp-textfield>
266980
266967
  </div>
266981
266968
  `;
266969
+ } else if (ps.type === "array" && ps.items?.type === "object" && ps.items?.properties) {
266970
+ const rows = Array.isArray(currentValue) ? currentValue : [];
266971
+ const itemProps = ps.items.properties;
266972
+ control = html3`
266973
+ <div class="array-object-field">
266974
+ ${rows.map((row, idx) => html3`
266975
+ <div
266976
+ class="array-object-row"
266977
+ style="display:flex;gap:4px;align-items:center;margin-bottom:4px"
266978
+ >
266979
+ ${Object.entries(itemProps).map(([propKey, propSchema]) => renderInlineField(propKey, propSchema, row[propKey], (val) => {
266980
+ const updated = [...rows];
266981
+ updated[idx] = { ...updated[idx], [propKey]: val };
266982
+ transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { [prop]: updated }));
266983
+ }, def3))}
266984
+ <sp-action-button
266985
+ quiet
266986
+ size="s"
266987
+ @click=${() => {
266988
+ const updated = rows.filter((_, i2) => i2 !== idx);
266989
+ transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { [prop]: updated.length ? updated : undefined }));
266990
+ ctx?.renderLeftPanel();
266991
+ }}
266992
+ >
266993
+ <sp-icon-delete slot="icon"></sp-icon-delete>
266994
+ </sp-action-button>
266995
+ </div>
266996
+ `)}
266997
+ <sp-action-button
266998
+ quiet
266999
+ size="s"
267000
+ @click=${(e) => {
267001
+ e.stopPropagation();
267002
+ const newRow = {};
267003
+ for (const [k, v] of Object.entries(itemProps)) {
267004
+ if (v.default !== undefined)
267005
+ newRow[k] = v.default;
267006
+ }
267007
+ transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { [prop]: [...rows, newRow] }));
267008
+ ctx?.renderLeftPanel();
267009
+ }}
267010
+ >+ Add</sp-action-button
267011
+ >
267012
+ </div>
267013
+ `;
266982
267014
  } else if (ps.type === "array" || ps.type === "object") {
266983
267015
  let debounce;
266984
267016
  control = html3`<sp-textfield
@@ -267021,17 +267053,20 @@ function renderSchemaFieldsTemplate(schema4, def3, name, _S) {
267021
267053
  widget: control
267022
267054
  });
267023
267055
  });
267056
+ return html3`${propertyFields}`;
267024
267057
  }
267025
267058
  function renderExternalPrototypeEditorTemplate(S, name, def3, ctx) {
267026
267059
  let schemaContent = nothing;
267027
- if (def3.$src && def3.$prototype) {
267028
- const cacheKey = `${def3.$src}::${def3.$prototype}`;
267060
+ const importedPath = def3.$prototype ? projectState?.projectConfig?.imports?.[def3.$prototype] : null;
267061
+ const resolvedSrc = def3.$src || importedPath;
267062
+ if (resolvedSrc && def3.$prototype) {
267063
+ const cacheKey = `${resolvedSrc}::${def3.$prototype}`;
267029
267064
  if (pluginSchemaCache.has(cacheKey)) {
267030
267065
  const schema4 = pluginSchemaCache.get(cacheKey);
267031
267066
  if (schema4) {
267032
267067
  schemaContent = html3`
267033
267068
  ${schema4.description ? html3`<div class="signal-hint" style="padding:4px 0 8px">${schema4.description}</div>` : nothing}
267034
- ${renderSchemaFieldsTemplate(schema4, def3, name, S)}
267069
+ ${renderSchemaFieldsTemplate(schema4, def3, name, S, ctx)}
267035
267070
  `;
267036
267071
  }
267037
267072
  } else {
@@ -267047,14 +267082,18 @@ function renderExternalPrototypeEditorTemplate(S, name, def3, ctx) {
267047
267082
  }
267048
267083
  }
267049
267084
  return html3`
267050
- ${signalFieldRow("Source", def3.$src || "", (v) => {
267085
+ ${importedPath ? html3`<div class="signal-hint" style="padding:4px 0 2px;font-size:11px;color:var(--fg-dim)">
267086
+ ${def3.$prototype}
267087
+ </div>` : html3`
267088
+ ${signalFieldRow("Source", def3.$src || "", (v) => {
267051
267089
  transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { $src: v || undefined }));
267052
267090
  pluginSchemaCache.delete(`${v}::${def3.$prototype}`);
267053
267091
  })}
267054
- ${signalFieldRow("Prototype", def3.$prototype || "", (v) => {
267092
+ ${signalFieldRow("Prototype", def3.$prototype || "", (v) => {
267055
267093
  transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { $prototype: v || undefined }));
267056
267094
  pluginSchemaCache.delete(`${def3.$src}::${v}`);
267057
267095
  })}
267096
+ `}
267058
267097
  ${def3.$export ? signalFieldRow("Export", def3.$export || "", (v) => transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { $export: v || undefined }))) : nothing}
267059
267098
  ${schemaContent}
267060
267099
  `;
@@ -268516,6 +268555,7 @@ init_workspace2();
268516
268555
  // src/editor/context-menu.js
268517
268556
  init_lit_html();
268518
268557
  init_ref();
268558
+ init_html_to_jx();
268519
268559
  init_store();
268520
268560
  init_workspace2();
268521
268561
 
@@ -269016,17 +269056,93 @@ function renderLayersTemplate(ctx) {
269016
269056
  }
269017
269057
 
269018
269058
  // src/editor/context-menu.js
269019
- function copyNode() {
269059
+ var JX_MIME = "web application/jx+json";
269060
+ function nodeToHtml(node2) {
269061
+ if (typeof node2 === "string")
269062
+ return node2;
269063
+ const tag3 = node2.tagName || "div";
269064
+ let attrs = "";
269065
+ if (node2.attributes) {
269066
+ for (const [k, v] of Object.entries(node2.attributes)) {
269067
+ attrs += v === "" ? ` ${k}` : ` ${k}="${v.replace(/"/g, "&quot;")}"`;
269068
+ }
269069
+ }
269070
+ if (node2.style) {
269071
+ const css = Object.entries(node2.style).map(([k, v]) => `${k}:${v}`).join(";");
269072
+ if (css)
269073
+ attrs += ` style="${css.replace(/"/g, "&quot;")}"`;
269074
+ }
269075
+ let inner = "";
269076
+ if (node2.textContent) {
269077
+ inner = node2.textContent;
269078
+ } else if (node2.children) {
269079
+ inner = node2.children.map((c) => nodeToHtml(c)).join("");
269080
+ }
269081
+ return `<${tag3}${attrs}>${inner}</${tag3}>`;
269082
+ }
269083
+ async function writeToClipboard(json2) {
269084
+ workspace.clipboard = json2;
269085
+ try {
269086
+ await navigator.clipboard.write([
269087
+ new ClipboardItem({
269088
+ [JX_MIME]: new Blob([JSON.stringify(json2)], { type: JX_MIME }),
269089
+ "text/html": new Blob([nodeToHtml(json2)], { type: "text/html" })
269090
+ })
269091
+ ]);
269092
+ } catch {
269093
+ try {
269094
+ await navigator.clipboard.writeText(JSON.stringify(json2));
269095
+ } catch {}
269096
+ }
269097
+ }
269098
+ async function readFromClipboard() {
269099
+ try {
269100
+ const items = await navigator.clipboard.read();
269101
+ for (const item of items) {
269102
+ if (item.types.includes(JX_MIME)) {
269103
+ const blob = await item.getType(JX_MIME);
269104
+ const json2 = JSON.parse(await blob.text());
269105
+ return [json2];
269106
+ }
269107
+ if (item.types.includes("text/html")) {
269108
+ const blob = await item.getType("text/html");
269109
+ const htmlStr = await blob.text();
269110
+ const nodes = htmlToJx(htmlStr);
269111
+ const jxNodes = nodes.map((n2) => typeof n2 === "string" ? { tagName: "p", textContent: n2 } : n2);
269112
+ if (jxNodes.length > 0)
269113
+ return jxNodes;
269114
+ }
269115
+ if (item.types.includes("text/plain")) {
269116
+ const blob = await item.getType("text/plain");
269117
+ const text6 = await blob.text();
269118
+ try {
269119
+ const parsed = JSON.parse(text6);
269120
+ if (parsed && parsed.tagName)
269121
+ return [parsed];
269122
+ } catch {}
269123
+ if (text6.trim())
269124
+ return [{ tagName: "p", textContent: text6.trim() }];
269125
+ }
269126
+ }
269127
+ } catch {
269128
+ if (workspace.clipboard) {
269129
+ return [JSON.parse(JSON.stringify(workspace.clipboard))];
269130
+ }
269131
+ }
269132
+ return null;
269133
+ }
269134
+ async function copyNode() {
269020
269135
  const tab = activeTab.value;
269021
269136
  if (!tab?.session.selection)
269022
269137
  return;
269023
269138
  const node2 = getNodeAtPath(tab.doc.document, tab.session.selection);
269024
269139
  if (!node2)
269025
269140
  return;
269026
- workspace.clipboard = structuredClone(node2);
269141
+ const json2 = JSON.parse(JSON.stringify(node2));
269142
+ await writeToClipboard(json2);
269027
269143
  statusMessage("Copied");
269028
269144
  }
269029
- function cutNode() {
269145
+ async function cutNode() {
269030
269146
  const tab = activeTab.value;
269031
269147
  if (!tab?.session.selection || tab.session.selection.length < 2)
269032
269148
  return;
@@ -269034,17 +269150,18 @@ function cutNode() {
269034
269150
  const node2 = getNodeAtPath(tab.doc.document, sel);
269035
269151
  if (!node2)
269036
269152
  return;
269037
- workspace.clipboard = structuredClone(node2);
269153
+ const json2 = JSON.parse(JSON.stringify(node2));
269154
+ await writeToClipboard(json2);
269038
269155
  transactDoc(tab, (t) => mutateRemoveNode(t, sel));
269039
269156
  statusMessage("Cut");
269040
269157
  }
269041
- function pasteNode() {
269042
- if (!workspace.clipboard)
269043
- return;
269158
+ async function pasteNode() {
269044
269159
  const tab = activeTab.value;
269045
269160
  if (!tab)
269046
269161
  return;
269047
- const clip = workspace.clipboard;
269162
+ const nodes = await readFromClipboard();
269163
+ if (!nodes || nodes.length === 0)
269164
+ return;
269048
269165
  const pPath = tab.session.selection || [];
269049
269166
  const parent = getNodeAtPath(tab.doc.document, pPath);
269050
269167
  if (!parent)
@@ -269052,10 +269169,18 @@ function pasteNode() {
269052
269169
  if (tab.session.selection && tab.session.selection.length >= 2) {
269053
269170
  const pp = parentElementPath(tab.session.selection);
269054
269171
  const idx = childIndex(tab.session.selection);
269055
- transactDoc(tab, (t) => mutateInsertNode(t, pp, idx + 1, structuredClone(clip)));
269172
+ transactDoc(tab, (t) => {
269173
+ for (let i2 = 0;i2 < nodes.length; i2++) {
269174
+ mutateInsertNode(t, pp, idx + 1 + i2, nodes[i2]);
269175
+ }
269176
+ });
269056
269177
  } else {
269057
269178
  const idx = parent.children ? parent.children.length : 0;
269058
- transactDoc(tab, (t) => mutateInsertNode(t, pPath, idx, structuredClone(clip)));
269179
+ transactDoc(tab, (t) => {
269180
+ for (let i2 = 0;i2 < nodes.length; i2++) {
269181
+ mutateInsertNode(t, pPath, idx + i2, nodes[i2]);
269182
+ }
269183
+ });
269059
269184
  }
269060
269185
  statusMessage("Pasted");
269061
269186
  }
@@ -269159,26 +269284,39 @@ function showContextMenu(e, path2, opts = {}) {
269159
269284
  danger: true
269160
269285
  });
269161
269286
  }
269162
- if (workspace.clipboard) {
269163
- const clip = workspace.clipboard;
269287
+ if (path2.length >= 2) {
269164
269288
  items.push({ label: "—" });
269165
269289
  items.push({
269166
269290
  label: "Paste inside",
269167
- action: () => {
269291
+ action: async () => {
269292
+ const nodes = await readFromClipboard();
269293
+ if (!nodes || nodes.length === 0)
269294
+ return;
269168
269295
  const idx = node2.children ? node2.children.length : 0;
269169
- transactDoc(activeTab.value, (t) => mutateInsertNode(t, path2, idx, structuredClone(clip)));
269296
+ transactDoc(activeTab.value, (t) => {
269297
+ for (let i2 = 0;i2 < nodes.length; i2++) {
269298
+ mutateInsertNode(t, path2, idx + i2, nodes[i2]);
269299
+ }
269300
+ });
269301
+ statusMessage("Pasted");
269302
+ }
269303
+ });
269304
+ items.push({
269305
+ label: "Paste after",
269306
+ action: async () => {
269307
+ const nodes = await readFromClipboard();
269308
+ if (!nodes || nodes.length === 0)
269309
+ return;
269310
+ const pp = parentElementPath(path2);
269311
+ const idx = childIndex(path2);
269312
+ transactDoc(activeTab.value, (t) => {
269313
+ for (let i2 = 0;i2 < nodes.length; i2++) {
269314
+ mutateInsertNode(t, pp, idx + 1 + i2, nodes[i2]);
269315
+ }
269316
+ });
269317
+ statusMessage("Pasted");
269170
269318
  }
269171
269319
  });
269172
- if (path2.length >= 2) {
269173
- items.push({
269174
- label: "Paste after",
269175
- action: () => {
269176
- const pp = parentElementPath(path2);
269177
- const idx = childIndex(path2);
269178
- transactDoc(activeTab.value, (t) => mutateInsertNode(t, pp, idx + 1, structuredClone(clip)));
269179
- }
269180
- });
269181
- }
269182
269320
  }
269183
269321
  let { clientX: x, clientY: y } = e;
269184
269322
  _ctxHandle = renderPopover(html3`<sp-popover
@@ -269266,7 +269404,8 @@ function onMouseMove(e) {
269266
269404
  if (!_ctx8 || !_helper)
269267
269405
  return;
269268
269406
  const { getCanvasMode } = _ctx8;
269269
- if (getCanvasMode() !== "design") {
269407
+ const mode = getCanvasMode();
269408
+ if (mode !== "design" && mode !== "edit") {
269270
269409
  hide2();
269271
269410
  return;
269272
269411
  }
@@ -270414,12 +270553,12 @@ function applyCanvasMediaOverrides(canvasEl, activeBreakpoints) {
270414
270553
  if (!tab)
270415
270554
  return;
270416
270555
  const docMedia = getEffectiveMedia(tab.doc.document.$media || {});
270417
- const validBreakpoints = new Set;
270556
+ const activeConditions = new Set;
270418
270557
  for (const name of activeBreakpoints) {
270419
270558
  if (docMedia[name])
270420
- validBreakpoints.add(name);
270559
+ activeConditions.add(docMedia[name]);
270421
270560
  }
270422
- const overrides = collectMediaOverrides(document.styleSheets, validBreakpoints);
270561
+ const overrides = collectMediaOverrides(document.styleSheets, activeConditions);
270423
270562
  applyOverridesToCanvas(canvasEl, overrides);
270424
270563
  }
270425
270564
  function renderOverlays() {
@@ -271639,6 +271778,21 @@ function cleanupGoogleFontPreconnects(head) {
271639
271778
  }
271640
271779
 
271641
271780
  // src/panels/head-panel.js
271781
+ init_platform3();
271782
+ var layoutEntries = null;
271783
+ async function loadLayoutEntries() {
271784
+ try {
271785
+ const platform3 = getPlatform();
271786
+ const listing = await platform3.listDirectory("layouts");
271787
+ layoutEntries = listing.filter((f) => f.type === "file" && f.name.endsWith(".json")).map((f) => ({
271788
+ name: f.name.replace(/\.json$/, "").replace(/[-_]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
271789
+ path: `./layouts/${f.name}`
271790
+ }));
271791
+ } catch {
271792
+ layoutEntries = [];
271793
+ }
271794
+ renderOnly("leftPanel");
271795
+ }
271642
271796
  var PAGE_FIELDS = [
271643
271797
  { label: "Description", attr: "name", key: "description" },
271644
271798
  { label: "Viewport", attr: "name", key: "viewport" }
@@ -271776,9 +271930,63 @@ function renderHeadTemplate({ document: doc, applyMutation, renderLeftPanel }) {
271776
271930
  const tab = activeTab.value;
271777
271931
  const isContent = tab?.doc.mode === "content";
271778
271932
  const frontmatterSection = isContent ? renderFrontmatterSection() : nothing;
271933
+ const isPage = tab?.documentPath && projectState?.isSiteProject && (tab.documentPath.startsWith("pages/") || tab.documentPath.startsWith("./pages/"));
271934
+ let layoutSection = nothing;
271935
+ if (isPage) {
271936
+ if (layoutEntries === null) {
271937
+ loadLayoutEntries();
271938
+ } else {
271939
+ const currentLayout = doc.$layout;
271940
+ const defaultLayout = projectState?.projectConfig?.defaults?.layout;
271941
+ const displayValue = currentLayout === false ? "__none__" : currentLayout ? currentLayout : "__default__";
271942
+ const defaultLabel = defaultLayout ? defaultLayout.replace(/^\.\/layouts\//, "").replace(/\.json$/, "").replace(/[-_]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()) : "";
271943
+ layoutSection = html3`
271944
+ <div class="imports-section">
271945
+ <div class="imports-section-header">
271946
+ <span class="imports-section-title">Layout</span>
271947
+ </div>
271948
+ <div class="head-section-body">
271949
+ ${renderFieldRow({
271950
+ prop: "layout",
271951
+ label: "Layout",
271952
+ hasValue: currentLayout !== undefined,
271953
+ onClear: () => applyMutation((d2) => {
271954
+ delete d2.$layout;
271955
+ }),
271956
+ widget: html3`
271957
+ <sp-picker
271958
+ size="s"
271959
+ value=${displayValue}
271960
+ @change=${(e) => {
271961
+ const val = e.target.value;
271962
+ applyMutation((d2) => {
271963
+ if (val === "__default__")
271964
+ delete d2.$layout;
271965
+ else if (val === "__none__")
271966
+ d2.$layout = false;
271967
+ else
271968
+ d2.$layout = val;
271969
+ });
271970
+ invalidateLayoutCache();
271971
+ }}
271972
+ >
271973
+ <sp-menu-item value="__default__"
271974
+ >Default${defaultLabel ? ` (${defaultLabel})` : ""}</sp-menu-item
271975
+ >
271976
+ <sp-menu-item value="__none__">None</sp-menu-item>
271977
+ <sp-menu-divider></sp-menu-divider>
271978
+ ${layoutEntries.map((l) => html3`<sp-menu-item value=${l.path}>${l.name}</sp-menu-item>`)}
271979
+ </sp-picker>
271980
+ `
271981
+ })}
271982
+ </div>
271983
+ </div>
271984
+ `;
271985
+ }
271986
+ }
271779
271987
  return html3`
271780
271988
  <div class="imports-panel">
271781
- ${frontmatterSection}
271989
+ ${frontmatterSection} ${layoutSection}
271782
271990
 
271783
271991
  <!-- Page section -->
271784
271992
  <div class="imports-section">
@@ -299628,7 +299836,7 @@ function renderHeadEditor(container) {
299628
299836
  } else if (tag5 === "script") {
299629
299837
  attrs.src = "";
299630
299838
  } else if (tag5 === "style") {
299631
- entry.content = "";
299839
+ entry.textContent = "";
299632
299840
  }
299633
299841
  headEntries.push(entry);
299634
299842
  save();
@@ -299642,7 +299850,7 @@ function renderHeadEditor(container) {
299642
299850
  const updateEntry = (idx, key, val) => {
299643
299851
  const entry = headEntries[idx];
299644
299852
  if (key === "content" && (entry.tagName === "script" || entry.tagName === "style")) {
299645
- entry.content = val;
299853
+ entry.textContent = val;
299646
299854
  } else {
299647
299855
  if (!entry.attributes)
299648
299856
  entry.attributes = {};
@@ -299752,7 +299960,7 @@ function renderEntryFields(entry, idx, updateEntry) {
299752
299960
  <label class="settings-field-label">Script body</label>
299753
299961
  <textarea
299754
299962
  class="head-code-editor"
299755
- .value=${entry.content || ""}
299963
+ .value=${entry.textContent || ""}
299756
299964
  @input=${onFieldChange("content")}
299757
299965
  rows="6"
299758
299966
  spellcheck="false"
@@ -299766,7 +299974,7 @@ function renderEntryFields(entry, idx, updateEntry) {
299766
299974
  <label class="settings-field-label">Style body</label>
299767
299975
  <textarea
299768
299976
  class="head-code-editor"
299769
- .value=${entry.content || ""}
299977
+ .value=${entry.textContent || ""}
299770
299978
  @input=${onFieldChange("content")}
299771
299979
  rows="8"
299772
299980
  spellcheck="false"
@@ -304057,6 +304265,47 @@ function styleSidebarTemplate(node2, activeMediaTab, activeSelector, effectiveSt
304057
304265
  }
304058
304266
  return false;
304059
304267
  });
304268
+ const isOpen2 = isFiltering ? true : tab.session.ui.styleSections[sec.key] ?? false;
304269
+ if (!isOpen2) {
304270
+ return html3`
304271
+ <sp-accordion-item
304272
+ label=${sec.label}
304273
+ .open=${false}
304274
+ @sp-accordion-item-toggle=${(e20) => {
304275
+ activeTab.value.session.ui.styleSections = {
304276
+ ...activeTab.value.session.ui.styleSections,
304277
+ [sec.key]: e20.target.open
304278
+ };
304279
+ }}
304280
+ >
304281
+ ${sectionActiveProps.length > 0 ? html3`
304282
+ <span slot="heading" style="display:flex;align-items:center;gap:6px">
304283
+ ${sec.label}
304284
+ <span
304285
+ class="set-dot set-dot--section"
304286
+ title="Clear all ${sec.label.toLowerCase()} properties"
304287
+ @click=${(e20) => {
304288
+ e20.stopPropagation();
304289
+ e20.preventDefault();
304290
+ transactDoc(activeTab.value, (t15) => {
304291
+ for (const { prop, entry } of sectionActiveProps) {
304292
+ if (activeStyle[prop] !== undefined)
304293
+ commitMutate(t15, prop, undefined);
304294
+ if (inferInputType(entry) === "shorthand") {
304295
+ for (const l of getLonghands(prop)) {
304296
+ if (activeStyle[l.name] !== undefined)
304297
+ commitMutate(t15, l.name, undefined);
304298
+ }
304299
+ }
304300
+ }
304301
+ });
304302
+ }}
304303
+ ></span>
304304
+ </span>
304305
+ ` : nothing}
304306
+ </sp-accordion-item>
304307
+ `;
304308
+ }
304060
304309
  const rows = [];
304061
304310
  for (const { prop, entry } of entries2) {
304062
304311
  const val = activeStyle[prop];
@@ -304094,7 +304343,6 @@ function styleSidebarTemplate(node2, activeMediaTab, activeSelector, effectiveSt
304094
304343
  }
304095
304344
  if (isFiltering && rows.length === 0)
304096
304345
  return nothing;
304097
- const isOpen2 = isFiltering ? true : tab.session.ui.styleSections[sec.key] ?? false;
304098
304346
  return html3`
304099
304347
  <sp-accordion-item
304100
304348
  label=${sec.label}
@@ -305153,17 +305401,17 @@ function mediaBreakpointRowTemplate(name, query3) {
305153
305401
  </div>
305154
305402
  `;
305155
305403
  }
305156
- var layoutEntries = null;
305157
- async function loadLayoutEntries() {
305404
+ var layoutEntries2 = null;
305405
+ async function loadLayoutEntries2() {
305158
305406
  try {
305159
305407
  const platform4 = getPlatform();
305160
305408
  const listing = await platform4.listDirectory("layouts");
305161
- layoutEntries = listing.filter((f) => f.type === "file" && f.name.endsWith(".json")).map((f) => ({
305409
+ layoutEntries2 = listing.filter((f) => f.type === "file" && f.name.endsWith(".json")).map((f) => ({
305162
305410
  name: f.name.replace(/\.json$/, ""),
305163
305411
  path: `./layouts/${f.name}`
305164
305412
  }));
305165
305413
  } catch {
305166
- layoutEntries = [];
305414
+ layoutEntries2 = [];
305167
305415
  }
305168
305416
  renderOnly("rightPanel");
305169
305417
  }
@@ -305176,8 +305424,8 @@ function renderPageSection(node2) {
305176
305424
  const tab = activeTab.value;
305177
305425
  if (!isPageDocument(tab.documentPath))
305178
305426
  return nothing;
305179
- if (layoutEntries === null) {
305180
- loadLayoutEntries();
305427
+ if (layoutEntries2 === null) {
305428
+ loadLayoutEntries2();
305181
305429
  return nothing;
305182
305430
  }
305183
305431
  const currentLayout = node2.$layout;
@@ -305219,7 +305467,7 @@ function renderPageSection(node2) {
305219
305467
  >
305220
305468
  <sp-menu-item value="__none__">None</sp-menu-item>
305221
305469
  <sp-menu-divider></sp-menu-divider>
305222
- ${layoutEntries.map((l) => html3`<sp-menu-item value=${l.path}>${l.name}</sp-menu-item>`)}
305470
+ ${layoutEntries2.map((l) => html3`<sp-menu-item value=${l.path}>${l.name}</sp-menu-item>`)}
305223
305471
  </sp-picker>
305224
305472
  </div>
305225
305473
  ${effectivePath ? html3`<div style="font-size:10px;color:var(--fg-dim);padding:2px 0;font-style:italic">
@@ -306640,8 +306888,20 @@ var _scope5 = null;
306640
306888
  var _rendering = false;
306641
306889
  var _scheduled2 = false;
306642
306890
  var _hasFocus = false;
306643
- function _onFocusIn() {
306644
- _hasFocus = true;
306891
+ function _isTextInput(el) {
306892
+ if (!el)
306893
+ return false;
306894
+ const tag5 = el.tagName.toLowerCase();
306895
+ if (tag5 === "input" || tag5 === "textarea")
306896
+ return true;
306897
+ if (tag5 === "sp-textfield" || tag5 === "sp-number-field" || tag5 === "sp-search")
306898
+ return true;
306899
+ if (el.shadowRoot?.activeElement)
306900
+ return _isTextInput(el.shadowRoot.activeElement);
306901
+ return false;
306902
+ }
306903
+ function _onFocusIn(e21) {
306904
+ _hasFocus = _isTextInput(e21.target);
306645
306905
  }
306646
306906
  function _onFocusOut() {
306647
306907
  _hasFocus = false;
@@ -306685,6 +306945,24 @@ function render6() {
306685
306945
  queueMicrotask(_flush2);
306686
306946
  }
306687
306947
  }
306948
+ var _propsContainer = null;
306949
+ var _eventsContainer = null;
306950
+ var _styleContainer = null;
306951
+ var _assistantContainer = null;
306952
+ var _lastTab = null;
306953
+ function _ensureContainers() {
306954
+ if (_propsContainer)
306955
+ return;
306956
+ _propsContainer = document.createElement("div");
306957
+ _propsContainer.className = "panel-body";
306958
+ _eventsContainer = document.createElement("div");
306959
+ _eventsContainer.className = "panel-body";
306960
+ _styleContainer = document.createElement("div");
306961
+ _styleContainer.className = "panel-body";
306962
+ _assistantContainer = document.createElement("div");
306963
+ _assistantContainer.className = "panel-body";
306964
+ _assistantContainer.style.cssText = "display:flex;flex-direction:column;overflow:hidden";
306965
+ }
306688
306966
  function _flush2() {
306689
306967
  _scheduled2 = false;
306690
306968
  if (!_ctx13)
@@ -306693,86 +306971,88 @@ function _flush2() {
306693
306971
  return;
306694
306972
  _rendering = true;
306695
306973
  try {
306696
- render2(rightPanelTemplate(), rightPanel);
306697
- } catch (e21) {
306698
- console.error("right-panel render error:", e21);
306699
- try {
306974
+ const ctx = _ctx13;
306975
+ const aTab = activeTab.value;
306976
+ if (!aTab) {
306700
306977
  rightPanel.textContent = "";
306701
- delete rightPanel["_$litPart$"];
306702
- render2(rightPanelTemplate(), rightPanel);
306703
- } catch (e22) {
306704
- console.error("right-panel retry failed:", e22);
306978
+ return;
306979
+ }
306980
+ const S = {
306981
+ ui: aTab.session.ui,
306982
+ document: aTab.doc.document,
306983
+ mode: aTab.doc.mode,
306984
+ selection: aTab.session.selection
306985
+ };
306986
+ const tab = S.ui.rightTab;
306987
+ const panelTabs = [
306988
+ { value: "properties", icon: "sp-icon-properties", label: "Properties" },
306989
+ { value: "events", icon: "sp-icon-event", label: "Events" },
306990
+ { value: "style", icon: "sp-icon-brush", label: "Style" },
306991
+ { value: "assistant", icon: "sp-icon-chat", label: "Assistant" }
306992
+ ];
306993
+ const tabsT = html3`
306994
+ <div class="panel-tabs">
306995
+ <sp-tabs
306996
+ selected=${tab}
306997
+ quiet
306998
+ @change=${(e21) => {
306999
+ const sel = e21.target.selected;
307000
+ if (sel && sel !== tab) {
307001
+ updateUi("rightTab", sel);
307002
+ render6();
307003
+ }
307004
+ }}
307005
+ >
307006
+ ${panelTabs.map((t16) => html3`
307007
+ <sp-tab value=${t16.value} title=${t16.label} aria-label=${t16.label}>
307008
+ ${tabIcon(t16.icon, "xs")}
307009
+ </sp-tab>
307010
+ `)}
307011
+ </sp-tabs>
307012
+ </div>
307013
+ `;
307014
+ _ensureContainers();
307015
+ const containers = [
307016
+ _propsContainer,
307017
+ _eventsContainer,
307018
+ _styleContainer,
307019
+ _assistantContainer
307020
+ ];
307021
+ const tabKeys = ["properties", "events", "style", "assistant"];
307022
+ for (let i8 = 0;i8 < containers.length; i8++) {
307023
+ if (tabKeys[i8] === tab) {
307024
+ containers[i8].style.display = tabKeys[i8] === "assistant" ? "flex" : "";
307025
+ } else {
307026
+ containers[i8].style.display = "none";
307027
+ }
307028
+ }
307029
+ render2(tabsT, rightPanel);
307030
+ for (const c7 of containers) {
307031
+ if (!c7.parentNode)
307032
+ rightPanel.appendChild(c7);
306705
307033
  }
307034
+ if (tab === "properties") {
307035
+ render2(renderPropertiesPanelTemplate({ navigateToComponent: ctx.navigateToComponent }), _propsContainer);
307036
+ } else if (tab === "events") {
307037
+ render2(eventsSidebarTemplate({ isCustomElementDoc: () => isCustomElementDoc(S) }), _eventsContainer);
307038
+ } else if (tab === "style") {
307039
+ try {
307040
+ render2(renderStylePanelTemplate({ getCanvasMode: ctx.getCanvasMode }), _styleContainer);
307041
+ } catch (e21) {
307042
+ console.error("[renderStylePanelTemplate]", e21);
307043
+ }
307044
+ } else if (tab === "assistant") {
307045
+ render2(renderAiPanelTemplate(), _assistantContainer);
307046
+ }
307047
+ _lastTab = tab;
307048
+ } catch (e21) {
307049
+ console.error("right-panel render error:", e21);
306706
307050
  } finally {
306707
307051
  _rendering = false;
306708
307052
  }
306709
307053
  requestAnimationFrame(() => mountQuikChat());
306710
307054
  _ctx13.updateForcedPseudoPreview();
306711
307055
  }
306712
- function rightPanelTemplate() {
306713
- const ctx = _ctx13;
306714
- const aTab = activeTab.value;
306715
- if (!aTab)
306716
- return nothing;
306717
- const S = {
306718
- ui: aTab.session.ui,
306719
- document: aTab.doc.document,
306720
- mode: aTab.doc.mode,
306721
- selection: aTab.session.selection
306722
- };
306723
- const tab = S.ui.rightTab;
306724
- const panelTabs = [
306725
- { value: "properties", icon: "sp-icon-properties", label: "Properties" },
306726
- { value: "events", icon: "sp-icon-event", label: "Events" },
306727
- { value: "style", icon: "sp-icon-brush", label: "Style" },
306728
- { value: "assistant", icon: "sp-icon-chat", label: "Assistant" }
306729
- ];
306730
- const tabsT = html3`
306731
- <div class="panel-tabs">
306732
- <sp-tabs
306733
- selected=${tab}
306734
- quiet
306735
- @change=${(e21) => {
306736
- const sel = e21.target.selected;
306737
- if (sel && sel !== tab) {
306738
- updateUi("rightTab", sel);
306739
- }
306740
- }}
306741
- >
306742
- ${panelTabs.map((t16) => html3`
306743
- <sp-tab value=${t16.value} title=${t16.label} aria-label=${t16.label}>
306744
- ${tabIcon(t16.icon, "xs")}
306745
- </sp-tab>
306746
- `)}
306747
- </sp-tabs>
306748
- </div>
306749
- `;
306750
- let bodyT = nothing;
306751
- if (tab === "properties") {
306752
- bodyT = renderPropertiesPanelTemplate({ navigateToComponent: ctx.navigateToComponent });
306753
- } else if (tab === "events") {
306754
- bodyT = eventsSidebarTemplate({
306755
- isCustomElementDoc: () => isCustomElementDoc(S)
306756
- });
306757
- } else if (tab === "style") {
306758
- try {
306759
- bodyT = renderStylePanelTemplate({ getCanvasMode: ctx.getCanvasMode });
306760
- } catch (e21) {
306761
- console.error("[renderStylePanelTemplate]", e21);
306762
- }
306763
- } else if (tab === "assistant") {
306764
- bodyT = renderAiPanelTemplate();
306765
- }
306766
- return html3`
306767
- ${tabsT}
306768
- <div
306769
- class="panel-body"
306770
- style=${tab === "assistant" ? "display:flex;flex-direction:column;overflow:hidden" : ""}
306771
- >
306772
- ${bodyT}
306773
- </div>
306774
- `;
306775
- }
306776
307056
 
306777
307057
  // src/panels/left-panel.js
306778
307058
  init_lit_html();
@@ -307749,5 +308029,5 @@ effect(() => {
307749
308029
  scheduleAutosave();
307750
308030
  });
307751
308031
 
307752
- //# debugId=F13607B73179696E64756E2164756E21
308032
+ //# debugId=44524F8AC477F4E864756E2164756E21
307753
308033
  //# sourceMappingURL=studio.js.map