@signal9/era-ui 1.7.1 → 1.7.3
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.
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
3
3
|
import { Button } from '../button';
|
|
4
|
+
import { cn } from '../../utils/index.js';
|
|
4
5
|
import X from '@lucide/svelte/icons/x';
|
|
5
6
|
|
|
6
7
|
let {
|
|
@@ -17,13 +18,16 @@
|
|
|
17
18
|
corner). A clean click still closes — neodrag only starts a drag on pointer
|
|
18
19
|
movement, and it suppresses the trailing click after an actual drag, so a
|
|
19
20
|
stationary click fires immediately with no delay. -->
|
|
21
|
+
<!-- Sized to h-xxs (matching the tab pills' highlight height) rather than the
|
|
22
|
+
icon default (h-xs), so the close hover box and the active-tab highlight are
|
|
23
|
+
the same size in the handle bar; aspect-square keeps it a square. -->
|
|
20
24
|
<Button
|
|
21
25
|
bind:ref
|
|
22
26
|
icon
|
|
23
27
|
size="icon"
|
|
24
28
|
tone="destructive"
|
|
25
29
|
aria-label="Close"
|
|
26
|
-
class={className}
|
|
30
|
+
class={cn('h-(--era-h-xxs) min-w-(--era-h-xxs)', className)}
|
|
27
31
|
{...restProps}
|
|
28
32
|
>
|
|
29
33
|
<X class="size-(--era-h-xs)" />
|
|
@@ -65,13 +65,21 @@
|
|
|
65
65
|
|
|
66
66
|
let resizing = $state(false);
|
|
67
67
|
|
|
68
|
-
//
|
|
69
|
-
// only refreshes it mid-drag
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
|
|
68
|
+
// The handle bar is the drag zone. neodrag's `controls` plugin measures that
|
|
69
|
+
// zone once at setup and only refreshes it mid-drag, so after a resize the
|
|
70
|
+
// widened bar keeps the old (narrow) zone and its new area won't start a drag.
|
|
71
|
+
// Recompute it by dropping controls while resizing and re-adding on release: a
|
|
72
|
+
// Compartment null→plugin swap re-runs the plugin's setup, re-measuring the
|
|
73
|
+
// handle at its new width — without re-initializing the whole draggable. You
|
|
74
|
+
// can't drag mid-resize anyway (the grip owns the pointer).
|
|
75
|
+
const controlsComp = Compartment.of(() =>
|
|
76
|
+
resizing
|
|
77
|
+
? null
|
|
78
|
+
: controls({
|
|
79
|
+
allow: ControlFrom.selector('[data-pane-handle]'),
|
|
80
|
+
block: ControlFrom.selector('[data-pane-control]')
|
|
81
|
+
})
|
|
82
|
+
);
|
|
75
83
|
|
|
76
84
|
// Corner-grip resize. The grip sits outside the handle allow-zone and is
|
|
77
85
|
// marked data-pane-control, so a drag can never start from it. Pointer
|
|
@@ -96,50 +104,22 @@
|
|
|
96
104
|
};
|
|
97
105
|
};
|
|
98
106
|
const onUp = (ev: PointerEvent) => {
|
|
107
|
+
// Clearing `resizing` re-adds controls (see controlsComp), re-measuring
|
|
108
|
+
// the handle zone at the new size.
|
|
99
109
|
resizing = false;
|
|
100
110
|
grip.releasePointerCapture(ev.pointerId);
|
|
101
111
|
grip.removeEventListener('pointermove', onMove);
|
|
102
112
|
grip.removeEventListener('pointerup', onUp);
|
|
103
|
-
// Recompute the handle drag-zone at the new size (see dragGeneration).
|
|
104
|
-
dragGeneration += 1;
|
|
105
113
|
};
|
|
106
114
|
grip.addEventListener('pointermove', onMove);
|
|
107
115
|
grip.addEventListener('pointerup', onUp);
|
|
108
116
|
}
|
|
109
|
-
|
|
110
|
-
// Reading dragGeneration ties this attachment's identity to it, so a resize
|
|
111
|
-
// re-creates the draggable and re-runs controls' setup (fresh handle zone).
|
|
112
|
-
// Position/disabled stay reactive without re-init via their Compartments.
|
|
113
|
-
const paneDraggable = $derived.by(() => {
|
|
114
|
-
void dragGeneration;
|
|
115
|
-
return draggable(() => [
|
|
116
|
-
// The handle bar initiates a drag; interactive controls inside it
|
|
117
|
-
// (close button, tab triggers) are carved back out so they click, not drag.
|
|
118
|
-
controls({
|
|
119
|
-
allow: ControlFrom.selector('[data-pane-handle]'),
|
|
120
|
-
block: ControlFrom.selector('[data-pane-control]')
|
|
121
|
-
}),
|
|
122
|
-
// Exposes data-neodrag-state="idle | dragging" (and a drag count) on
|
|
123
|
-
// the root — the hover-highlight and layer-promotion hooks hang off it.
|
|
124
|
-
stateMarker(),
|
|
125
|
-
events({
|
|
126
|
-
onDragStart,
|
|
127
|
-
onDrag: (data) => {
|
|
128
|
-
sync(data);
|
|
129
|
-
onDrag?.(data);
|
|
130
|
-
},
|
|
131
|
-
onDragEnd: (data) => {
|
|
132
|
-
sync(data);
|
|
133
|
-
onDragEnd?.(data);
|
|
134
|
-
}
|
|
135
|
-
}),
|
|
136
|
-
positionComp,
|
|
137
|
-
disabledComp,
|
|
138
|
-
...(typeof plugins === 'function' ? plugins() : plugins)
|
|
139
|
-
]);
|
|
140
|
-
});
|
|
141
117
|
</script>
|
|
142
118
|
|
|
119
|
+
<!-- Size via style: DIRECTIVES, not a style="…" string. neodrag positions the
|
|
120
|
+
pane by writing element.style.transform imperatively; a whole-attribute
|
|
121
|
+
style binding would clobber that transform on every size change, snapping
|
|
122
|
+
the pane to 0,0 mid-resize. Directives set individual properties only. -->
|
|
143
123
|
<div
|
|
144
124
|
bind:this={ref}
|
|
145
125
|
class={cn(
|
|
@@ -154,9 +134,31 @@
|
|
|
154
134
|
'data-[neodrag-state=dragging]:will-change-transform',
|
|
155
135
|
className
|
|
156
136
|
)}
|
|
157
|
-
style={size ? `width:${size.width}px;height:${size.height}px` : undefined}
|
|
158
137
|
{...restProps}
|
|
159
|
-
{
|
|
138
|
+
style:width={size ? `${size.width}px` : undefined}
|
|
139
|
+
style:height={size ? `${size.height}px` : undefined}
|
|
140
|
+
{@attach draggable(() => [
|
|
141
|
+
// controlsComp restricts drags to the handle bar (and carves interactive
|
|
142
|
+
// controls back out); it re-measures the handle after a resize. See above.
|
|
143
|
+
controlsComp,
|
|
144
|
+
// Exposes data-neodrag-state="idle | dragging" on the root — the drag-only
|
|
145
|
+
// layer-promotion hook hangs off it.
|
|
146
|
+
stateMarker(),
|
|
147
|
+
events({
|
|
148
|
+
onDragStart,
|
|
149
|
+
onDrag: (data) => {
|
|
150
|
+
sync(data);
|
|
151
|
+
onDrag?.(data);
|
|
152
|
+
},
|
|
153
|
+
onDragEnd: (data) => {
|
|
154
|
+
sync(data);
|
|
155
|
+
onDragEnd?.(data);
|
|
156
|
+
}
|
|
157
|
+
}),
|
|
158
|
+
positionComp,
|
|
159
|
+
disabledComp,
|
|
160
|
+
...(typeof plugins === 'function' ? plugins() : plugins)
|
|
161
|
+
])}
|
|
160
162
|
>
|
|
161
163
|
{@render children?.()}
|
|
162
164
|
{#if resizable}
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
bind:ref
|
|
18
18
|
data-pane-control
|
|
19
19
|
class={cn(
|
|
20
|
-
'flex cursor-pointer items-center gap-(--era-gap) rounded-(--era-rd-xs) px-(--era-inset-sm)
|
|
20
|
+
'flex h-(--era-h-xxs) cursor-pointer items-center gap-(--era-gap) rounded-(--era-rd-xs) px-(--era-inset-sm) text-body leading-none text-muted outline-none select-none hover:text-fg focus-visible:bg-(--era-highlight) data-[state=active]:bg-hover data-[state=active]:text-bright',
|
|
21
21
|
className
|
|
22
22
|
)}
|
|
23
23
|
{...restProps}
|