@atomm-developer/generator-workbench 0.1.3 → 0.1.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.
- package/README.md +12 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.es.js +96 -14
- package/dist/index.umd.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,6 +25,8 @@ pnpm add @atomm-developer/generator-workbench
|
|
|
25
25
|
<script src="https://static-res.atomm.com/scripts/js/generator-sdk/generator-workbench/index.umd.js"></script>
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
`generator-workbench` will inject the default `atomm-ui` CDN CSS into its Shadow DOM and auto-load the default `atomm-ui` CDN script when `window.AtommUI` is absent. You only need to provide Vue 3 in environments that rely on the global CDN build.
|
|
29
|
+
|
|
28
30
|
## Usage
|
|
29
31
|
|
|
30
32
|
```html
|
|
@@ -48,6 +50,16 @@ workbench.config = {
|
|
|
48
50
|
await workbench.mount()
|
|
49
51
|
```
|
|
50
52
|
|
|
53
|
+
If you need to override the default CDN addresses, pass:
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
workbench.config = {
|
|
57
|
+
title: 'My Generator',
|
|
58
|
+
atommUiCssUrl: 'https://your-cdn/atomm-ui.css',
|
|
59
|
+
atommUiScriptUrl: 'https://your-cdn/atomm-ui.js',
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
51
63
|
## Shell Modes
|
|
52
64
|
|
|
53
65
|
- `mode: 'full'` keeps the default shell with the top bar and the sidebar footer export area.
|
package/dist/index.d.ts
CHANGED
|
@@ -103,6 +103,8 @@ export declare interface GeneratorWorkbenchConfig {
|
|
|
103
103
|
avatarMenuTrigger?: 'hover' | 'click';
|
|
104
104
|
/** Override the default atomm-ui CDN CSS URL injected into Shadow DOM */
|
|
105
105
|
atommUiCssUrl?: string;
|
|
106
|
+
/** Override the default atomm-ui CDN script URL auto-loaded when AtommUI is absent */
|
|
107
|
+
atommUiScriptUrl?: string;
|
|
106
108
|
runtimePanelFilter?: PanelFilter;
|
|
107
109
|
getTemplateMeta?: () => Record<string, unknown>;
|
|
108
110
|
getTemplateFieldPaths?: (panelSchema: PanelSchema) => string[];
|
package/dist/index.es.js
CHANGED
|
@@ -279,6 +279,7 @@ function collectWorkbenchRefs(root) {
|
|
|
279
279
|
};
|
|
280
280
|
}
|
|
281
281
|
const ATOMM_UI_CDN_CSS_URL = "https://minio-download.makeblock.com/resource/atomm-ui-umd/dist-browser/atomm-ui.min.css";
|
|
282
|
+
const ATOMM_UI_CDN_SCRIPT_URL = "https://minio-download.makeblock.com/resource/atomm-ui-umd/dist-browser/atomm-ui.js";
|
|
282
283
|
const CREDIT_ICON_DATA_URI = "data:image/svg+xml,%3csvg%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3ccircle%20cx='12'%20cy='12'%20r='9'%20fill='url(%23paint0_linear_503_69253)'/%3e%3cg%20filter='url(%23filter0_d_503_69253)'%3e%3crect%20x='7.75781'%20y='12'%20width='6'%20height='6'%20rx='1'%20transform='rotate(-45%207.75781%2012)'%20fill='url(%23paint1_linear_503_69253)'/%3e%3c/g%3e%3cdefs%3e%3cfilter%20id='filter0_d_503_69253'%20x='2.17188'%20y='4.17188'%20width='19.6572'%20height='19.6562'%20filterUnits='userSpaceOnUse'%20color-interpolation-filters='sRGB'%3e%3cfeFlood%20flood-opacity='0'%20result='BackgroundImageFix'/%3e%3cfeColorMatrix%20in='SourceAlpha'%20type='matrix'%20values='0%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200%20127%200'%20result='hardAlpha'/%3e%3cfeOffset%20dy='2'/%3e%3cfeGaussianBlur%20stdDeviation='3'/%3e%3cfeComposite%20in2='hardAlpha'%20operator='out'/%3e%3cfeColorMatrix%20type='matrix'%20values='0%200%200%200%201%200%200%200%200%200.206957%200%200%200%200%200.0670085%200%200%200%201%200'/%3e%3cfeBlend%20mode='normal'%20in2='BackgroundImageFix'%20result='effect1_dropShadow_503_69253'/%3e%3cfeBlend%20mode='normal'%20in='SourceGraphic'%20in2='effect1_dropShadow_503_69253'%20result='shape'/%3e%3c/filter%3e%3clinearGradient%20id='paint0_linear_503_69253'%20x1='12'%20y1='3'%20x2='12'%20y2='21'%20gradientUnits='userSpaceOnUse'%3e%3cstop%20stop-color='%23FFA346'/%3e%3cstop%20offset='1'%20stop-color='%23FF7C23'/%3e%3c/linearGradient%3e%3clinearGradient%20id='paint1_linear_503_69253'%20x1='13.2327'%20y1='12.5252'%20x2='8.63652'%20y2='18.5356'%20gradientUnits='userSpaceOnUse'%3e%3cstop%20stop-color='white'/%3e%3cstop%20offset='1'%20stop-color='%23FFD3B5'/%3e%3c/linearGradient%3e%3c/defs%3e%3c/svg%3e";
|
|
283
284
|
const EXPORT_ICON_DATA_URI = "data:image/svg+xml,%3Csvg%20viewBox%3D'0%200%201088%201024'%20xmlns%3D'http%3A//www.w3.org/2000/svg'%3E%3Cpath%20d%3D'M416%20128v85.312h-128A42.688%2042.688%200%200%200%20245.312%20256v512c0%2023.552%2019.136%2042.688%2042.688%2042.688h512a42.688%2042.688%200%200%200%2042.688-42.688V597.312H928V768a128%20128%200%200%201-128%20128h-512a128%20128%200%200%201-128-128V256a128%20128%200%200%201%20128-128h128z'%20fill%3D'%23ffffff'/%3E%3Cpath%20d%3D'M723.52%20520.832L924.352%20320l-200.832-200.832-60.352%2060.352%2097.856%2097.792h-67.712A298.688%20298.688%200%200%200%20394.688%20576v85.312H480V576a213.312%20213.312%200%200%201%20213.312-213.312h67.712l-97.856%2097.792%2060.352%2060.352z'%20fill%3D'%23ffffff'/%3E%3C/svg%3E";
|
|
284
285
|
const WORKBENCH_SHELL_STYLES = `
|
|
@@ -967,6 +968,8 @@ const WORKBENCH_VUE_TEMPLATE = `
|
|
|
967
968
|
</xt-modal>
|
|
968
969
|
</div>
|
|
969
970
|
`;
|
|
971
|
+
let atommUiLoadPromise = null;
|
|
972
|
+
const atommUiCssTextPromises = /* @__PURE__ */ new Map();
|
|
970
973
|
function requireVue() {
|
|
971
974
|
const Vue = globalThis.Vue;
|
|
972
975
|
if (!Vue || typeof Vue.createApp !== "function") {
|
|
@@ -976,11 +979,44 @@ function requireVue() {
|
|
|
976
979
|
}
|
|
977
980
|
return Vue;
|
|
978
981
|
}
|
|
979
|
-
function
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
982
|
+
function getAtommUiPlugin() {
|
|
983
|
+
return globalThis.AtommUI;
|
|
984
|
+
}
|
|
985
|
+
function normalizeAtommUiCssForShadowDom(cssText) {
|
|
986
|
+
return cssText.replace(/(^|})\s*:root(?=\s*{)/g, "$1:host");
|
|
987
|
+
}
|
|
988
|
+
function loadAtommUiCssText(cssUrl) {
|
|
989
|
+
const cached = atommUiCssTextPromises.get(cssUrl);
|
|
990
|
+
if (cached) {
|
|
991
|
+
return cached;
|
|
992
|
+
}
|
|
993
|
+
const request = fetch(cssUrl).then(async (response) => {
|
|
994
|
+
if (!response.ok) {
|
|
995
|
+
atommUiCssTextPromises.delete(cssUrl);
|
|
996
|
+
return null;
|
|
997
|
+
}
|
|
998
|
+
return normalizeAtommUiCssForShadowDom(await response.text());
|
|
999
|
+
}).catch(() => {
|
|
1000
|
+
atommUiCssTextPromises.delete(cssUrl);
|
|
1001
|
+
return null;
|
|
1002
|
+
});
|
|
1003
|
+
atommUiCssTextPromises.set(cssUrl, request);
|
|
1004
|
+
return request;
|
|
1005
|
+
}
|
|
1006
|
+
async function injectStyles(root, cdnCssUrl) {
|
|
1007
|
+
const cssUrl = cdnCssUrl || ATOMM_UI_CDN_CSS_URL;
|
|
1008
|
+
const atommUiCssText = await loadAtommUiCssText(cssUrl);
|
|
1009
|
+
if (atommUiCssText) {
|
|
1010
|
+
const atommUiStyle = document.createElement("style");
|
|
1011
|
+
atommUiStyle.dataset.generatorWorkbenchAtommUi = "true";
|
|
1012
|
+
atommUiStyle.textContent = atommUiCssText;
|
|
1013
|
+
root.appendChild(atommUiStyle);
|
|
1014
|
+
} else {
|
|
1015
|
+
const link = document.createElement("link");
|
|
1016
|
+
link.rel = "stylesheet";
|
|
1017
|
+
link.href = cssUrl;
|
|
1018
|
+
root.appendChild(link);
|
|
1019
|
+
}
|
|
984
1020
|
const style = document.createElement("style");
|
|
985
1021
|
style.textContent = WORKBENCH_SHELL_STYLES;
|
|
986
1022
|
root.appendChild(style);
|
|
@@ -1087,24 +1123,70 @@ function registerFallbackComponents(app) {
|
|
|
1087
1123
|
`
|
|
1088
1124
|
});
|
|
1089
1125
|
}
|
|
1090
|
-
function
|
|
1126
|
+
function loadAtommUiScript(scriptUrl) {
|
|
1127
|
+
if (atommUiLoadPromise) {
|
|
1128
|
+
return atommUiLoadPromise;
|
|
1129
|
+
}
|
|
1130
|
+
atommUiLoadPromise = new Promise((resolve) => {
|
|
1131
|
+
const existingPlugin = getAtommUiPlugin();
|
|
1132
|
+
if (existingPlugin) {
|
|
1133
|
+
resolve(existingPlugin);
|
|
1134
|
+
return;
|
|
1135
|
+
}
|
|
1136
|
+
const existingScript = document.querySelector(
|
|
1137
|
+
`script[data-generator-workbench-atomm-ui="true"][src="${scriptUrl}"]`
|
|
1138
|
+
);
|
|
1139
|
+
if (existingScript) {
|
|
1140
|
+
const finalize = () => resolve(getAtommUiPlugin());
|
|
1141
|
+
existingScript.addEventListener("load", finalize, { once: true });
|
|
1142
|
+
existingScript.addEventListener("error", () => resolve(void 0), {
|
|
1143
|
+
once: true
|
|
1144
|
+
});
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
const script = document.createElement("script");
|
|
1148
|
+
script.src = scriptUrl;
|
|
1149
|
+
script.async = true;
|
|
1150
|
+
script.dataset.generatorWorkbenchAtommUi = "true";
|
|
1151
|
+
script.addEventListener(
|
|
1152
|
+
"load",
|
|
1153
|
+
() => {
|
|
1154
|
+
resolve(getAtommUiPlugin());
|
|
1155
|
+
},
|
|
1156
|
+
{ once: true }
|
|
1157
|
+
);
|
|
1158
|
+
script.addEventListener("error", () => resolve(void 0), { once: true });
|
|
1159
|
+
(document.head || document.body || document.documentElement).appendChild(
|
|
1160
|
+
script
|
|
1161
|
+
);
|
|
1162
|
+
});
|
|
1163
|
+
return atommUiLoadPromise;
|
|
1164
|
+
}
|
|
1165
|
+
async function resolveAtommUiPlugin(config) {
|
|
1166
|
+
const existingPlugin = getAtommUiPlugin();
|
|
1167
|
+
if (existingPlugin) {
|
|
1168
|
+
return existingPlugin;
|
|
1169
|
+
}
|
|
1170
|
+
return loadAtommUiScript(config.atommUiScriptUrl || ATOMM_UI_CDN_SCRIPT_URL);
|
|
1171
|
+
}
|
|
1172
|
+
async function renderWorkbenchShell(root, config) {
|
|
1091
1173
|
const vue = requireVue();
|
|
1092
1174
|
ensureBrowserProcessEnv();
|
|
1093
|
-
injectStyles(root, config.atommUiCssUrl);
|
|
1175
|
+
await injectStyles(root, config.atommUiCssUrl);
|
|
1094
1176
|
const state = stateFromConfig(vue, config);
|
|
1095
1177
|
const callbacks = createNoopCallbacks();
|
|
1096
1178
|
const container = document.createElement("div");
|
|
1097
1179
|
container.setAttribute("data-workbench-vue-root", "");
|
|
1098
1180
|
root.appendChild(container);
|
|
1099
|
-
const
|
|
1181
|
+
const atommUi = await resolveAtommUiPlugin(config);
|
|
1100
1182
|
const app = vue.createApp({
|
|
1101
1183
|
setup() {
|
|
1102
1184
|
return { state, callbacks };
|
|
1103
1185
|
},
|
|
1104
1186
|
template: WORKBENCH_VUE_TEMPLATE
|
|
1105
1187
|
});
|
|
1106
|
-
if (
|
|
1107
|
-
app.use(
|
|
1188
|
+
if (atommUi) {
|
|
1189
|
+
app.use(atommUi);
|
|
1108
1190
|
} else {
|
|
1109
1191
|
registerFallbackComponents(app);
|
|
1110
1192
|
}
|
|
@@ -1168,7 +1250,7 @@ class GeneratorWorkbenchElement extends HTMLElement {
|
|
|
1168
1250
|
set config(value) {
|
|
1169
1251
|
this._config = normalizeWorkbenchConfig(value);
|
|
1170
1252
|
if (this._mounted) {
|
|
1171
|
-
this.render();
|
|
1253
|
+
void this.render();
|
|
1172
1254
|
}
|
|
1173
1255
|
}
|
|
1174
1256
|
connectedCallback() {
|
|
@@ -1193,7 +1275,7 @@ class GeneratorWorkbenchElement extends HTMLElement {
|
|
|
1193
1275
|
if (!this._runtime) {
|
|
1194
1276
|
throw new Error("[generator-workbench] runtime is required before mount()");
|
|
1195
1277
|
}
|
|
1196
|
-
this.render();
|
|
1278
|
+
await this.render();
|
|
1197
1279
|
this.bindControllers();
|
|
1198
1280
|
this.bindShellCallbacks();
|
|
1199
1281
|
this.bindAuthState();
|
|
@@ -1306,13 +1388,13 @@ class GeneratorWorkbenchElement extends HTMLElement {
|
|
|
1306
1388
|
}
|
|
1307
1389
|
await this._sdk.auth.syncToken(normalizedToken);
|
|
1308
1390
|
}
|
|
1309
|
-
render() {
|
|
1391
|
+
async render() {
|
|
1310
1392
|
if (!this.shadowRoot) return;
|
|
1311
1393
|
if (this._shellContext) {
|
|
1312
1394
|
unmountWorkbenchShell(this._shellContext);
|
|
1313
1395
|
this.shadowRoot.innerHTML = "";
|
|
1314
1396
|
}
|
|
1315
|
-
this._shellContext = renderWorkbenchShell(this.shadowRoot, this._config);
|
|
1397
|
+
this._shellContext = await renderWorkbenchShell(this.shadowRoot, this._config);
|
|
1316
1398
|
this.syncAuthUI();
|
|
1317
1399
|
this.syncBillingUI();
|
|
1318
1400
|
}
|
package/dist/index.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).GeneratorWorkbench={})}(this,function(t){"use strict";var e=Object.defineProperty,n=(t,n,a)=>((t,n,a)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:a}):t[n]=a)(t,"symbol"!=typeof n?n+"":n,a);function a(t,e){if(!t)throw new Error(e)}function o(t,e){const n=(null==e?void 0:e.length)?new Set(e):null;return t.groups.map(t=>{var e;const a=t.fields.map(t=>{var e,a,o;const r=null==(a=null==(e=t.bind)?void 0:e.path)?void 0:a.trim();return r?n&&!n.has(r)?null:{id:t.id,label:(null==(o=t.label)?void 0:o.trim())||t.id||r,path:r}:null}).filter(t=>Boolean(t));return{id:t.id,title:(null==(e=t.title)?void 0:e.trim())||t.id,fields:a}}).filter(t=>t.fields.length>0)}function r(t,e){var n;if(null==(n=t.generatorId)?void 0:n.trim())return t.generatorId.trim();const a=e.meta;if(a&&"object"==typeof a&&"generatorId"in a&&"string"==typeof a.generatorId&&a.generatorId.trim())return a.generatorId.trim();throw new Error("[generator-workbench] generatorId is required in panelSchema.generatorId or state.meta.generatorId")}function i(t){const{sdk:e,runtime:n,config:i}=t;function l(){var t;const e=n.getState(),l=n.getPanelSchema(),s=o(l,null==(t=i.getTemplateFieldPaths)?void 0:t.call(i,l)),p=s.flatMap(t=>t.fields.map(t=>t.path));return a(p.length>0,"[generator-workbench] exportTemplate requires at least one panel field path"),{generatorId:r(l,e),state:e,panelSchema:l,fieldGroups:s,selectedFieldPaths:p}}return{async importTemplate(t){const a=await t.text(),o=e.template.parse(a);let r;return await e.template.applyToRuntime(n,o,{onPanelFilter(t){r=t}}),{template:o,panelFilter:r}},prepareTemplateExport:l,async exportTemplate(t){var n;const r=l(),s=(null==t?void 0:t.length)?o(r.panelSchema,t).flatMap(t=>t.fields.map(t=>t.path)):r.selectedFieldPaths;a(s.length>0,"[generator-workbench] exportTemplate requires at least one panel field path");const p=e.template.build({generatorId:r.generatorId,state:r.state,panelSchema:r.panelSchema,selectedFieldPaths:s,templateMeta:null==(n=i.getTemplateMeta)?void 0:n.call(i)});return e.template.download(p),{template:p}}}}function l(t,e,n){return t.dispatchEvent(new CustomEvent(e,{detail:n,bubbles:!0,composed:!0}))}function s(t,e){const n=t.querySelector(e);if(!n)throw new Error(`[generator-workbench] required DOM node not found: ${e}`);return n}const p="data:image/svg+xml,%3csvg%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3ccircle%20cx='12'%20cy='12'%20r='9'%20fill='url(%23paint0_linear_503_69253)'/%3e%3cg%20filter='url(%23filter0_d_503_69253)'%3e%3crect%20x='7.75781'%20y='12'%20width='6'%20height='6'%20rx='1'%20transform='rotate(-45%207.75781%2012)'%20fill='url(%23paint1_linear_503_69253)'/%3e%3c/g%3e%3cdefs%3e%3cfilter%20id='filter0_d_503_69253'%20x='2.17188'%20y='4.17188'%20width='19.6572'%20height='19.6562'%20filterUnits='userSpaceOnUse'%20color-interpolation-filters='sRGB'%3e%3cfeFlood%20flood-opacity='0'%20result='BackgroundImageFix'/%3e%3cfeColorMatrix%20in='SourceAlpha'%20type='matrix'%20values='0%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200%20127%200'%20result='hardAlpha'/%3e%3cfeOffset%20dy='2'/%3e%3cfeGaussianBlur%20stdDeviation='3'/%3e%3cfeComposite%20in2='hardAlpha'%20operator='out'/%3e%3cfeColorMatrix%20type='matrix'%20values='0%200%200%200%201%200%200%200%200%200.206957%200%200%200%200%200.0670085%200%200%200%201%200'/%3e%3cfeBlend%20mode='normal'%20in2='BackgroundImageFix'%20result='effect1_dropShadow_503_69253'/%3e%3cfeBlend%20mode='normal'%20in='SourceGraphic'%20in2='effect1_dropShadow_503_69253'%20result='shape'/%3e%3c/filter%3e%3clinearGradient%20id='paint0_linear_503_69253'%20x1='12'%20y1='3'%20x2='12'%20y2='21'%20gradientUnits='userSpaceOnUse'%3e%3cstop%20stop-color='%23FFA346'/%3e%3cstop%20offset='1'%20stop-color='%23FF7C23'/%3e%3c/linearGradient%3e%3clinearGradient%20id='paint1_linear_503_69253'%20x1='13.2327'%20y1='12.5252'%20x2='8.63652'%20y2='18.5356'%20gradientUnits='userSpaceOnUse'%3e%3cstop%20stop-color='white'/%3e%3cstop%20offset='1'%20stop-color='%23FFD3B5'/%3e%3c/linearGradient%3e%3c/defs%3e%3c/svg%3e",d=`\n <div class="shell">\n <header v-if="state.shellMode !== 'template'" class="topbar app-topbar">\n <div class="logo-area app-topbar-main" data-role="logo-area">\n <img\n :src="state.logoSrc"\n :alt="state.logoText || 'Atomm'"\n class="brand-logo"\n data-role="brand-logo"\n draggable="false"\n />\n <div class="app-topbar-nav">\n <xt-button\n v-show="state.templateEnabled"\n type="secondary"\n size="small"\n data-role="import-template"\n @click="callbacks.onImportTemplate()"\n >导入模板</xt-button>\n <xt-button\n v-show="state.templateEnabled"\n type="secondary"\n size="small"\n data-role="export-template"\n @click="callbacks.onExportTemplate()"\n >生成模板</xt-button>\n </div>\n </div>\n <div class="app-topbar-auth">\n <div\n v-if="state.isLogin"\n class="topbar-credits-badge"\n data-role="topbar-credits"\n title="Remaining credits"\n >\n <img src="${p}" alt="" class="credits-token-icon" draggable="false" />\n <span class="topbar-credits-value" data-role="topbar-credits-value">{{ state.creditsBalance }}</span>\n </div>\n\n <div\n v-if="state.isLogin && state.avatarMenuTrigger === 'hover'"\n class="auth-hover-card"\n >\n <div class="auth-avatar-trigger" data-role="avatar-button" tabindex="0">\n <div class="auth-avatar">\n <img\n v-if="state.avatarSrc"\n :src="state.avatarSrc"\n alt="Avatar"\n data-role="avatar-image"\n />\n <span v-else data-role="avatar-image">{{ state.avatarText }}</span>\n </div>\n </div>\n <div class="auth-hover-panel">\n <div class="auth-popover-body" data-role="avatar-menu">\n <div class="auth-popover-header">\n <div class="auth-avatar auth-avatar--lg">\n <img v-if="state.avatarSrc" :src="state.avatarSrc" alt="Avatar" />\n <span v-else>{{ state.avatarText }}</span>\n </div>\n <div class="auth-popover-user-text">\n <span class="auth-popover-name">{{ state.authDisplayName }}</span>\n <span class="auth-popover-sub">{{ state.authSubline }}</span>\n </div>\n </div>\n <div class="auth-popover-divider"></div>\n <div class="auth-popover-action" data-role="logout" @click="callbacks.onLogout()">\n Logout\n </div>\n </div>\n </div>\n </div>\n\n <xt-dropdown-menu\n v-else-if="state.isLogin"\n trigger="click"\n :portal-disabled="true"\n placement="bottomRight"\n >\n <template #trigger>\n <div class="auth-avatar-trigger" data-role="avatar-button">\n <div class="auth-avatar">\n <img\n v-if="state.avatarSrc"\n :src="state.avatarSrc"\n alt="Avatar"\n data-role="avatar-image"\n />\n <span v-else data-role="avatar-image">{{ state.avatarText }}</span>\n </div>\n </div>\n </template>\n <template #overlay>\n <div class="auth-popover-body" data-role="avatar-menu">\n <div class="auth-popover-header">\n <div class="auth-avatar auth-avatar--lg">\n <img v-if="state.avatarSrc" :src="state.avatarSrc" alt="Avatar" />\n <span v-else>{{ state.avatarText }}</span>\n </div>\n <div class="auth-popover-user-text">\n <span class="auth-popover-name">{{ state.authDisplayName }}</span>\n <span class="auth-popover-sub">{{ state.authSubline }}</span>\n </div>\n </div>\n <div class="auth-popover-divider"></div>\n <div class="auth-popover-action" data-role="logout" @click="callbacks.onLogout()">\n Logout\n </div>\n </div>\n </template>\n </xt-dropdown-menu>\n\n <xt-button\n size="small"\n type="secondary"\n data-role="login"\n :loading="state.loginLoading"\n v-if="!state.isLogin"\n @click="callbacks.onLogin()"\n >Login</xt-button>\n </div>\n </header>\n\n <div\n class="workspace"\n :class="state.panelTarget === 'left' ? 'panel-left' : 'panel-right'"\n data-role="workspace"\n >\n <main class="canvas-host" data-role="canvas-host"></main>\n <aside class="panel-sidebar" data-role="panel-sidebar">\n <div class="panel-host" data-role="panel-host"></div>\n <div id="sidebar-footer" class="sidebar-footer-export panel-actions" data-role="panel-actions">\n <xt-dropdown-menu\n trigger="click"\n :portal-disabled="true"\n placement="topLeft"\n domTriggerClass="sidebar-export-trigger-btn-wrap"\n :show-trigger-icon="false"\n domContentClass="sidebar-export-dropdown-menu"\n >\n <template #trigger>\n <xt-button class="sidebar-export-trigger-btn" block data-role="fab-trigger">\n <template #icon>\n <img\n src="data:image/svg+xml,%3Csvg%20viewBox%3D'0%200%201088%201024'%20xmlns%3D'http%3A//www.w3.org/2000/svg'%3E%3Cpath%20d%3D'M416%20128v85.312h-128A42.688%2042.688%200%200%200%20245.312%20256v512c0%2023.552%2019.136%2042.688%2042.688%2042.688h512a42.688%2042.688%200%200%200%2042.688-42.688V597.312H928V768a128%20128%200%200%201-128%20128h-512a128%20128%200%200%201-128-128V256a128%20128%200%200%201%20128-128h128z'%20fill%3D'%23ffffff'/%3E%3Cpath%20d%3D'M723.52%20520.832L924.352%20320l-200.832-200.832-60.352%2060.352%2097.856%2097.792h-67.712A298.688%20298.688%200%200%200%20394.688%20576v85.312H480V576a213.312%20213.312%200%200%201%20213.312-213.312h67.712l-97.856%2097.792%2060.352%2060.352z'%20fill%3D'%23ffffff'/%3E%3C/svg%3E"\n alt=""\n width="16"\n height="16"\n draggable="false"\n />\n </template>\n Export SVG\n <template #append-icon>\n <div v-if="state.isLogin" class="export-credits-hint">\n <img src="${p}" alt="" class="credits-token-icon credits-token-icon--sm" draggable="false" />\n <span class="export-credits-hint-value" data-role="export-credits-value">{{ state.exportCreditsCost }}</span>\n </div>\n </template>\n </xt-button>\n </template>\n <template #overlay>\n <div class="export-overlay-menu fab-menu-content" data-role="fab-menu">\n <div\n v-show="state.exportEnabled"\n class="export-overlay-item"\n data-role="export-svg"\n @click="callbacks.onExportSvg()"\n >\n <span class="export-overlay-item-icon export-overlay-item-icon--svg"></span>\n Export SVG\n </div>\n <div\n v-show="state.studioEnabled"\n class="export-overlay-item"\n data-role="open-in-studio"\n @click="callbacks.onOpenInStudio()"\n >\n <span class="export-overlay-item-icon export-overlay-item-icon--studio"></span>\n Open in Studio\n </div>\n </div>\n </template>\n </xt-dropdown-menu>\n </div>\n </aside>\n </div>\n\n <input\n data-role="template-file-input"\n type="file"\n accept="application/json"\n style="display:none"\n @change="callbacks.onFileChange($event)"\n />\n\n <xt-modal\n :model-value="state.templateDialogOpen"\n title="发布模板"\n :show-footer="false"\n :portal-disabled="true"\n @update:model-value="callbacks.onToggleTemplateDialog($event)"\n >\n <div\n v-if="state.templateDialogOpen"\n class="template-export-modal"\n data-role="template-export-modal"\n >\n \n <div class="template-export-groups">\n <div\n v-for="group in state.templateFieldGroups"\n :key="group.id"\n class="template-export-group"\n >\n <div class="template-export-group-title">{{ group.title }}</div>\n <div class="template-export-field-list">\n <div\n v-for="field in group.fields"\n :key="field.path"\n class="template-export-field"\n data-role="template-export-field"\n >\n <xt-checkbox\n :model-value="state.templateSelectedFieldPaths.includes(field.path)"\n :disabled="state.templateExportLoading"\n @update:model-value="callbacks.onToggleTemplateField(field.path, $event)"\n >{{ field.label }}</xt-checkbox>\n <div class="template-export-field-path">{{ field.path }}</div>\n </div>\n </div>\n </div>\n </div>\n\n <div class="template-export-footer">\n <xt-button\n type="secondary"\n :disabled="state.templateExportLoading"\n @click="callbacks.onCloseTemplateDialog()"\n >取消</xt-button>\n <xt-button\n type="primary"\n data-role="template-export-confirm"\n :loading="state.templateExportLoading"\n :disabled="state.templateSelectedFieldPaths.length === 0"\n @click="callbacks.onConfirmTemplateExport()"\n >发布模板</xt-button>\n </div>\n </div>\n </xt-modal>\n </div>\n`;function c(t,e){const n=function(){const t=globalThis.Vue;if(!t||"function"!=typeof t.createApp)throw new Error('[generator-workbench] Vue 3 is required. Load it via CDN: <script src="https://unpkg.com/vue@3/dist/vue.global.js"><\/script>');return t}();!function(){const t=globalThis;t.process?t.process.env?t.process.env.NODE_ENV||(t.process.env.NODE_ENV="production"):t.process.env={NODE_ENV:"production"}:t.process={env:{NODE_ENV:"production"}}}(),function(t,e){const n=document.createElement("link");n.rel="stylesheet",n.href=e||"https://minio-download.makeblock.com/resource/atomm-ui-umd/dist-browser/atomm-ui.min.css",t.appendChild(n);const a=document.createElement("style");a.textContent='\n :host {\n display: block;\n height: 100%;\n color: #111827;\n font-family: Inter, "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;\n --bg-soft: #f3f4f6;\n --border-default: #e5e7eb;\n --text-primary: #111827;\n --text-secondary: #4b5563;\n --text-muted: #9ca3af;\n }\n\n * {\n box-sizing: border-box;\n }\n\n [data-workbench-vue-root] {\n height: 100%;\n }\n\n .shell {\n height: 100%;\n display: flex;\n flex-direction: column;\n background:\n radial-gradient(rgba(17, 24, 39, 0.06) 1px, transparent 1px),\n linear-gradient(180deg, rgba(255, 255, 255, 0.7), rgba(249, 250, 251, 0.96));\n background-size: 20px 20px, auto;\n }\n\n .topbar,\n .app-topbar {\n height: 64px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 0 24px;\n background: rgba(255, 255, 255, 0.92);\n border-bottom: 1px solid var(--border-default);\n backdrop-filter: blur(12px);\n position: relative;\n z-index: 20;\n }\n\n .logo-area,\n .app-topbar-main {\n display: flex;\n align-items: center;\n gap: 18px;\n min-width: 0;\n flex: 1;\n }\n\n .app-topbar-nav {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n }\n\n .workspace {\n flex: 1;\n min-height: 0;\n display: grid;\n grid-template-columns: minmax(0, 1fr) 320px;\n }\n\n .workspace.panel-left {\n grid-template-columns: 320px minmax(0, 1fr);\n }\n\n .workspace.panel-right .canvas-host {\n grid-column: 1;\n }\n\n .workspace.panel-right .panel-sidebar {\n grid-column: 2;\n }\n\n .workspace.panel-left .panel-sidebar {\n grid-column: 1;\n }\n\n .workspace.panel-left .canvas-host {\n grid-column: 2;\n }\n\n .panel-sidebar {\n min-height: 0;\n display: flex;\n flex-direction: column;\n background: #ffffff;\n }\n\n .panel-host {\n flex: 1;\n min-height: 0;\n overflow: auto;\n }\n\n .canvas-host {\n position: relative;\n min-height: 480px;\n display: grid;\n place-items: center;\n }\n\n .brand-logo {\n height: 32px;\n width: 92px;\n display: block;\n cursor: pointer;\n flex: 0 0 auto;\n }\n\n .app-topbar-auth {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 12px;\n flex: 0 0 auto;\n }\n\n .topbar-credits-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 0;\n color: #2d3541;\n font-size: 14px;\n font-weight: 500;\n line-height: 1;\n white-space: nowrap;\n cursor: default;\n }\n\n .topbar-credits-value {\n font-variant-numeric: tabular-nums;\n }\n\n .credits-token-icon {\n width: 20px;\n height: 20px;\n flex: 0 0 16px;\n user-select: none;\n -webkit-user-drag: none;\n }\n\n .credits-token-icon--sm {\n width: 16px;\n height: 16px;\n flex-basis: 16px;\n }\n\n .auth-avatar-trigger {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 8px 4px 4px;\n border-radius: 999px;\n cursor: pointer;\n transition: background 150ms ease;\n }\n\n .auth-avatar-trigger:hover {\n background: var(--bg-soft);\n }\n\n .auth-avatar {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n overflow: hidden;\n flex: 0 0 auto;\n background: #f3f4f6;\n color: var(--text-secondary);\n font-size: 14px;\n font-weight: 600;\n }\n\n .auth-avatar--lg {\n width: 40px;\n height: 40px;\n font-size: 14px;\n }\n\n .auth-avatar img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n }\n\n .auth-popover-body {\n min-width: 200px;\n padding: 4px 0;\n }\n\n .auth-popover-header {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n }\n\n .auth-popover-user-text {\n min-width: 0;\n flex: 1;\n }\n\n .auth-popover-name {\n display: block;\n font-size: 14px;\n font-weight: 600;\n color: var(--text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .auth-popover-sub {\n display: block;\n margin-top: 2px;\n font-size: 12px;\n color: var(--text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .auth-popover-divider {\n height: 1px;\n background: var(--border-default);\n margin: 4px 0;\n }\n\n .auth-popover-action {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n font-size: 13px;\n color: var(--text-secondary);\n cursor: pointer;\n transition: all 150ms ease;\n }\n\n .auth-popover-action:hover {\n background: var(--bg-soft);\n color: var(--text-primary);\n }\n\n .auth-hover-card {\n position: relative;\n display: inline-flex;\n align-items: center;\n }\n\n .auth-hover-panel {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n z-index: 40;\n min-width: 200px;\n background: #fff;\n border: 1px solid var(--border-default);\n border-radius: 12px;\n box-shadow: 0 8px 28px rgba(17, 24, 39, 0.12);\n opacity: 0;\n transform: translateY(4px);\n pointer-events: none;\n transition: opacity 150ms ease, transform 150ms ease;\n }\n\n .auth-hover-card:hover .auth-hover-panel,\n .auth-hover-card:focus-within .auth-hover-panel {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n }\n\n .panel-actions,\n #sidebar-footer {\n flex-shrink: 0;\n padding: 14px 24px;\n border-top: 1px solid var(--border-default);\n background: #ffffff;\n display: flex;\n align-items: center;\n }\n\n .sidebar-footer-export {\n width: 100%;\n }\n\n .sidebar-footer-export .sidebar-export-trigger-btn,\n .sidebar-footer-export .sidebar-export-trigger-btn-wrap,\n .sidebar-export-trigger-btn-wrap {\n width: 100%;\n }\n\n .sidebar-export-dropdown-menu {\n width: 268px;\n }\n\n .sidebar-export-trigger-btn img {\n margin-right: 4px;\n }\n\n .export-credits-hint {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 2px;\n padding: 0;\n font-size: 12px;\n font-weight: 600;\n line-height: 1;\n color: #ff7c23;\n margin-left: 10px;\n white-space: nowrap;\n }\n\n .export-credits-hint-value {\n color: white;\n font-size: 13px;\n font-weight: 700;\n font-variant-numeric: tabular-nums;\n }\n\n .export-overlay-menu,\n .fab-menu-content {\n padding: 4px;\n }\n\n .export-overlay-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: 6px;\n font-size: 14px;\n color: var(--text-primary);\n cursor: pointer;\n transition: background 120ms ease;\n user-select: none;\n }\n\n .export-overlay-item:hover {\n background: var(--bg-soft);\n }\n\n .export-overlay-item-icon {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n background: #cbd5e1;\n display: inline-block;\n flex: 0 0 auto;\n }\n\n .export-overlay-item-icon--svg {\n background: linear-gradient(180deg, #94a3b8, #64748b);\n }\n\n .export-overlay-item-icon--studio {\n background: linear-gradient(180deg, #cbd5e1, #94a3b8);\n }\n\n .workspace.panel-right .panel-sidebar {\n border-left: 1px solid var(--border-default);\n }\n\n .workspace.panel-left .panel-sidebar {\n border-right: 1px solid var(--border-default);\n }\n\n .template-export-modal {\n display: grid;\n gap: 16px;\n }\n\n \n\n .template-export-groups {\n display: grid;\n gap: 12px;\n max-height: 360px;\n overflow: auto;\n }\n\n .template-export-group {\n display: grid;\n gap: 10px;\n padding: 14px 16px;\n border: 1px solid var(--border-default);\n border-radius: 12px;\n background: #ffffff;\n }\n\n .template-export-group-title {\n font-size: 13px;\n font-weight: 700;\n color: var(--text-primary);\n }\n\n .template-export-field-list {\n display: grid;\n gap: 10px;\n }\n\n .template-export-field {\n display: grid;\n gap: 4px;\n }\n\n .template-export-field-path {\n padding-left: 28px;\n font-size: 12px;\n color: var(--text-muted);\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;\n }\n\n .template-export-footer {\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding: 8px 24px;\n }\n',t.appendChild(a)}(t,e.atommUiCssUrl);const a=function(t,e){return t.reactive({shellMode:e.mode||"full",logoText:e.logoText||e.title,logoSrc:e.logoUrl||"https://storage-us.atomm.com/resource/xart/static/agent/imgs/atomm-logo.svg",panelTarget:e.panelTarget||"right",avatarMenuTrigger:e.avatarMenuTrigger||"hover",templateEnabled:!1!==e.templateEnabled,exportEnabled:!1!==e.exportEnabled,studioEnabled:!1!==e.studioEnabled,isLogin:!1,avatarSrc:"",avatarText:"U",authDisplayName:"",authSubline:"",creditsBalance:0,exportCreditsCost:1,loginLoading:!1,templateDialogOpen:!1,templateExportLoading:!1,templateSelectedFieldPaths:[],templateFieldGroups:[]})}(n,e),o={onLogin:()=>{},onLogout:()=>{},onImportTemplate:()=>{},onExportTemplate:()=>{},onCloseTemplateDialog:()=>{},onToggleTemplateDialog:()=>{},onToggleTemplateField:()=>{},onConfirmTemplateExport:()=>{},onExportSvg:()=>{},onOpenInStudio:()=>{},onFileChange:()=>{}},r=document.createElement("div");r.setAttribute("data-workbench-vue-root",""),t.appendChild(r);const i=globalThis.AtommUI,l=n.createApp({setup:()=>({state:a,callbacks:o}),template:d});i?l.use(i):function(t){t.component("xt-button",{inheritAttrs:!0,template:'<button v-bind="$attrs"><slot name="icon" /><slot /><slot name="append-icon" /></button>'}),t.component("xt-avatar",{inheritAttrs:!0,template:'<span v-bind="$attrs"><slot /></span>'}),t.component("xt-dropdown-menu",{inheritAttrs:!0,template:'<div v-bind="$attrs"><slot name="trigger" /><slot name="overlay" /><slot /></div>'}),t.component("xt-hover-card",{inheritAttrs:!0,template:'<div v-bind="$attrs"><slot name="trigger" /><slot name="content" /></div>'}),t.component("xt-modal",{inheritAttrs:!1,props:{modelValue:{type:Boolean,default:!1},title:{type:String,default:""}},emits:["update:modelValue"],template:'\n <div v-if="modelValue" v-bind="$attrs">\n <div>{{ title }}</div>\n <slot />\n </div>\n '}),t.component("xt-checkbox",{inheritAttrs:!1,props:{modelValue:{type:Boolean,default:!1},label:{type:String,default:""},disabled:{type:Boolean,default:!1}},emits:["update:modelValue","change"],template:'\n <label v-bind="$attrs">\n <input\n type="checkbox"\n :checked="modelValue"\n :disabled="disabled"\n @change="$emit(\'update:modelValue\', $event.target.checked)"\n />\n <span><slot>{{ label }}</slot></span>\n </label>\n '})}(l),l.mount(r);const p=function(t){return{root:t,workspace:s(t,'[data-role="workspace"]'),logoArea:t.querySelector('[data-role="logo-area"]'),canvasHost:s(t,'[data-role="canvas-host"]'),panelHost:s(t,'[data-role="panel-host"]'),templateFileInput:s(t,'[data-role="template-file-input"]')}}(t);return{state:a,callbacks:o,app:l,refs:p}}function h(t){t.app.unmount()}const u={title:"",mode:"full",templateEnabled:!0,exportEnabled:!0,studioEnabled:!0,autoMount:!0,panelTarget:"right",avatarMenuTrigger:"hover"};class g extends HTMLElement{constructor(){super(),n(this,"_sdk",null),n(this,"_runtime",null),n(this,"_config",{...u}),n(this,"_mounted",!1),n(this,"_state",{authStatus:{isLogin:!1,userInfo:null},creditsBalance:0,billingUsage:null,busy:{login:!1,importTemplate:!1,exportTemplate:!1,exportSvg:!1,openInStudio:!1},menu:{avatarOpen:!1,fabOpen:!1}}),n(this,"_cleanupAuth"),n(this,"_cleanupCredits"),n(this,"_cleanupBilling"),n(this,"_authController"),n(this,"_templateController"),n(this,"_exportController"),n(this,"_runtimeController"),n(this,"_shellContext"),this.attachShadow({mode:"open"})}get sdk(){return this._sdk}set sdk(t){this._sdk=t}get runtime(){return this._runtime}set runtime(t){this._runtime=t}get config(){return this._config}set config(t){var e;this._config=(e=t,{...u,...e}),this._mounted&&this.render()}connectedCallback(){!1!==this._config.autoMount&&!this._mounted&&this._sdk&&this._runtime&&this.mount()}disconnectedCallback(){this.unmount()}async mount(){var t,e;if(this._mounted)return;if(!this.shadowRoot)throw new Error("[generator-workbench] shadowRoot is required");if(!this._sdk)throw new Error("[generator-workbench] sdk is required before mount()");if(!this._runtime)throw new Error("[generator-workbench] runtime is required before mount()");this.render(),this.bindControllers(),this.bindShellCallbacks(),this.bindAuthState(),await this.syncBillingState();const n=this.requireRefs();await(null==(t=this._runtimeController)?void 0:t.mountCanvas(n.canvasHost)),await(null==(e=this._runtimeController)?void 0:e.mountPanel(n.panelHost,this._state.activePanelFilter)),this._mounted=!0,l(this,"workbench-ready",{sdk:this._sdk,runtime:this._runtime})}async unmount(){var t,e,n,a;null==(t=this._cleanupAuth)||t.call(this),this._cleanupAuth=void 0,null==(e=this._cleanupCredits)||e.call(this),this._cleanupCredits=void 0,null==(n=this._cleanupBilling)||n.call(this),this._cleanupBilling=void 0,await(null==(a=this._runtimeController)?void 0:a.unmountAll()),this._shellContext&&(h(this._shellContext),this._shellContext=void 0),this._mounted=!1}refreshLayout(){}async importTemplate(t){try{const e=await this.requireTemplateController().importTemplate(t);this._state.activePanelFilter=e.panelFilter;const n=this.requireRefs();this._runtimeController&&await this._runtimeController.remountPanel(n.panelHost,e.panelFilter),l(this,"template-imported",e)}catch(e){this.handleError("template",e)}}async exportTemplate(){return this.exportTemplateWithFields()}async exportTemplateWithFields(t){try{this._state.busy.exportTemplate=!0,this._shellContext&&(this._shellContext.state.templateExportLoading=!0);l(this,"template-exported",await this.requireTemplateController().exportTemplate(t)),t&&this.closeTemplateExportDialog()}catch(e){this.handleError("template",e)}finally{this._state.busy.exportTemplate=!1,this._shellContext&&(this._shellContext.state.templateExportLoading=!1)}}async exportSvg(){try{l(this,"svg-export",await this.requireExportController().exportSvg())}catch(t){this.handleError("export",t)}}async openInStudio(){try{l(this,"studio-open",await this.requireExportController().openInStudio())}catch(t){this.handleError("export",t)}}async setAuthToken(t){var e,n;const a=t.trim();if(!a)throw new Error("[generator-workbench] token is required");if(!this._sdk)throw new Error("[generator-workbench] sdk is required before setAuthToken()");const o=null==(n=(e=this._sdk).getAppKey)?void 0:n.call(e);if(!o)throw new Error("[generator-workbench] sdk.getAppKey() is required for setAuthToken()");if("function"!=typeof this._sdk.auth.syncToken)throw new Error("[generator-workbench] sdk.auth.syncToken() is required for setAuthToken()");try{localStorage.setItem(`__atomm_sdk_token__${o}`,a)}catch{}await this._sdk.auth.syncToken(a)}render(){this.shadowRoot&&(this._shellContext&&(h(this._shellContext),this.shadowRoot.innerHTML=""),this._shellContext=c(this.shadowRoot,this._config),this.syncAuthUI(),this.syncBillingUI())}bindControllers(){this._sdk&&this._runtime&&(this._authController=function(t){const{sdk:e}=t;return{getStatus:()=>e.auth.getStatus(),subscribe:t=>(t(e.auth.getStatus()),e.auth.onChange(t)),async login(){await e.auth.login()},async logout(){await e.auth.logout()}}}({sdk:this._sdk}),this._templateController=i({sdk:this._sdk,runtime:this._runtime,config:this._config}),this._exportController=function(t){const{sdk:e,runtime:n,config:a,element:o}=t;async function r(){if(!e.auth.getStatus().isLogin&&(await e.auth.login(),!e.auth.getStatus().isLogin))throw new Error("[generator-workbench] login is required before export")}async function i(){var t;(null==(t=e.billing)?void 0:t.consume)&&await e.billing.consume()}return{async exportSvg(){var t;return await(null==(t=a.beforeExportSvg)?void 0:t.call(a,{sdk:e,runtime:n,element:o})),await r(),await i(),e.export.download({format:"svg"})},async openInStudio(){var t;return await(null==(t=a.beforeOpenInStudio)?void 0:t.call(a,{sdk:e,runtime:n,element:o})),await r(),await i(),e.export.openInStudio({format:"svg"})}}}({sdk:this._sdk,runtime:this._runtime,config:this._config,element:this}),this._runtimeController=function(t){const{runtime:e}=t;let n=null,a=null;async function o(t,n){null==a||a.unmount(),a=await Promise.resolve(e.mount({mode:"embed",target:"panel",container:t,panelFilter:n}))}return{mountCanvas:async function(t){null==n||n.unmount(),n=await Promise.resolve(e.mount({mode:"embed",target:"canvas",container:t}))},mountPanel:o,async remountPanel(t,e){await o(t,e)},async unmountAll(){null==n||n.unmount(),null==a||a.unmount(),n=null,a=null}}}({runtime:this._runtime}))}bindShellCallbacks(){if(!this._shellContext)return;const{callbacks:t}=this._shellContext;t.onLogin=()=>{this.handleLogin()},t.onLogout=()=>{this.handleLogout()},t.onImportTemplate=()=>{this.requireRefs().templateFileInput.click()},t.onExportTemplate=()=>{this.openTemplateExportDialog()},t.onCloseTemplateDialog=()=>{this.closeTemplateExportDialog()},t.onToggleTemplateDialog=t=>{t||this.closeTemplateExportDialog()},t.onToggleTemplateField=(t,e)=>{this.toggleTemplateExportField(t,e)},t.onConfirmTemplateExport=()=>{var t;this.exportTemplateWithFields((null==(t=this._shellContext)?void 0:t.state.templateSelectedFieldPaths)||[])},t.onExportSvg=()=>{this.exportSvg()},t.onOpenInStudio=()=>{this.openInStudio()},t.onFileChange=t=>{var e;const n=t.target,a=null==(e=n.files)?void 0:e[0];a&&(this.importTemplate(a),n.value="")}}openTemplateExportDialog(){try{if(!this._shellContext)return;const t=this.requireTemplateController().prepareTemplateExport();this._shellContext.state.templateFieldGroups=t.fieldGroups.map(t=>({...t,fields:t.fields.map(t=>({...t}))})),this._shellContext.state.templateSelectedFieldPaths=[...t.selectedFieldPaths],this._shellContext.state.templateDialogOpen=!0}catch(t){this.handleError("template",t)}}closeTemplateExportDialog(){this._shellContext&&(this._shellContext.state.templateDialogOpen=!1,this._shellContext.state.templateFieldGroups=[],this._shellContext.state.templateSelectedFieldPaths=[])}toggleTemplateExportField(t,e){if(!this._shellContext)return;const n=new Set(this._shellContext.state.templateSelectedFieldPaths);e?n.add(t):n.delete(t),this._shellContext.state.templateSelectedFieldPaths=Array.from(n)}bindAuthState(){var t;const e=this.requireAuthController();null==(t=this._cleanupAuth)||t.call(this),this._cleanupAuth=e.subscribe(t=>{this._state.authStatus=t,this.syncAuthUI(),this.syncBillingState(t),l(this,"auth-change",t)}),this.bindBillingSubscriptions()}bindBillingSubscriptions(){var t,e,n,a;null==(t=this._cleanupCredits)||t.call(this),this._cleanupCredits=void 0,null==(e=this._cleanupBilling)||e.call(this),this._cleanupBilling=void 0;const o=null==(n=this._sdk)?void 0:n.credits;"function"==typeof(null==o?void 0:o.onChange)&&(this._cleanupCredits=o.onChange(t=>{this._state.creditsBalance=Number(t)||0,this.syncBillingUI()}));const r=null==(a=this._sdk)?void 0:a.billing;"function"==typeof(null==r?void 0:r.onChange)&&(this._cleanupBilling=r.onChange(t=>{this.applyBillingUsage(t)}))}syncAuthUI(){var t,e,n,a;if(!this._shellContext)return;const{state:o}=this._shellContext,{isLogin:r,userInfo:i}=this._state.authStatus,l=(null==(t=null==i?void 0:i.userName)?void 0:t.trim())||(null==(e=null==i?void 0:i.email)?void 0:e.trim())||(null==(n=null==i?void 0:i.phoneNumber)?void 0:n.trim())||"",s=l?l.charAt(0).toUpperCase():"U",p=(null==(a=null==i?void 0:i.email)?void 0:a.trim())||((null==i?void 0:i.phoneNumber)?`${i.phoneZone||""}${i.phoneNumber}`:"Connected to Generator SDK");o.isLogin=r,o.avatarSrc=r&&(null==i?void 0:i.headpic)||"",o.avatarText=s,o.authDisplayName=l,o.authSubline=r?p:""}syncBillingUI(){if(!this._shellContext)return;const{state:t}=this._shellContext,e=this._state.billingUsage;t.creditsBalance=this._state.creditsBalance,t.exportCreditsCost=(null==e?void 0:e.creditsPerUse)??(e&&"unitPrice"in e&&Number(e.unitPrice)||1)}applyBillingUsage(t){this._state.billingUsage=t||null,t&&"number"==typeof t.creditsBalance&&(this._state.creditsBalance=t.creditsBalance),this.syncBillingUI()}resetBillingState(){this._state.creditsBalance=0,this._state.billingUsage=null,this.syncBillingUI()}async syncBillingState(t=this._state.authStatus){var e,n,a,o,r,i,l,s;if(!t.isLogin||!this._sdk)return void this.resetBillingState();const p=null==(n=null==(e=this._sdk.credits)?void 0:e.getCachedBalance)?void 0:n.call(e);"number"==typeof p&&(this._state.creditsBalance=p);const d=null==(o=null==(a=this._sdk.billing)?void 0:a.getCachedUsage)?void 0:o.call(a);d?this.applyBillingUsage(d):this.syncBillingUI();try{const[t,e]=await Promise.all([null==(i=null==(r=this._sdk.credits)?void 0:r.getBalance)?void 0:i.call(r),null==(s=null==(l=this._sdk.billing)?void 0:l.getUsage)?void 0:s.call(l)]);if("number"==typeof(null==t?void 0:t.quota)&&(this._state.creditsBalance=t.quota),e)return void this.applyBillingUsage(e);this.syncBillingUI()}catch(c){this.handleError("auth",c)}}async handleLogin(){try{this._state.busy.login=!0,this._shellContext&&(this._shellContext.state.loginLoading=!0),await this.requireAuthController().login()}catch(t){this.handleError("auth",t)}finally{this._state.busy.login=!1,this._shellContext&&(this._shellContext.state.loginLoading=!1)}}async handleLogout(){try{await this.requireAuthController().logout()}catch(t){this.handleError("auth",t)}}handleError(t,e){var n,a;const o=e instanceof Error?e:new Error(String(e));null==(a=(n=this._config).onError)||a.call(n,o,t),l(this,"workbench-error",{source:t,error:o})}requireRefs(){if(!this._shellContext)throw new Error("[generator-workbench] shell context is not ready");return this._shellContext.refs}requireAuthController(){if(!this._authController)throw new Error("[generator-workbench] auth controller is not ready");return this._authController}requireTemplateController(){if(!this._templateController)throw new Error("[generator-workbench] template controller is not ready");return this._templateController}requireExportController(){if(!this._exportController)throw new Error("[generator-workbench] export controller is not ready");return this._exportController}}const m="generator-workbench";t.GENERATOR_WORKBENCH_TAG_NAME=m,t.GeneratorWorkbenchElement=g,t.defineGeneratorWorkbench=function(t=m){const e=customElements.get(t);return e||(customElements.define(t,g),g)},Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
|
|
1
|
+
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).GeneratorWorkbench={})}(this,function(t){"use strict";var e=Object.defineProperty,n=(t,n,a)=>((t,n,a)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:a}):t[n]=a)(t,"symbol"!=typeof n?n+"":n,a);function a(t,e){if(!t)throw new Error(e)}function o(t,e){const n=(null==e?void 0:e.length)?new Set(e):null;return t.groups.map(t=>{var e;const a=t.fields.map(t=>{var e,a,o;const r=null==(a=null==(e=t.bind)?void 0:e.path)?void 0:a.trim();return r?n&&!n.has(r)?null:{id:t.id,label:(null==(o=t.label)?void 0:o.trim())||t.id||r,path:r}:null}).filter(t=>Boolean(t));return{id:t.id,title:(null==(e=t.title)?void 0:e.trim())||t.id,fields:a}}).filter(t=>t.fields.length>0)}function r(t,e){var n;if(null==(n=t.generatorId)?void 0:n.trim())return t.generatorId.trim();const a=e.meta;if(a&&"object"==typeof a&&"generatorId"in a&&"string"==typeof a.generatorId&&a.generatorId.trim())return a.generatorId.trim();throw new Error("[generator-workbench] generatorId is required in panelSchema.generatorId or state.meta.generatorId")}function i(t){const{sdk:e,runtime:n,config:i}=t;function l(){var t;const e=n.getState(),l=n.getPanelSchema(),s=o(l,null==(t=i.getTemplateFieldPaths)?void 0:t.call(i,l)),p=s.flatMap(t=>t.fields.map(t=>t.path));return a(p.length>0,"[generator-workbench] exportTemplate requires at least one panel field path"),{generatorId:r(l,e),state:e,panelSchema:l,fieldGroups:s,selectedFieldPaths:p}}return{async importTemplate(t){const a=await t.text(),o=e.template.parse(a);let r;return await e.template.applyToRuntime(n,o,{onPanelFilter(t){r=t}}),{template:o,panelFilter:r}},prepareTemplateExport:l,async exportTemplate(t){var n;const r=l(),s=(null==t?void 0:t.length)?o(r.panelSchema,t).flatMap(t=>t.fields.map(t=>t.path)):r.selectedFieldPaths;a(s.length>0,"[generator-workbench] exportTemplate requires at least one panel field path");const p=e.template.build({generatorId:r.generatorId,state:r.state,panelSchema:r.panelSchema,selectedFieldPaths:s,templateMeta:null==(n=i.getTemplateMeta)?void 0:n.call(i)});return e.template.download(p),{template:p}}}}function l(t,e,n){return t.dispatchEvent(new CustomEvent(e,{detail:n,bubbles:!0,composed:!0}))}function s(t,e){const n=t.querySelector(e);if(!n)throw new Error(`[generator-workbench] required DOM node not found: ${e}`);return n}const p="data:image/svg+xml,%3csvg%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3ccircle%20cx='12'%20cy='12'%20r='9'%20fill='url(%23paint0_linear_503_69253)'/%3e%3cg%20filter='url(%23filter0_d_503_69253)'%3e%3crect%20x='7.75781'%20y='12'%20width='6'%20height='6'%20rx='1'%20transform='rotate(-45%207.75781%2012)'%20fill='url(%23paint1_linear_503_69253)'/%3e%3c/g%3e%3cdefs%3e%3cfilter%20id='filter0_d_503_69253'%20x='2.17188'%20y='4.17188'%20width='19.6572'%20height='19.6562'%20filterUnits='userSpaceOnUse'%20color-interpolation-filters='sRGB'%3e%3cfeFlood%20flood-opacity='0'%20result='BackgroundImageFix'/%3e%3cfeColorMatrix%20in='SourceAlpha'%20type='matrix'%20values='0%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200%20127%200'%20result='hardAlpha'/%3e%3cfeOffset%20dy='2'/%3e%3cfeGaussianBlur%20stdDeviation='3'/%3e%3cfeComposite%20in2='hardAlpha'%20operator='out'/%3e%3cfeColorMatrix%20type='matrix'%20values='0%200%200%200%201%200%200%200%200%200.206957%200%200%200%200%200.0670085%200%200%200%201%200'/%3e%3cfeBlend%20mode='normal'%20in2='BackgroundImageFix'%20result='effect1_dropShadow_503_69253'/%3e%3cfeBlend%20mode='normal'%20in='SourceGraphic'%20in2='effect1_dropShadow_503_69253'%20result='shape'/%3e%3c/filter%3e%3clinearGradient%20id='paint0_linear_503_69253'%20x1='12'%20y1='3'%20x2='12'%20y2='21'%20gradientUnits='userSpaceOnUse'%3e%3cstop%20stop-color='%23FFA346'/%3e%3cstop%20offset='1'%20stop-color='%23FF7C23'/%3e%3c/linearGradient%3e%3clinearGradient%20id='paint1_linear_503_69253'%20x1='13.2327'%20y1='12.5252'%20x2='8.63652'%20y2='18.5356'%20gradientUnits='userSpaceOnUse'%3e%3cstop%20stop-color='white'/%3e%3cstop%20offset='1'%20stop-color='%23FFD3B5'/%3e%3c/linearGradient%3e%3c/defs%3e%3c/svg%3e",d=`\n <div class="shell">\n <header v-if="state.shellMode !== 'template'" class="topbar app-topbar">\n <div class="logo-area app-topbar-main" data-role="logo-area">\n <img\n :src="state.logoSrc"\n :alt="state.logoText || 'Atomm'"\n class="brand-logo"\n data-role="brand-logo"\n draggable="false"\n />\n <div class="app-topbar-nav">\n <xt-button\n v-show="state.templateEnabled"\n type="secondary"\n size="small"\n data-role="import-template"\n @click="callbacks.onImportTemplate()"\n >导入模板</xt-button>\n <xt-button\n v-show="state.templateEnabled"\n type="secondary"\n size="small"\n data-role="export-template"\n @click="callbacks.onExportTemplate()"\n >生成模板</xt-button>\n </div>\n </div>\n <div class="app-topbar-auth">\n <div\n v-if="state.isLogin"\n class="topbar-credits-badge"\n data-role="topbar-credits"\n title="Remaining credits"\n >\n <img src="${p}" alt="" class="credits-token-icon" draggable="false" />\n <span class="topbar-credits-value" data-role="topbar-credits-value">{{ state.creditsBalance }}</span>\n </div>\n\n <div\n v-if="state.isLogin && state.avatarMenuTrigger === 'hover'"\n class="auth-hover-card"\n >\n <div class="auth-avatar-trigger" data-role="avatar-button" tabindex="0">\n <div class="auth-avatar">\n <img\n v-if="state.avatarSrc"\n :src="state.avatarSrc"\n alt="Avatar"\n data-role="avatar-image"\n />\n <span v-else data-role="avatar-image">{{ state.avatarText }}</span>\n </div>\n </div>\n <div class="auth-hover-panel">\n <div class="auth-popover-body" data-role="avatar-menu">\n <div class="auth-popover-header">\n <div class="auth-avatar auth-avatar--lg">\n <img v-if="state.avatarSrc" :src="state.avatarSrc" alt="Avatar" />\n <span v-else>{{ state.avatarText }}</span>\n </div>\n <div class="auth-popover-user-text">\n <span class="auth-popover-name">{{ state.authDisplayName }}</span>\n <span class="auth-popover-sub">{{ state.authSubline }}</span>\n </div>\n </div>\n <div class="auth-popover-divider"></div>\n <div class="auth-popover-action" data-role="logout" @click="callbacks.onLogout()">\n Logout\n </div>\n </div>\n </div>\n </div>\n\n <xt-dropdown-menu\n v-else-if="state.isLogin"\n trigger="click"\n :portal-disabled="true"\n placement="bottomRight"\n >\n <template #trigger>\n <div class="auth-avatar-trigger" data-role="avatar-button">\n <div class="auth-avatar">\n <img\n v-if="state.avatarSrc"\n :src="state.avatarSrc"\n alt="Avatar"\n data-role="avatar-image"\n />\n <span v-else data-role="avatar-image">{{ state.avatarText }}</span>\n </div>\n </div>\n </template>\n <template #overlay>\n <div class="auth-popover-body" data-role="avatar-menu">\n <div class="auth-popover-header">\n <div class="auth-avatar auth-avatar--lg">\n <img v-if="state.avatarSrc" :src="state.avatarSrc" alt="Avatar" />\n <span v-else>{{ state.avatarText }}</span>\n </div>\n <div class="auth-popover-user-text">\n <span class="auth-popover-name">{{ state.authDisplayName }}</span>\n <span class="auth-popover-sub">{{ state.authSubline }}</span>\n </div>\n </div>\n <div class="auth-popover-divider"></div>\n <div class="auth-popover-action" data-role="logout" @click="callbacks.onLogout()">\n Logout\n </div>\n </div>\n </template>\n </xt-dropdown-menu>\n\n <xt-button\n size="small"\n type="secondary"\n data-role="login"\n :loading="state.loginLoading"\n v-if="!state.isLogin"\n @click="callbacks.onLogin()"\n >Login</xt-button>\n </div>\n </header>\n\n <div\n class="workspace"\n :class="state.panelTarget === 'left' ? 'panel-left' : 'panel-right'"\n data-role="workspace"\n >\n <main class="canvas-host" data-role="canvas-host"></main>\n <aside class="panel-sidebar" data-role="panel-sidebar">\n <div class="panel-host" data-role="panel-host"></div>\n <div id="sidebar-footer" class="sidebar-footer-export panel-actions" data-role="panel-actions">\n <xt-dropdown-menu\n trigger="click"\n :portal-disabled="true"\n placement="topLeft"\n domTriggerClass="sidebar-export-trigger-btn-wrap"\n :show-trigger-icon="false"\n domContentClass="sidebar-export-dropdown-menu"\n >\n <template #trigger>\n <xt-button class="sidebar-export-trigger-btn" block data-role="fab-trigger">\n <template #icon>\n <img\n src="data:image/svg+xml,%3Csvg%20viewBox%3D'0%200%201088%201024'%20xmlns%3D'http%3A//www.w3.org/2000/svg'%3E%3Cpath%20d%3D'M416%20128v85.312h-128A42.688%2042.688%200%200%200%20245.312%20256v512c0%2023.552%2019.136%2042.688%2042.688%2042.688h512a42.688%2042.688%200%200%200%2042.688-42.688V597.312H928V768a128%20128%200%200%201-128%20128h-512a128%20128%200%200%201-128-128V256a128%20128%200%200%201%20128-128h128z'%20fill%3D'%23ffffff'/%3E%3Cpath%20d%3D'M723.52%20520.832L924.352%20320l-200.832-200.832-60.352%2060.352%2097.856%2097.792h-67.712A298.688%20298.688%200%200%200%20394.688%20576v85.312H480V576a213.312%20213.312%200%200%201%20213.312-213.312h67.712l-97.856%2097.792%2060.352%2060.352z'%20fill%3D'%23ffffff'/%3E%3C/svg%3E"\n alt=""\n width="16"\n height="16"\n draggable="false"\n />\n </template>\n Export SVG\n <template #append-icon>\n <div v-if="state.isLogin" class="export-credits-hint">\n <img src="${p}" alt="" class="credits-token-icon credits-token-icon--sm" draggable="false" />\n <span class="export-credits-hint-value" data-role="export-credits-value">{{ state.exportCreditsCost }}</span>\n </div>\n </template>\n </xt-button>\n </template>\n <template #overlay>\n <div class="export-overlay-menu fab-menu-content" data-role="fab-menu">\n <div\n v-show="state.exportEnabled"\n class="export-overlay-item"\n data-role="export-svg"\n @click="callbacks.onExportSvg()"\n >\n <span class="export-overlay-item-icon export-overlay-item-icon--svg"></span>\n Export SVG\n </div>\n <div\n v-show="state.studioEnabled"\n class="export-overlay-item"\n data-role="open-in-studio"\n @click="callbacks.onOpenInStudio()"\n >\n <span class="export-overlay-item-icon export-overlay-item-icon--studio"></span>\n Open in Studio\n </div>\n </div>\n </template>\n </xt-dropdown-menu>\n </div>\n </aside>\n </div>\n\n <input\n data-role="template-file-input"\n type="file"\n accept="application/json"\n style="display:none"\n @change="callbacks.onFileChange($event)"\n />\n\n <xt-modal\n :model-value="state.templateDialogOpen"\n title="发布模板"\n :show-footer="false"\n :portal-disabled="true"\n @update:model-value="callbacks.onToggleTemplateDialog($event)"\n >\n <div\n v-if="state.templateDialogOpen"\n class="template-export-modal"\n data-role="template-export-modal"\n >\n \n <div class="template-export-groups">\n <div\n v-for="group in state.templateFieldGroups"\n :key="group.id"\n class="template-export-group"\n >\n <div class="template-export-group-title">{{ group.title }}</div>\n <div class="template-export-field-list">\n <div\n v-for="field in group.fields"\n :key="field.path"\n class="template-export-field"\n data-role="template-export-field"\n >\n <xt-checkbox\n :model-value="state.templateSelectedFieldPaths.includes(field.path)"\n :disabled="state.templateExportLoading"\n @update:model-value="callbacks.onToggleTemplateField(field.path, $event)"\n >{{ field.label }}</xt-checkbox>\n <div class="template-export-field-path">{{ field.path }}</div>\n </div>\n </div>\n </div>\n </div>\n\n <div class="template-export-footer">\n <xt-button\n type="secondary"\n :disabled="state.templateExportLoading"\n @click="callbacks.onCloseTemplateDialog()"\n >取消</xt-button>\n <xt-button\n type="primary"\n data-role="template-export-confirm"\n :loading="state.templateExportLoading"\n :disabled="state.templateSelectedFieldPaths.length === 0"\n @click="callbacks.onConfirmTemplateExport()"\n >发布模板</xt-button>\n </div>\n </div>\n </xt-modal>\n </div>\n`;let c=null;const u=new Map;function h(){return globalThis.AtommUI}async function m(t,e){const n=e||"https://minio-download.makeblock.com/resource/atomm-ui-umd/dist-browser/atomm-ui.min.css",a=await function(t){const e=u.get(t);if(e)return e;const n=fetch(t).then(async e=>e.ok?(await e.text()).replace(/(^|})\s*:root(?=\s*{)/g,"$1:host"):(u.delete(t),null)).catch(()=>(u.delete(t),null));return u.set(t,n),n}(n);if(a){const e=document.createElement("style");e.dataset.generatorWorkbenchAtommUi="true",e.textContent=a,t.appendChild(e)}else{const e=document.createElement("link");e.rel="stylesheet",e.href=n,t.appendChild(e)}const o=document.createElement("style");o.textContent='\n :host {\n display: block;\n height: 100%;\n color: #111827;\n font-family: Inter, "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;\n --bg-soft: #f3f4f6;\n --border-default: #e5e7eb;\n --text-primary: #111827;\n --text-secondary: #4b5563;\n --text-muted: #9ca3af;\n }\n\n * {\n box-sizing: border-box;\n }\n\n [data-workbench-vue-root] {\n height: 100%;\n }\n\n .shell {\n height: 100%;\n display: flex;\n flex-direction: column;\n background:\n radial-gradient(rgba(17, 24, 39, 0.06) 1px, transparent 1px),\n linear-gradient(180deg, rgba(255, 255, 255, 0.7), rgba(249, 250, 251, 0.96));\n background-size: 20px 20px, auto;\n }\n\n .topbar,\n .app-topbar {\n height: 64px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 0 24px;\n background: rgba(255, 255, 255, 0.92);\n border-bottom: 1px solid var(--border-default);\n backdrop-filter: blur(12px);\n position: relative;\n z-index: 20;\n }\n\n .logo-area,\n .app-topbar-main {\n display: flex;\n align-items: center;\n gap: 18px;\n min-width: 0;\n flex: 1;\n }\n\n .app-topbar-nav {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n }\n\n .workspace {\n flex: 1;\n min-height: 0;\n display: grid;\n grid-template-columns: minmax(0, 1fr) 320px;\n }\n\n .workspace.panel-left {\n grid-template-columns: 320px minmax(0, 1fr);\n }\n\n .workspace.panel-right .canvas-host {\n grid-column: 1;\n }\n\n .workspace.panel-right .panel-sidebar {\n grid-column: 2;\n }\n\n .workspace.panel-left .panel-sidebar {\n grid-column: 1;\n }\n\n .workspace.panel-left .canvas-host {\n grid-column: 2;\n }\n\n .panel-sidebar {\n min-height: 0;\n display: flex;\n flex-direction: column;\n background: #ffffff;\n }\n\n .panel-host {\n flex: 1;\n min-height: 0;\n overflow: auto;\n }\n\n .canvas-host {\n position: relative;\n min-height: 480px;\n display: grid;\n place-items: center;\n }\n\n .brand-logo {\n height: 32px;\n width: 92px;\n display: block;\n cursor: pointer;\n flex: 0 0 auto;\n }\n\n .app-topbar-auth {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 12px;\n flex: 0 0 auto;\n }\n\n .topbar-credits-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 0;\n color: #2d3541;\n font-size: 14px;\n font-weight: 500;\n line-height: 1;\n white-space: nowrap;\n cursor: default;\n }\n\n .topbar-credits-value {\n font-variant-numeric: tabular-nums;\n }\n\n .credits-token-icon {\n width: 20px;\n height: 20px;\n flex: 0 0 16px;\n user-select: none;\n -webkit-user-drag: none;\n }\n\n .credits-token-icon--sm {\n width: 16px;\n height: 16px;\n flex-basis: 16px;\n }\n\n .auth-avatar-trigger {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 8px 4px 4px;\n border-radius: 999px;\n cursor: pointer;\n transition: background 150ms ease;\n }\n\n .auth-avatar-trigger:hover {\n background: var(--bg-soft);\n }\n\n .auth-avatar {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n overflow: hidden;\n flex: 0 0 auto;\n background: #f3f4f6;\n color: var(--text-secondary);\n font-size: 14px;\n font-weight: 600;\n }\n\n .auth-avatar--lg {\n width: 40px;\n height: 40px;\n font-size: 14px;\n }\n\n .auth-avatar img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n }\n\n .auth-popover-body {\n min-width: 200px;\n padding: 4px 0;\n }\n\n .auth-popover-header {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n }\n\n .auth-popover-user-text {\n min-width: 0;\n flex: 1;\n }\n\n .auth-popover-name {\n display: block;\n font-size: 14px;\n font-weight: 600;\n color: var(--text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .auth-popover-sub {\n display: block;\n margin-top: 2px;\n font-size: 12px;\n color: var(--text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .auth-popover-divider {\n height: 1px;\n background: var(--border-default);\n margin: 4px 0;\n }\n\n .auth-popover-action {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n font-size: 13px;\n color: var(--text-secondary);\n cursor: pointer;\n transition: all 150ms ease;\n }\n\n .auth-popover-action:hover {\n background: var(--bg-soft);\n color: var(--text-primary);\n }\n\n .auth-hover-card {\n position: relative;\n display: inline-flex;\n align-items: center;\n }\n\n .auth-hover-panel {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n z-index: 40;\n min-width: 200px;\n background: #fff;\n border: 1px solid var(--border-default);\n border-radius: 12px;\n box-shadow: 0 8px 28px rgba(17, 24, 39, 0.12);\n opacity: 0;\n transform: translateY(4px);\n pointer-events: none;\n transition: opacity 150ms ease, transform 150ms ease;\n }\n\n .auth-hover-card:hover .auth-hover-panel,\n .auth-hover-card:focus-within .auth-hover-panel {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n }\n\n .panel-actions,\n #sidebar-footer {\n flex-shrink: 0;\n padding: 14px 24px;\n border-top: 1px solid var(--border-default);\n background: #ffffff;\n display: flex;\n align-items: center;\n }\n\n .sidebar-footer-export {\n width: 100%;\n }\n\n .sidebar-footer-export .sidebar-export-trigger-btn,\n .sidebar-footer-export .sidebar-export-trigger-btn-wrap,\n .sidebar-export-trigger-btn-wrap {\n width: 100%;\n }\n\n .sidebar-export-dropdown-menu {\n width: 268px;\n }\n\n .sidebar-export-trigger-btn img {\n margin-right: 4px;\n }\n\n .export-credits-hint {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 2px;\n padding: 0;\n font-size: 12px;\n font-weight: 600;\n line-height: 1;\n color: #ff7c23;\n margin-left: 10px;\n white-space: nowrap;\n }\n\n .export-credits-hint-value {\n color: white;\n font-size: 13px;\n font-weight: 700;\n font-variant-numeric: tabular-nums;\n }\n\n .export-overlay-menu,\n .fab-menu-content {\n padding: 4px;\n }\n\n .export-overlay-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: 6px;\n font-size: 14px;\n color: var(--text-primary);\n cursor: pointer;\n transition: background 120ms ease;\n user-select: none;\n }\n\n .export-overlay-item:hover {\n background: var(--bg-soft);\n }\n\n .export-overlay-item-icon {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n background: #cbd5e1;\n display: inline-block;\n flex: 0 0 auto;\n }\n\n .export-overlay-item-icon--svg {\n background: linear-gradient(180deg, #94a3b8, #64748b);\n }\n\n .export-overlay-item-icon--studio {\n background: linear-gradient(180deg, #cbd5e1, #94a3b8);\n }\n\n .workspace.panel-right .panel-sidebar {\n border-left: 1px solid var(--border-default);\n }\n\n .workspace.panel-left .panel-sidebar {\n border-right: 1px solid var(--border-default);\n }\n\n .template-export-modal {\n display: grid;\n gap: 16px;\n }\n\n \n\n .template-export-groups {\n display: grid;\n gap: 12px;\n max-height: 360px;\n overflow: auto;\n }\n\n .template-export-group {\n display: grid;\n gap: 10px;\n padding: 14px 16px;\n border: 1px solid var(--border-default);\n border-radius: 12px;\n background: #ffffff;\n }\n\n .template-export-group-title {\n font-size: 13px;\n font-weight: 700;\n color: var(--text-primary);\n }\n\n .template-export-field-list {\n display: grid;\n gap: 10px;\n }\n\n .template-export-field {\n display: grid;\n gap: 4px;\n }\n\n .template-export-field-path {\n padding-left: 28px;\n font-size: 12px;\n color: var(--text-muted);\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;\n }\n\n .template-export-footer {\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding: 8px 24px;\n }\n',t.appendChild(o)}async function g(t){const e=h();return e||(n=t.atommUiScriptUrl||"https://minio-download.makeblock.com/resource/atomm-ui-umd/dist-browser/atomm-ui.js",c||(c=new Promise(t=>{const e=h();if(e)return void t(e);const a=document.querySelector(`script[data-generator-workbench-atomm-ui="true"][src="${n}"]`);if(a){const e=()=>t(h());return a.addEventListener("load",e,{once:!0}),void a.addEventListener("error",()=>t(void 0),{once:!0})}const o=document.createElement("script");o.src=n,o.async=!0,o.dataset.generatorWorkbenchAtommUi="true",o.addEventListener("load",()=>{t(h())},{once:!0}),o.addEventListener("error",()=>t(void 0),{once:!0}),(document.head||document.body||document.documentElement).appendChild(o)}),c));var n}async function v(t,e){const n=function(){const t=globalThis.Vue;if(!t||"function"!=typeof t.createApp)throw new Error('[generator-workbench] Vue 3 is required. Load it via CDN: <script src="https://unpkg.com/vue@3/dist/vue.global.js"><\/script>');return t}();!function(){const t=globalThis;t.process?t.process.env?t.process.env.NODE_ENV||(t.process.env.NODE_ENV="production"):t.process.env={NODE_ENV:"production"}:t.process={env:{NODE_ENV:"production"}}}(),await m(t,e.atommUiCssUrl);const a=function(t,e){return t.reactive({shellMode:e.mode||"full",logoText:e.logoText||e.title,logoSrc:e.logoUrl||"https://storage-us.atomm.com/resource/xart/static/agent/imgs/atomm-logo.svg",panelTarget:e.panelTarget||"right",avatarMenuTrigger:e.avatarMenuTrigger||"hover",templateEnabled:!1!==e.templateEnabled,exportEnabled:!1!==e.exportEnabled,studioEnabled:!1!==e.studioEnabled,isLogin:!1,avatarSrc:"",avatarText:"U",authDisplayName:"",authSubline:"",creditsBalance:0,exportCreditsCost:1,loginLoading:!1,templateDialogOpen:!1,templateExportLoading:!1,templateSelectedFieldPaths:[],templateFieldGroups:[]})}(n,e),o={onLogin:()=>{},onLogout:()=>{},onImportTemplate:()=>{},onExportTemplate:()=>{},onCloseTemplateDialog:()=>{},onToggleTemplateDialog:()=>{},onToggleTemplateField:()=>{},onConfirmTemplateExport:()=>{},onExportSvg:()=>{},onOpenInStudio:()=>{},onFileChange:()=>{}},r=document.createElement("div");r.setAttribute("data-workbench-vue-root",""),t.appendChild(r);const i=await g(e),l=n.createApp({setup:()=>({state:a,callbacks:o}),template:d});i?l.use(i):function(t){t.component("xt-button",{inheritAttrs:!0,template:'<button v-bind="$attrs"><slot name="icon" /><slot /><slot name="append-icon" /></button>'}),t.component("xt-avatar",{inheritAttrs:!0,template:'<span v-bind="$attrs"><slot /></span>'}),t.component("xt-dropdown-menu",{inheritAttrs:!0,template:'<div v-bind="$attrs"><slot name="trigger" /><slot name="overlay" /><slot /></div>'}),t.component("xt-hover-card",{inheritAttrs:!0,template:'<div v-bind="$attrs"><slot name="trigger" /><slot name="content" /></div>'}),t.component("xt-modal",{inheritAttrs:!1,props:{modelValue:{type:Boolean,default:!1},title:{type:String,default:""}},emits:["update:modelValue"],template:'\n <div v-if="modelValue" v-bind="$attrs">\n <div>{{ title }}</div>\n <slot />\n </div>\n '}),t.component("xt-checkbox",{inheritAttrs:!1,props:{modelValue:{type:Boolean,default:!1},label:{type:String,default:""},disabled:{type:Boolean,default:!1}},emits:["update:modelValue","change"],template:'\n <label v-bind="$attrs">\n <input\n type="checkbox"\n :checked="modelValue"\n :disabled="disabled"\n @change="$emit(\'update:modelValue\', $event.target.checked)"\n />\n <span><slot>{{ label }}</slot></span>\n </label>\n '})}(l),l.mount(r);const p=function(t){return{root:t,workspace:s(t,'[data-role="workspace"]'),logoArea:t.querySelector('[data-role="logo-area"]'),canvasHost:s(t,'[data-role="canvas-host"]'),panelHost:s(t,'[data-role="panel-host"]'),templateFileInput:s(t,'[data-role="template-file-input"]')}}(t);return{state:a,callbacks:o,app:l,refs:p}}function f(t){t.app.unmount()}const x={title:"",mode:"full",templateEnabled:!0,exportEnabled:!0,studioEnabled:!0,autoMount:!0,panelTarget:"right",avatarMenuTrigger:"hover"};class b extends HTMLElement{constructor(){super(),n(this,"_sdk",null),n(this,"_runtime",null),n(this,"_config",{...x}),n(this,"_mounted",!1),n(this,"_state",{authStatus:{isLogin:!1,userInfo:null},creditsBalance:0,billingUsage:null,busy:{login:!1,importTemplate:!1,exportTemplate:!1,exportSvg:!1,openInStudio:!1},menu:{avatarOpen:!1,fabOpen:!1}}),n(this,"_cleanupAuth"),n(this,"_cleanupCredits"),n(this,"_cleanupBilling"),n(this,"_authController"),n(this,"_templateController"),n(this,"_exportController"),n(this,"_runtimeController"),n(this,"_shellContext"),this.attachShadow({mode:"open"})}get sdk(){return this._sdk}set sdk(t){this._sdk=t}get runtime(){return this._runtime}set runtime(t){this._runtime=t}get config(){return this._config}set config(t){var e;this._config=(e=t,{...x,...e}),this._mounted&&this.render()}connectedCallback(){!1!==this._config.autoMount&&!this._mounted&&this._sdk&&this._runtime&&this.mount()}disconnectedCallback(){this.unmount()}async mount(){var t,e;if(this._mounted)return;if(!this.shadowRoot)throw new Error("[generator-workbench] shadowRoot is required");if(!this._sdk)throw new Error("[generator-workbench] sdk is required before mount()");if(!this._runtime)throw new Error("[generator-workbench] runtime is required before mount()");await this.render(),this.bindControllers(),this.bindShellCallbacks(),this.bindAuthState(),await this.syncBillingState();const n=this.requireRefs();await(null==(t=this._runtimeController)?void 0:t.mountCanvas(n.canvasHost)),await(null==(e=this._runtimeController)?void 0:e.mountPanel(n.panelHost,this._state.activePanelFilter)),this._mounted=!0,l(this,"workbench-ready",{sdk:this._sdk,runtime:this._runtime})}async unmount(){var t,e,n,a;null==(t=this._cleanupAuth)||t.call(this),this._cleanupAuth=void 0,null==(e=this._cleanupCredits)||e.call(this),this._cleanupCredits=void 0,null==(n=this._cleanupBilling)||n.call(this),this._cleanupBilling=void 0,await(null==(a=this._runtimeController)?void 0:a.unmountAll()),this._shellContext&&(f(this._shellContext),this._shellContext=void 0),this._mounted=!1}refreshLayout(){}async importTemplate(t){try{const e=await this.requireTemplateController().importTemplate(t);this._state.activePanelFilter=e.panelFilter;const n=this.requireRefs();this._runtimeController&&await this._runtimeController.remountPanel(n.panelHost,e.panelFilter),l(this,"template-imported",e)}catch(e){this.handleError("template",e)}}async exportTemplate(){return this.exportTemplateWithFields()}async exportTemplateWithFields(t){try{this._state.busy.exportTemplate=!0,this._shellContext&&(this._shellContext.state.templateExportLoading=!0);l(this,"template-exported",await this.requireTemplateController().exportTemplate(t)),t&&this.closeTemplateExportDialog()}catch(e){this.handleError("template",e)}finally{this._state.busy.exportTemplate=!1,this._shellContext&&(this._shellContext.state.templateExportLoading=!1)}}async exportSvg(){try{l(this,"svg-export",await this.requireExportController().exportSvg())}catch(t){this.handleError("export",t)}}async openInStudio(){try{l(this,"studio-open",await this.requireExportController().openInStudio())}catch(t){this.handleError("export",t)}}async setAuthToken(t){var e,n;const a=t.trim();if(!a)throw new Error("[generator-workbench] token is required");if(!this._sdk)throw new Error("[generator-workbench] sdk is required before setAuthToken()");const o=null==(n=(e=this._sdk).getAppKey)?void 0:n.call(e);if(!o)throw new Error("[generator-workbench] sdk.getAppKey() is required for setAuthToken()");if("function"!=typeof this._sdk.auth.syncToken)throw new Error("[generator-workbench] sdk.auth.syncToken() is required for setAuthToken()");try{localStorage.setItem(`__atomm_sdk_token__${o}`,a)}catch{}await this._sdk.auth.syncToken(a)}async render(){this.shadowRoot&&(this._shellContext&&(f(this._shellContext),this.shadowRoot.innerHTML=""),this._shellContext=await v(this.shadowRoot,this._config),this.syncAuthUI(),this.syncBillingUI())}bindControllers(){this._sdk&&this._runtime&&(this._authController=function(t){const{sdk:e}=t;return{getStatus:()=>e.auth.getStatus(),subscribe:t=>(t(e.auth.getStatus()),e.auth.onChange(t)),async login(){await e.auth.login()},async logout(){await e.auth.logout()}}}({sdk:this._sdk}),this._templateController=i({sdk:this._sdk,runtime:this._runtime,config:this._config}),this._exportController=function(t){const{sdk:e,runtime:n,config:a,element:o}=t;async function r(){if(!e.auth.getStatus().isLogin&&(await e.auth.login(),!e.auth.getStatus().isLogin))throw new Error("[generator-workbench] login is required before export")}async function i(){var t;(null==(t=e.billing)?void 0:t.consume)&&await e.billing.consume()}return{async exportSvg(){var t;return await(null==(t=a.beforeExportSvg)?void 0:t.call(a,{sdk:e,runtime:n,element:o})),await r(),await i(),e.export.download({format:"svg"})},async openInStudio(){var t;return await(null==(t=a.beforeOpenInStudio)?void 0:t.call(a,{sdk:e,runtime:n,element:o})),await r(),await i(),e.export.openInStudio({format:"svg"})}}}({sdk:this._sdk,runtime:this._runtime,config:this._config,element:this}),this._runtimeController=function(t){const{runtime:e}=t;let n=null,a=null;async function o(t,n){null==a||a.unmount(),a=await Promise.resolve(e.mount({mode:"embed",target:"panel",container:t,panelFilter:n}))}return{mountCanvas:async function(t){null==n||n.unmount(),n=await Promise.resolve(e.mount({mode:"embed",target:"canvas",container:t}))},mountPanel:o,async remountPanel(t,e){await o(t,e)},async unmountAll(){null==n||n.unmount(),null==a||a.unmount(),n=null,a=null}}}({runtime:this._runtime}))}bindShellCallbacks(){if(!this._shellContext)return;const{callbacks:t}=this._shellContext;t.onLogin=()=>{this.handleLogin()},t.onLogout=()=>{this.handleLogout()},t.onImportTemplate=()=>{this.requireRefs().templateFileInput.click()},t.onExportTemplate=()=>{this.openTemplateExportDialog()},t.onCloseTemplateDialog=()=>{this.closeTemplateExportDialog()},t.onToggleTemplateDialog=t=>{t||this.closeTemplateExportDialog()},t.onToggleTemplateField=(t,e)=>{this.toggleTemplateExportField(t,e)},t.onConfirmTemplateExport=()=>{var t;this.exportTemplateWithFields((null==(t=this._shellContext)?void 0:t.state.templateSelectedFieldPaths)||[])},t.onExportSvg=()=>{this.exportSvg()},t.onOpenInStudio=()=>{this.openInStudio()},t.onFileChange=t=>{var e;const n=t.target,a=null==(e=n.files)?void 0:e[0];a&&(this.importTemplate(a),n.value="")}}openTemplateExportDialog(){try{if(!this._shellContext)return;const t=this.requireTemplateController().prepareTemplateExport();this._shellContext.state.templateFieldGroups=t.fieldGroups.map(t=>({...t,fields:t.fields.map(t=>({...t}))})),this._shellContext.state.templateSelectedFieldPaths=[...t.selectedFieldPaths],this._shellContext.state.templateDialogOpen=!0}catch(t){this.handleError("template",t)}}closeTemplateExportDialog(){this._shellContext&&(this._shellContext.state.templateDialogOpen=!1,this._shellContext.state.templateFieldGroups=[],this._shellContext.state.templateSelectedFieldPaths=[])}toggleTemplateExportField(t,e){if(!this._shellContext)return;const n=new Set(this._shellContext.state.templateSelectedFieldPaths);e?n.add(t):n.delete(t),this._shellContext.state.templateSelectedFieldPaths=Array.from(n)}bindAuthState(){var t;const e=this.requireAuthController();null==(t=this._cleanupAuth)||t.call(this),this._cleanupAuth=e.subscribe(t=>{this._state.authStatus=t,this.syncAuthUI(),this.syncBillingState(t),l(this,"auth-change",t)}),this.bindBillingSubscriptions()}bindBillingSubscriptions(){var t,e,n,a;null==(t=this._cleanupCredits)||t.call(this),this._cleanupCredits=void 0,null==(e=this._cleanupBilling)||e.call(this),this._cleanupBilling=void 0;const o=null==(n=this._sdk)?void 0:n.credits;"function"==typeof(null==o?void 0:o.onChange)&&(this._cleanupCredits=o.onChange(t=>{this._state.creditsBalance=Number(t)||0,this.syncBillingUI()}));const r=null==(a=this._sdk)?void 0:a.billing;"function"==typeof(null==r?void 0:r.onChange)&&(this._cleanupBilling=r.onChange(t=>{this.applyBillingUsage(t)}))}syncAuthUI(){var t,e,n,a;if(!this._shellContext)return;const{state:o}=this._shellContext,{isLogin:r,userInfo:i}=this._state.authStatus,l=(null==(t=null==i?void 0:i.userName)?void 0:t.trim())||(null==(e=null==i?void 0:i.email)?void 0:e.trim())||(null==(n=null==i?void 0:i.phoneNumber)?void 0:n.trim())||"",s=l?l.charAt(0).toUpperCase():"U",p=(null==(a=null==i?void 0:i.email)?void 0:a.trim())||((null==i?void 0:i.phoneNumber)?`${i.phoneZone||""}${i.phoneNumber}`:"Connected to Generator SDK");o.isLogin=r,o.avatarSrc=r&&(null==i?void 0:i.headpic)||"",o.avatarText=s,o.authDisplayName=l,o.authSubline=r?p:""}syncBillingUI(){if(!this._shellContext)return;const{state:t}=this._shellContext,e=this._state.billingUsage;t.creditsBalance=this._state.creditsBalance,t.exportCreditsCost=(null==e?void 0:e.creditsPerUse)??(e&&"unitPrice"in e&&Number(e.unitPrice)||1)}applyBillingUsage(t){this._state.billingUsage=t||null,t&&"number"==typeof t.creditsBalance&&(this._state.creditsBalance=t.creditsBalance),this.syncBillingUI()}resetBillingState(){this._state.creditsBalance=0,this._state.billingUsage=null,this.syncBillingUI()}async syncBillingState(t=this._state.authStatus){var e,n,a,o,r,i,l,s;if(!t.isLogin||!this._sdk)return void this.resetBillingState();const p=null==(n=null==(e=this._sdk.credits)?void 0:e.getCachedBalance)?void 0:n.call(e);"number"==typeof p&&(this._state.creditsBalance=p);const d=null==(o=null==(a=this._sdk.billing)?void 0:a.getCachedUsage)?void 0:o.call(a);d?this.applyBillingUsage(d):this.syncBillingUI();try{const[t,e]=await Promise.all([null==(i=null==(r=this._sdk.credits)?void 0:r.getBalance)?void 0:i.call(r),null==(s=null==(l=this._sdk.billing)?void 0:l.getUsage)?void 0:s.call(l)]);if("number"==typeof(null==t?void 0:t.quota)&&(this._state.creditsBalance=t.quota),e)return void this.applyBillingUsage(e);this.syncBillingUI()}catch(c){this.handleError("auth",c)}}async handleLogin(){try{this._state.busy.login=!0,this._shellContext&&(this._shellContext.state.loginLoading=!0),await this.requireAuthController().login()}catch(t){this.handleError("auth",t)}finally{this._state.busy.login=!1,this._shellContext&&(this._shellContext.state.loginLoading=!1)}}async handleLogout(){try{await this.requireAuthController().logout()}catch(t){this.handleError("auth",t)}}handleError(t,e){var n,a;const o=e instanceof Error?e:new Error(String(e));null==(a=(n=this._config).onError)||a.call(n,o,t),l(this,"workbench-error",{source:t,error:o})}requireRefs(){if(!this._shellContext)throw new Error("[generator-workbench] shell context is not ready");return this._shellContext.refs}requireAuthController(){if(!this._authController)throw new Error("[generator-workbench] auth controller is not ready");return this._authController}requireTemplateController(){if(!this._templateController)throw new Error("[generator-workbench] template controller is not ready");return this._templateController}requireExportController(){if(!this._exportController)throw new Error("[generator-workbench] export controller is not ready");return this._exportController}}const y="generator-workbench";t.GENERATOR_WORKBENCH_TAG_NAME=y,t.GeneratorWorkbenchElement=b,t.defineGeneratorWorkbench=function(t=y){const e=customElements.get(t);return e||(customElements.define(t,b),b)},Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
|