regular-layout 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,8 +9,7 @@
9
9
  // ┃ * [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). * ┃
10
10
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
11
11
 
12
- import { MIN_DRAG_DISTANCE, OVERLAY_CLASSNAME } from "./layout/constants.ts";
13
- import type { Layout, LayoutPath } from "./layout/types.ts";
12
+ import type { LayoutPath } from "./layout/types.ts";
14
13
  import type { RegularLayoutEvent } from "./extensions.ts";
15
14
  import type { RegularLayout } from "./regular-layout.ts";
16
15
  import type { RegularLayoutTab } from "./regular-layout-tab.ts";
@@ -30,6 +29,8 @@ const HTML_TEMPLATE = `
30
29
  <slot part="container"></slot>
31
30
  `;
32
31
 
32
+ type DragState = { moved?: boolean; path: LayoutPath };
33
+
33
34
  /**
34
35
  * A custom element that represents a draggable panel within a
35
36
  * `<regular-layout>`.
@@ -56,29 +57,31 @@ const HTML_TEMPLATE = `
56
57
  * ```
57
58
  */
58
59
  export class RegularLayoutFrame extends HTMLElement {
59
- private _shadowRoot: ShadowRoot;
60
- private _container_sheet: CSSStyleSheet;
60
+ private _shadowRoot!: ShadowRoot;
61
+ private _container_sheet!: CSSStyleSheet;
61
62
  private _layout!: RegularLayout;
62
63
  private _header!: HTMLElement;
63
- private _drag_state: LayoutPath<Layout> | null = null;
64
- private _drag_moved: boolean = false;
64
+ private _drag: DragState | null = null;
65
65
  private _tab_to_index_map: WeakMap<RegularLayoutTab, number> = new WeakMap();
66
- constructor() {
67
- super();
68
- this._container_sheet = new CSSStyleSheet();
69
- this._container_sheet.replaceSync(CSS);
70
- this._shadowRoot = this.attachShadow({ mode: "open" });
71
- this._shadowRoot.adoptedStyleSheets = [this._container_sheet];
72
- }
73
66
 
67
+ /**
68
+ * Initializes this elements. Override this method and
69
+ * `disconnectedCallback` to modify how this subclass renders the Shadow
70
+ * DOM and registers events.
71
+ */
74
72
  connectedCallback() {
73
+ this._container_sheet ??= new CSSStyleSheet();
74
+ this._container_sheet.replaceSync(CSS);
75
+ this._shadowRoot ??= this.attachShadow({ mode: "open" });
76
+ this._shadowRoot.adoptedStyleSheets = [this._container_sheet];
75
77
  this._shadowRoot.innerHTML = HTML_TEMPLATE;
76
78
  this._layout = this.parentElement as RegularLayout;
77
79
  this._header = this._shadowRoot.children[0] as HTMLElement;
78
80
  this._header.addEventListener("pointerdown", this.onPointerDown);
79
- this._header.addEventListener("pointermove", this.onPointerMove);
80
- this._header.addEventListener("pointerup", this.onPointerUp);
81
- this._header.addEventListener("lostpointercapture", this.onPointerLost);
81
+ this.addEventListener("pointermove", this.onPointerMove);
82
+ this.addEventListener("pointerup", this.onPointerUp);
83
+ this.addEventListener("pointercancel", this.onPointerCancel);
84
+ this.addEventListener("lostpointercapture", this.onPointerLost);
82
85
  this._layout.addEventListener("regular-layout-update", this.drawTabs);
83
86
  this._layout.addEventListener(
84
87
  "regular-layout-before-update",
@@ -86,11 +89,15 @@ export class RegularLayoutFrame extends HTMLElement {
86
89
  );
87
90
  }
88
91
 
92
+ /**
93
+ * Destroys this element.
94
+ */
89
95
  disconnectedCallback() {
90
96
  this._header.removeEventListener("pointerdown", this.onPointerDown);
91
- this._header.removeEventListener("pointermove", this.onPointerMove);
92
- this._header.removeEventListener("pointerup", this.onPointerUp);
93
- this._header.removeEventListener("lostpointercapture", this.onPointerLost);
97
+ this.removeEventListener("pointermove", this.onPointerMove);
98
+ this.removeEventListener("pointerup", this.onPointerUp);
99
+ this.removeEventListener("pointercancel", this.onPointerUp);
100
+ this.removeEventListener("lostpointercapture", this.onPointerLost);
94
101
  this._layout.removeEventListener("regular-layout-update", this.drawTabs);
95
102
  this._layout.removeEventListener(
96
103
  "regular-layout-before-update",
@@ -101,71 +108,52 @@ export class RegularLayoutFrame extends HTMLElement {
101
108
  private onPointerDown = (event: PointerEvent): void => {
102
109
  const elem = event.target as RegularLayoutTab;
103
110
  if (elem.part.contains("tab")) {
104
- this._drag_state = this._layout.calculateIntersect(
105
- event.clientX,
106
- event.clientY,
107
- );
108
-
109
- if (this._drag_state) {
110
- this._header.setPointerCapture(event.pointerId);
111
+ const path = this._layout.calculateIntersect(event);
112
+ if (path) {
113
+ this._drag = { path };
114
+ this.setPointerCapture(event.pointerId);
111
115
  event.preventDefault();
116
+ } else {
117
+ this._drag = null;
112
118
  }
113
119
  }
114
120
  };
115
121
 
116
122
  private onPointerMove = (event: PointerEvent): void => {
117
- if (this._drag_state) {
118
- // Only initiate a drag if the cursor has moved sufficiently.
119
- if (!this._drag_moved) {
120
- const [current_col, current_row, box] =
121
- this._layout.relativeCoordinates(event.clientX, event.clientY);
122
-
123
- const dx = (current_col - this._drag_state.column) * box.width;
124
- const dy = (current_row - this._drag_state.row) * box.height;
125
- if (Math.sqrt(dx * dx + dy * dy) <= MIN_DRAG_DISTANCE) {
123
+ if (this._drag) {
124
+ const physics = this._layout.savePhysics();
125
+ if (!this._drag.moved) {
126
+ const diff = this._layout.diffCoordinates(event, this._drag.path);
127
+ if (diff <= physics.MIN_DRAG_DISTANCE) {
126
128
  return;
127
129
  }
128
130
  }
129
131
 
130
- this._drag_moved = true;
131
- this._layout.setOverlayState(
132
- event.clientX,
133
- event.clientY,
134
- this._drag_state,
135
- OVERLAY_CLASSNAME,
136
- );
132
+ this._drag.moved = true;
133
+ this._layout.setOverlayState(event, this._drag.path);
137
134
  }
138
135
  };
139
136
 
140
137
  private onPointerUp = (event: PointerEvent): void => {
141
- if (this._drag_state && this._drag_moved) {
142
- this._layout.clearOverlayState(
143
- event.clientX,
144
- event.clientY,
145
- this._drag_state,
146
- OVERLAY_CLASSNAME,
147
- );
138
+ if (this._drag?.moved) {
139
+ this._layout.clearOverlayState(event, this._drag.path);
148
140
  }
149
-
150
- // TODO This may be handled by `onPointerLost`, not sure if this is
151
- // browser-specific behavior ...
152
- this._header.releasePointerCapture(event.pointerId);
153
- this._drag_state = null;
154
- this._drag_moved = false;
155
141
  };
156
142
 
157
- private onPointerLost = (event: PointerEvent): void => {
158
- if (this._drag_state) {
159
- this._layout.clearOverlayState(-1, -1, this._drag_state);
143
+ private onPointerCancel = (_: PointerEvent): void => {
144
+ if (this._drag?.moved) {
145
+ this._layout.clearOverlayState(null, this._drag.path);
160
146
  }
147
+ };
161
148
 
162
- this._header.releasePointerCapture(event.pointerId);
163
- this._drag_state = null;
164
- this._drag_moved = false;
149
+ private onPointerLost = (event: PointerEvent): void => {
150
+ this.releasePointerCapture(event.pointerId);
151
+ this._drag = null;
165
152
  };
166
153
 
167
154
  private drawTabs = (event: RegularLayoutEvent) => {
168
- const slot = this.getAttribute("name");
155
+ const attr = this._layout.savePhysics().CHILD_ATTRIBUTE_NAME;
156
+ const slot = this.getAttribute(attr);
169
157
  if (!slot) {
170
158
  return;
171
159
  }
@@ -175,12 +163,12 @@ export class RegularLayoutFrame extends HTMLElement {
175
163
  if (!new_tab_panel) {
176
164
  new_tab_panel = {
177
165
  type: "child-panel",
178
- child: [slot],
166
+ tabs: [slot],
179
167
  selected: 0,
180
168
  };
181
169
  }
182
170
 
183
- for (let i = 0; i < new_tab_panel.child.length; i++) {
171
+ for (let i = 0; i < new_tab_panel.tabs.length; i++) {
184
172
  if (i >= this._header.children.length) {
185
173
  const new_tab = document.createElement("regular-layout-tab");
186
174
  new_tab.populate(this._layout, new_tab_panel, i);
@@ -192,7 +180,7 @@ export class RegularLayoutFrame extends HTMLElement {
192
180
  }
193
181
  }
194
182
 
195
- const last_index = new_tab_panel.child.length;
183
+ const last_index = new_tab_panel.tabs.length;
196
184
  for (let j = this._header.children.length - 1; j >= last_index; j--) {
197
185
  this._header.removeChild(this._header.children[j]);
198
186
  }
@@ -40,11 +40,11 @@ export class RegularLayoutTab extends HTMLElement {
40
40
  (index === this._tab_panel?.selected);
41
41
 
42
42
  const index_changed =
43
- tab_changed || this._tab_panel?.child[index] !== tab_panel.child[index];
43
+ tab_changed || this._tab_panel?.tabs[index] !== tab_panel.tabs[index];
44
44
 
45
45
  if (index_changed) {
46
46
  const selected = tab_panel.selected === index;
47
- const slot = tab_panel.child[index];
47
+ const slot = tab_panel.tabs[index];
48
48
  this.children[0].textContent = slot;
49
49
 
50
50
  if (selected) {
@@ -56,7 +56,7 @@ export class RegularLayoutTab extends HTMLElement {
56
56
  }
57
57
  }
58
58
  } else {
59
- const slot = tab_panel.child[index];
59
+ const slot = tab_panel.tabs[index];
60
60
  const selected = tab_panel.selected === index;
61
61
  const parts = selected ? "active-close close" : "close";
62
62
  this.innerHTML = `<div part="title"></div><button part="${parts}"></button>`;
@@ -78,7 +78,7 @@ export class RegularLayoutTab extends HTMLElement {
78
78
 
79
79
  private onTabClose = (_: Event) => {
80
80
  if (this._tab_panel !== undefined && this._index !== undefined) {
81
- this._layout?.removePanel(this._tab_panel.child[this._index]);
81
+ this._layout?.removePanel(this._tab_panel.tabs[this._index]);
82
82
  }
83
83
  };
84
84
 
@@ -90,7 +90,7 @@ export class RegularLayoutTab extends HTMLElement {
90
90
  ) {
91
91
  const new_layout = this._layout?.save();
92
92
  const new_tab_panel = this._layout?.getPanel(
93
- this._tab_panel.child[this._index],
93
+ this._tab_panel.tabs[this._index],
94
94
  new_layout,
95
95
  );
96
96