@atomm-developer/generator-workbench 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,55 @@
1
+ # Generator Workbench
2
+
3
+ `generator-workbench` is the unified host shell for generators built on top of `generator-sdk` and the generator runtime contract.
4
+
5
+ V1 provides:
6
+
7
+ - Web Component shell
8
+ - login / avatar / logout entry
9
+ - local template import / export entry
10
+ - floating export actions
11
+ - runtime panel / canvas mounting
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ pnpm add @atomm-developer/generator-sdk
17
+ pnpm add @atomm-developer/generator-workbench
18
+ ```
19
+
20
+ ## CDN
21
+
22
+ ```html
23
+ <script src="https://static-res.atomm.com/scripts/js/generator-sdk/index.umd.js"></script>
24
+ <script src="https://static-res.atomm.com/scripts/js/generator-workbench/index.umd.js"></script>
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ```html
30
+ <generator-workbench id="workbench"></generator-workbench>
31
+ ```
32
+
33
+ ```js
34
+ GeneratorWorkbench.defineGeneratorWorkbench()
35
+
36
+ const workbench = document.getElementById('workbench')
37
+ workbench.sdk = sdk
38
+ workbench.runtime = runtime
39
+ workbench.config = {
40
+ title: 'My Generator',
41
+ templateEnabled: true,
42
+ exportEnabled: true,
43
+ studioEnabled: true,
44
+ }
45
+
46
+ await workbench.mount()
47
+ ```
48
+
49
+ ## Local Preview
50
+
51
+ ```bash
52
+ pnpm --dir generator-workbench dev
53
+ ```
54
+
55
+ Then open `http://127.0.0.1:5173/examples/basic/`.
@@ -0,0 +1,164 @@
1
+ import { AuthStatus } from '@atomm-developer/generator-sdk';
2
+ import { ExportDownloadResult } from '@atomm-developer/generator-sdk';
3
+ import { ExportOpenInStudioResult } from '@atomm-developer/generator-sdk';
4
+ import { GeneratorTemplateDefinition } from '@atomm-developer/generator-sdk';
5
+ import { PanelFilter } from '@atomm-developer/generator-sdk';
6
+ import { PanelSchema } from '@atomm-developer/generator-sdk';
7
+ import { TemplateBuildOptions } from '@atomm-developer/generator-sdk';
8
+ import { UserInfo } from '@atomm-developer/generator-sdk';
9
+
10
+ export declare function defineGeneratorWorkbench(tagName?: string): typeof GeneratorWorkbenchElement;
11
+
12
+ export declare const GENERATOR_WORKBENCH_TAG_NAME = "generator-workbench";
13
+
14
+ export declare interface GeneratorRuntimeLike {
15
+ mount(options: {
16
+ mode: 'embed' | 'full';
17
+ target?: 'full' | 'canvas' | 'panel';
18
+ container: HTMLElement;
19
+ state?: Record<string, unknown>;
20
+ panelFilter?: PanelFilter;
21
+ }): Promise<{
22
+ unmount(): void;
23
+ }> | {
24
+ unmount(): void;
25
+ };
26
+ getState(): Record<string, unknown>;
27
+ setState(nextState: Record<string, unknown>, options?: Record<string, unknown>): Promise<void> | void;
28
+ patchState?(patch: Record<string, unknown>, options?: Record<string, unknown>): Promise<void> | void;
29
+ getPanelSchema(options?: {
30
+ panelFilter?: PanelFilter;
31
+ }): PanelSchema;
32
+ subscribe?(listener: (event: unknown) => void): () => void;
33
+ }
34
+
35
+ export declare interface GeneratorSDKLike {
36
+ auth: {
37
+ getStatus(): AuthStatus;
38
+ login(): Promise<UserInfo>;
39
+ logout(): Promise<void>;
40
+ onChange(callback: (status: AuthStatus) => void): () => void;
41
+ };
42
+ template: {
43
+ build(args: TemplateBuildOptions): GeneratorTemplateDefinition;
44
+ parse(text: string): GeneratorTemplateDefinition;
45
+ download(template: GeneratorTemplateDefinition, options?: {
46
+ fileName?: string;
47
+ }): void;
48
+ applyToRuntime(runtime: GeneratorRuntimeLike, template: GeneratorTemplateDefinition, options?: {
49
+ source?: string;
50
+ onPanelFilter?: (panelFilter: PanelFilter) => void | Promise<void>;
51
+ }): Promise<void>;
52
+ };
53
+ export: {
54
+ download(options?: {
55
+ format?: 'svg' | 'png' | 'jpeg' | 'webp';
56
+ fileName?: string;
57
+ }): Promise<ExportDownloadResult>;
58
+ openInStudio(options?: {
59
+ format?: 'svg' | 'png' | 'jpeg' | 'webp';
60
+ }): Promise<ExportOpenInStudioResult>;
61
+ };
62
+ }
63
+
64
+ export declare interface GeneratorWorkbenchActionHookContext {
65
+ sdk: GeneratorSDKLike;
66
+ runtime: GeneratorRuntimeLike;
67
+ element: GeneratorWorkbenchElement;
68
+ }
69
+
70
+ export declare interface GeneratorWorkbenchConfig {
71
+ title: string;
72
+ logoText?: string;
73
+ logoUrl?: string;
74
+ logoHref?: string;
75
+ templateEnabled?: boolean;
76
+ exportEnabled?: boolean;
77
+ studioEnabled?: boolean;
78
+ autoMount?: boolean;
79
+ panelTarget?: 'left' | 'right';
80
+ avatarMenuTrigger?: 'hover' | 'click';
81
+ runtimePanelFilter?: PanelFilter;
82
+ getTemplateMeta?: () => Record<string, unknown>;
83
+ getTemplateFieldPaths?: (panelSchema: PanelSchema) => string[];
84
+ beforeExportSvg?: (context: GeneratorWorkbenchActionHookContext) => Promise<void> | void;
85
+ beforeOpenInStudio?: (context: GeneratorWorkbenchActionHookContext) => Promise<void> | void;
86
+ onError?: (error: Error, source: WorkbenchErrorSource) => void;
87
+ }
88
+
89
+ export declare class GeneratorWorkbenchElement extends HTMLElement {
90
+ private _sdk;
91
+ private _runtime;
92
+ private _config;
93
+ private _refs;
94
+ private _mounted;
95
+ private _state;
96
+ private _cleanupAuth?;
97
+ private _authController?;
98
+ private _templateController?;
99
+ private _exportController?;
100
+ private _runtimeController?;
101
+ constructor();
102
+ get sdk(): GeneratorSDKLike | null;
103
+ set sdk(value: GeneratorSDKLike | null);
104
+ get runtime(): GeneratorRuntimeLike | null;
105
+ set runtime(value: GeneratorRuntimeLike | null);
106
+ get config(): GeneratorWorkbenchConfig;
107
+ set config(value: GeneratorWorkbenchConfig);
108
+ connectedCallback(): void;
109
+ disconnectedCallback(): void;
110
+ mount(): Promise<void>;
111
+ unmount(): Promise<void>;
112
+ refreshLayout(): void;
113
+ importTemplate(file: File): Promise<void>;
114
+ exportTemplate(): Promise<void>;
115
+ exportSvg(): Promise<void>;
116
+ openInStudio(): Promise<void>;
117
+ private render;
118
+ private bindControllers;
119
+ private bindShellEvents;
120
+ private bindAuthState;
121
+ private syncAuthUI;
122
+ private toggleFabMenu;
123
+ private toggleAvatarMenu;
124
+ private setAvatarMenuOpen;
125
+ private syncMenuUI;
126
+ private handleLogin;
127
+ private handleLogout;
128
+ private handleError;
129
+ private requireRefs;
130
+ private requireAuthController;
131
+ private requireTemplateController;
132
+ private requireExportController;
133
+ }
134
+
135
+ export declare interface WorkbenchErrorDetail {
136
+ source: WorkbenchErrorSource;
137
+ error: Error;
138
+ }
139
+
140
+ export declare type WorkbenchErrorSource = 'auth' | 'template' | 'export' | 'runtime' | 'unknown';
141
+
142
+ export declare interface WorkbenchEventMap {
143
+ 'workbench-ready': WorkbenchReadyDetail;
144
+ 'auth-change': AuthStatus;
145
+ 'template-imported': {
146
+ template: GeneratorTemplateDefinition;
147
+ panelFilter?: PanelFilter;
148
+ };
149
+ 'template-exported': {
150
+ template: GeneratorTemplateDefinition;
151
+ };
152
+ 'svg-export': ExportDownloadResult;
153
+ 'studio-open': ExportOpenInStudioResult;
154
+ 'workbench-error': WorkbenchErrorDetail;
155
+ }
156
+
157
+ export declare type WorkbenchEventName = keyof WorkbenchEventMap;
158
+
159
+ export declare interface WorkbenchReadyDetail {
160
+ sdk: GeneratorSDKLike;
161
+ runtime: GeneratorRuntimeLike;
162
+ }
163
+
164
+ export { }
@@ -0,0 +1,759 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+ function createAuthController(args) {
5
+ const { sdk } = args;
6
+ return {
7
+ getStatus() {
8
+ return sdk.auth.getStatus();
9
+ },
10
+ subscribe(listener) {
11
+ listener(sdk.auth.getStatus());
12
+ return sdk.auth.onChange(listener);
13
+ },
14
+ async login() {
15
+ await sdk.auth.login();
16
+ },
17
+ async logout() {
18
+ await sdk.auth.logout();
19
+ }
20
+ };
21
+ }
22
+ function createExportController(args) {
23
+ const { sdk, runtime, config, element } = args;
24
+ return {
25
+ async exportSvg() {
26
+ var _a;
27
+ await ((_a = config.beforeExportSvg) == null ? void 0 : _a.call(config, {
28
+ sdk,
29
+ runtime,
30
+ element
31
+ }));
32
+ return sdk.export.download({ format: "svg" });
33
+ },
34
+ async openInStudio() {
35
+ var _a;
36
+ await ((_a = config.beforeOpenInStudio) == null ? void 0 : _a.call(config, {
37
+ sdk,
38
+ runtime,
39
+ element
40
+ }));
41
+ return sdk.export.openInStudio({ format: "svg" });
42
+ }
43
+ };
44
+ }
45
+ function createRuntimeController(args) {
46
+ const { runtime } = args;
47
+ let canvasInstance = null;
48
+ let panelInstance = null;
49
+ async function mountCanvas(container) {
50
+ canvasInstance == null ? void 0 : canvasInstance.unmount();
51
+ canvasInstance = await Promise.resolve(
52
+ runtime.mount({
53
+ mode: "embed",
54
+ target: "canvas",
55
+ container
56
+ })
57
+ );
58
+ }
59
+ async function mountPanel(container, panelFilter) {
60
+ panelInstance == null ? void 0 : panelInstance.unmount();
61
+ panelInstance = await Promise.resolve(
62
+ runtime.mount({
63
+ mode: "embed",
64
+ target: "panel",
65
+ container,
66
+ panelFilter
67
+ })
68
+ );
69
+ }
70
+ return {
71
+ mountCanvas,
72
+ mountPanel,
73
+ async remountPanel(container, panelFilter) {
74
+ await mountPanel(container, panelFilter);
75
+ },
76
+ async unmountAll() {
77
+ canvasInstance == null ? void 0 : canvasInstance.unmount();
78
+ panelInstance == null ? void 0 : panelInstance.unmount();
79
+ canvasInstance = null;
80
+ panelInstance = null;
81
+ }
82
+ };
83
+ }
84
+ function assert(condition, message) {
85
+ if (!condition) {
86
+ throw new Error(message);
87
+ }
88
+ }
89
+ function collectPanelFieldPaths(panelSchema) {
90
+ return panelSchema.groups.flatMap(
91
+ (group) => group.fields.map((field) => {
92
+ var _a, _b;
93
+ return (_b = (_a = field.bind) == null ? void 0 : _a.path) == null ? void 0 : _b.trim();
94
+ }).filter((path) => Boolean(path))
95
+ );
96
+ }
97
+ function resolveGeneratorId(panelSchema, state) {
98
+ var _a;
99
+ if ((_a = panelSchema.generatorId) == null ? void 0 : _a.trim()) {
100
+ return panelSchema.generatorId.trim();
101
+ }
102
+ const meta = state.meta;
103
+ if (meta && typeof meta === "object" && "generatorId" in meta && typeof meta.generatorId === "string" && meta.generatorId.trim()) {
104
+ return meta.generatorId.trim();
105
+ }
106
+ throw new Error(
107
+ "[generator-workbench] generatorId is required in panelSchema.generatorId or state.meta.generatorId"
108
+ );
109
+ }
110
+ function createTemplateController(args) {
111
+ const { sdk, runtime, config } = args;
112
+ return {
113
+ async importTemplate(file) {
114
+ const text = await file.text();
115
+ const template = sdk.template.parse(text);
116
+ let capturedPanelFilter;
117
+ await sdk.template.applyToRuntime(runtime, template, {
118
+ onPanelFilter(panelFilter) {
119
+ capturedPanelFilter = panelFilter;
120
+ }
121
+ });
122
+ return {
123
+ template,
124
+ panelFilter: capturedPanelFilter
125
+ };
126
+ },
127
+ async exportTemplate() {
128
+ var _a, _b;
129
+ const state = runtime.getState();
130
+ const panelSchema = runtime.getPanelSchema();
131
+ const selectedFieldPaths = ((_a = config.getTemplateFieldPaths) == null ? void 0 : _a.call(config, panelSchema)) ?? collectPanelFieldPaths(panelSchema);
132
+ assert(
133
+ selectedFieldPaths.length > 0,
134
+ "[generator-workbench] exportTemplate requires at least one panel field path"
135
+ );
136
+ const template = sdk.template.build({
137
+ generatorId: resolveGeneratorId(panelSchema, state),
138
+ state,
139
+ panelSchema,
140
+ selectedFieldPaths,
141
+ templateMeta: (_b = config.getTemplateMeta) == null ? void 0 : _b.call(config)
142
+ });
143
+ sdk.template.download(template);
144
+ return { template };
145
+ }
146
+ };
147
+ }
148
+ function createInitialWorkbenchState() {
149
+ return {
150
+ authStatus: {
151
+ isLogin: false,
152
+ userInfo: null
153
+ },
154
+ busy: {
155
+ login: false,
156
+ importTemplate: false,
157
+ exportTemplate: false,
158
+ exportSvg: false,
159
+ openInStudio: false
160
+ },
161
+ menu: {
162
+ avatarOpen: false,
163
+ fabOpen: false
164
+ }
165
+ };
166
+ }
167
+ function dispatchWorkbenchEvent(target, name, detail) {
168
+ return target.dispatchEvent(
169
+ new CustomEvent(name, {
170
+ detail,
171
+ bubbles: true,
172
+ composed: true
173
+ })
174
+ );
175
+ }
176
+ function queryRequired(root, selector) {
177
+ const node = root.querySelector(selector);
178
+ if (!node) {
179
+ throw new Error(
180
+ `[generator-workbench] required DOM node not found: ${selector}`
181
+ );
182
+ }
183
+ return node;
184
+ }
185
+ function collectWorkbenchRefs(root) {
186
+ return {
187
+ root,
188
+ topbar: queryRequired(root, ".topbar"),
189
+ workspace: queryRequired(root, '[data-role="workspace"]'),
190
+ logoArea: queryRequired(root, '[data-role="logo-area"]'),
191
+ importTemplateBtn: queryRequired(root, '[data-role="import-template"]'),
192
+ exportTemplateBtn: queryRequired(root, '[data-role="export-template"]'),
193
+ loginBtn: queryRequired(root, '[data-role="login"]'),
194
+ avatarButton: queryRequired(root, '[data-role="avatar-button"]'),
195
+ avatarImage: queryRequired(root, '[data-role="avatar-image"]'),
196
+ avatarMenu: queryRequired(root, '[data-role="avatar-menu"]'),
197
+ logoutBtn: queryRequired(root, '[data-role="logout"]'),
198
+ panelSidebar: queryRequired(root, '[data-role="panel-sidebar"]'),
199
+ panelHost: queryRequired(root, '[data-role="panel-host"]'),
200
+ panelActions: queryRequired(root, '[data-role="panel-actions"]'),
201
+ canvasHost: queryRequired(root, '[data-role="canvas-host"]'),
202
+ fabTrigger: queryRequired(root, '[data-role="fab-trigger"]'),
203
+ fabMenu: queryRequired(root, '[data-role="fab-menu"]'),
204
+ exportSvgBtn: queryRequired(root, '[data-role="export-svg"]'),
205
+ openInStudioBtn: queryRequired(root, '[data-role="open-in-studio"]'),
206
+ templateFileInput: queryRequired(root, '[data-role="template-file-input"]')
207
+ };
208
+ }
209
+ function applyWorkbenchConfig(refs, config) {
210
+ refs.logoArea.textContent = config.logoText || config.title;
211
+ refs.workspace.classList.toggle("panel-left", config.panelTarget === "left");
212
+ refs.workspace.classList.toggle("panel-right", config.panelTarget !== "left");
213
+ refs.importTemplateBtn.hidden = config.templateEnabled === false;
214
+ refs.exportTemplateBtn.hidden = config.templateEnabled === false;
215
+ refs.exportSvgBtn.hidden = config.exportEnabled === false;
216
+ refs.openInStudioBtn.hidden = config.studioEnabled === false;
217
+ }
218
+ const WORKBENCH_TEMPLATE = `
219
+ <style>
220
+ :host {
221
+ display: block;
222
+ min-height: 100%;
223
+ color: #111827;
224
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
225
+ }
226
+
227
+ * {
228
+ box-sizing: border-box;
229
+ }
230
+
231
+ .shell {
232
+ min-height: 100%;
233
+ display: flex;
234
+ flex-direction: column;
235
+ background: #f5f7fb;
236
+ }
237
+
238
+ .topbar {
239
+ height: 56px;
240
+ display: flex;
241
+ align-items: center;
242
+ justify-content: space-between;
243
+ gap: 16px;
244
+ padding: 0 16px;
245
+ background: #fff;
246
+ border-bottom: 1px solid #e5e7eb;
247
+ }
248
+
249
+ .logo-area {
250
+ font-weight: 600;
251
+ }
252
+
253
+ .topbar-actions {
254
+ display: flex;
255
+ align-items: center;
256
+ gap: 8px;
257
+ }
258
+
259
+ .workspace {
260
+ flex: 1;
261
+ min-height: 0;
262
+ display: grid;
263
+ grid-template-columns: minmax(0, 1fr) 320px;
264
+ }
265
+
266
+ .workspace.panel-left {
267
+ grid-template-columns: 320px minmax(0, 1fr);
268
+ }
269
+
270
+ .workspace.panel-right .canvas-host {
271
+ grid-column: 1;
272
+ }
273
+
274
+ .workspace.panel-right .panel-sidebar {
275
+ grid-column: 2;
276
+ }
277
+
278
+ .workspace.panel-left .panel-sidebar {
279
+ grid-column: 1;
280
+ }
281
+
282
+ .workspace.panel-left .canvas-host {
283
+ grid-column: 2;
284
+ }
285
+
286
+ .panel-sidebar {
287
+ min-height: 0;
288
+ display: flex;
289
+ flex-direction: column;
290
+ background: #fff;
291
+ }
292
+
293
+ .panel-host {
294
+ flex: 1;
295
+ min-height: 0;
296
+ overflow: auto;
297
+ }
298
+
299
+ .canvas-host {
300
+ position: relative;
301
+ min-height: 480px;
302
+ padding: 24px;
303
+ display: grid;
304
+ place-items: center;
305
+ }
306
+
307
+ button {
308
+ border: 0;
309
+ border-radius: 10px;
310
+ padding: 10px 14px;
311
+ cursor: pointer;
312
+ background: #111827;
313
+ color: #fff;
314
+ font: inherit;
315
+ }
316
+
317
+ button.secondary {
318
+ background: #e5e7eb;
319
+ color: #111827;
320
+ }
321
+
322
+ button:focus-visible {
323
+ outline: 2px solid #4338ca;
324
+ outline-offset: 2px;
325
+ }
326
+
327
+ .auth-area {
328
+ position: relative;
329
+ display: flex;
330
+ align-items: center;
331
+ }
332
+
333
+ .avatar-button {
334
+ display: none;
335
+ align-items: center;
336
+ gap: 8px;
337
+ background: transparent;
338
+ color: #111827;
339
+ padding: 0;
340
+ }
341
+
342
+ .avatar-image {
343
+ width: 32px;
344
+ height: 32px;
345
+ border-radius: 999px;
346
+ object-fit: cover;
347
+ background: #e5e7eb;
348
+ }
349
+
350
+ .avatar-menu {
351
+ position: absolute;
352
+ right: 0;
353
+ top: calc(100% + 8px);
354
+ min-width: 140px;
355
+ padding: 8px;
356
+ display: none;
357
+ background: #fff;
358
+ border: 1px solid #e5e7eb;
359
+ border-radius: 12px;
360
+ box-shadow: 0 12px 32px rgba(15, 23, 42, 0.08);
361
+ }
362
+
363
+ .avatar-menu.is-open,
364
+ .fab-menu.is-open {
365
+ display: block;
366
+ }
367
+
368
+ .avatar-menu button,
369
+ .fab-menu button {
370
+ width: 100%;
371
+ }
372
+
373
+ .panel-actions {
374
+ padding: 12px;
375
+ border-top: 1px solid #e5e7eb;
376
+ }
377
+
378
+ .workspace.panel-right .panel-sidebar {
379
+ border-left: 1px solid #e5e7eb;
380
+ }
381
+
382
+ .workspace.panel-left .panel-sidebar {
383
+ border-right: 1px solid #e5e7eb;
384
+ }
385
+
386
+ .fab {
387
+ display: flex;
388
+ flex-direction: column;
389
+ align-items: stretch;
390
+ gap: 8px;
391
+ width: 100%;
392
+ }
393
+
394
+ .fab-menu {
395
+ width: 100%;
396
+ display: none;
397
+ padding: 8px;
398
+ background: #fff;
399
+ border: 1px solid #e5e7eb;
400
+ border-radius: 12px;
401
+ box-shadow: 0 16px 40px rgba(15, 23, 42, 0.12);
402
+ }
403
+
404
+ .fab-menu button + button {
405
+ margin-top: 8px;
406
+ }
407
+ </style>
408
+ <div class="shell">
409
+ <header class="topbar">
410
+ <div class="logo-area" data-role="logo-area"></div>
411
+ <div class="topbar-actions">
412
+ <button class="secondary" data-role="import-template">导入模板</button>
413
+ <button class="secondary" data-role="export-template">生成模板</button>
414
+ <div class="auth-area" data-role="auth-area">
415
+ <button data-role="login">登录</button>
416
+ <button class="avatar-button" data-role="avatar-button" aria-expanded="false">
417
+ <img class="avatar-image" data-role="avatar-image" alt="User avatar" />
418
+ </button>
419
+ <div class="avatar-menu" data-role="avatar-menu">
420
+ <button class="secondary" data-role="logout">退出登录</button>
421
+ </div>
422
+ </div>
423
+ </div>
424
+ </header>
425
+ <div class="workspace" data-role="workspace">
426
+ <main class="canvas-host" data-role="canvas-host"></main>
427
+ <aside class="panel-sidebar" data-role="panel-sidebar">
428
+ <div class="panel-host" data-role="panel-host"></div>
429
+ <div class="panel-actions" data-role="panel-actions">
430
+ <div class="fab">
431
+ <div class="fab-menu" data-role="fab-menu">
432
+ <button class="secondary" data-role="open-in-studio">导入 Studio</button>
433
+ <button class="secondary" data-role="export-svg">导出 SVG</button>
434
+ </div>
435
+ <button data-role="fab-trigger" aria-expanded="false">导出</button>
436
+ </div>
437
+ </div>
438
+ </aside>
439
+ </div>
440
+ <input data-role="template-file-input" type="file" accept="application/json" hidden />
441
+ </div>
442
+ `;
443
+ function renderWorkbenchShell(root, _config) {
444
+ root.innerHTML = WORKBENCH_TEMPLATE;
445
+ return collectWorkbenchRefs(root);
446
+ }
447
+ const DEFAULT_CONFIG = {
448
+ title: "",
449
+ templateEnabled: true,
450
+ exportEnabled: true,
451
+ studioEnabled: true,
452
+ autoMount: true,
453
+ panelTarget: "right",
454
+ avatarMenuTrigger: "hover"
455
+ };
456
+ function normalizeWorkbenchConfig(config) {
457
+ return {
458
+ ...DEFAULT_CONFIG,
459
+ ...config
460
+ };
461
+ }
462
+ class GeneratorWorkbenchElement extends HTMLElement {
463
+ constructor() {
464
+ super();
465
+ __publicField(this, "_sdk", null);
466
+ __publicField(this, "_runtime", null);
467
+ __publicField(this, "_config", { ...DEFAULT_CONFIG });
468
+ __publicField(this, "_refs", null);
469
+ __publicField(this, "_mounted", false);
470
+ __publicField(this, "_state", createInitialWorkbenchState());
471
+ __publicField(this, "_cleanupAuth");
472
+ __publicField(this, "_authController");
473
+ __publicField(this, "_templateController");
474
+ __publicField(this, "_exportController");
475
+ __publicField(this, "_runtimeController");
476
+ this.attachShadow({ mode: "open" });
477
+ }
478
+ get sdk() {
479
+ return this._sdk;
480
+ }
481
+ set sdk(value) {
482
+ this._sdk = value;
483
+ }
484
+ get runtime() {
485
+ return this._runtime;
486
+ }
487
+ set runtime(value) {
488
+ this._runtime = value;
489
+ }
490
+ get config() {
491
+ return this._config;
492
+ }
493
+ set config(value) {
494
+ this._config = normalizeWorkbenchConfig(value);
495
+ if (this._mounted) {
496
+ this.render();
497
+ }
498
+ }
499
+ connectedCallback() {
500
+ if (this._config.autoMount !== false && !this._mounted && this._sdk && this._runtime) {
501
+ void this.mount();
502
+ }
503
+ }
504
+ disconnectedCallback() {
505
+ void this.unmount();
506
+ }
507
+ async mount() {
508
+ var _a, _b;
509
+ if (this._mounted) {
510
+ return;
511
+ }
512
+ if (!this.shadowRoot) {
513
+ throw new Error("[generator-workbench] shadowRoot is required");
514
+ }
515
+ if (!this._sdk) {
516
+ throw new Error("[generator-workbench] sdk is required before mount()");
517
+ }
518
+ if (!this._runtime) {
519
+ throw new Error("[generator-workbench] runtime is required before mount()");
520
+ }
521
+ this.render();
522
+ this.bindControllers();
523
+ this.bindShellEvents();
524
+ this.bindAuthState();
525
+ await ((_a = this._runtimeController) == null ? void 0 : _a.mountCanvas(this.requireRefs().canvasHost));
526
+ await ((_b = this._runtimeController) == null ? void 0 : _b.mountPanel(
527
+ this.requireRefs().panelHost,
528
+ this._state.activePanelFilter
529
+ ));
530
+ this._mounted = true;
531
+ dispatchWorkbenchEvent(this, "workbench-ready", {
532
+ sdk: this._sdk,
533
+ runtime: this._runtime
534
+ });
535
+ }
536
+ async unmount() {
537
+ var _a, _b;
538
+ (_a = this._cleanupAuth) == null ? void 0 : _a.call(this);
539
+ this._cleanupAuth = void 0;
540
+ await ((_b = this._runtimeController) == null ? void 0 : _b.unmountAll());
541
+ this._mounted = false;
542
+ }
543
+ refreshLayout() {
544
+ }
545
+ async importTemplate(file) {
546
+ try {
547
+ const result = await this.requireTemplateController().importTemplate(file);
548
+ this._state.activePanelFilter = result.panelFilter;
549
+ if (this._runtimeController && this._refs) {
550
+ await this._runtimeController.remountPanel(
551
+ this._refs.panelHost,
552
+ result.panelFilter
553
+ );
554
+ }
555
+ dispatchWorkbenchEvent(this, "template-imported", result);
556
+ } catch (error) {
557
+ this.handleError("template", error);
558
+ }
559
+ }
560
+ async exportTemplate() {
561
+ try {
562
+ const result = await this.requireTemplateController().exportTemplate();
563
+ dispatchWorkbenchEvent(this, "template-exported", result);
564
+ } catch (error) {
565
+ this.handleError("template", error);
566
+ }
567
+ }
568
+ async exportSvg() {
569
+ try {
570
+ const result = await this.requireExportController().exportSvg();
571
+ dispatchWorkbenchEvent(this, "svg-export", result);
572
+ } catch (error) {
573
+ this.handleError("export", error);
574
+ }
575
+ }
576
+ async openInStudio() {
577
+ try {
578
+ const result = await this.requireExportController().openInStudio();
579
+ dispatchWorkbenchEvent(this, "studio-open", result);
580
+ } catch (error) {
581
+ this.handleError("export", error);
582
+ }
583
+ }
584
+ render() {
585
+ if (!this.shadowRoot) return;
586
+ this._refs = renderWorkbenchShell(this.shadowRoot, this._config);
587
+ applyWorkbenchConfig(this._refs, this._config);
588
+ this.syncAuthUI();
589
+ }
590
+ bindControllers() {
591
+ if (!this._sdk || !this._runtime) return;
592
+ this._authController = createAuthController({ sdk: this._sdk });
593
+ this._templateController = createTemplateController({
594
+ sdk: this._sdk,
595
+ runtime: this._runtime,
596
+ config: this._config
597
+ });
598
+ this._exportController = createExportController({
599
+ sdk: this._sdk,
600
+ runtime: this._runtime,
601
+ config: this._config,
602
+ element: this
603
+ });
604
+ this._runtimeController = createRuntimeController({
605
+ runtime: this._runtime
606
+ });
607
+ }
608
+ bindShellEvents() {
609
+ const refs = this.requireRefs();
610
+ refs.loginBtn.addEventListener("click", () => {
611
+ void this.handleLogin();
612
+ });
613
+ refs.logoutBtn.addEventListener("click", () => {
614
+ void this.handleLogout();
615
+ });
616
+ refs.importTemplateBtn.addEventListener("click", () => {
617
+ refs.templateFileInput.click();
618
+ });
619
+ refs.exportTemplateBtn.addEventListener("click", () => {
620
+ void this.exportTemplate();
621
+ });
622
+ refs.templateFileInput.addEventListener("change", () => {
623
+ var _a;
624
+ const file = (_a = refs.templateFileInput.files) == null ? void 0 : _a[0];
625
+ if (!file) return;
626
+ void this.importTemplate(file);
627
+ refs.templateFileInput.value = "";
628
+ });
629
+ refs.fabTrigger.addEventListener("click", () => {
630
+ this.toggleFabMenu();
631
+ });
632
+ refs.exportSvgBtn.addEventListener("click", () => {
633
+ void this.exportSvg();
634
+ });
635
+ refs.openInStudioBtn.addEventListener("click", () => {
636
+ void this.openInStudio();
637
+ });
638
+ refs.avatarButton.addEventListener("click", () => {
639
+ this.toggleAvatarMenu();
640
+ });
641
+ if (this._config.avatarMenuTrigger === "hover") {
642
+ refs.avatarButton.addEventListener("mouseenter", () => {
643
+ this.setAvatarMenuOpen(true);
644
+ });
645
+ refs.avatarMenu.addEventListener("mouseleave", () => {
646
+ this.setAvatarMenuOpen(false);
647
+ });
648
+ }
649
+ }
650
+ bindAuthState() {
651
+ var _a;
652
+ const controller = this.requireAuthController();
653
+ (_a = this._cleanupAuth) == null ? void 0 : _a.call(this);
654
+ this._cleanupAuth = controller.subscribe((status) => {
655
+ this._state.authStatus = status;
656
+ this.syncAuthUI();
657
+ dispatchWorkbenchEvent(this, "auth-change", status);
658
+ });
659
+ }
660
+ syncAuthUI() {
661
+ if (!this._refs) return;
662
+ const { loginBtn, avatarButton, avatarImage } = this._refs;
663
+ const { isLogin, userInfo } = this._state.authStatus;
664
+ loginBtn.style.display = isLogin ? "none" : "";
665
+ avatarButton.style.display = isLogin ? "inline-flex" : "none";
666
+ avatarImage.src = isLogin ? (userInfo == null ? void 0 : userInfo.headpic) || "" : "";
667
+ if (!isLogin) {
668
+ this.setAvatarMenuOpen(false);
669
+ }
670
+ }
671
+ toggleFabMenu() {
672
+ this._state.menu.fabOpen = !this._state.menu.fabOpen;
673
+ this.syncMenuUI();
674
+ }
675
+ toggleAvatarMenu() {
676
+ this.setAvatarMenuOpen(!this._state.menu.avatarOpen);
677
+ }
678
+ setAvatarMenuOpen(open) {
679
+ this._state.menu.avatarOpen = open;
680
+ this.syncMenuUI();
681
+ }
682
+ syncMenuUI() {
683
+ if (!this._refs) return;
684
+ this._refs.avatarMenu.classList.toggle("is-open", this._state.menu.avatarOpen);
685
+ this._refs.fabMenu.classList.toggle("is-open", this._state.menu.fabOpen);
686
+ this._refs.avatarButton.setAttribute(
687
+ "aria-expanded",
688
+ String(this._state.menu.avatarOpen)
689
+ );
690
+ this._refs.fabTrigger.setAttribute(
691
+ "aria-expanded",
692
+ String(this._state.menu.fabOpen)
693
+ );
694
+ }
695
+ async handleLogin() {
696
+ try {
697
+ this._state.busy.login = true;
698
+ await this.requireAuthController().login();
699
+ } catch (error) {
700
+ this.handleError("auth", error);
701
+ } finally {
702
+ this._state.busy.login = false;
703
+ }
704
+ }
705
+ async handleLogout() {
706
+ try {
707
+ await this.requireAuthController().logout();
708
+ } catch (error) {
709
+ this.handleError("auth", error);
710
+ }
711
+ }
712
+ handleError(source, error) {
713
+ var _a, _b;
714
+ const normalized = error instanceof Error ? error : new Error(String(error));
715
+ (_b = (_a = this._config).onError) == null ? void 0 : _b.call(_a, normalized, source);
716
+ dispatchWorkbenchEvent(this, "workbench-error", {
717
+ source,
718
+ error: normalized
719
+ });
720
+ }
721
+ requireRefs() {
722
+ if (!this._refs) {
723
+ throw new Error("[generator-workbench] refs are not ready");
724
+ }
725
+ return this._refs;
726
+ }
727
+ requireAuthController() {
728
+ if (!this._authController) {
729
+ throw new Error("[generator-workbench] auth controller is not ready");
730
+ }
731
+ return this._authController;
732
+ }
733
+ requireTemplateController() {
734
+ if (!this._templateController) {
735
+ throw new Error("[generator-workbench] template controller is not ready");
736
+ }
737
+ return this._templateController;
738
+ }
739
+ requireExportController() {
740
+ if (!this._exportController) {
741
+ throw new Error("[generator-workbench] export controller is not ready");
742
+ }
743
+ return this._exportController;
744
+ }
745
+ }
746
+ const GENERATOR_WORKBENCH_TAG_NAME = "generator-workbench";
747
+ function defineGeneratorWorkbench(tagName = GENERATOR_WORKBENCH_TAG_NAME) {
748
+ const existing = customElements.get(tagName);
749
+ if (existing) {
750
+ return existing;
751
+ }
752
+ customElements.define(tagName, GeneratorWorkbenchElement);
753
+ return GeneratorWorkbenchElement;
754
+ }
755
+ export {
756
+ GENERATOR_WORKBENCH_TAG_NAME,
757
+ GeneratorWorkbenchElement,
758
+ defineGeneratorWorkbench
759
+ };
@@ -0,0 +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){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 r(t){const{sdk:e,runtime:n,config:r}=t;return{async importTemplate(t){const a=await t.text(),r=e.template.parse(a);let o;return await e.template.applyToRuntime(n,r,{onPanelFilter(t){o=t}}),{template:r,panelFilter:o}},async exportTemplate(){var t,o;const i=n.getState(),s=n.getPanelSchema(),l=(null==(t=r.getTemplateFieldPaths)?void 0:t.call(r,s))??function(t){return t.groups.flatMap(t=>t.fields.map(t=>{var e,n;return null==(n=null==(e=t.bind)?void 0:e.path)?void 0:n.trim()}).filter(t=>Boolean(t)))}(s);!function(t,e){if(!t)throw new Error(e)}(l.length>0,"[generator-workbench] exportTemplate requires at least one panel field path");const u=e.template.build({generatorId:a(s,i),state:i,panelSchema:s,selectedFieldPaths:l,templateMeta:null==(o=r.getTemplateMeta)?void 0:o.call(r)});return e.template.download(u),{template:u}}}}function o(t,e,n){return t.dispatchEvent(new CustomEvent(e,{detail:n,bubbles:!0,composed:!0}))}function i(t,e){const n=t.querySelector(e);if(!n)throw new Error(`[generator-workbench] required DOM node not found: ${e}`);return n}function s(t,e){return t.innerHTML='\n <style>\n :host {\n display: block;\n min-height: 100%;\n color: #111827;\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;\n }\n\n * {\n box-sizing: border-box;\n }\n\n .shell {\n min-height: 100%;\n display: flex;\n flex-direction: column;\n background: #f5f7fb;\n }\n\n .topbar {\n height: 56px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n padding: 0 16px;\n background: #fff;\n border-bottom: 1px solid #e5e7eb;\n }\n\n .logo-area {\n font-weight: 600;\n }\n\n .topbar-actions {\n display: flex;\n align-items: center;\n gap: 8px;\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: #fff;\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 padding: 24px;\n display: grid;\n place-items: center;\n }\n\n button {\n border: 0;\n border-radius: 10px;\n padding: 10px 14px;\n cursor: pointer;\n background: #111827;\n color: #fff;\n font: inherit;\n }\n\n button.secondary {\n background: #e5e7eb;\n color: #111827;\n }\n\n button:focus-visible {\n outline: 2px solid #4338ca;\n outline-offset: 2px;\n }\n\n .auth-area {\n position: relative;\n display: flex;\n align-items: center;\n }\n\n .avatar-button {\n display: none;\n align-items: center;\n gap: 8px;\n background: transparent;\n color: #111827;\n padding: 0;\n }\n\n .avatar-image {\n width: 32px;\n height: 32px;\n border-radius: 999px;\n object-fit: cover;\n background: #e5e7eb;\n }\n\n .avatar-menu {\n position: absolute;\n right: 0;\n top: calc(100% + 8px);\n min-width: 140px;\n padding: 8px;\n display: none;\n background: #fff;\n border: 1px solid #e5e7eb;\n border-radius: 12px;\n box-shadow: 0 12px 32px rgba(15, 23, 42, 0.08);\n }\n\n .avatar-menu.is-open,\n .fab-menu.is-open {\n display: block;\n }\n\n .avatar-menu button,\n .fab-menu button {\n width: 100%;\n }\n\n .panel-actions {\n padding: 12px;\n border-top: 1px solid #e5e7eb;\n }\n\n .workspace.panel-right .panel-sidebar {\n border-left: 1px solid #e5e7eb;\n }\n\n .workspace.panel-left .panel-sidebar {\n border-right: 1px solid #e5e7eb;\n }\n\n .fab {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: 8px;\n width: 100%;\n }\n\n .fab-menu {\n width: 100%;\n display: none;\n padding: 8px;\n background: #fff;\n border: 1px solid #e5e7eb;\n border-radius: 12px;\n box-shadow: 0 16px 40px rgba(15, 23, 42, 0.12);\n }\n\n .fab-menu button + button {\n margin-top: 8px;\n }\n </style>\n <div class="shell">\n <header class="topbar">\n <div class="logo-area" data-role="logo-area"></div>\n <div class="topbar-actions">\n <button class="secondary" data-role="import-template">导入模板</button>\n <button class="secondary" data-role="export-template">生成模板</button>\n <div class="auth-area" data-role="auth-area">\n <button data-role="login">登录</button>\n <button class="avatar-button" data-role="avatar-button" aria-expanded="false">\n <img class="avatar-image" data-role="avatar-image" alt="User avatar" />\n </button>\n <div class="avatar-menu" data-role="avatar-menu">\n <button class="secondary" data-role="logout">退出登录</button>\n </div>\n </div>\n </div>\n </header>\n <div class="workspace" data-role="workspace">\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 class="panel-actions" data-role="panel-actions">\n <div class="fab">\n <div class="fab-menu" data-role="fab-menu">\n <button class="secondary" data-role="open-in-studio">导入 Studio</button>\n <button class="secondary" data-role="export-svg">导出 SVG</button>\n </div>\n <button data-role="fab-trigger" aria-expanded="false">导出</button>\n </div>\n </div>\n </aside>\n </div>\n <input data-role="template-file-input" type="file" accept="application/json" hidden />\n </div>\n',function(t){return{root:t,topbar:i(t,".topbar"),workspace:i(t,'[data-role="workspace"]'),logoArea:i(t,'[data-role="logo-area"]'),importTemplateBtn:i(t,'[data-role="import-template"]'),exportTemplateBtn:i(t,'[data-role="export-template"]'),loginBtn:i(t,'[data-role="login"]'),avatarButton:i(t,'[data-role="avatar-button"]'),avatarImage:i(t,'[data-role="avatar-image"]'),avatarMenu:i(t,'[data-role="avatar-menu"]'),logoutBtn:i(t,'[data-role="logout"]'),panelSidebar:i(t,'[data-role="panel-sidebar"]'),panelHost:i(t,'[data-role="panel-host"]'),panelActions:i(t,'[data-role="panel-actions"]'),canvasHost:i(t,'[data-role="canvas-host"]'),fabTrigger:i(t,'[data-role="fab-trigger"]'),fabMenu:i(t,'[data-role="fab-menu"]'),exportSvgBtn:i(t,'[data-role="export-svg"]'),openInStudioBtn:i(t,'[data-role="open-in-studio"]'),templateFileInput:i(t,'[data-role="template-file-input"]')}}(t)}const l={title:"",templateEnabled:!0,exportEnabled:!0,studioEnabled:!0,autoMount:!0,panelTarget:"right",avatarMenuTrigger:"hover"};class u extends HTMLElement{constructor(){super(),n(this,"_sdk",null),n(this,"_runtime",null),n(this,"_config",{...l}),n(this,"_refs",null),n(this,"_mounted",!1),n(this,"_state",{authStatus:{isLogin:!1,userInfo:null},busy:{login:!1,importTemplate:!1,exportTemplate:!1,exportSvg:!1,openInStudio:!1},menu:{avatarOpen:!1,fabOpen:!1}}),n(this,"_cleanupAuth"),n(this,"_authController"),n(this,"_templateController"),n(this,"_exportController"),n(this,"_runtimeController"),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,{...l,...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){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.bindShellEvents(),this.bindAuthState(),await(null==(t=this._runtimeController)?void 0:t.mountCanvas(this.requireRefs().canvasHost)),await(null==(e=this._runtimeController)?void 0:e.mountPanel(this.requireRefs().panelHost,this._state.activePanelFilter)),this._mounted=!0,o(this,"workbench-ready",{sdk:this._sdk,runtime:this._runtime})}}async unmount(){var t,e;null==(t=this._cleanupAuth)||t.call(this),this._cleanupAuth=void 0,await(null==(e=this._runtimeController)?void 0:e.unmountAll()),this._mounted=!1}refreshLayout(){}async importTemplate(t){try{const e=await this.requireTemplateController().importTemplate(t);this._state.activePanelFilter=e.panelFilter,this._runtimeController&&this._refs&&await this._runtimeController.remountPanel(this._refs.panelHost,e.panelFilter),o(this,"template-imported",e)}catch(e){this.handleError("template",e)}}async exportTemplate(){try{o(this,"template-exported",await this.requireTemplateController().exportTemplate())}catch(t){this.handleError("template",t)}}async exportSvg(){try{o(this,"svg-export",await this.requireExportController().exportSvg())}catch(t){this.handleError("export",t)}}async openInStudio(){try{o(this,"studio-open",await this.requireExportController().openInStudio())}catch(t){this.handleError("export",t)}}render(){var t,e;this.shadowRoot&&(this._refs=s(this.shadowRoot,this._config),t=this._refs,e=this._config,t.logoArea.textContent=e.logoText||e.title,t.workspace.classList.toggle("panel-left","left"===e.panelTarget),t.workspace.classList.toggle("panel-right","left"!==e.panelTarget),t.importTemplateBtn.hidden=!1===e.templateEnabled,t.exportTemplateBtn.hidden=!1===e.templateEnabled,t.exportSvgBtn.hidden=!1===e.exportEnabled,t.openInStudioBtn.hidden=!1===e.studioEnabled,this.syncAuthUI())}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=r({sdk:this._sdk,runtime:this._runtime,config:this._config}),this._exportController=function(t){const{sdk:e,runtime:n,config:a,element:r}=t;return{async exportSvg(){var t;return await(null==(t=a.beforeExportSvg)?void 0:t.call(a,{sdk:e,runtime:n,element:r})),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:r})),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 r(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:r,async remountPanel(t,e){await r(t,e)},async unmountAll(){null==n||n.unmount(),null==a||a.unmount(),n=null,a=null}}}({runtime:this._runtime}))}bindShellEvents(){const t=this.requireRefs();t.loginBtn.addEventListener("click",()=>{this.handleLogin()}),t.logoutBtn.addEventListener("click",()=>{this.handleLogout()}),t.importTemplateBtn.addEventListener("click",()=>{t.templateFileInput.click()}),t.exportTemplateBtn.addEventListener("click",()=>{this.exportTemplate()}),t.templateFileInput.addEventListener("change",()=>{var e;const n=null==(e=t.templateFileInput.files)?void 0:e[0];n&&(this.importTemplate(n),t.templateFileInput.value="")}),t.fabTrigger.addEventListener("click",()=>{this.toggleFabMenu()}),t.exportSvgBtn.addEventListener("click",()=>{this.exportSvg()}),t.openInStudioBtn.addEventListener("click",()=>{this.openInStudio()}),t.avatarButton.addEventListener("click",()=>{this.toggleAvatarMenu()}),"hover"===this._config.avatarMenuTrigger&&(t.avatarButton.addEventListener("mouseenter",()=>{this.setAvatarMenuOpen(!0)}),t.avatarMenu.addEventListener("mouseleave",()=>{this.setAvatarMenuOpen(!1)}))}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(),o(this,"auth-change",t)})}syncAuthUI(){if(!this._refs)return;const{loginBtn:t,avatarButton:e,avatarImage:n}=this._refs,{isLogin:a,userInfo:r}=this._state.authStatus;t.style.display=a?"none":"",e.style.display=a?"inline-flex":"none",n.src=a&&(null==r?void 0:r.headpic)||"",a||this.setAvatarMenuOpen(!1)}toggleFabMenu(){this._state.menu.fabOpen=!this._state.menu.fabOpen,this.syncMenuUI()}toggleAvatarMenu(){this.setAvatarMenuOpen(!this._state.menu.avatarOpen)}setAvatarMenuOpen(t){this._state.menu.avatarOpen=t,this.syncMenuUI()}syncMenuUI(){this._refs&&(this._refs.avatarMenu.classList.toggle("is-open",this._state.menu.avatarOpen),this._refs.fabMenu.classList.toggle("is-open",this._state.menu.fabOpen),this._refs.avatarButton.setAttribute("aria-expanded",String(this._state.menu.avatarOpen)),this._refs.fabTrigger.setAttribute("aria-expanded",String(this._state.menu.fabOpen)))}async handleLogin(){try{this._state.busy.login=!0,await this.requireAuthController().login()}catch(t){this.handleError("auth",t)}finally{this._state.busy.login=!1}}async handleLogout(){try{await this.requireAuthController().logout()}catch(t){this.handleError("auth",t)}}handleError(t,e){var n,a;const r=e instanceof Error?e:new Error(String(e));null==(a=(n=this._config).onError)||a.call(n,r,t),o(this,"workbench-error",{source:t,error:r})}requireRefs(){if(!this._refs)throw new Error("[generator-workbench] refs are not ready");return this._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 d="generator-workbench";t.GENERATOR_WORKBENCH_TAG_NAME=d,t.GeneratorWorkbenchElement=u,t.defineGeneratorWorkbench=function(t=d){const e=customElements.get(t);return e||(customElements.define(t,u),u)},Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@atomm-developer/generator-workbench",
3
+ "version": "0.1.0",
4
+ "description": "Unified generator shell based on Web Components",
5
+ "keywords": [
6
+ "atomm",
7
+ "generator",
8
+ "workbench",
9
+ "web-component"
10
+ ],
11
+ "license": "MIT",
12
+ "type": "module",
13
+ "main": "./dist/index.umd.js",
14
+ "module": "./dist/index.es.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.es.js",
20
+ "require": "./dist/index.umd.js"
21
+ }
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "README.md"
26
+ ],
27
+ "publishConfig": {
28
+ "registry": "https://registry.npmjs.org/",
29
+ "access": "public"
30
+ },
31
+ "scripts": {
32
+ "dev": "vite --host 127.0.0.1 --open /examples/basic/",
33
+ "build": "vite build",
34
+ "test": "vitest run",
35
+ "type-check": "tsc --noEmit"
36
+ },
37
+ "peerDependencies": {
38
+ "@atomm-developer/generator-sdk": "^1.0.5"
39
+ },
40
+ "devDependencies": {
41
+ "jsdom": "^26.0.0",
42
+ "terser": "^5.46.0",
43
+ "typescript": "^5.7.3",
44
+ "vite": "^6.2.4",
45
+ "vite-plugin-dts": "^4.5.4",
46
+ "vitest": "^2.1.8"
47
+ }
48
+ }