@jxsuite/studio 0.28.2 → 0.28.4

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 (104) hide show
  1. package/dist/studio.js +86144 -83971
  2. package/dist/studio.js.map +229 -219
  3. package/package.json +5 -5
  4. package/src/browse/browse-modal.ts +9 -3
  5. package/src/browse/browse.ts +139 -82
  6. package/src/canvas/canvas-diff.ts +35 -18
  7. package/src/canvas/canvas-helpers.ts +55 -21
  8. package/src/canvas/canvas-live-render.ts +140 -89
  9. package/src/canvas/canvas-render.ts +127 -82
  10. package/src/canvas/canvas-utils.ts +68 -42
  11. package/src/canvas/nested-site-style.ts +15 -7
  12. package/src/editor/component-inline-edit.ts +90 -51
  13. package/src/editor/content-inline-edit.ts +75 -72
  14. package/src/editor/context-menu.ts +125 -71
  15. package/src/editor/convert-targets.ts +17 -13
  16. package/src/editor/convert-to-component.ts +51 -28
  17. package/src/editor/convert-to-repeater.ts +44 -19
  18. package/src/editor/inline-edit.ts +107 -52
  19. package/src/editor/inline-format.ts +128 -60
  20. package/src/editor/insertion-helper.ts +26 -14
  21. package/src/editor/shortcuts.ts +89 -43
  22. package/src/editor/slash-menu.ts +41 -26
  23. package/src/files/components.ts +9 -7
  24. package/src/files/file-ops.ts +53 -33
  25. package/src/files/files.ts +246 -143
  26. package/src/format/constraints.ts +25 -15
  27. package/src/format/format-host.ts +33 -10
  28. package/src/github/github-auth.ts +24 -14
  29. package/src/github/github-publish.ts +20 -14
  30. package/src/new-project/new-project-modal.ts +27 -18
  31. package/src/panels/activity-bar.ts +27 -26
  32. package/src/panels/ai-panel.ts +100 -44
  33. package/src/panels/block-action-bar.ts +84 -52
  34. package/src/panels/canvas-dnd.ts +47 -28
  35. package/src/panels/data-explorer.ts +24 -11
  36. package/src/panels/dnd.ts +148 -100
  37. package/src/panels/editors.ts +54 -37
  38. package/src/panels/elements-panel.ts +23 -13
  39. package/src/panels/events-panel.ts +48 -38
  40. package/src/panels/git-panel.ts +95 -60
  41. package/src/panels/head-panel.ts +138 -84
  42. package/src/panels/imports-panel.ts +66 -29
  43. package/src/panels/layers-panel.ts +80 -36
  44. package/src/panels/left-panel.ts +86 -53
  45. package/src/panels/overlays.ts +36 -19
  46. package/src/panels/panel-events.ts +48 -27
  47. package/src/panels/panel-scheduler.ts +41 -23
  48. package/src/panels/preview-render.ts +26 -26
  49. package/src/panels/properties-panel.ts +155 -118
  50. package/src/panels/pseudo-preview.ts +31 -15
  51. package/src/panels/quick-search.ts +28 -13
  52. package/src/panels/right-panel.ts +35 -24
  53. package/src/panels/shared.ts +46 -29
  54. package/src/panels/signals-panel.ts +303 -186
  55. package/src/panels/statusbar.ts +27 -12
  56. package/src/panels/style-inputs.ts +30 -24
  57. package/src/panels/style-panel.ts +130 -90
  58. package/src/panels/style-utils.ts +63 -23
  59. package/src/panels/stylebook-layers-panel.ts +27 -30
  60. package/src/panels/stylebook-panel.ts +140 -72
  61. package/src/panels/tab-strip.ts +21 -10
  62. package/src/panels/toolbar.ts +52 -40
  63. package/src/panels/welcome-screen.ts +1 -1
  64. package/src/platform.ts +2 -1
  65. package/src/platforms/devserver.ts +221 -105
  66. package/src/recent-projects.ts +15 -7
  67. package/src/resize-edges.ts +7 -5
  68. package/src/services/cem-export.ts +73 -57
  69. package/src/services/code-services.ts +52 -25
  70. package/src/services/monaco-setup.ts +5 -5
  71. package/src/settings/content-types-editor.ts +133 -62
  72. package/src/settings/css-vars-editor.ts +31 -14
  73. package/src/settings/defs-editor.ts +125 -63
  74. package/src/settings/general-settings.ts +11 -6
  75. package/src/settings/head-editor.ts +30 -15
  76. package/src/settings/schema-field-ui.ts +75 -35
  77. package/src/settings/settings-modal.ts +35 -17
  78. package/src/site-context.ts +80 -47
  79. package/src/state.ts +98 -65
  80. package/src/store.ts +42 -23
  81. package/src/studio.ts +165 -144
  82. package/src/tabs/tab.ts +51 -45
  83. package/src/tabs/transact.ts +230 -109
  84. package/src/types.ts +60 -51
  85. package/src/ui/button-group.ts +3 -2
  86. package/src/ui/color-selector.ts +33 -15
  87. package/src/ui/expression-editor.ts +139 -86
  88. package/src/ui/field-input.ts +35 -18
  89. package/src/ui/field-row.ts +1 -1
  90. package/src/ui/icons.ts +5 -6
  91. package/src/ui/layers.ts +33 -26
  92. package/src/ui/media-picker.ts +13 -7
  93. package/src/ui/panel-resize.ts +39 -20
  94. package/src/ui/spectrum.ts +4 -2
  95. package/src/ui/unit-selector.ts +20 -11
  96. package/src/ui/value-selector.ts +13 -7
  97. package/src/ui/widgets.ts +34 -18
  98. package/src/utils/canvas-media.ts +66 -33
  99. package/src/utils/edit-display.ts +43 -44
  100. package/src/utils/google-fonts.ts +10 -6
  101. package/src/utils/inherited-style.ts +22 -8
  102. package/src/utils/studio-utils.ts +88 -45
  103. package/src/view.ts +9 -5
  104. package/src/workspace/workspace.ts +49 -29
