@flowgram.ai/panel-manager-plugin 1.0.3 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -17,16 +17,19 @@ interface PanelConfig {
17
17
  interface PanelFactory<T extends any> {
18
18
  key: string;
19
19
  defaultSize: number;
20
+ fullscreen?: boolean;
20
21
  maxSize?: number;
21
22
  minSize?: number;
22
23
  style?: React.CSSProperties;
23
24
  /** Allows multiple panels with the same key to be rendered simultaneously */
24
25
  allowDuplicates?: boolean;
25
26
  resize?: boolean;
27
+ keepDOM?: boolean;
26
28
  render: (props: T) => React.ReactNode;
27
29
  }
28
30
  interface PanelEntityConfig<T extends any = any> {
29
31
  defaultSize?: number;
32
+ fullscreen?: boolean;
30
33
  style?: React.CSSProperties;
31
34
  props?: T;
32
35
  }
@@ -96,12 +99,15 @@ type PanelEntityConfigConstant = PanelEntityConfig<any> & {
96
99
  };
97
100
  interface PanelEntityState {
98
101
  size: number;
102
+ fullscreen: boolean;
103
+ visible: boolean;
99
104
  }
100
105
  declare class PanelEntity {
101
106
  restore: PanelRestore;
102
107
  /** 面板工厂 */
103
108
  factory: PanelEntityFactoryConstant;
104
109
  config: PanelEntityConfigConstant;
110
+ readonly globalConfig: PanelManagerConfig;
105
111
  private initialized;
106
112
  /** 实例唯一标识 */
107
113
  id: string;
@@ -109,9 +115,18 @@ declare class PanelEntity {
109
115
  node: React.ReactNode;
110
116
  store: StoreApi<PanelEntityState>;
111
117
  get area(): Area;
118
+ get mode(): "docked" | "floating";
112
119
  get key(): string;
113
120
  get renderer(): react.ReactNode;
121
+ get fullscreen(): boolean;
122
+ set fullscreen(next: boolean);
123
+ get resizable(): boolean;
124
+ get keepDOM(): boolean | undefined;
125
+ get visible(): boolean;
126
+ set visible(next: boolean);
127
+ get layer(): Element | null;
114
128
  init(): void;
129
+ mergeState(): void;
115
130
  dispose(): void;
116
131
  }
117
132
 
@@ -145,10 +160,6 @@ declare const createPanelManagerPlugin: _flowgram_ai_core.PluginCreator<Partial<
145
160
 
146
161
  declare const usePanelManager: () => PanelManager;
147
162
 
148
- /**
149
- * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
150
- * SPDX-License-Identifier: MIT
151
- */
152
163
  declare const usePanel: () => PanelEntity;
153
164
 
154
165
  /**
package/dist/index.d.ts CHANGED
@@ -17,16 +17,19 @@ interface PanelConfig {
17
17
  interface PanelFactory<T extends any> {
18
18
  key: string;
19
19
  defaultSize: number;
20
+ fullscreen?: boolean;
20
21
  maxSize?: number;
21
22
  minSize?: number;
22
23
  style?: React.CSSProperties;
23
24
  /** Allows multiple panels with the same key to be rendered simultaneously */
24
25
  allowDuplicates?: boolean;
25
26
  resize?: boolean;
27
+ keepDOM?: boolean;
26
28
  render: (props: T) => React.ReactNode;
27
29
  }
28
30
  interface PanelEntityConfig<T extends any = any> {
29
31
  defaultSize?: number;
32
+ fullscreen?: boolean;
30
33
  style?: React.CSSProperties;
31
34
  props?: T;
32
35
  }
@@ -96,12 +99,15 @@ type PanelEntityConfigConstant = PanelEntityConfig<any> & {
96
99
  };
97
100
  interface PanelEntityState {
98
101
  size: number;
102
+ fullscreen: boolean;
103
+ visible: boolean;
99
104
  }
100
105
  declare class PanelEntity {
101
106
  restore: PanelRestore;
102
107
  /** 面板工厂 */
103
108
  factory: PanelEntityFactoryConstant;
104
109
  config: PanelEntityConfigConstant;
110
+ readonly globalConfig: PanelManagerConfig;
105
111
  private initialized;
106
112
  /** 实例唯一标识 */
107
113
  id: string;
@@ -109,9 +115,18 @@ declare class PanelEntity {
109
115
  node: React.ReactNode;
110
116
  store: StoreApi<PanelEntityState>;
111
117
  get area(): Area;
118
+ get mode(): "docked" | "floating";
112
119
  get key(): string;
113
120
  get renderer(): react.ReactNode;
121
+ get fullscreen(): boolean;
122
+ set fullscreen(next: boolean);
123
+ get resizable(): boolean;
124
+ get keepDOM(): boolean | undefined;
125
+ get visible(): boolean;
126
+ set visible(next: boolean);
127
+ get layer(): Element | null;
114
128
  init(): void;
129
+ mergeState(): void;
115
130
  dispose(): void;
116
131
  }
117
132
 
@@ -145,10 +160,6 @@ declare const createPanelManagerPlugin: _flowgram_ai_core.PluginCreator<Partial<
145
160
 
146
161
  declare const usePanelManager: () => PanelManager;
147
162
 
148
- /**
149
- * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
150
- * SPDX-License-Identifier: MIT
151
- */
152
163
  declare const usePanel: () => PanelEntity;
153
164
 
154
165
  /**
package/dist/index.js CHANGED
@@ -74,59 +74,6 @@ PanelRestoreImpl = __decorateClass([
74
74
  (0, import_inversify.injectable)()
75
75
  ], PanelRestoreImpl);
76
76
 
77
- // src/services/panel-factory.ts
78
- var PanelEntityFactory = Symbol("PanelEntityFactory");
79
- var PanelEntityFactoryConstant = Symbol("PanelEntityFactoryConstant");
80
- var PanelEntityConfigConstant = Symbol("PanelEntityConfigConstant");
81
- var PANEL_SIZE_DEFAULT = 400;
82
- var PanelEntity = class {
83
- constructor() {
84
- this.initialized = false;
85
- /** 实例唯一标识 */
86
- this.id = (0, import_nanoid.nanoid)();
87
- /** 渲染缓存 */
88
- this.node = null;
89
- }
90
- get area() {
91
- return this.config.area;
92
- }
93
- get key() {
94
- return this.factory.key;
95
- }
96
- get renderer() {
97
- if (!this.node) {
98
- this.node = this.factory.render(this.config.props);
99
- }
100
- return this.node;
101
- }
102
- init() {
103
- if (this.initialized) {
104
- return;
105
- }
106
- this.initialized = true;
107
- const cache = this.restore.restore(this.key);
108
- this.store = (0, import_vanilla.createStore)(() => ({
109
- size: this.config.defaultSize || this.factory.defaultSize || PANEL_SIZE_DEFAULT,
110
- ...cache ?? {}
111
- }));
112
- }
113
- dispose() {
114
- this.restore.store(this.key, this.store.getState());
115
- }
116
- };
117
- __decorateClass([
118
- (0, import_inversify2.inject)(PanelRestore)
119
- ], PanelEntity.prototype, "restore", 2);
120
- __decorateClass([
121
- (0, import_inversify2.inject)(PanelEntityFactoryConstant)
122
- ], PanelEntity.prototype, "factory", 2);
123
- __decorateClass([
124
- (0, import_inversify2.inject)(PanelEntityConfigConstant)
125
- ], PanelEntity.prototype, "config", 2);
126
- PanelEntity = __decorateClass([
127
- (0, import_inversify2.injectable)()
128
- ], PanelEntity);
129
-
130
77
  // src/components/resize-bar/index.tsx
