@atomm-developer/generator-workbench 0.1.1 → 0.1.2

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 CHANGED
@@ -7,7 +7,7 @@ V1 provides:
7
7
  - Web Component shell
8
8
  - login / avatar / logout entry
9
9
  - credits badge and export credit hint
10
- - local template import / export entry
10
+ - local template import entry and template publish modal
11
11
  - billing-backed export actions
12
12
  - runtime panel / canvas mounting
13
13
 
@@ -39,6 +39,7 @@ workbench.sdk = sdk
39
39
  workbench.runtime = runtime
40
40
  workbench.config = {
41
41
  title: 'My Generator',
42
+ mode: 'full',
42
43
  templateEnabled: true,
43
44
  exportEnabled: true,
44
45
  studioEnabled: true,
@@ -47,12 +48,32 @@ workbench.config = {
47
48
  await workbench.mount()
48
49
  ```
49
50
 
51
+ ## Shell Modes
52
+
53
+ - `mode: 'full'` keeps the default shell with the top bar and the sidebar footer export area.
54
+ - `mode: 'template'` hides the top bar, keeps `#sidebar-footer`, and is useful when the host page already owns branding and login UI.
55
+
56
+ In `template` mode, the host shell can pass an external token into the workbench:
57
+
58
+ ```js
59
+ await workbench.setAuthToken(token)
60
+ ```
61
+
62
+ This writes the token to `localStorage` using the SDK app key and then syncs the login state through `sdk.auth.syncToken(token)`.
63
+
50
64
  ## Billing Behavior
51
65
 
52
66
  - When `sdk.credits` and `sdk.billing` are available, the top bar shows the current credits balance after login.
53
67
  - The export trigger shows the current `creditsPerUse` hint from `sdk.billing.getUsage()`.
54
68
  - `exportSvg()` and `openInStudio()` now follow the standard generator flow: ensure login first, then call `sdk.billing.consume()`, then perform the export action.
55
69
 
70
+ ## Template Publish Behavior
71
+
72
+ - Clicking the top bar template publish action no longer downloads immediately.
73
+ - `generator-workbench` reads `runtime.getPanelSchema()`, renders the generator's own field groups in a modal, and preselects exportable `bind.path` fields.
74
+ - The template JSON is downloaded only after the user confirms the selected fields.
75
+ - `config.getTemplateFieldPaths()` still works as the default subset for the publish modal.
76
+
56
77
  ## Local Preview
57
78
 
58
79
  ```bash
package/dist/index.d.ts CHANGED
@@ -38,8 +38,10 @@ export declare interface GeneratorRuntimeLike {
38
38
  }
39
39
 
40
40
  export declare interface GeneratorSDKLike {
41
+ getAppKey?(): string;
41
42
  auth: {
42
43
  getStatus(): AuthStatus;
44
+ syncToken?(token: string): Promise<AuthStatus> | AuthStatus;
43
45
  login(): Promise<UserInfo>;
44
46
  logout(): Promise<void>;
45
47
  onChange(callback: (status: AuthStatus) => void): () => void;
@@ -89,6 +91,7 @@ export declare interface GeneratorWorkbenchActionHookContext {
89
91
 
90
92
  export declare interface GeneratorWorkbenchConfig {
91
93
  title: string;
94
+ mode?: 'full' | 'template';
92
95
  logoText?: string;
93
96
  logoUrl?: string;
94
97
  logoHref?: string;
@@ -136,11 +139,16 @@ export declare class GeneratorWorkbenchElement extends HTMLElement {
136
139
  refreshLayout(): void;
137
140
  importTemplate(file: File): Promise<void>;
138
141
  exportTemplate(): Promise<void>;
142
+ exportTemplateWithFields(selectedFieldPaths?: string[]): Promise<void>;
139
143
  exportSvg(): Promise<void>;
140
144
  openInStudio(): Promise<void>;
145
+ setAuthToken(token: string): Promise<void>;
141
146
  private render;
142
147
  private bindControllers;
143
148
  private bindShellCallbacks;
149
+ private openTemplateExportDialog;
150
+ private closeTemplateExportDialog;
151
+ private toggleTemplateExportField;
144
152
  private bindAuthState;
145
153
  private bindBillingSubscriptions;
146
154
  private syncAuthUI;
package/dist/index.es.js CHANGED
@@ -106,12 +106,35 @@ function assert(condition, message) {
106
106
  throw new Error(message);
107
107
  }
108
108
  }
109
- function collectPanelFieldPaths(panelSchema) {
110
- return panelSchema.groups.flatMap(
111
- (group) => group.fields.map((field) => {
112
- var _a, _b;
113
- return (_b = (_a = field.bind) == null ? void 0 : _a.path) == null ? void 0 : _b.trim();
114
- }).filter((path) => Boolean(path))
109
+ function collectPanelFieldGroups(panelSchema, allowedFieldPaths) {
110
+ const allowedPathSet = (allowedFieldPaths == null ? void 0 : allowedFieldPaths.length) ? new Set(allowedFieldPaths) : null;
111
+ return panelSchema.groups.map((group) => {
112
+ var _a;
113
+ const fields = group.fields.map((field) => {
114
+ var _a2, _b, _c;
115
+ const path = (_b = (_a2 = field.bind) == null ? void 0 : _a2.path) == null ? void 0 : _b.trim();
116
+ if (!path) {
117
+ return null;
118
+ }
119
+ if (allowedPathSet && !allowedPathSet.has(path)) {
120
+ return null;
121
+ }
122
+ return {
123
+ id: field.id,
124
+ label: ((_c = field.label) == null ? void 0 : _c.trim()) || field.id || path,
125
+ path
126
+ };
127
+ }).filter((field) => Boolean(field));
128
+ return {
129
+ id: group.id,
130
+ title: ((_a = group.title) == null ? void 0 : _a.trim()) || group.id,
131
+ fields
132
+ };
133
+ }).filter((group) => group.fields.length > 0);
134
+ }
135
+ function collectPanelFieldPaths(panelSchema, allowedFieldPaths) {
136
+ return collectPanelFieldGroups(panelSchema, allowedFieldPaths).flatMap(
137
+ (group) => group.fields.map((field) => field.path)
115
138
  );
116
139
  }
117
140
  function resolveGeneratorId(panelSchema, state) {
@@ -129,6 +152,27 @@ function resolveGeneratorId(panelSchema, state) {
129
152
  }
130
153
  function createTemplateController(args) {
131
154
  const { sdk, runtime, config } = args;
155
+ function prepareTemplateExport() {
156
+ var _a;
157
+ const state = runtime.getState();
158
+ const panelSchema = runtime.getPanelSchema();
159
+ const configuredFieldPaths = (_a = config.getTemplateFieldPaths) == null ? void 0 : _a.call(config, panelSchema);
160
+ const fieldGroups = collectPanelFieldGroups(panelSchema, configuredFieldPaths);
161
+ const defaultSelectedFieldPaths = fieldGroups.flatMap(
162
+ (group) => group.fields.map((field) => field.path)
163
+ );
164
+ assert(
165
+ defaultSelectedFieldPaths.length > 0,
166
+ "[generator-workbench] exportTemplate requires at least one panel field path"
167
+ );
168
+ return {
169
+ generatorId: resolveGeneratorId(panelSchema, state),
170
+ state,
171
+ panelSchema,
172
+ fieldGroups,
173
+ selectedFieldPaths: defaultSelectedFieldPaths
174
+ };
175
+ }
132
176
  return {
133
177
  async importTemplate(file) {
134
178
  const text = await file.text();
@@ -144,21 +188,21 @@ function createTemplateController(args) {
144
188
  panelFilter: capturedPanelFilter
145
189
  };
146
190
  },
147
- async exportTemplate() {
148
- var _a, _b;
149
- const state = runtime.getState();
150
- const panelSchema = runtime.getPanelSchema();
151
- const selectedFieldPaths = ((_a = config.getTemplateFieldPaths) == null ? void 0 : _a.call(config, panelSchema)) ?? collectPanelFieldPaths(panelSchema);
191
+ prepareTemplateExport,
192
+ async exportTemplate(selectedFieldPaths) {
193
+ var _a;
194
+ const prepared = prepareTemplateExport();
195
+ const finalSelectedFieldPaths = (selectedFieldPaths == null ? void 0 : selectedFieldPaths.length) ? collectPanelFieldPaths(prepared.panelSchema, selectedFieldPaths) : prepared.selectedFieldPaths;
152
196
  assert(
153
- selectedFieldPaths.length > 0,
197
+ finalSelectedFieldPaths.length > 0,
154
198
  "[generator-workbench] exportTemplate requires at least one panel field path"
155
199
  );
156
200
  const template = sdk.template.build({
157
- generatorId: resolveGeneratorId(panelSchema, state),
158
- state,
159
- panelSchema,
160
- selectedFieldPaths,
161
- templateMeta: (_b = config.getTemplateMeta) == null ? void 0 : _b.call(config)
201
+ generatorId: prepared.generatorId,
202
+ state: prepared.state,
203
+ panelSchema: prepared.panelSchema,
204
+ selectedFieldPaths: finalSelectedFieldPaths,
205
+ templateMeta: (_a = config.getTemplateMeta) == null ? void 0 : _a.call(config)
162
206
  });
163
207
  sdk.template.download(template);
164
208
  return { template };
@@ -195,6 +239,26 @@ function dispatchWorkbenchEvent(target, name, detail) {
195
239
  })
196
240
  );
197
241
  }
242
+ function ensureBrowserProcessEnv() {
243
+ const browserGlobal = globalThis;
244
+ if (!browserGlobal.process) {
245
+ browserGlobal.process = {
246
+ env: {
247
+ NODE_ENV: "production"
248
+ }
249
+ };
250
+ return;
251
+ }
252
+ if (!browserGlobal.process.env) {
253
+ browserGlobal.process.env = {
254
+ NODE_ENV: "production"
255
+ };
256
+ return;
257
+ }
258
+ if (!browserGlobal.process.env.NODE_ENV) {
259
+ browserGlobal.process.env.NODE_ENV = "production";
260
+ }
261
+ }
198
262
  function queryRequired(root, selector) {
199
263
  const node = root.querySelector(selector);
200
264
  if (!node) {
@@ -208,7 +272,7 @@ function collectWorkbenchRefs(root) {
208
272
  return {
209
273
  root,
210
274
  workspace: queryRequired(root, '[data-role="workspace"]'),
211
- logoArea: queryRequired(root, '[data-role="logo-area"]'),
275
+ logoArea: root.querySelector('[data-role="logo-area"]'),
212
276
  canvasHost: queryRequired(root, '[data-role="canvas-host"]'),
213
277
  panelHost: queryRequired(root, '[data-role="panel-host"]'),
214
278
  templateFileInput: queryRequired(root, '[data-role="template-file-input"]')
@@ -597,10 +661,63 @@ const WORKBENCH_SHELL_STYLES = `
597
661
  .workspace.panel-left .panel-sidebar {
598
662
  border-right: 1px solid var(--border-default);
599
663
  }
664
+
665
+ .template-export-modal {
666
+ display: grid;
667
+ gap: 16px;
668
+ }
669
+
670
+
671
+
672
+ .template-export-groups {
673
+ display: grid;
674
+ gap: 12px;
675
+ max-height: 360px;
676
+ overflow: auto;
677
+ }
678
+
679
+ .template-export-group {
680
+ display: grid;
681
+ gap: 10px;
682
+ padding: 14px 16px;
683
+ border: 1px solid var(--border-default);
684
+ border-radius: 12px;
685
+ background: #ffffff;
686
+ }
687
+
688
+ .template-export-group-title {
689
+ font-size: 13px;
690
+ font-weight: 700;
691
+ color: var(--text-primary);
692
+ }
693
+
694
+ .template-export-field-list {
695
+ display: grid;
696
+ gap: 10px;
697
+ }
698
+
699
+ .template-export-field {
700
+ display: grid;
701
+ gap: 4px;
702
+ }
703
+
704
+ .template-export-field-path {
705
+ padding-left: 28px;
706
+ font-size: 12px;
707
+ color: var(--text-muted);
708
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
709
+ }
710
+
711
+ .template-export-footer {
712
+ display: flex;
713
+ justify-content: flex-end;
714
+ gap: 12px;
715
+ padding: 8px 24px;
716
+ }
600
717
  `;
601
718
  const WORKBENCH_VUE_TEMPLATE = `
602
719
  <div class="shell">
603
- <header class="topbar app-topbar">
720
+ <header v-if="state.shellMode !== 'template'" class="topbar app-topbar">
604
721
  <div class="logo-area app-topbar-main" data-role="logo-area">
605
722
  <img
606
723
  :src="state.logoSrc"
@@ -793,6 +910,61 @@ const WORKBENCH_VUE_TEMPLATE = `
793
910
  style="display:none"
794
911
  @change="callbacks.onFileChange($event)"
795
912
  />
913
+
914
+ <xt-modal
915
+ :model-value="state.templateDialogOpen"
916
+ title="发布模板"
917
+ :show-footer="false"
918
+ :portal-disabled="true"
919
+ @update:model-value="callbacks.onToggleTemplateDialog($event)"
920
+ >
921
+ <div
922
+ v-if="state.templateDialogOpen"
923
+ class="template-export-modal"
924
+ data-role="template-export-modal"
925
+ >
926
+
927
+ <div class="template-export-groups">
928
+ <div
929
+ v-for="group in state.templateFieldGroups"
930
+ :key="group.id"
931
+ class="template-export-group"
932
+ >
933
+ <div class="template-export-group-title">{{ group.title }}</div>
934
+ <div class="template-export-field-list">
935
+ <div
936
+ v-for="field in group.fields"
937
+ :key="field.path"
938
+ class="template-export-field"
939
+ data-role="template-export-field"
940
+ >
941
+ <xt-checkbox
942
+ :model-value="state.templateSelectedFieldPaths.includes(field.path)"
943
+ :disabled="state.templateExportLoading"
944
+ @update:model-value="callbacks.onToggleTemplateField(field.path, $event)"
945
+ >{{ field.label }}</xt-checkbox>
946
+ <div class="template-export-field-path">{{ field.path }}</div>
947
+ </div>
948
+ </div>
949
+ </div>
950
+ </div>
951
+
952
+ <div class="template-export-footer">
953
+ <xt-button
954
+ type="secondary"
955
+ :disabled="state.templateExportLoading"
956
+ @click="callbacks.onCloseTemplateDialog()"
957
+ >取消</xt-button>
958
+ <xt-button
959
+ type="primary"
960
+ data-role="template-export-confirm"
961
+ :loading="state.templateExportLoading"
962
+ :disabled="state.templateSelectedFieldPaths.length === 0"
963
+ @click="callbacks.onConfirmTemplateExport()"
964
+ >发布模板</xt-button>
965
+ </div>
966
+ </div>
967
+ </xt-modal>
796
968
  </div>
797
969
  `;
798
970
  function requireVue() {
@@ -815,6 +987,7 @@ function injectStyles(root, cdnCssUrl) {
815
987
  }
816
988
  function stateFromConfig(vue, config) {
817
989
  return vue.reactive({
990
+ shellMode: config.mode || "full",
818
991
  logoText: config.logoText || config.title,
819
992
  logoSrc: config.logoUrl || "https://storage-us.atomm.com/resource/xart/static/agent/imgs/atomm-logo.svg",
820
993
  panelTarget: config.panelTarget || "right",
@@ -829,7 +1002,11 @@ function stateFromConfig(vue, config) {
829
1002
  authSubline: "",
830
1003
  creditsBalance: 0,
831
1004
  exportCreditsCost: 1,
832
- loginLoading: false
1005
+ loginLoading: false,
1006
+ templateDialogOpen: false,
1007
+ templateExportLoading: false,
1008
+ templateSelectedFieldPaths: [],
1009
+ templateFieldGroups: []
833
1010
  });
834
1011
  }
835
1012
  function createNoopCallbacks() {
@@ -842,6 +1019,14 @@ function createNoopCallbacks() {
842
1019
  },
843
1020
  onExportTemplate: () => {
844
1021
  },
1022
+ onCloseTemplateDialog: () => {
1023
+ },
1024
+ onToggleTemplateDialog: () => {
1025
+ },
1026
+ onToggleTemplateField: () => {
1027
+ },
1028
+ onConfirmTemplateExport: () => {
1029
+ },
845
1030
  onExportSvg: () => {
846
1031
  },
847
1032
  onOpenInStudio: () => {
@@ -867,9 +1052,44 @@ function registerFallbackComponents(app) {
867
1052
  inheritAttrs: true,
868
1053
  template: '<div v-bind="$attrs"><slot name="trigger" /><slot name="content" /></div>'
869
1054
  });
1055
+ app.component("xt-modal", {
1056
+ inheritAttrs: false,
1057
+ props: {
1058
+ modelValue: { type: Boolean, default: false },
1059
+ title: { type: String, default: "" }
1060
+ },
1061
+ emits: ["update:modelValue"],
1062
+ template: `
1063
+ <div v-if="modelValue" v-bind="$attrs">
1064
+ <div>{{ title }}</div>
1065
+ <slot />
1066
+ </div>
1067
+ `
1068
+ });
1069
+ app.component("xt-checkbox", {
1070
+ inheritAttrs: false,
1071
+ props: {
1072
+ modelValue: { type: Boolean, default: false },
1073
+ label: { type: String, default: "" },
1074
+ disabled: { type: Boolean, default: false }
1075
+ },
1076
+ emits: ["update:modelValue", "change"],
1077
+ template: `
1078
+ <label v-bind="$attrs">
1079
+ <input
1080
+ type="checkbox"
1081
+ :checked="modelValue"
1082
+ :disabled="disabled"
1083
+ @change="$emit('update:modelValue', $event.target.checked)"
1084
+ />
1085
+ <span><slot>{{ label }}</slot></span>
1086
+ </label>
1087
+ `
1088
+ });
870
1089
  }
871
1090
  function renderWorkbenchShell(root, config) {
872
1091
  const vue = requireVue();
1092
+ ensureBrowserProcessEnv();
873
1093
  injectStyles(root, config.atommUiCssUrl);
874
1094
  const state = stateFromConfig(vue, config);
875
1095
  const callbacks = createNoopCallbacks();
@@ -897,6 +1117,7 @@ function unmountWorkbenchShell(context) {
897
1117
  }
898
1118
  const DEFAULT_CONFIG = {
899
1119
  title: "",
1120
+ mode: "full",
900
1121
  templateEnabled: true,
901
1122
  exportEnabled: true,
902
1123
  studioEnabled: true,
@@ -904,6 +1125,7 @@ const DEFAULT_CONFIG = {
904
1125
  panelTarget: "right",
905
1126
  avatarMenuTrigger: "hover"
906
1127
  };
1128
+ const TOKEN_STORAGE_KEY_PREFIX = "__atomm_sdk_token__";
907
1129
  function normalizeWorkbenchConfig(config) {
908
1130
  return {
909
1131
  ...DEFAULT_CONFIG,
@@ -1022,11 +1244,28 @@ class GeneratorWorkbenchElement extends HTMLElement {
1022
1244
  }
1023
1245
  }
1024
1246
  async exportTemplate() {
1247
+ return this.exportTemplateWithFields();
1248
+ }
1249
+ async exportTemplateWithFields(selectedFieldPaths) {
1025
1250
  try {
1026
- const result = await this.requireTemplateController().exportTemplate();
1251
+ this._state.busy.exportTemplate = true;
1252
+ if (this._shellContext) {
1253
+ this._shellContext.state.templateExportLoading = true;
1254
+ }
1255
+ const result = await this.requireTemplateController().exportTemplate(
1256
+ selectedFieldPaths
1257
+ );
1027
1258
  dispatchWorkbenchEvent(this, "template-exported", result);
1259
+ if (selectedFieldPaths) {
1260
+ this.closeTemplateExportDialog();
1261
+ }
1028
1262
  } catch (error) {
1029
1263
  this.handleError("template", error);
1264
+ } finally {
1265
+ this._state.busy.exportTemplate = false;
1266
+ if (this._shellContext) {
1267
+ this._shellContext.state.templateExportLoading = false;
1268
+ }
1030
1269
  }
1031
1270
  }
1032
1271
  async exportSvg() {
@@ -1045,6 +1284,28 @@ class GeneratorWorkbenchElement extends HTMLElement {
1045
1284
  this.handleError("export", error);
1046
1285
  }
1047
1286
  }
1287
+ async setAuthToken(token) {
1288
+ var _a, _b;
1289
+ const normalizedToken = token.trim();
1290
+ if (!normalizedToken) {
1291
+ throw new Error("[generator-workbench] token is required");
1292
+ }
1293
+ if (!this._sdk) {
1294
+ throw new Error("[generator-workbench] sdk is required before setAuthToken()");
1295
+ }
1296
+ const appKey = (_b = (_a = this._sdk).getAppKey) == null ? void 0 : _b.call(_a);
1297
+ if (!appKey) {
1298
+ throw new Error("[generator-workbench] sdk.getAppKey() is required for setAuthToken()");
1299
+ }
1300
+ if (typeof this._sdk.auth.syncToken !== "function") {
1301
+ throw new Error("[generator-workbench] sdk.auth.syncToken() is required for setAuthToken()");
1302
+ }
1303
+ try {
1304
+ localStorage.setItem(`${TOKEN_STORAGE_KEY_PREFIX}${appKey}`, normalizedToken);
1305
+ } catch {
1306
+ }
1307
+ await this._sdk.auth.syncToken(normalizedToken);
1308
+ }
1048
1309
  render() {
1049
1310
  if (!this.shadowRoot) return;
1050
1311
  if (this._shellContext) {
@@ -1086,7 +1347,24 @@ class GeneratorWorkbenchElement extends HTMLElement {
1086
1347
  this.requireRefs().templateFileInput.click();
1087
1348
  };
1088
1349
  callbacks.onExportTemplate = () => {
1089
- void this.exportTemplate();
1350
+ this.openTemplateExportDialog();
1351
+ };
1352
+ callbacks.onCloseTemplateDialog = () => {
1353
+ this.closeTemplateExportDialog();
1354
+ };
1355
+ callbacks.onToggleTemplateDialog = (open) => {
1356
+ if (!open) {
1357
+ this.closeTemplateExportDialog();
1358
+ }
1359
+ };
1360
+ callbacks.onToggleTemplateField = (path, checked) => {
1361
+ this.toggleTemplateExportField(path, checked);
1362
+ };
1363
+ callbacks.onConfirmTemplateExport = () => {
1364
+ var _a;
1365
+ void this.exportTemplateWithFields(
1366
+ ((_a = this._shellContext) == null ? void 0 : _a.state.templateSelectedFieldPaths) || []
1367
+ );
1090
1368
  };
1091
1369
  callbacks.onExportSvg = () => {
1092
1370
  void this.exportSvg();
@@ -1103,6 +1381,40 @@ class GeneratorWorkbenchElement extends HTMLElement {
1103
1381
  input.value = "";
1104
1382
  };
1105
1383
  }
1384
+ openTemplateExportDialog() {
1385
+ try {
1386
+ if (!this._shellContext) return;
1387
+ const prepared = this.requireTemplateController().prepareTemplateExport();
1388
+ this._shellContext.state.templateFieldGroups = prepared.fieldGroups.map(
1389
+ (group) => ({
1390
+ ...group,
1391
+ fields: group.fields.map((field) => ({ ...field }))
1392
+ })
1393
+ );
1394
+ this._shellContext.state.templateSelectedFieldPaths = [
1395
+ ...prepared.selectedFieldPaths
1396
+ ];
1397
+ this._shellContext.state.templateDialogOpen = true;
1398
+ } catch (error) {
1399
+ this.handleError("template", error);
1400
+ }
1401
+ }
1402
+ closeTemplateExportDialog() {
1403
+ if (!this._shellContext) return;
1404
+ this._shellContext.state.templateDialogOpen = false;
1405
+ this._shellContext.state.templateFieldGroups = [];
1406
+ this._shellContext.state.templateSelectedFieldPaths = [];
1407
+ }
1408
+ toggleTemplateExportField(path, checked) {
1409
+ if (!this._shellContext) return;
1410
+ const selected = new Set(this._shellContext.state.templateSelectedFieldPaths);
1411
+ if (checked) {
1412
+ selected.add(path);
1413
+ } else {
1414
+ selected.delete(path);
1415
+ }
1416
+ this._shellContext.state.templateSelectedFieldPaths = Array.from(selected);
1417
+ }
1106
1418
  bindAuthState() {
1107
1419
  var _a;
1108
1420
  const controller = this.requireAuthController();
package/dist/index.umd.js CHANGED
@@ -1 +1 @@
1
- !function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self).GeneratorWorkbench={})}(this,function(t){"use strict";var n=Object.defineProperty,e=(t,e,a)=>((t,e,a)=>e in t?n(t,e,{enumerable:!0,configurable:!0,writable:!0,value:a}):t[e]=a)(t,"symbol"!=typeof e?e+"":e,a);function a(t,n){var e;if(null==(e=t.generatorId)?void 0:e.trim())return t.generatorId.trim();const a=n.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 r(t){const{sdk:n,runtime:e,config:r}=t;return{async importTemplate(t){const a=await t.text(),r=n.template.parse(a);let i;return await n.template.applyToRuntime(e,r,{onPanelFilter(t){i=t}}),{template:r,panelFilter:i}},async exportTemplate(){var t,i;const o=e.getState(),l=e.getPanelSchema(),s=(null==(t=r.getTemplateFieldPaths)?void 0:t.call(r,l))??function(t){return t.groups.flatMap(t=>t.fields.map(t=>{var n,e;return null==(e=null==(n=t.bind)?void 0:n.path)?void 0:e.trim()}).filter(t=>Boolean(t)))}(l);!function(t,n){if(!t)throw new Error(n)}(s.length>0,"[generator-workbench] exportTemplate requires at least one panel field path");const p=n.template.build({generatorId:a(l,o),state:o,panelSchema:l,selectedFieldPaths:s,templateMeta:null==(i=r.getTemplateMeta)?void 0:i.call(r)});return n.template.download(p),{template:p}}}}function i(t,n,e){return t.dispatchEvent(new CustomEvent(n,{detail:e,bubbles:!0,composed:!0}))}function o(t,n){const e=t.querySelector(n);if(!e)throw new Error(`[generator-workbench] required DOM node not found: ${n}`);return e}const l="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",s=`\n <div class="shell">\n <header 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="${l}" 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="${l}" 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 </div>\n`;function p(t,n){const e=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(t,n){const e=document.createElement("link");e.rel="stylesheet",e.href=n||"https://minio-download.makeblock.com/resource/atomm-ui-umd/dist-browser/atomm-ui.min.css",t.appendChild(e);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',t.appendChild(a)}(t,n.atommUiCssUrl);const a=function(t,n){return t.reactive({logoText:n.logoText||n.title,logoSrc:n.logoUrl||"https://storage-us.atomm.com/resource/xart/static/agent/imgs/atomm-logo.svg",panelTarget:n.panelTarget||"right",avatarMenuTrigger:n.avatarMenuTrigger||"hover",templateEnabled:!1!==n.templateEnabled,exportEnabled:!1!==n.exportEnabled,studioEnabled:!1!==n.studioEnabled,isLogin:!1,avatarSrc:"",avatarText:"U",authDisplayName:"",authSubline:"",creditsBalance:0,exportCreditsCost:1,loginLoading:!1})}(e,n),r={onLogin:()=>{},onLogout:()=>{},onImportTemplate:()=>{},onExportTemplate:()=>{},onExportSvg:()=>{},onOpenInStudio:()=>{},onFileChange:()=>{}},i=document.createElement("div");i.setAttribute("data-workbench-vue-root",""),t.appendChild(i);const l=globalThis.AtommUI,p=e.createApp({setup:()=>({state:a,callbacks:r}),template:s});l?p.use(l):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>'})}(p),p.mount(i);const d=function(t){return{root:t,workspace:o(t,'[data-role="workspace"]'),logoArea:o(t,'[data-role="logo-area"]'),canvasHost:o(t,'[data-role="canvas-host"]'),panelHost:o(t,'[data-role="panel-host"]'),templateFileInput:o(t,'[data-role="template-file-input"]')}}(t);return{state:a,callbacks:r,app:p,refs:d}}function d(t){t.app.unmount()}const c={title:"",templateEnabled:!0,exportEnabled:!0,studioEnabled:!0,autoMount:!0,panelTarget:"right",avatarMenuTrigger:"hover"};class u extends HTMLElement{constructor(){super(),e(this,"_sdk",null),e(this,"_runtime",null),e(this,"_config",{...c}),e(this,"_mounted",!1),e(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}}),e(this,"_cleanupAuth"),e(this,"_cleanupCredits"),e(this,"_cleanupBilling"),e(this,"_authController"),e(this,"_templateController"),e(this,"_exportController"),e(this,"_runtimeController"),e(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 n;this._config=(n=t,{...c,...n}),this._mounted&&this.render()}connectedCallback(){!1!==this._config.autoMount&&!this._mounted&&this._sdk&&this._runtime&&this.mount()}disconnectedCallback(){this.unmount()}async mount(){var t,n;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 e=this.requireRefs();await(null==(t=this._runtimeController)?void 0:t.mountCanvas(e.canvasHost)),await(null==(n=this._runtimeController)?void 0:n.mountPanel(e.panelHost,this._state.activePanelFilter)),this._mounted=!0,i(this,"workbench-ready",{sdk:this._sdk,runtime:this._runtime})}async unmount(){var t,n,e,a;null==(t=this._cleanupAuth)||t.call(this),this._cleanupAuth=void 0,null==(n=this._cleanupCredits)||n.call(this),this._cleanupCredits=void 0,null==(e=this._cleanupBilling)||e.call(this),this._cleanupBilling=void 0,await(null==(a=this._runtimeController)?void 0:a.unmountAll()),this._shellContext&&(d(this._shellContext),this._shellContext=void 0),this._mounted=!1}refreshLayout(){}async importTemplate(t){try{const n=await this.requireTemplateController().importTemplate(t);this._state.activePanelFilter=n.panelFilter;const e=this.requireRefs();this._runtimeController&&await this._runtimeController.remountPanel(e.panelHost,n.panelFilter),i(this,"template-imported",n)}catch(n){this.handleError("template",n)}}async exportTemplate(){try{i(this,"template-exported",await this.requireTemplateController().exportTemplate())}catch(t){this.handleError("template",t)}}async exportSvg(){try{i(this,"svg-export",await this.requireExportController().exportSvg())}catch(t){this.handleError("export",t)}}async openInStudio(){try{i(this,"studio-open",await this.requireExportController().openInStudio())}catch(t){this.handleError("export",t)}}render(){this.shadowRoot&&(this._shellContext&&(d(this._shellContext),this.shadowRoot.innerHTML=""),this._shellContext=p(this.shadowRoot,this._config),this.syncAuthUI(),this.syncBillingUI())}bindControllers(){this._sdk&&this._runtime&&(this._authController=function(t){const{sdk:n}=t;return{getStatus:()=>n.auth.getStatus(),subscribe:t=>(t(n.auth.getStatus()),n.auth.onChange(t)),async login(){await n.auth.login()},async logout(){await n.auth.logout()}}}({sdk:this._sdk}),this._templateController=r({sdk:this._sdk,runtime:this._runtime,config:this._config}),this._exportController=function(t){const{sdk:n,runtime:e,config:a,element:r}=t;async function i(){if(!n.auth.getStatus().isLogin&&(await n.auth.login(),!n.auth.getStatus().isLogin))throw new Error("[generator-workbench] login is required before export")}async function o(){var t;(null==(t=n.billing)?void 0:t.consume)&&await n.billing.consume()}return{async exportSvg(){var t;return await(null==(t=a.beforeExportSvg)?void 0:t.call(a,{sdk:n,runtime:e,element:r})),await i(),await o(),n.export.download({format:"svg"})},async openInStudio(){var t;return await(null==(t=a.beforeOpenInStudio)?void 0:t.call(a,{sdk:n,runtime:e,element:r})),await i(),await o(),n.export.openInStudio({format:"svg"})}}}({sdk:this._sdk,runtime:this._runtime,config:this._config,element:this}),this._runtimeController=function(t){const{runtime:n}=t;let e=null,a=null;async function r(t,e){null==a||a.unmount(),a=await Promise.resolve(n.mount({mode:"embed",target:"panel",container:t,panelFilter:e}))}return{mountCanvas:async function(t){null==e||e.unmount(),e=await Promise.resolve(n.mount({mode:"embed",target:"canvas",container:t}))},mountPanel:r,async remountPanel(t,n){await r(t,n)},async unmountAll(){null==e||e.unmount(),null==a||a.unmount(),e=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.exportTemplate()},t.onExportSvg=()=>{this.exportSvg()},t.onOpenInStudio=()=>{this.openInStudio()},t.onFileChange=t=>{var n;const e=t.target,a=null==(n=e.files)?void 0:n[0];a&&(this.importTemplate(a),e.value="")}}bindAuthState(){var t;const n=this.requireAuthController();null==(t=this._cleanupAuth)||t.call(this),this._cleanupAuth=n.subscribe(t=>{this._state.authStatus=t,this.syncAuthUI(),this.syncBillingState(t),i(this,"auth-change",t)}),this.bindBillingSubscriptions()}bindBillingSubscriptions(){var t,n,e,a;null==(t=this._cleanupCredits)||t.call(this),this._cleanupCredits=void 0,null==(n=this._cleanupBilling)||n.call(this),this._cleanupBilling=void 0;const r=null==(e=this._sdk)?void 0:e.credits;"function"==typeof(null==r?void 0:r.onChange)&&(this._cleanupCredits=r.onChange(t=>{this._state.creditsBalance=Number(t)||0,this.syncBillingUI()}));const i=null==(a=this._sdk)?void 0:a.billing;"function"==typeof(null==i?void 0:i.onChange)&&(this._cleanupBilling=i.onChange(t=>{this.applyBillingUsage(t)}))}syncAuthUI(){var t,n,e,a;if(!this._shellContext)return;const{state:r}=this._shellContext,{isLogin:i,userInfo:o}=this._state.authStatus,l=(null==(t=null==o?void 0:o.userName)?void 0:t.trim())||(null==(n=null==o?void 0:o.email)?void 0:n.trim())||(null==(e=null==o?void 0:o.phoneNumber)?void 0:e.trim())||"",s=l?l.charAt(0).toUpperCase():"U",p=(null==(a=null==o?void 0:o.email)?void 0:a.trim())||((null==o?void 0:o.phoneNumber)?`${o.phoneZone||""}${o.phoneNumber}`:"Connected to Generator SDK");r.isLogin=i,r.avatarSrc=i&&(null==o?void 0:o.headpic)||"",r.avatarText=s,r.authDisplayName=l,r.authSubline=i?p:""}syncBillingUI(){if(!this._shellContext)return;const{state:t}=this._shellContext,n=this._state.billingUsage;t.creditsBalance=this._state.creditsBalance,t.exportCreditsCost=(null==n?void 0:n.creditsPerUse)??(n&&"unitPrice"in n&&Number(n.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 n,e,a,r,i,o,l,s;if(!t.isLogin||!this._sdk)return void this.resetBillingState();const p=null==(e=null==(n=this._sdk.credits)?void 0:n.getCachedBalance)?void 0:e.call(n);"number"==typeof p&&(this._state.creditsBalance=p);const d=null==(r=null==(a=this._sdk.billing)?void 0:a.getCachedUsage)?void 0:r.call(a);d?this.applyBillingUsage(d):this.syncBillingUI();try{const[t,n]=await Promise.all([null==(o=null==(i=this._sdk.credits)?void 0:i.getBalance)?void 0:o.call(i),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),n)return void this.applyBillingUsage(n);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,n){var e,a;const r=n instanceof Error?n:new Error(String(n));null==(a=(e=this._config).onError)||a.call(e,r,t),i(this,"workbench-error",{source:t,error:r})}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 h="generator-workbench";t.GENERATOR_WORKBENCH_TAG_NAME=h,t.GeneratorWorkbenchElement=u,t.defineGeneratorWorkbench=function(t=h){const n=customElements.get(t);return n||(customElements.define(t,u),u)},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`;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"})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atomm-developer/generator-workbench",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Unified generator shell based on Web Components",
5
5
  "keywords": [
6
6
  "atomm",