@@ -5,15 +5,16 @@
5
5
  */
6
6
 
7
7
  import { getNodeAtPath } from "../store";
8
+ import { getNestedStyle } from "@jxsuite/schema/guards";
8
9
  import { activeTab } from "../workspace/workspace";
9
10
  import { view } from "../view";
10
- import { getActivePanel, findCanvasElement } from "../canvas/canvas-helpers";
11
+ import { findCanvasElement, getActivePanel } from "../canvas/canvas-helpers";
11
12
 
12
13
  import type { JxStyle } from "@jxsuite/schema/types";
13
14
 
14
15
  const pseudoStyleHost = document.createElement("div");
15
16
  pseudoStyleHost.style.display = "contents";
16
- (document.querySelector("sp-theme") || document.body).appendChild(pseudoStyleHost);
17
+ (document.querySelector("sp-theme") || document.body).append(pseudoStyleHost);
17
18
 
18
19
  export function updateForcedPseudoPreview() {
19
20
  if (view.forcedStyleTag) {
@@ -21,39 +22,54 @@ export function updateForcedPseudoPreview() {
21
22
  view.forcedStyleTag = null;
22
23
  }
23
24
  if (view.forcedAttrEl) {
24
- view.forcedAttrEl.removeAttribute("data-studio-forced");
25
+ delete view.forcedAttrEl.dataset.studioForced;
25
26
  view.forcedAttrEl = null;
26
27
  }
27
28
 
28
29
  const tab = activeTab.value;
29
30
  const sel = tab?.session.ui?.activeSelector;
30
- if (!sel || !sel.startsWith(":") || !tab?.session.selection) return;
31
+ if (!sel || !sel.startsWith(":") || !tab?.session.selection) {
32
+ return;
33
+ }
31
34
 
32
35
  const panel = getActivePanel();
33
- if (!panel) return;
36
+ if (!panel) {
37
+ return;
38
+ }
34
39
  const el = findCanvasElement(tab.session.selection, panel.canvas);
35
- if (!el) return;
40
+ if (!el) {
41
+ return;
42
+ }
36
43
 
37
44
  const node = getNodeAtPath(tab.doc.document, tab.session.selection);
38
- if (!node?.style) return;
39
- const activeMedia = tab.session.ui.activeMedia;
40
- const ctx: JxStyle = activeMedia ? node.style[`@${activeMedia}`] || {} : node.style;
41
- const rules = ctx[sel];
42
- if (!rules || typeof rules !== "object") return;
45
+ if (!node?.style) {
46
+ return;
47
+ }
48
+ const { activeMedia } = tab.session.ui;
49
+ const ctx: JxStyle = activeMedia
50
+ ? (getNestedStyle(node.style, `@${activeMedia}`) ?? {})
51
+ : node.style;
52
+ const rules = getNestedStyle(ctx, sel);
53
+ if (!rules) {
54
+ return;
55
+ }
43
56
 
44
57
  const cssProps = Object.entries(rules)
45
58
  .filter(([k]) => typeof rules[k] === "string" || typeof rules[k] === "number")
46
59
  .map(
47
- ([k, v]) => `${k.replace(/[A-Z]/g, (c: string) => `-${c.toLowerCase()}`)}: ${v} !important`,
60
+ ([k, v]) =>
61
+ `${k.replaceAll(/[A-Z]/g, (c: string) => `-${c.toLowerCase()}`)}: ${v} !important`,
48
62
  )
49
63
  .join("; ");
50
- if (!cssProps) return;
64
+ if (!cssProps) {
65
+ return;
66
+ }
51
67
 
52
- el.setAttribute("data-studio-forced", "1");
68
+ el.dataset.studioForced = "1";
53
69
  view.forcedAttrEl = el;
54
70
 
55
71
  const tag = document.createElement("style");
56
72
  tag.textContent = `[data-studio-forced] { ${cssProps} }`;
57
- pseudoStyleHost.appendChild(tag);
73
+ pseudoStyleHost.append(tag);
58
74
  view.forcedStyleTag = tag;
59
75
  }
@@ -4,7 +4,7 @@ import { classMap } from "lit-html/directives/class-map.js";
4
4
  import { live } from "lit-html/directives/live.js";
5
5
  import { ref } from "lit-html/directives/ref.js";
6
6
  import { getPlatform } from "../platform";
7
- import { loadFormats, documentExtensions, formatByExtension } from "../format/format-host";
7
+ import { documentExtensions, formatByExtension, loadFormats } from "../format/format-host";
8
8
  import { openFileInTab } from "../files/files";
9
9
  import { getRecentFiles, trackRecentFile } from "../recent-projects";
10
10
  import { getLayerSlot } from "../ui/layers";
@@ -67,45 +67,58 @@ function onInput(e: Event) {
67
67
  function onKeydown(e: KeyboardEvent) {
68
68
  const items = _query.trim() ? _results : getRecentFiles();
69
69
  switch (e.key) {
70
- case "ArrowDown":
70
+ case "ArrowDown": {
71
71
  e.preventDefault();
72
72
  _selectedIndex = Math.min(_selectedIndex + 1, items.length - 1);
73
73
  renderOverlay();
74
74
  break;
75
- case "ArrowUp":
75
+ }
76
+ case "ArrowUp": {
76
77
  e.preventDefault();
77
78
  _selectedIndex = Math.max(_selectedIndex - 1, 0);
78
79
  renderOverlay();
79
80
  break;
80
- case "Enter":
81
+ }
82
+ case "Enter": {
81
83
  e.preventDefault();
82
- if (items[_selectedIndex]) selectItem(items[_selectedIndex]);
84
+ if (items[_selectedIndex]) {
85
+ selectItem(items[_selectedIndex]);
86
+ }
83
87
  break;
84
- case "Escape":
88
+ }
89
+ case "Escape": {
85
90
  e.preventDefault();
86
91
  closeQuickSearch();
87
92
  break;
93
+ }
94
+ default: {
95
+ break;
96
+ }
88
97
  }
89
98
  }
90
99
 
91
100
  function selectItem(item: { path: string; name?: string }) {
92
101
  closeQuickSearch();
93
- const path = item.path;
94
- trackRecentFile({ path, name: path.split("/").pop() || "" });
102
+ const { path } = item;
103
+ trackRecentFile({ name: path.split("/").pop() || "", path });
95
104
  openFileInTab(path);
96
105
  }
97
106
 
98
107
  function fileIcon(name: string) {
99
108
  const ext = name.split(".").pop()?.toLowerCase();
100
- if (ext === "json") return html`<sp-icon-file-code size="s"></sp-icon-file-code>`;
101
- if (ext && formatByExtension(ext)) return html`<sp-icon-file-txt size="s"></sp-icon-file-txt>`;
109
+ if (ext === "json") {
110
+ return html`<sp-icon-file-code size="s"></sp-icon-file-code>`;
111
+ }
112
+ if (ext && formatByExtension(ext)) {
113
+ return html`<sp-icon-file-txt size="s"></sp-icon-file-txt>`;
114
+ }
102
115
  return html`<sp-icon-document size="s"></sp-icon-document>`;
103
116
  }
104
117
 
105
118
  function dirPart(path: string) {
106
119
  const parts = path.split("/");
107
120
  parts.pop();
108
- return parts.length ? parts.join("/") : "";
121
+ return parts.length > 0 ? parts.join("/") : "";
109
122
  }
110
123
 
111
124
  function renderOverlay() {
@@ -130,7 +143,9 @@ function renderOverlay() {
130
143
  @input=${onInput}
131
144
  @keydown=${onKeydown}
132
145
  ${ref((el) => {
133
- if (el) requestAnimationFrame(() => (el as HTMLInputElement).focus());
146
+ if (el) {
147
+ requestAnimationFrame(() => (el as HTMLInputElement).focus());
148
+ }
134
149
  })}
135
150
  />
136
151
  <div class="quick-search-results">
@@ -140,7 +155,7 @@ function renderOverlay() {
140
155
  ${items.length === 0 && !_query.trim() && recentFiles.length === 0
141
156
  ? html`<div class="quick-search-empty">Type to search project files</div>`
142
157
  : nothing}
143
- ${showRecent && recentFiles.length
158
+ ${showRecent && recentFiles.length > 0
144
159
  ? html`<div class="quick-search-section-label">Recently opened</div>`
145
160
  : nothing}
146
161
  ${items.map(
@@ -6,9 +6,10 @@
6
6
  */
7
7
 
8
8
  import { html, render as litRender } from "lit-html";
9
- import { updateUi, rightPanel } from "../store";
9
+ import { rightPanel, updateUi } from "../store";
10
10
  import { effect, effectScope } from "../reactivity";
11
- import { createPanelScheduler, type PanelScheduler } from "./panel-scheduler";
11
+ import { createPanelScheduler } from "./panel-scheduler";
12
+ import type { PanelScheduler } from "./panel-scheduler";
12
13
  import { activeTab } from "../workspace/workspace";
13
14
  import { tabIcon } from "./activity-bar";
14
15
  import { eventsSidebarTemplate } from "./events-panel";
@@ -17,13 +18,8 @@ import { isCustomElementDoc } from "./signals-panel";
17
18
  import { isColorPopoverOpen } from "../ui/color-selector";
18
19
  import { renderStylePanelTemplate } from "./style-panel";
19
20
  import { renderPropertiesPanelTemplate } from "./properties-panel";
20
- interface RightPanelCtx {
21
- navigateToComponent: (path: string) => void;
22
- getCanvasMode: () => string;
23
- renderCanvas: () => void;
24
- updateForcedPseudoPreview: () => void;
25
- }
26
21
 
22
+ import type { EffectScope } from "@vue/reactivity";
27
23
  import {
28
24
  renderAiPanelTemplate,
29
25
  mountAiPanel,
@@ -31,9 +27,16 @@ import {
31
27
  registerRightPanelRender,
32
28
  } from "./ai-panel";
33
29
 
30
+ interface RightPanelCtx {
31
+ navigateToComponent: (path: string) => void;
32
+ getCanvasMode: () => string;
33
+ renderCanvas: () => void;
34
+ updateForcedPseudoPreview: () => void;
35
+ }
36
+
34
37
  let _ctx: RightPanelCtx | null = null;
35
38
 
36
- let _scope: import("@vue/reactivity").EffectScope | null = null;
39
+ let _scope: EffectScope | null = null;
37
40
 
38
41
  let _scheduler: PanelScheduler | null = null;
39
42
 
@@ -47,16 +50,18 @@ export function mount(ctx: RightPanelCtx) {
47
50
  mountAiPanel();
48
51
  registerRightPanelRender(render);
49
52
  _scheduler = createPanelScheduler({
50
- root: rightPanel,
51
- render: _doRender,
52
53
  blockWhile: isColorPopoverOpen,
54
+ render: _doRender,
55
+ root: rightPanel,
53
56
  });
54
57
  _scheduler.bindFocus();
55
58
  _scope = effectScope();
56
59
  _scope.run(() => {
57
60
  effect(() => {
58
61
  const tab = activeTab.value;
59
- if (!tab) return;
62
+ if (!tab) {
63
+ return;
64
+ }
60
65
  // Track properties the right panel reads
61
66
  void tab.doc.document;
62
67
  void tab.session.selection;
@@ -102,7 +107,9 @@ let _assistantContainer: HTMLElement | null = null;
102
107
  let _lastTab: string | null = null;
103
108
 
104
109
  function _ensureContainers() {
105
- if (_propsContainer) return;
110
+ if (_propsContainer) {
111
+ return;
112
+ }
106
113
  _propsContainer = document.createElement("div");
107
114
  _propsContainer.className = "panel-body";
108
115
  _eventsContainer = document.createElement("div");
@@ -115,7 +122,9 @@ function _ensureContainers() {
115
122
  }
116
123
 
117
124
  function _doRender() {
118
- if (!_ctx) return;
125
+ if (!_ctx) {
126
+ return;
127
+ }
119
128
  try {
120
129
  const ctx = _ctx as RightPanelCtx;
121
130
  const aTab = activeTab.value;
@@ -124,19 +133,19 @@ function _doRender() {
124
133
  return;
125
134
  }
126
135
  const S = {
127
- ui: aTab.session.ui,
128
136
  document: aTab.doc.document,
129
137
  mode: aTab.doc.mode,
130
138
  selection: aTab.session.selection,
139
+ ui: aTab.session.ui,
131
140
  };
132
141
  const tab = S.ui.rightTab;
133
142
 
134
143
  // Render tabs header
135
144
  const panelTabs = [
136
- { value: "properties", icon: "sp-icon-properties", label: "Properties" },
137
- { value: "events", icon: "sp-icon-event", label: "Events" },
138
- { value: "style", icon: "sp-icon-brush", label: "Style" },
139
- { value: "assistant", icon: "sp-icon-chat", label: "Assistant" },
145
+ { icon: "sp-icon-properties", label: "Properties", value: "properties" },
146
+ { icon: "sp-icon-event", label: "Events", value: "events" },
147
+ { icon: "sp-icon-brush", label: "Style", value: "style" },
148
+ { icon: "sp-icon-chat", label: "Assistant", value: "assistant" },
140
149
  ];
141
150
  const tabsT = html`
142
151
  <div class="panel-tabs">
@@ -183,7 +192,9 @@ function _doRender() {
183
192
  // Render tabs into the right panel, append containers
184
193
  litRender(tabsT, rightPanel);
185
194
  for (const c of containers) {
186
- if (!c.parentNode) rightPanel.appendChild(c);
195
+ if (!c.parentNode) {
196
+ rightPanel.append(c);
197
+ }
187
198
  }
188
199
 
189
200
  // Only render the active panel's content
@@ -204,16 +215,16 @@ function _doRender() {
204
215
  } else if (tab === "style") {
205
216
  try {
206
217
  litRender(renderStylePanelTemplate({ getCanvasMode: ctx.getCanvasMode }), _styleContainer!);
207
- } catch (e) {
208
- console.error("[renderStylePanelTemplate]", e);
218
+ } catch (error) {
219
+ console.error("[renderStylePanelTemplate]", error);
209
220
  }
210
221
  } else if (tab === "assistant") {
211
222
  litRender(renderAiPanelTemplate(), _assistantContainer!);
212
223
  }
213
224
 
214
225
  _lastTab = tab;
215
- } catch (e) {
216
- console.error("right-panel render error:", e);
226
+ } catch (error) {
227
+ console.error("right-panel render error:", error);
217
228
  }
218
229
  requestAnimationFrame(() => mountQuikChat());
219
230
  _ctx.updateForcedPseudoPreview();
@@ -12,12 +12,14 @@ import type { JxMutableNode } from "@jxsuite/schema/types";
12
12
  * @param {string} name
13
13
  */
14
14
  export function mediaDisplayName(name: string) {
15
- if (name === "--") return "Base";
15
+ if (name === "--") {
16
+ return "Base";
17
+ }
16
18
  return (
17
19
  name
18
20
  .replace(/^--/, "")
19
- .replace(/-/g, " ")
20
- .replace(/\b\w/g, (c: string) => c.toUpperCase()) || name
21
+ .replaceAll("-", " ")
22
+ .replaceAll(/\b\w/g, (c: string) => c.toUpperCase()) || name
21
23
  );
22
24
  }
23
25
 
@@ -28,11 +30,13 @@ export const unsafeTags = new Set(["script", "style", "link", "iframe", "object"
28
30
  *
29
31
  * @param {string} tag
30
32
  */
31
- export function defaultDef(tag: string) {
33
+ export function defaultDef(tag: string): JxMutableNode {
32
34
  const def: JxMutableNode = { tagName: tag };
33
- if (/^h[1-6]$/.test(tag)) def.textContent = "Heading";
34
- else if (tag === "p") def.textContent = "Paragraph text";
35
- else if (
35
+ if (/^h[1-6]$/.test(tag)) {
36
+ def.textContent = "Heading";
37
+ } else if (tag === "p") {
38
+ def.textContent = "Paragraph text";
39
+ } else if (
36
40
  tag === "span" ||
37
41
  tag === "strong" ||
38
42
  tag === "em" ||
@@ -44,57 +48,70 @@ export function defaultDef(tag: string) {
44
48
  tag === "sub" ||
45
49
  tag === "sup" ||
46
50
  tag === "time"
47
- )
51
+ ) {
48
52
  def.textContent = "Text";
49
- else if (tag === "a") {
53
+ } else if (tag === "a") {
50
54
  def.textContent = "Link";
51
55
  def.attributes = { href: "#" };
52
- } else if (tag === "button") def.textContent = "Button";
53
- else if (tag === "label") def.textContent = "Label";
54
- else if (tag === "legend") def.textContent = "Legend";
55
- else if (tag === "caption") def.textContent = "Caption";
56
- else if (tag === "summary") def.textContent = "Summary";
57
- else if (
56
+ } else if (tag === "button") {
57
+ def.textContent = "Button";
58
+ } else if (tag === "label") {
59
+ def.textContent = "Label";
60
+ } else if (tag === "legend") {
61
+ def.textContent = "Legend";
62
+ } else if (tag === "caption") {
63
+ def.textContent = "Caption";
64
+ } else if (tag === "summary") {
65
+ def.textContent = "Summary";
66
+ } else if (
58
67
  tag === "li" ||
59
68
  tag === "dt" ||
60
69
  tag === "dd" ||
61
70
  tag === "th" ||
62
71
  tag === "td" ||
63
72
  tag === "option"
64
- )
73
+ ) {
65
74
  def.textContent = "Item";
66
- else if (tag === "blockquote") def.textContent = "Quote";
67
- else if (tag === "pre") def.textContent = "Preformatted text";
68
- else if (tag === "input") def.attributes = { type: "text", placeholder: "Enter text..." };
69
- else if (tag === "img") def.attributes = { alt: "Image" };
70
- else if (tag === "iframe") def.attributes = { src: "" };
71
- else if (tag === "select") def.children = [{ tagName: "option", textContent: "Option 1" }];
72
- else if (tag === "ul" || tag === "ol") def.children = [{ tagName: "li", textContent: "Item" }];
73
- else if (tag === "dl")
75
+ } else if (tag === "blockquote") {
76
+ def.textContent = "Quote";
77
+ } else if (tag === "pre") {
78
+ def.textContent = "Preformatted text";
79
+ } else if (tag === "input") {
80
+ def.attributes = { placeholder: "Enter text...", type: "text" };
81
+ } else if (tag === "img") {
82
+ def.attributes = { alt: "Image" };
83
+ } else if (tag === "iframe") {
84
+ def.attributes = { src: "" };
85
+ } else if (tag === "select") {
86
+ def.children = [{ tagName: "option", textContent: "Option 1" }];
87
+ } else if (tag === "ul" || tag === "ol") {
88
+ def.children = [{ tagName: "li", textContent: "Item" }];
89
+ } else if (tag === "dl") {
74
90
  def.children = [
75
91
  { tagName: "dt", textContent: "Term" },
76
92
  { tagName: "dd", textContent: "Definition" },
77
93
  ];
78
- else if (tag === "table")
94
+ } else if (tag === "table") {
79
95
  def.children = [
80
96
  {
81
- tagName: "thead",
82
97
  children: [
83
98
  {
84
- tagName: "tr",
85
99
  children: [{ tagName: "th", textContent: "Header" }],
100
+ tagName: "tr",
86
101
  },
87
102
  ],
103
+ tagName: "thead",
88
104
  },
89
105
  {
106
+ children: [{ children: [{ tagName: "td", textContent: "Cell" }], tagName: "tr" }],
90
107
  tagName: "tbody",
91
- children: [{ tagName: "tr", children: [{ tagName: "td", textContent: "Cell" }] }],
92
108
  },
93
109
  ];
94
- else if (tag === "details")
110
+ } else if (tag === "details") {
95
111
  def.children = [
96
112
  { tagName: "summary", textContent: "Summary" },
97
113
  { tagName: "p", textContent: "Detail content" },
98
114
  ];
115
+ }
99
116
  return def;
100
117
  }