131
78
  var import_react = require("react");
132
79
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -226,14 +173,125 @@ var defineConfig = (config) => {
226
173
  };
227
174
  };
228
175
 
176
+ // src/utils.ts
177
+ var merge = (...objs) => {
178
+ const result = {};
179
+ for (const obj of objs) {
180
+ if (!obj || typeof obj !== "object") continue;
181
+ for (const key of Object.keys(obj)) {
182
+ const value = obj[key];
183
+ if (result[key] === void 0) {
184
+ result[key] = value;
185
+ }
186
+ }
187
+ }
188
+ return result;
189
+ };
190
+
191
+ // src/services/panel-factory.ts
192
+ var PanelEntityFactory = Symbol("PanelEntityFactory");
193
+ var PanelEntityFactoryConstant = Symbol("PanelEntityFactoryConstant");
194
+ var PanelEntityConfigConstant = Symbol("PanelEntityConfigConstant");
195
+ var PANEL_SIZE_DEFAULT = 400;
196
+ var PanelEntity = class {
197
+ constructor() {
198
+ this.initialized = false;
199
+ /** 实例唯一标识 */
200
+ this.id = (0, import_nanoid.nanoid)();
201
+ /** 渲染缓存 */
202
+ this.node = null;
203
+ }
204
+ get area() {
205
+ return this.config.area;
206
+ }
207
+ get mode() {
208
+ return this.config.area.startsWith("docked") ? "docked" : "floating";
209
+ }
210
+ get key() {
211
+ return this.factory.key;
212
+ }
213
+ get renderer() {
214
+ if (!this.node) {
215
+ this.node = this.factory.render(this.config.props);
216
+ }
217
+ return this.node;
218
+ }
219
+ get fullscreen() {
220
+ return this.store.getState().fullscreen;
221
+ }
222
+ set fullscreen(next) {
223
+ this.store.setState({ fullscreen: next });
224
+ }
225
+ get resizable() {
226
+ if (this.fullscreen) {
227
+ return false;
228
+ }
229
+ return this.factory.resize !== void 0 ? this.factory.resize : this.globalConfig.autoResize;
230
+ }
231
+ get keepDOM() {
232
+ return this.factory.keepDOM;
233
+ }
234
+ get visible() {
235
+ return this.store.getState().visible;
236
+ }
237
+ set visible(next) {
238
+ this.store.setState({ visible: next });
239
+ }
240
+ get layer() {
241
+ return document.querySelector(
242
+ this.mode ? ".gedit-flow-panel-layer-wrap-docked" : ".gedit-flow-panel-layer-wrap-floating"
243
+ );
244
+ }
245
+ init() {
246
+ if (this.initialized) {
247
+ return;
248
+ }
249
+ this.initialized = true;
250
+ const cache = this.restore.restore(this.key);
251
+ const initialState = merge(
252
+ {
253
+ size: this.config.defaultSize,
254
+ fullscreen: this.config.fullscreen
255
+ },
256
+ cache ? cache : {},
257
+ {
258
+ size: this.factory.defaultSize || PANEL_SIZE_DEFAULT,
259
+ fullscreen: this.factory.fullscreen || false,
260
+ ...this.factory.keepDOM ? { visible: true } : {}
261
+ }
262
+ );
263
+ this.store = (0, import_vanilla.createStore)(() => initialState);
264
+ }
265
+ mergeState() {
266
+ }
267
+ dispose() {
268
+ this.restore.store(this.key, this.store.getState());
269
+ }
270
+ };
271
+ __decorateClass([
272
+ (0, import_inversify2.inject)(PanelRestore)
273
+ ], PanelEntity.prototype, "restore", 2);
274
+ __decorateClass([
275
+ (0, import_inversify2.inject)(PanelEntityFactoryConstant)
276
+ ], PanelEntity.prototype, "factory", 2);
277
+ __decorateClass([
278
+ (0, import_inversify2.inject)(PanelEntityConfigConstant)
279
+ ], PanelEntity.prototype, "config", 2);
280
+ __decorateClass([
281
+ (0, import_inversify2.inject)(PanelManagerConfig)
282
+ ], PanelEntity.prototype, "globalConfig", 2);
283
+ PanelEntity = __decorateClass([
284
+ (0, import_inversify2.injectable)()
285
+ ], PanelEntity);
286
+
229
287
  // src/services/panel-manager.ts
