@signal9/era-ui 1.11.3 → 1.11.5
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/ui/pane/pane-root.svelte +42 -26
- package/package.json +1 -1
|
@@ -88,12 +88,13 @@
|
|
|
88
88
|
// that gaps the close button from the pane edge) OUTSIDE the pane. n + w are
|
|
89
89
|
// that thin outward-only. s + e straddle (translate ±50%, double thickness)
|
|
90
90
|
// so they also reach xs-inset-sm INWARD — on the right, into the close-button
|
|
91
|
-
// gap. Corners are
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
//
|
|
91
|
+
// gap. Corners are 2·xs-inset-sm squares straddling each corner — the same
|
|
92
|
+
// thickness as the blue rails, so they protrude the matching xs-inset-sm and
|
|
93
|
+
// reach xs-inset-sm along both edges; the edges are inset by that at both ends
|
|
94
|
+
// and stop right where a corner begins instead of running under it. `dir` is
|
|
95
|
+
// any of n/s/e/w; a 2-letter dir is a corner. Handles live in a layer aligned
|
|
96
|
+
// to the pane's border box (markup) and are data-pane-control so they never
|
|
97
|
+
// start a pane drag.
|
|
97
98
|
type ResizeDir = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw';
|
|
98
99
|
const RESIZE_HANDLES: { dir: ResizeDir; cursor: string; place: string }[] = [
|
|
99
100
|
// edges FIRST so the corners (rendered after) paint on top of them and win
|
|
@@ -105,25 +106,25 @@
|
|
|
105
106
|
dir: 'n',
|
|
106
107
|
cursor: 'cursor-ns-resize',
|
|
107
108
|
place:
|
|
108
|
-
'top:0;left:
|
|
109
|
+
'top:0;left:var(--era-xs-inset-sm);right:var(--era-xs-inset-sm);translate:0 -100%;height:var(--era-xs-inset-sm)'
|
|
109
110
|
},
|
|
110
111
|
{
|
|
111
112
|
dir: 's',
|
|
112
113
|
cursor: 'cursor-ns-resize',
|
|
113
114
|
place:
|
|
114
|
-
'bottom:0;left:
|
|
115
|
+
'bottom:0;left:var(--era-xs-inset-sm);right:var(--era-xs-inset-sm);translate:0 50%;height:calc(var(--era-xs-inset-sm)*2)'
|
|
115
116
|
},
|
|
116
117
|
{
|
|
117
118
|
dir: 'w',
|
|
118
119
|
cursor: 'cursor-ew-resize',
|
|
119
120
|
place:
|
|
120
|
-
'left:0;top:
|
|
121
|
+
'left:0;top:var(--era-xs-inset-sm);bottom:var(--era-xs-inset-sm);translate:-100% 0;width:var(--era-xs-inset-sm)'
|
|
121
122
|
},
|
|
122
123
|
{
|
|
123
124
|
dir: 'e',
|
|
124
125
|
cursor: 'cursor-ew-resize',
|
|
125
126
|
place:
|
|
126
|
-
'right:0;top:
|
|
127
|
+
'right:0;top:var(--era-xs-inset-sm);bottom:var(--era-xs-inset-sm);translate:50% 0;width:calc(var(--era-xs-inset-sm)*2)'
|
|
127
128
|
},
|
|
128
129
|
// corners LAST — a square at each corner (diagonal gap filler), painted
|
|
129
130
|
// above the edges so the red grab zone is always on top of the blue.
|
|
@@ -131,19 +132,19 @@
|
|
|
131
132
|
dir: 'nw',
|
|
132
133
|
cursor: 'cursor-nwse-resize',
|
|
133
134
|
place:
|
|
134
|
-
'top:0;left:0;translate:-50% -50%;width:calc(var(--era-
|
|
135
|
+
'top:0;left:0;translate:-50% -50%;width:calc(var(--era-xs-inset-sm)*2);height:calc(var(--era-xs-inset-sm)*2)'
|
|
135
136
|
},
|
|
136
137
|
{
|
|
137
138
|
dir: 'ne',
|
|
138
139
|
cursor: 'cursor-nesw-resize',
|
|
139
140
|
place:
|
|
140
|
-
'top:0;right:0;translate:50% -50%;width:calc(var(--era-
|
|
141
|
+
'top:0;right:0;translate:50% -50%;width:calc(var(--era-xs-inset-sm)*2);height:calc(var(--era-xs-inset-sm)*2)'
|
|
141
142
|
},
|
|
142
143
|
{
|
|
143
144
|
dir: 'sw',
|
|
144
145
|
cursor: 'cursor-nesw-resize',
|
|
145
146
|
place:
|
|
146
|
-
'bottom:0;left:0;translate:-50% 50%;width:calc(var(--era-
|
|
147
|
+
'bottom:0;left:0;translate:-50% 50%;width:calc(var(--era-xs-inset-sm)*2);height:calc(var(--era-xs-inset-sm)*2)'
|
|
147
148
|
},
|
|
148
149
|
{
|
|
149
150
|
// All four corners straddle (translate ±50%): 6px out AND 6px in, so they
|
|
@@ -151,14 +152,20 @@
|
|
|
151
152
|
dir: 'se',
|
|
152
153
|
cursor: 'cursor-nwse-resize',
|
|
153
154
|
place:
|
|
154
|
-
'bottom:0;right:0;translate:50% 50%;width:calc(var(--era-
|
|
155
|
+
'bottom:0;right:0;translate:50% 50%;width:calc(var(--era-xs-inset-sm)*2);height:calc(var(--era-xs-inset-sm)*2)'
|
|
155
156
|
}
|
|
156
157
|
];
|
|
157
158
|
|
|
158
|
-
// Pointer-capture resize.
|
|
159
|
-
//
|
|
160
|
-
//
|
|
161
|
-
// transform
|
|
159
|
+
// Pointer-capture resize. e/s grow from the anchored top-left — pure size, so
|
|
160
|
+
// they're already rock-solid. w/n also move the left/top edge: the box must
|
|
161
|
+
// grow AND shift so the far edge stays put. We do that shift with `margin`, not
|
|
162
|
+
// neodrag's position/transform. Why: on any `position` change neodrag clears its
|
|
163
|
+
// transform and re-applies it on its OWN rAF a frame later, so for one frame the
|
|
164
|
+
// box is new-size + stale-origin — the far edge wiggles every move. `margin` is
|
|
165
|
+
// neodrag-independent and lands in the same frame as style:width, so both edges
|
|
166
|
+
// commit together and the anchored edge holds still. On release we fold the
|
|
167
|
+
// margin back into neodrag's offset (position) and clear it, so neodrag's model
|
|
168
|
+
// matches the DOM and the next drag tracks cleanly.
|
|
162
169
|
function startResize(e: PointerEvent, dir: ResizeDir) {
|
|
163
170
|
if (!ref) return;
|
|
164
171
|
e.preventDefault();
|
|
@@ -179,26 +186,25 @@
|
|
|
179
186
|
let latest: { dx: number; dy: number } | null = null;
|
|
180
187
|
const apply = () => {
|
|
181
188
|
frame = 0;
|
|
182
|
-
if (!latest) return;
|
|
189
|
+
if (!latest || !ref) return;
|
|
183
190
|
const { dx, dy } = latest;
|
|
184
191
|
let w = startW;
|
|
185
192
|
let h = startH;
|
|
186
|
-
let
|
|
187
|
-
let
|
|
193
|
+
let mx = 0;
|
|
194
|
+
let my = 0;
|
|
188
195
|
if (dir.includes('e')) w = Math.max(minWidth, startW + dx);
|
|
189
196
|
if (dir.includes('w')) {
|
|
190
197
|
w = Math.max(minWidth, startW - dx);
|
|
191
|
-
|
|
198
|
+
mx = startW - w; // ≤ 0: the left edge slides out, right edge fixed
|
|
192
199
|
}
|
|
193
200
|
if (dir.includes('s')) h = Math.max(minHeight, startH + dy);
|
|
194
201
|
if (dir.includes('n')) {
|
|
195
202
|
h = Math.max(minHeight, startH - dy);
|
|
196
|
-
|
|
203
|
+
my = startH - h;
|
|
197
204
|
}
|
|
198
205
|
size = { width: w, height: h };
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
if (px !== position.x || py !== position.y) position = { x: px, y: py };
|
|
206
|
+
ref.style.marginLeft = mx ? `${mx}px` : '';
|
|
207
|
+
ref.style.marginTop = my ? `${my}px` : '';
|
|
202
208
|
};
|
|
203
209
|
const onMove = (ev: PointerEvent) => {
|
|
204
210
|
latest = { dx: ev.clientX - startX, dy: ev.clientY - startY };
|
|
@@ -207,6 +213,16 @@
|
|
|
207
213
|
const onUp = (ev: PointerEvent) => {
|
|
208
214
|
if (frame) cancelAnimationFrame(frame);
|
|
209
215
|
apply(); // flush the final delta synchronously
|
|
216
|
+
// Fold the margin shift into neodrag's offset and clear the margin — a
|
|
217
|
+
// net-zero swap that leaves the pane exactly where it looks, but with
|
|
218
|
+
// neodrag's position matching the DOM again so the next drag is true.
|
|
219
|
+
const mx = parseFloat(ref!.style.marginLeft) || 0;
|
|
220
|
+
const my = parseFloat(ref!.style.marginTop) || 0;
|
|
221
|
+
if (mx || my) {
|
|
222
|
+
position = { x: startPos.x + mx, y: startPos.y + my };
|
|
223
|
+
ref!.style.marginLeft = '';
|
|
224
|
+
ref!.style.marginTop = '';
|
|
225
|
+
}
|
|
210
226
|
// Clearing `resizing` re-adds controls (see controlsComp), re-measuring
|
|
211
227
|
// the handle zone at the new size.
|
|
212
228
|
resizing = false;
|