@signal9/era-ui 1.14.0 → 1.14.1
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 +30 -37
- package/package.json +1 -1
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
4
|
import {
|
|
5
5
|
draggable,
|
|
6
|
-
controls,
|
|
7
|
-
ControlFrom,
|
|
8
6
|
disabled as disabledPlugin,
|
|
9
7
|
events,
|
|
10
8
|
position as positionPlugin,
|
|
@@ -65,11 +63,31 @@
|
|
|
65
63
|
|
|
66
64
|
let resizing = $state(false);
|
|
67
65
|
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
66
|
+
// What may start a drag, decided PER POINTERDOWN from the real event — no
|
|
67
|
+
// cached zones, no reactive state, nothing to fall out of sync. neodrag's
|
|
68
|
+
// `shouldStart` hook runs on the initiating pointer event; returning false
|
|
69
|
+
// vetoes the drag. Because this is a pure function of that event, it's correct
|
|
70
|
+
// after resizes, re-renders, or anything else — the ctrl-drag can't break.
|
|
71
|
+
// • Ctrl held → the WHOLE pane is a handle (read live off the event).
|
|
72
|
+
// • otherwise → only the handle bar, and never a resize handle / control
|
|
73
|
+
// (those carry data-pane-control).
|
|
74
|
+
const dragGate: Plugin = {
|
|
75
|
+
name: 'era:pane-drag-gate',
|
|
76
|
+
shouldStart(_ctx, _state, event) {
|
|
77
|
+
const e = event as PointerEvent;
|
|
78
|
+
const target = e.target as Element | null;
|
|
79
|
+
if (!target) return false;
|
|
80
|
+
if (e.ctrlKey) return true;
|
|
81
|
+
if (target.closest('[data-pane-control]')) return false;
|
|
82
|
+
return target.closest('[data-pane-handle]') != null;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// Ctrl held is ALSO tracked reactively — but only for the visual affordances
|
|
87
|
+
// (grab cursor, no text selection, inert tabs), never for the drag itself. If
|
|
88
|
+
// this lags the keypress, the drag still works (the gate reads the event); the
|
|
89
|
+
// styling just catches up a frame later. blur resets it so a Ctrl released
|
|
90
|
+
// off-window doesn't stick.
|
|
73
91
|
let ctrlHeld = $state(false);
|
|
74
92
|
$effect(() => {
|
|
75
93
|
const sync = (e: KeyboardEvent) => (ctrlHeld = e.ctrlKey);
|
|
@@ -84,31 +102,6 @@
|
|
|
84
102
|
};
|
|
85
103
|
});
|
|
86
104
|
|
|
87
|
-
// The handle bar is the drag zone. neodrag's `controls` plugin measures that
|
|
88
|
-
// zone once at setup and only refreshes it mid-drag, so after a resize the
|
|
89
|
-
// widened bar keeps the old (narrow) zone and its new area won't start a drag.
|
|
90
|
-
// Recompute it by dropping controls (→ null) and re-adding: a Compartment
|
|
91
|
-
// null→plugin swap re-runs the plugin's setup, re-measuring the handle. Two
|
|
92
|
-
// states drop it to null:
|
|
93
|
-
// • resizing — the grip owns the pointer, you can't drag anyway.
|
|
94
|
-
// • Ctrl held — no allow/block restriction, so the WHOLE pane is a drag handle
|
|
95
|
-
// (ctrl-drag). Resize handles keep resizing because their own pointerdown
|
|
96
|
-
// stops propagation before neodrag sees it.
|
|
97
|
-
// Read BOTH flags into locals first: `resizing || ctrlHeld` would short-circuit
|
|
98
|
-
// while resizing and drop the ctrlHeld reactive dependency, so a resize could
|
|
99
|
-
// leave ctrl-drag un-tracked until something else re-ran this. Assigning both
|
|
100
|
-
// forces the compartment to always depend on both.
|
|
101
|
-
const controlsComp = Compartment.of(() => {
|
|
102
|
-
const isResizing = resizing;
|
|
103
|
-
const isCtrl = ctrlHeld;
|
|
104
|
-
return isResizing || isCtrl
|
|
105
|
-
? null
|
|
106
|
-
: controls({
|
|
107
|
-
allow: ControlFrom.selector('[data-pane-handle]'),
|
|
108
|
-
block: ControlFrom.selector('[data-pane-control]')
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
|
|
112
105
|
// Dev aid: tint the grab zones so you can see them while tuning geometry. Off
|
|
113
106
|
// in production — flip to true when adjusting the handle placement above.
|
|
114
107
|
const SHOW_RESIZE_ZONES = false;
|
|
@@ -252,8 +245,8 @@
|
|
|
252
245
|
ref!.style.marginLeft = '';
|
|
253
246
|
ref!.style.marginTop = '';
|
|
254
247
|
}
|
|
255
|
-
//
|
|
256
|
-
// the
|
|
248
|
+
// `resizing` now only suppresses the ctrl grab-cursor while the grip is
|
|
249
|
+
// active (the drag gate reads the DOM live, so nothing to re-measure).
|
|
257
250
|
resizing = false;
|
|
258
251
|
handle.releasePointerCapture(ev.pointerId);
|
|
259
252
|
handle.removeEventListener('pointermove', onMove);
|
|
@@ -301,9 +294,9 @@
|
|
|
301
294
|
style:width={size ? `${size.width}px` : undefined}
|
|
302
295
|
style:height={size ? `${size.height}px` : undefined}
|
|
303
296
|
{@attach draggable(() => [
|
|
304
|
-
//
|
|
305
|
-
//
|
|
306
|
-
|
|
297
|
+
// Gates which pointerdown starts a drag: handle bar only, or the whole pane
|
|
298
|
+
// while Ctrl is held. Stateless — decided live off the event. See above.
|
|
299
|
+
dragGate,
|
|
307
300
|
// Exposes data-neodrag-state="idle | dragging" on the root — the drag-only
|
|
308
301
|
// layer-promotion hook hangs off it.
|
|
309
302
|
stateMarker(),
|