230
288
  var import_inversify3 = require("inversify");
231
- var import_utils = require("@flowgram.ai/utils");
289
+ var import_utils2 = require("@flowgram.ai/utils");
232
290
  var PanelManager = class {
233
291
  constructor() {
234
292
  this.panelRegistry = /* @__PURE__ */ new Map();
235
293
  this.panels = /* @__PURE__ */ new Map();
236
- this.onPanelsChangeEvent = new import_utils.Emitter();
294
+ this.onPanelsChangeEvent = new import_utils2.Emitter();
237
295
  this.onPanelsChange = this.onPanelsChangeEvent.event;
238
296
  }
239
297
  init() {
@@ -251,7 +309,11 @@ var PanelManager = class {
251
309
  }
252
310
  const sameKeyPanels = this.getPanels(area).filter((p) => p.key === key);
253
311
  if (!factory.allowDuplicates && sameKeyPanels.length) {
254
- sameKeyPanels.forEach((p) => this.remove(p.id));
312
+ !factory.keepDOM && sameKeyPanels.forEach((p) => this.remove(p.id));
313
+ }
314
+ if (factory.keepDOM && sameKeyPanels.length) {
315
+ sameKeyPanels[0].visible = true;
316
+ return;
255
317
  }
256
318
  const panel = this.createPanel({
257
319
  factory,
@@ -263,19 +325,23 @@ var PanelManager = class {
263
325
  this.panels.set(panel.id, panel);
264
326
  this.trim(area);
265
327
  this.onPanelsChangeEvent.fire();
266
- console.log("jxj", this.panels);
267
328
  }
268
329
  /** close panel */
269
330
  close(key) {
270
331
  const panels = this.getPanels();
271
332
  const closedPanels = key ? panels.filter((p) => p.key === key) : panels;
272
- closedPanels.forEach((p) => this.remove(p.id));
333
+ closedPanels.forEach((panel) => {
334
+ if (panel.keepDOM) {
335
+ panel.visible = false;
336
+ return;
337
+ }
338
+ this.remove(panel.id);
339
+ });
273
340
  this.onPanelsChangeEvent.fire();
274
341
  }
275
342
  trim(area) {
276
- const panels = this.getPanels(area);
343
+ const panels = this.getPanels(area).filter((p) => !p.keepDOM);
277
344
  const areaConfig = this.getAreaConfig(area);
278
- console.log("jxj", areaConfig.max, panels.length);
279
345
  while (panels.length > areaConfig.max) {
280
346
  const removed = panels.shift();
281
347
  if (removed) {
@@ -328,9 +394,9 @@ PanelManager = __decorateClass([
328
394
 
329
395
  // src/services/panel-layer.ts
330
396
  var import_react_dom = __toESM(require("react-dom"));
331
- var import_react5 = require("react");
397
+ var import_react6 = require("react");
332
398
  var import_inversify4 = require("inversify");
333
- var import_utils2 = require("@flowgram.ai/utils");
399
+ var import_utils3 = require("@flowgram.ai/utils");
334
400
  var import_core2 = require("@flowgram.ai/core");
335
401
 
336
402
  // src/components/panel-layer/panel-layer.tsx
@@ -354,28 +420,40 @@ var useGlobalCSS = ({ cssText, id, cleanup }) => {
354
420
  };
355
421
 
356
422
  // src/components/panel-layer/panel.tsx
357
- var import_react4 = require("react");
358
- var import_traditional = require("zustand/traditional");
359
- var import_shallow = require("zustand/shallow");
360
- var import_clsx = __toESM(require("clsx"));
423
+ var import_react5 = require("react");
424
+ var import_clsx = require("clsx");
361
425
 
362
426
  // src/hooks/use-panel-manager.ts
363
427
  var import_core = require("@flowgram.ai/core");
364
428
  var usePanelManager = () => (0, import_core.useService)(PanelManager);
365
429
 
430
+ // src/hooks/use-panel.ts
431
+ var import_react4 = require("react");
432
+ var import_traditional = require("zustand/traditional");
433
+ var import_shallow = require("zustand/shallow");
434
+
366
435
  // src/contexts.ts
367
436
  var import_react3 = require("react");
368
437
  var PanelContext = (0, import_react3.createContext)({});
369
438
 
439
+ // src/hooks/use-panel.ts
440
+ var usePanel = () => (0, import_react4.useContext)(PanelContext);
441
+ var usePanelStore = (selector) => {
442
+ const panel = usePanel();
443
+ return (0, import_traditional.useStoreWithEqualityFn)(panel.store, selector, import_shallow.shallow);
444
+ };
445
+
370
446
  // src/components/panel-layer/panel.tsx
371
447
  var import_jsx_runtime2 = require("react/jsx-runtime");
372
448
  var PanelItem = ({ panel }) => {
373
449
  const panelManager = usePanelManager();
374
- const ref = (0, import_react4.useRef)(null);
375
- const resize = panel.factory.resize !== void 0 ? panel.factory.resize : panelManager.config.autoResize;
450
+ const ref = (0, import_react5.useRef)(null);
376
451
  const isHorizontal = ["right", "docked-right"].includes(panel.area);
377
- const size = (0, import_traditional.useStoreWithEqualityFn)(panel.store, (s) => s.size, import_shallow.shallow);
378
- const sizeStyle = isHorizontal ? { width: size } : { height: size };
452
+ const { size, fullscreen, visible } = usePanelStore((s) => ({ size: s.size, fullscreen: s.fullscreen, visible: s.visible }));
453
+ const [layerSize, setLayerSize] = (0, import_react5.useState)(size);
454
+ const [displayStyle, setDisplayStyle] = (0, import_react5.useState)({});
455
+ const currentSize = fullscreen ? layerSize : size;
456
+ const sizeStyle = isHorizontal ? { width: currentSize } : { height: currentSize };
379
457
  const handleResize = (next) => {
380
458
  let nextSize = next;
381
459
  if (typeof panel.factory.maxSize === "number" && nextSize > panel.factory.maxSize) {
@@ -385,24 +463,44 @@ var PanelItem = ({ panel }) => {
385
463
  }
386
464
  panel.store.setState({ size: nextSize });
387
465
  };
388
- (0, import_react4.useEffect)(() => {
389
- if (ref.current) {
466
+ (0, import_react5.useEffect)(() => {
467
+ if (ref.current && !fullscreen) {
390
468
  const { width, height } = ref.current.getBoundingClientRect();
391
469
  const realSize = isHorizontal ? width : height;
392
470
  panel.store.setState({ size: realSize });
393
471
  }
394
- }, []);
472
+ }, [fullscreen]);
473
+ (0, import_react5.useEffect)(() => {
474
+ if (!fullscreen) {
475
+ return;
476
+ }
477
+ const layer = panel.layer;
478
+ if (!layer) {
479
+ return;
480
+ }
481
+ const observer = new ResizeObserver(([entry]) => {
482
+ const { width, height } = entry.contentRect;
483
+ setLayerSize(isHorizontal ? width : height);
484
+ });
485
+ observer.observe(layer);
486
+ return () => observer.disconnect();
487
+ }, [fullscreen]);
488
+ (0, import_react5.useEffect)(() => {
489
+ if (panel.keepDOM) {
490
+ setDisplayStyle({ display: visible ? "block" : "none" });
491
+ }
492
+ }, [visible]);
395
493
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
396
494
  "div",
397
495
  {
398
- className: (0, import_clsx.default)(
496
+ className: (0, import_clsx.clsx)(
399
497
  "gedit-flow-panel-wrap",
400
498
  isHorizontal ? "panel-horizontal" : "panel-vertical"
401
499
  ),
402
500
  ref,
403
- style: { ...panel.factory.style, ...panel.config.style, ...sizeStyle },
501
+ style: { ...displayStyle, ...panel.factory.style, ...panel.config.style, ...sizeStyle },
404
502
  children: [
405
- resize && panelManager.config.resizeBarRender({
503
+ panel.resizable && panelManager.config.resizeBarRender({
406
504
  size,
407
505
  direction: isHorizontal ? "vertical" : "horizontal",
408
506
  onResize: handleResize
@@ -415,10 +513,10 @@ var PanelItem = ({ panel }) => {
415
513
  };
416
514
  var PanelArea = ({ area }) => {
417
515
  const panelManager = usePanelManager();
418
- const [panels, setPanels] = (0, import_react4.useState)(panelManager.getPanels(area));
419
- (0, import_react4.useEffect)(() => {
516
+ const [panels, setPanels] = (0, import_react5.useState)(panelManager.getPanels(area));
517
+ (0, import_react5.useEffect)(() => {
420
518
  const dispose = panelManager.onPanelsChange(() => {
421
- (0, import_react4.startTransition)(() => {
519
+ (0, import_react5.startTransition)(() => {
422
520
  setPanels(panelManager.getPanels(area));
423
521
  });
424
522
  });
@@ -445,8 +543,6 @@ var globalCSS = `
445
543
 
446
544
  }
447
545
  .gedit-flow-panel-layer-wrap-floating {
448
- column-gap: 4px;
449
- padding: 4px;
450
546
  pointer-events: none;
451
547
  }
452
548
 
@@ -458,16 +554,12 @@ var globalCSS = `
458
554
  display: flex;
459
555
  flex-direction: column;
460
556
  }
461
- .gedit-flow-panel-layer-wrap-floating .gedit-flow-panel-left-area {
462
- row-gap: 4px;
463
- }
464
557
  .gedit-flow-panel-right-area {
465
558
  height: 100%;
466
559
  flex-grow: 1;
467
560
  flex-shrink: 0;
468
561
  min-width: 0;
469
562
  display: flex;
470
- column-gap: 4px;
471
563
  max-width: 100%;
472
564
  }
473
565
 
@@ -539,13 +631,13 @@ var DockedPanelLayer = (props) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(P
539
631
  var PanelLayer2 = class extends import_core2.Layer {
540
632
  constructor() {
541
633
  super(...arguments);
542
- this.panelRoot = import_utils2.domUtils.createDivWithClass("gedit-flow-panel-layer");
634
+ this.panelRoot = import_utils3.domUtils.createDivWithClass("gedit-flow-panel-layer");
543
635
  this.layout = null;
544
636
  }
545
637
  onReady() {
546
638
  this.panelConfig.getPopupContainer(this.pluginContext).appendChild(this.panelRoot);
547
639
  this.toDispose.push(
548
- import_utils2.Disposable.create(() => {
640
+ import_utils3.Disposable.create(() => {
549
641
  this.panelRoot.remove();
550
642
  })
551
643
  );
@@ -558,12 +650,12 @@ var PanelLayer2 = class extends import_core2.Layer {
558
650
  top: 0,
559
651
  zIndex: 100
560
652
  };
561
- import_utils2.domUtils.setStyle(this.panelRoot, commonStyle);
653
+ import_utils3.domUtils.setStyle(this.panelRoot, commonStyle);
562
654
  }
563
655
  render() {
564
656
  if (!this.layout) {
565
657
  const { children, ...layoutProps } = this.panelConfig.layerProps;
566
- this.layout = (0, import_react5.createElement)(PanelLayer, layoutProps, children);
658
+ this.layout = (0, import_react6.createElement)(PanelLayer, layoutProps, children);
567
659
  }
568
660
  return import_react_dom.default.createPortal(this.layout, this.panelRoot);
569
661
  }
@@ -604,10 +696,6 @@ var createPanelManagerPlugin = (0, import_core3.definePluginCreator)({
604
696
  panelManager.init();
605
697
  }
606
698
  });
607
-
608
- // src/hooks/use-panel.ts
609
- var import_react6 = require("react");
610
- var usePanel = () => (0, import_react6.useContext)(PanelContext);
611
699
  // Annotate the CommonJS export names for ESM import in node:
612
700
  0 && (module.exports = {
613
701
  DockedPanelLayer,