@api-client/ui 0.0.9 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/.eslintrc +8 -1
  2. package/demo/index.html +3 -0
  3. package/demo/layout/index.html +91 -0
  4. package/demo/layout/index.ts +182 -0
  5. package/dist/elements/layout/SplitItem.d.ts +1 -9
  6. package/dist/elements/layout/SplitItem.d.ts.map +1 -1
  7. package/dist/elements/layout/SplitItem.js +27 -20
  8. package/dist/elements/layout/SplitItem.js.map +1 -1
  9. package/dist/elements/layout/SplitLayout.d.ts +16 -14
  10. package/dist/elements/layout/SplitLayout.d.ts.map +1 -1
  11. package/dist/elements/layout/SplitLayout.js +47 -42
  12. package/dist/elements/layout/SplitLayout.js.map +1 -1
  13. package/dist/elements/layout/SplitPanel.d.ts +7 -2
  14. package/dist/elements/layout/SplitPanel.d.ts.map +1 -1
  15. package/dist/elements/layout/SplitPanel.js +130 -52
  16. package/dist/elements/layout/SplitPanel.js.map +1 -1
  17. package/dist/elements/layout/SplitView.d.ts.map +1 -1
  18. package/dist/elements/layout/SplitView.js +18 -14
  19. package/dist/elements/layout/SplitView.js.map +1 -1
  20. package/dist/elements/layout/type.d.ts +3 -3
  21. package/dist/elements/layout/type.d.ts.map +1 -1
  22. package/dist/elements/layout/type.js.map +1 -1
  23. package/dist/elements/schema-design/DataModelVisualizationElement.d.ts.map +1 -1
  24. package/dist/elements/schema-design/DataModelVisualizationElement.js +18 -1
  25. package/dist/elements/schema-design/DataModelVisualizationElement.js.map +1 -1
  26. package/dist/pages/http-project/HttpClientCommands.d.ts.map +1 -1
  27. package/dist/pages/http-project/HttpClientCommands.js +28 -12
  28. package/dist/pages/http-project/HttpClientCommands.js.map +1 -1
  29. package/package.json +2 -1
  30. package/src/elements/layout/SplitItem.ts +29 -21
  31. package/src/elements/layout/SplitLayout.ts +53 -43
  32. package/src/elements/layout/SplitPanel.ts +140 -57
  33. package/src/elements/layout/SplitView.ts +18 -15
  34. package/src/elements/layout/type.ts +3 -4
  35. package/src/elements/schema-design/DataModelVisualizationElement.ts +18 -1
  36. package/src/pages/http-project/HttpClientCommands.ts +28 -12
  37. package/test/elements/layout/SplitItem.test.ts +76 -75
  38. package/test/elements/layout/SplitLayoutManager.test.ts +70 -69
  39. package/test/elements/layout/SplitPanel.test.ts +10 -7
  40. package/tsconfig.eslint.json +8 -0
  41. package/web-test-runner.config.mjs +4 -1
  42. package/dist/define/layout/layout-panel.d.ts +0 -7
  43. package/dist/define/layout/layout-panel.d.ts.map +0 -1
  44. package/dist/define/layout/layout-panel.js +0 -3
  45. package/dist/define/layout/layout-panel.js.map +0 -1
  46. package/dist/elements/layout/LayoutManager.d.ts +0 -327
  47. package/dist/elements/layout/LayoutManager.d.ts.map +0 -1
  48. package/dist/elements/layout/LayoutManager.js +0 -747
  49. package/dist/elements/layout/LayoutManager.js.map +0 -1
  50. package/dist/elements/layout/LayoutPanelElement.d.ts +0 -62
  51. package/dist/elements/layout/LayoutPanelElement.d.ts.map +0 -1
  52. package/dist/elements/layout/LayoutPanelElement.js +0 -628
  53. package/dist/elements/layout/LayoutPanelElement.js.map +0 -1
  54. package/src/define/layout/layout-panel.ts +0 -9
  55. package/src/elements/layout/LayoutManager.ts +0 -930
  56. package/src/elements/layout/LayoutPanelElement.ts +0 -651
@@ -179,30 +179,38 @@ export class SplitItem implements ISplitItem {
179
179
  return result;
180
180
  }
181
181
 
