@signal9/era-ui 1.11.4 → 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.
@@ -156,10 +156,16 @@
156
156
  }
157
157
  ];
158
158
 
159
- // Pointer-capture resize. The active edges follow `dir`: e/s grow from the
160
- // anchored top-left; w/n move the left/top edge, so both size AND position
161
- // change (position is the neodrag offset style:width/height leaves the
162
- // transform intact). min-clamping stops the moving edge instead of the box.
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.
163
169
  function startResize(e: PointerEvent, dir: ResizeDir) {
164
170
  if (!ref) return;
165
171
  e.preventDefault();
@@ -180,26 +186,25 @@
180
186
  let latest: { dx: number; dy: number } | null = null;
181
187
  const apply = () => {
182
188
  frame = 0;
183
- if (!latest) return;
189
+ if (!latest || !ref) return;
184
190
  const { dx, dy } = latest;
185
191
  let w = startW;
186
192
  let h = startH;
187
- let px = startPos.x;
188
- let py = startPos.y;
193
+ let mx = 0;
194
+ let my = 0;
189
195
  if (dir.includes('e')) w = Math.max(minWidth, startW + dx);
190
196
  if (dir.includes('w')) {
191
197
  w = Math.max(minWidth, startW - dx);
192
- px = startPos.x + (startW - w);
198
+ mx = startW - w; // ≤ 0: the left edge slides out, right edge fixed
193
199
  }
194
200
  if (dir.includes('s')) h = Math.max(minHeight, startH + dy);
195
201
  if (dir.includes('n')) {
196
202
  h = Math.max(minHeight, startH - dy);
197
- py = startPos.y + (startH - h);
203
+ my = startH - h;
198
204
  }
199
205
  size = { width: w, height: h };
200
- // Only e/s corners never move the origin — skip the position write (and
201
- // its Compartment re-resolve) unless it actually changed.
202
- 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` : '';
203
208
  };
204
209
  const onMove = (ev: PointerEvent) => {
205
210
  latest = { dx: ev.clientX - startX, dy: ev.clientY - startY };
@@ -208,6 +213,16 @@
208
213
  const onUp = (ev: PointerEvent) => {
209
214
  if (frame) cancelAnimationFrame(frame);
210
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
+ }
211
226
  // Clearing `resizing` re-adds controls (see controlsComp), re-measuring
212
227
  // the handle zone at the new size.
213
228
  resizing = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signal9/era-ui",
3
- "version": "1.11.4",
3
+ "version": "1.11.5",
4
4
  "scripts": {
5
5
  "dev": "vite dev --host",
6
6
  "build": "vite build && npm run prepack",