182
- /**
183
- * @returns The parent of the item. Returns undefined when the item was removed from layout.
184
- */
185
- getParent(): SplitPanel | undefined {
186
- return this.manager.getParent(this.key);
187
- }
182
+ // /**
183
+ // * @returns The parent of the item. Returns undefined when the item was removed from layout.
184
+ // * @deprecated Use `getParents()` instead.
185
+ // */
186
+ // getParent(): SplitPanel | undefined {
187
+ // return this.manager.getParent(this.key);
188
+ // }
188
189
 
189
190
  /**
190
- * Removes self from the layout
191
+ * @returns The parent of the item. Returns undefined when the item was removed from layout.
191
192
  */
192
- remove(): void {
193
- this.manager.removeItem(this.key);
193
+ getParents(): SplitPanel[] {
194
+ return this.manager.getParents(this.key);
194
195
  }
195
196
 
196
- /**
197
- * Sets the item active in the parent layout.
198
- */
199
- setSelected(): void {
200
- const parent = this.getParent();
201
- if (parent) {
202
- parent.selected = this.key;
203
- this.notifyChange();
204
- }
205
- }
197
+ // /**
198
+ // * Removes self from the layout. This removes the item from all panels.
199
+ // */
200
+ // remove(): void {
201
+ // this.manager.removeItem(this.key);
202
+ // }
203
+
204
+ // /**
205
+ // * Sets the item active in the parent layout.
206
+ // */
207
+ // setSelected(): void {
208
+ // const parent = this.getParent();
209
+ // if (parent) {
210
+ // parent.selected = this.key;
211
+ // this.notifyChange();
212
+ // }
213
+ // }
206
214
 
207
215
  /**
208
216
  * Updates the label and triggers side effects like layout and view update.
@@ -222,8 +230,8 @@ export class SplitItem implements ISplitItem {
222
230
  }
223
231
 
224
232
  updateView(): void {
225
- const panel = this.getParent();
226
- panel?.updateView();
233
+ const panels = this.getParents();
234
+ panels.forEach(panel => panel.updateView());
227
235
  }
228
236
 
229
237
  notifyChange(): void {
@@ -3,7 +3,7 @@ import { TemplateResult } from "lit";
3
3
  import { ISplitItem, SplitItem } from "./SplitItem.js";
4
4
  import { ISplitPanel, SplitPanel } from "./SplitPanel.js";
5
5
  import SplitView from "./SplitView.js";
6
- import { IPanelObject, LayoutType, SplitCloseDirection, SplitDirection, SplitItemRenderCallback, SplitLayoutInit, SplitPanelAddOptions } from "./type.js";
6
+ import { IPanelObject, LayoutType, SplitDirection, SplitItemRenderCallback, SplitLayoutAddOptions, SplitLayoutInit, SplitPanelAddOptions } from "./type.js";
7
7
 
8
8
  interface LayoutObject {
9
9
  type: LayoutType;
@@ -33,6 +33,11 @@ export interface ISplitLayout {
33
33
  active?: string;
34
34
  }
35
35
 
36
+ export interface ITabCloseDetail {
37
+ tab: string;
38
+ panel: string;
39
+ }
40
+
36
41
  /**
37
42
  * Split layout manager creates a view where the application can put "items" into
38
43
  * and render them inside "panels". The application can create as many panels as needed.
@@ -109,7 +114,7 @@ export class SplitLayout extends EventTarget {
109
114
  return value as SplitPanel;
110
115
  }
111
116
  const item = value as SplitItem;
112
- return this.getParent(item.key);
117
+ return this.getParents(item.key)[0];
113
118
  }
114
119
 
115
120
  /**
@@ -316,22 +321,25 @@ export class SplitLayout extends EventTarget {
316
321
  }
317
322
 
318
323
  /**
319
- * Finds a parent for an item.
320
- * @param panelKey The key of the item (panel or panel's item) to find a parent for.
321
- * @returns The parent panel or `undefined` when the item was removed or the panel has no parents.
324
+ * Finds parents an item or another panel is anchored to.
325
+ * An item can have multiple parents. A panel can only have a single parent.
326
+ *
327
+ * @param itemOrPanelKey The key of the panel or an item.
328
+ * @returns THe list of panels the item is added. It can only return up to 1 result when looking for a panel's parent.
322
329
  */
323
- getParent(panelKey: string): SplitPanel | undefined {
330
+ getParents(itemOrPanelKey: string): SplitPanel[] {
331
+ const result: SplitPanel[] = [];
324
332
  for (const { type, value } of this.definitions.values()) {
325
333
  if (type !== LayoutType.panel) {
326
334
  continue;
327
335
  }
328
336
  const panel = value as SplitPanel;
329
- const result = panel.items.some(i => i.key === panelKey);
330
- if (result) {
331
- return panel;
337
+ const has = panel.items.some(i => i.key === itemOrPanelKey);
338
+ if (has) {
339
+ result.push(panel);
332
340
  }
333
341
  }
334
- return undefined;
342
+ return result;
335
343
  }
336
344
 
337
345
  /**
@@ -396,12 +404,15 @@ export class SplitLayout extends EventTarget {
396
404
  * Do not call this method from the outside of the layout manager logic.
397
405
  * It is a way to communicate a tab was closed.
398
406
  */
399
- notifyTabClose(itemKey: string): void {
400
- this.dispatchEvent(new CustomEvent('closetab', {
407
+ notifyTabClose(itemKey: string, panel: string): void {
408
+ this.dispatchEvent(new CustomEvent<ITabCloseDetail>('closetab', {
401
409
  bubbles: true,
402
410
  cancelable: true,
403
411
  composed: true,
404
- detail: itemKey,
412
+ detail: {
413
+ tab: itemKey,
414
+ panel,
415
+ },
405
416
  }));
406
417
  }
407
418
 
@@ -431,10 +442,8 @@ export class SplitLayout extends EventTarget {
431
442
  const before = item.label;
432
443
  this.dispatchNameItem(item);
433
444
  if (before !== item.label) {
434
- const panel = item.getParent();
435
- if (panel) {
436
- this.updateView(panel.key);
437
- }
445
+ const panels = this.getParents(item.key);
446
+ panels.forEach(panel => this.updateView(panel.key));
438
447
  }
439
448
  }
440
449
 
@@ -450,8 +459,8 @@ export class SplitLayout extends EventTarget {
450
459
  const before = item.label;
451
460
  this.dispatchNameItem(item);
452
461
  if (before !== item.label) {
453
- const panel = item.getParent() as SplitPanel;
454
- updatePanels.add(panel);
462
+ const panels = this.getParents(item.key);
463
+ panels.forEach(panel => updatePanels.add(panel));
455
464
  }
456
465
  }
457
466
 
@@ -532,7 +541,9 @@ export class SplitLayout extends EventTarget {
532
541
  }
533
542
 
534
543
  /**
535
- * Removes an item from layout.
544
+ * Removes an item from the layout. This means removing an item from all panels.
545
+ * If you want to remove an item from a specific panel then find the panel first and then call `removeItem()`.
546
+ *
536
547
  * @param key The key of the item to remove.
537
548
  */
538
549
  removeItem(key: string): void {
@@ -540,27 +551,26 @@ export class SplitLayout extends EventTarget {
540
551
  if (!item) {
541
552
  return;
542
553
  }
543
- const panel = item.getParent();
544
- if (panel) {
545
- panel.removeItem(key);
546
- }
554
+ const parents = this.getParents(key);
555
+ parents.forEach(parent => parent.removeChildItem(item));
547
556
  }
548
557
 
549
- /**
550
- * Removes other items relative to the `key` item.
551
- * @param key The key of the item to perform a relative operation from.
552
- * @param dir The direction to which close other items. Default to both directions leaving only the `key` item
553
- */
554
- removeRelative(key: string, dir?: SplitCloseDirection): void {
555
- const item = this.findItem(key);
556
- if (!item) {
557
- return;
558
- }
559
- const panel = item.getParent();
560
- if (panel) {
561
- panel.removeRelative(key, dir);
562
- }
563
- }
558
+ // /**
559
+ // * Removes other items relative to the `key` item.
560
+ // * @param key The key of the item to perform a relative operation from.
561
+ // * @param dir The direction to which close other items. Default to both directions leaving only the `key` item
562
+ // * @deprecated this function does not work as intended. Find the parent panel first and then call the `removeRelative()`.
563
+ // */
564
+ // removeRelative(key: string, dir?: SplitCloseDirection): void {
565
+ // const item = this.findItem(key);
566
+ // if (!item) {
567
+ // return;
568
+ // }
569
+ // const panel = item.getParent();
570
+ // if (panel) {
571
+ // panel.removeRelative(key, dir);
572
+ // }
573
+ // }
564
574
 
565
575
  /**
566
576
  * Moves a tab between panels or inside a panel
@@ -570,14 +580,14 @@ export class SplitLayout extends EventTarget {
570
580
  * @param itemKey The key of the item
571
581
  * @param toIndex The index to which add the item. Default as the last.
572
582
  */
573
- moveItem(fromPanelKey: string, toPanelKey: string, itemKey: string, toIndex?: number): void {
583
+ moveItem(fromPanelKey: string, toPanelKey: string, itemKey: string, opts?: SplitLayoutAddOptions): void {
574
584
  const singlePanel = fromPanelKey === toPanelKey;
575
585
  const from = this.findPanel(fromPanelKey);
576
586
  if (!from) {
577
587
  throw new Error(`Source layout panel not found.`);
578
588
  }
579
589
  if (singlePanel) {
580
- from.moveItem(itemKey, toIndex);
590
+ from.moveItem(itemKey, opts);
581
591
  } else {
582
592
  const to = this.findPanel(toPanelKey);
583
593
  if (!to) {
@@ -587,7 +597,7 @@ export class SplitLayout extends EventTarget {
587
597
  if (!removed) {
588
598
  throw new Error(`Item not found.`);
589
599
  }
590
- to.addItem(removed, { index: toIndex });
600
+ to.addItem(removed, opts);
591
601
  }
592
602
  this.notifyChange();
593
603
  }
@@ -686,7 +696,7 @@ export class SplitLayout extends EventTarget {
686
696
  panel = activePanel;
687
697
  } else {
688
698
  // any panel that has the item
689
- panel = this.getParent(itemKey);
699
+ [panel] = this.getParents(itemKey);
690
700
  }
691
701
  if (!panel) {
692
702
  return;
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-param-reassign */
1
2
  /* eslint-disable import/no-cycle */
2
3
  import { html, TemplateResult } from "lit";
3
4
  import { uuidV4 } from "@api-client/core/build/browser.js";
@@ -108,7 +109,7 @@ export class SplitPanel {
108
109
  }
109
110
 
110
111
  getParent(): SplitPanel | undefined {
111
- return this.manager.getParent(this.key);
112
+ return this.manager.getParents(this.key)[0];
112
113
  }
113
114
 
114
115
  /**
@@ -226,6 +227,14 @@ export class SplitPanel {
226
227
  return instance;
227
228
  }
228
229
 
230
+ const panel = this.splitByRegion(region);
231
+ // we don't call request update here because
232
+ // the app has to redo the view rendering first as
233
+ // the panel purpose has changed.
234
+ return panel.addItem(item, { index });
235
+ }
236
+
237
+ protected splitByRegion(region: SplitRegion): SplitPanel {
229
238
  let panel: SplitPanel;
230
239
  if (region === 'east') {
231
240
  [, panel] = this.split({
@@ -252,10 +261,7 @@ export class SplitPanel {
252
261
  noSideEffects: true,
253
262
  });
254
263
  }
255
- // we don't call request update here because
256
- // the app has to redo the view rendering first as
257
- // the panel purpose has changed.
258
- return panel.addItem(item, { index });
264
+ return panel;
259
265
  }
260
266
 
261
267
  /**
@@ -273,11 +279,8 @@ export class SplitPanel {
273
279
  this.items = [];
274
280
  this.selected = undefined;
275
281
 
276
- const p1 = this.addPanel()
277
- const p2 = this.addPanel()
278
-
279
-
280
-
282
+ const p1 = this.addPanel();
283
+ const p2 = this.addPanel();
281
284
 
282
285
  // const p1 = new SplitPanel(this.manager);
283
286
  // const p2 = new SplitPanel(this.manager);
@@ -368,24 +371,19 @@ export class SplitPanel {
368
371
  }
369
372
  }
370
373
 
371
- /**
372
- * Removes an item from the layout
373
- * @param key The `key` of the item.
374
- * @returns The removed item, if any.
375
- */
376
- removeItem(key: string, opts: SplitPanelRemoveItemOptions = {}): SplitItem | undefined {
377
- const removed = this.manager.findItem(key);
378
- if (!removed) {
379
- return undefined;
380
- }
381
- const index = this.items.findIndex(i => i.key === key);
374
+ removeChildItem(item: SplitItem, opts: SplitPanelRemoveItemOptions = {}): SplitItem | undefined {
375
+ const index = this.items.findIndex(i => i.key === item.key);
382
376
  if (index < 0) {
383
377
  return undefined;
384
378
  }
385
379
  const itemInfo = this.items[index];
386
380
  this.items.splice(index, 1);
387
- this.manager.definitions.delete(itemInfo.key);
388
- this.decreaseIndex(removed.index || 0);
381
+ this.decreaseIndex(item.index || 0);
382
+ const parents = this.manager.getParents(item.key);
383
+ if (!parents.length) {
384
+ // remove the definition since no other panel have this item.
385
+ this.manager.definitions.delete(itemInfo.key);
386
+ }
389
387
 
390
388
  if (this.items.length === 0) {
391
389
  // remove panel (self)
@@ -393,29 +391,82 @@ export class SplitPanel {
393
391
  if (parent) {
394
392
  parent.removePanel(this.key);
395
393
  // Note, ignore `opts.noSideEffects` for tab close. It won't get dispatched elsewhere.
396
- this.manager.notifyTabClose(key);
394
+ this.manager.notifyTabClose(item.key, this.key);
397
395
  // no point doing the stuff below as the whole panel is removed.
398
- return removed;
396
+ return item;
399
397
  }
400
398
  }
401
- if (this.selected === key) {
399
+
400
+ if (this.selected === item.key) {
402
401
  let nextKey: string | undefined;
403
402
  if (this.items[index]) {
404
403
  nextKey = this.items[index].key;
405
404
  } else if (this.items[index - 1]) {
406
405
  nextKey = this.items[index - 1].key;
407
406
  } else if (this.items.length) {
408
- const [item] = this.items;
409
- nextKey = item.key;
407
+ const [other] = this.items;
408
+ nextKey = other.key;
410
409
  }
411
410
  this.selected = nextKey;
412
411
  }
412
+
413
413
  if (!opts.noSideEffects) {
414
- this.manager.notifyTabClose(key);
414
+ this.manager.notifyTabClose(item.key, this.key);
415
415
  this.manager.notifyChange();
416
416
  this.manager.updateView(this.key);
417
417
  }
418
- return removed;
418
+ return item;
419
+ }
420
+
421
+ /**
422
+ * Removes an item from the layout
423
+ * @param key The `key` of the item.
424
+ * @returns The removed item, if any.
425
+ */
426
+ removeItem(key: string, opts?: SplitPanelRemoveItemOptions): SplitItem | undefined {
427
+ const removed = this.manager.findItem(key);
428
+ if (!removed) {
429
+ return undefined;
430
+ }
431
+ return this.removeChildItem(removed, opts);
432
+ // const index = this.items.findIndex(i => i.key === key);
433
+ // if (index < 0) {
434
+ // return undefined;
435
+ // }
436
+ // const itemInfo = this.items[index];
437
+ // this.items.splice(index, 1);
438
+ // this.manager.definitions.delete(itemInfo.key);
439
+ // this.decreaseIndex(removed.index || 0);
440
+
441
+ // if (this.items.length === 0) {
442
+ // // remove panel (self)
443
+ // const parent = this.getParent();
444
+ // if (parent) {
445
+ // parent.removePanel(this.key);
446
+ // // Note, ignore `opts.noSideEffects` for tab close. It won't get dispatched elsewhere.
447
+ // this.manager.notifyTabClose(key);
448
+ // // no point doing the stuff below as the whole panel is removed.
449
+ // return removed;
450
+ // }
451
+ // }
452
+ // if (this.selected === key) {
453
+ // let nextKey: string | undefined;
454
+ // if (this.items[index]) {
455
+ // nextKey = this.items[index].key;
456
+ // } else if (this.items[index - 1]) {
457
+ // nextKey = this.items[index - 1].key;
458
+ // } else if (this.items.length) {
459
+ // const [item] = this.items;
460
+ // nextKey = item.key;
461
+ // }
462
+ // this.selected = nextKey;
463
+ // }
464
+ // if (!opts.noSideEffects) {
465
+ // this.manager.notifyTabClose(key);
466
+ // this.manager.notifyChange();
467
+ // this.manager.updateView(this.key);
468
+ // }
469
+ // return removed;
419
470
  }
420
471
 
421
472
  /**
@@ -423,30 +474,30 @@ export class SplitPanel {
423
474
  * @param dir The direction to which close other items. Default to both directions leaving only the `key` item
424
475
  */
425
476
  removeRelative(key: string, dir: SplitCloseDirection = SplitCloseDirection.both): void {
426
- const index = this.items.findIndex(i => i.key === key);
477
+ const items = this.sortedItems();
478
+ const index = items.findIndex(i => i.key === key);
427
479
  if (index < 0) {
428
480
  return;
429
481
  }
430
- // note, even though we keep indexes in the item, the logic actually
431
- // keeps track of them and orders the `items` accordingly.
432
- const item = this.items[index];
433
- let removed: IPanelObject[];
482
+
483
+ const item = items[index];
484
+ let removed: string[] = [];
434
485
  if (dir === SplitCloseDirection.both) {
435
- removed = this.items.filter(i => i !== item);
436
- this.items = [item];
437
- this.selected = item.key;
486
+ removed = items.filter(i => i !== item).map(i => i.key);
438
487
  } else if (dir === SplitCloseDirection.left) {
439
- removed = this.items.slice(0, index);
440
- this.items = this.items.splice(index);
441
- this.selected = item.key;
488
+ removed = items.slice(0, index).map(i => i.key);
442
489
  } else {
443
- removed = this.items.slice(index + 1);
444
- this.items = this.items.splice(0, index + 1);
445
- this.selected = item.key;
490
+ removed = this.items.slice(index + 1).map(i => i.key);
446
491
  }
492
+ this.items = this.items.filter(i => !removed.includes(i.key));
493
+ this.selected = item.key;
494
+
447
495
  removed.forEach(i => {
448
- this.manager.definitions.delete(i.key);
449
- this.manager.notifyTabClose(i.key);
496
+ const parents = this.manager.getParents(i);
497
+ if (!parents.length) {
498
+ this.manager.definitions.delete(i);
499
+ }
500
+ this.manager.notifyTabClose(i, this.key);
450
501
  });
451
502
  this.manager.notifyChange();
452
503
  this.manager.updateView(this.key);
@@ -490,7 +541,7 @@ export class SplitPanel {
490
541
  * @param key The item key
491
542
  * @param toIndex The new index. When not set it moves the item to the end.
492
543
  */
493
- moveItem(key: string, toIndex?: number): void {
544
+ moveItem(key: string, opts: SplitLayoutAddOptions = {}): void {
494
545
  const info = this.items.find(i => i.key === key);
495
546
  if (!info) {
496
547
  return;
@@ -499,22 +550,54 @@ export class SplitPanel {
499
550
  if (!item) {
500
551
  return;
501
552
  }
502
- const hasIndex = typeof toIndex === 'number';
503
- if (hasIndex && item.index === toIndex) {
553
+ const { index, region } = opts;
554
+ if (region) {
555
+ this.moveToRegion(item, region);
556
+ } else if (typeof index === 'number') {
557
+ this.moveToIndex(item, index);
558
+ } else {
559
+ this.moveToEnd(item);
560
+ }
561
+ }
562
+
563
+ moveToRegion(item: SplitItem, region: SplitRegion): void {
564
+ if (this.items.length < 2) {
565
+ // nothing to split.
504
566
  return;
505
567
  }
506
- let hasTargetAtTarget = false;
507
- if (hasIndex) {
508
- hasTargetAtTarget = !!this.items[toIndex];
568
+ if (region === SplitRegion.center) {
569
+ // the item is already there.
570
+ return;
509
571
  }
510
- if (item.index !== undefined) {
511
- this.decreaseIndex(item.index);
572
+ const itemsIndex = this.items.findIndex(i => i.key === item.key);
573
+ if (itemsIndex < 0) {
574
+ return;
575
+ }
576
+ this.items.splice(itemsIndex, 1);
577
+ const index = typeof item.index === 'number' ? item.index : this.nextIndex();
578
+ const panel = this.splitByRegion(region);
579
+ panel.addItem(item, { index });
580
+ }
581
+
582
+ moveToIndex(item: SplitItem, index: number): void {
583
+ if (item.index === index) {
584
+ return;
512
585
  }
513
- const finalIndex = hasIndex ? toIndex as number : this.nextIndex();
586
+ const hasTargetAtTarget = !!this.items[index as number];
587
+ this.decreaseIndex(item.index);
514
588
  if (hasTargetAtTarget) {
515
- this.increaseIndex(finalIndex);
589
+ this.increaseIndex(index);
590
+ }
591
+ item.index = index;
592
+ this.manager.notifyChange();
593
+ this.manager.updateView(this.key);
594
+ }
595
+
596
+ moveToEnd(item: SplitItem): void {
597
+ if (item.index !== undefined) {
598
+ this.decreaseIndex(item.index);
516
599
  }
517
- item.index = finalIndex;
600
+ item.index = this.nextIndex();
518
601
  this.manager.notifyChange();
519
602
  this.manager.updateView(this.key);
520
603
  }
@@ -70,7 +70,7 @@ export default class SplitView extends LitElement {
70
70
  e.stopPropagation();
71
71
  dataTransfer.dropEffect = 'copy';
72
72
  }
73
-
73
+
74
74
  protected handleDragOver(e: DragEvent): void {
75
75
  const { dataTransfer } = e;
76
76
  if (!dataTransfer || !this.panelCanDrop(e)) {
@@ -90,7 +90,8 @@ export default class SplitView extends LitElement {
90
90
 
91
91
  protected handleDrop(e: DragEvent): void {
92
92
  const { dataTransfer } = e;
93
- if (!dataTransfer || !this.panelCanDrop(e)) {
93
+ const { panel } = this;
94
+ if (!dataTransfer || !panel || !this.panelCanDrop(e)) {
94
95
  return;
95
96
  }
96
97
  e.preventDefault();
@@ -100,22 +101,23 @@ export default class SplitView extends LitElement {
100
101
  if (!kind || !key) {
101
102
  return;
102
103
  }
104
+ const layoutKey = dataTransfer.getData('layout/key');
103
105
  this.inDrag = false;
104
- const { panel } = this;
105
- let dispatch = true;
106
- if (panel) {
106
+ // TODO: When the drag originated in another panel then we
107
+ // move the panel between them. Otherwise we add the item to the panel.
108
+ if (layoutKey) {
109
+ // move operation not add.
110
+ panel.manager.moveItem(layoutKey, panel.key, key, { region: this.dragRegion });
111
+ } else {
107
112
  panel.addItem({ key, kind, label: 'New tab' }, { region: this.dragRegion });
108
113
  panel.manager.requestNameUpdate(key);
109
- dispatch = true;
110
- }
111
- if (dispatch) {
112
- this.dispatchEvent(new CustomEvent('datadrop', {
113
- detail: { kind, key, region: this.dragRegion },
114
- composed: true,
115
- bubbles: true,
116
- cancelable: true,
117
- }));
118
114
  }
115
+ this.dispatchEvent(new CustomEvent('datadrop', {
116
+ detail: { kind, key, region: this.dragRegion },
117
+ composed: true,
118
+ bubbles: true,
119
+ cancelable: true,
120
+ }));
119
121
  this.requestUpdate();
120
122
  }
121
123
 
@@ -282,7 +284,7 @@ export default class SplitView extends LitElement {
282
284
  protected moveTab(fromLayout: string, toLayout: string, key: string, toIndex?: number): void {
283
285
  const { panel } = this;
284
286
  if (panel) {
285
- panel.manager.moveItem(fromLayout, toLayout, key, toIndex);
287
+ panel.manager.moveItem(fromLayout, toLayout, key, { index: toIndex });
286
288
  }
287
289
  }
288
290
 
@@ -452,6 +454,7 @@ export default class SplitView extends LitElement {
452
454
  data-index="${index}"
453
455
  data-parent="${ifDefined(parent)}"
454
456
  data-dirty="${isDirty}"
457
+ data-panel="${ifDefined(panel?.key)}"
455
458
  role="tab"
456
459
  class="${classMap(classes)}"
457
460
  draggable="true"
@@ -1,7 +1,6 @@
1
- /* eslint-disable import/no-cycle */
2
- import { TemplateResult } from "lit";
3
- import { SplitItem } from "./SplitItem.js";
4
- import { ISplitLayout } from "./SplitLayout.js";
1
+ import type { TemplateResult } from "lit";
2
+ import type { SplitItem } from "./SplitItem.js";
3
+ import type { ISplitLayout } from "./SplitLayout.js";
5
4
 
6
5
  export enum SplitDirection {
7
6
  horizontal = 'horizontal',