@invopop/popui 0.1.100 → 0.1.102
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.
|
@@ -3,8 +3,9 @@ export declare const SIDEBAR_WIDTH_STORAGE_KEY = "sidebar_width";
|
|
|
3
3
|
export declare const SIDEBAR_COOKIE_MAX_AGE: number;
|
|
4
4
|
export declare const SIDEBAR_WIDTH = "16rem";
|
|
5
5
|
export declare const SIDEBAR_WIDTH_MOBILE = "18rem";
|
|
6
|
-
export declare const SIDEBAR_WIDTH_ICON = "
|
|
6
|
+
export declare const SIDEBAR_WIDTH_ICON = "3.5rem";
|
|
7
|
+
export declare const SIDEBAR_WIDTH_ICON_PX = 56;
|
|
7
8
|
export declare const SIDEBAR_KEYBOARD_SHORTCUT = ".";
|
|
8
|
-
export declare const SIDEBAR_MIN_WIDTH_PX =
|
|
9
|
+
export declare const SIDEBAR_MIN_WIDTH_PX = 180;
|
|
9
10
|
export declare const SIDEBAR_MAX_WIDTH_PX = 384;
|
|
10
11
|
export declare const SIDEBAR_DRAG_THRESHOLD_PX = 4;
|
|
@@ -3,8 +3,9 @@ export const SIDEBAR_WIDTH_STORAGE_KEY = 'sidebar_width';
|
|
|
3
3
|
export const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
|
|
4
4
|
export const SIDEBAR_WIDTH = '16rem';
|
|
5
5
|
export const SIDEBAR_WIDTH_MOBILE = '18rem';
|
|
6
|
-
export const SIDEBAR_WIDTH_ICON = '
|
|
6
|
+
export const SIDEBAR_WIDTH_ICON = '3.5rem';
|
|
7
|
+
export const SIDEBAR_WIDTH_ICON_PX = 56;
|
|
7
8
|
export const SIDEBAR_KEYBOARD_SHORTCUT = '.';
|
|
8
|
-
export const SIDEBAR_MIN_WIDTH_PX =
|
|
9
|
+
export const SIDEBAR_MIN_WIDTH_PX = 180;
|
|
9
10
|
export const SIDEBAR_MAX_WIDTH_PX = 384;
|
|
10
11
|
export const SIDEBAR_DRAG_THRESHOLD_PX = 4;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import ShortcutWrapper from '../ShortcutWrapper.svelte'
|
|
5
5
|
import TooltipContent from '../tooltip/tooltip-content.svelte'
|
|
6
6
|
import { cn, type WithElementRef } from '../utils.js'
|
|
7
|
-
import { SIDEBAR_DRAG_THRESHOLD_PX,
|
|
7
|
+
import { SIDEBAR_DRAG_THRESHOLD_PX, SIDEBAR_WIDTH_ICON_PX } from './constants.js'
|
|
8
8
|
import { useSidebar } from './context.svelte.js'
|
|
9
9
|
|
|
10
10
|
let {
|
|
@@ -20,8 +20,11 @@
|
|
|
20
20
|
let dragStartWidthPx = 0
|
|
21
21
|
let dragMoved = false
|
|
22
22
|
let dragDirection: 1 | -1 = 1
|
|
23
|
+
let activePointerId: number | null = null
|
|
24
|
+
let resizeCommitted = false
|
|
23
25
|
|
|
24
26
|
let isDragging = $state(false)
|
|
27
|
+
let isPointerDown = $state(false)
|
|
25
28
|
let tooltipOpen = $state(false)
|
|
26
29
|
let cursorX = $state(0)
|
|
27
30
|
let cursorY = $state(0)
|
|
@@ -37,6 +40,30 @@
|
|
|
37
40
|
}
|
|
38
41
|
})
|
|
39
42
|
|
|
43
|
+
$effect(() => {
|
|
44
|
+
if ((isDragging || isPointerDown) && tooltipOpen) {
|
|
45
|
+
tooltipOpen = false
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
let globalDragStyleEl: HTMLStyleElement | null = null
|
|
50
|
+
|
|
51
|
+
function setGlobalDragStyles() {
|
|
52
|
+
if (globalDragStyleEl) return
|
|
53
|
+
globalDragStyleEl = document.createElement('style')
|
|
54
|
+
globalDragStyleEl.textContent =
|
|
55
|
+
'*, *::before, *::after { cursor: col-resize !important; user-select: none !important; }'
|
|
56
|
+
document.head.appendChild(globalDragStyleEl)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function clearGlobalDragStyles() {
|
|
60
|
+
globalDragStyleEl?.remove()
|
|
61
|
+
globalDragStyleEl = null
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const POST_DRAG_CLICK_GUARD_MS = 250
|
|
65
|
+
let dragEndTime = 0
|
|
66
|
+
|
|
40
67
|
function onPointerEnter(e: PointerEvent) {
|
|
41
68
|
const sidebarRoot = (e.currentTarget as HTMLElement).closest('[data-slot="sidebar"]')
|
|
42
69
|
dragDirection = sidebarRoot?.getAttribute('data-side') === 'right' ? -1 : 1
|
|
@@ -44,15 +71,35 @@
|
|
|
44
71
|
cursorY = e.clientY
|
|
45
72
|
}
|
|
46
73
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
74
|
+
function onPointerMoveOnTrigger(e: PointerEvent) {
|
|
75
|
+
if (activePointerId !== null) return
|
|
76
|
+
cursorX = e.clientX
|
|
77
|
+
cursorY = e.clientY
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function endDrag() {
|
|
81
|
+
if (activePointerId !== null) {
|
|
82
|
+
window.removeEventListener('pointermove', onWindowPointerMove)
|
|
83
|
+
window.removeEventListener('pointerup', onWindowPointerUp)
|
|
84
|
+
window.removeEventListener('pointercancel', onWindowPointerUp)
|
|
85
|
+
activePointerId = null
|
|
86
|
+
}
|
|
87
|
+
clearGlobalDragStyles()
|
|
88
|
+
isDragging = false
|
|
89
|
+
isPointerDown = false
|
|
90
|
+
sidebar.isResizing = false
|
|
91
|
+
resizeCommitted = false
|
|
92
|
+
if (dragMoved) {
|
|
93
|
+
dragEndTime = Date.now()
|
|
94
|
+
dragMoved = false
|
|
95
|
+
}
|
|
96
|
+
}
|
|
50
97
|
|
|
51
|
-
function
|
|
98
|
+
function onWindowPointerMove(e: PointerEvent) {
|
|
99
|
+
if (e.pointerId !== activePointerId) return
|
|
52
100
|
cursorX = e.clientX
|
|
53
101
|
cursorY = e.clientY
|
|
54
|
-
|
|
55
|
-
if (!button.hasPointerCapture(e.pointerId)) return
|
|
102
|
+
if (resizeCommitted) return
|
|
56
103
|
const delta = (e.clientX - dragStartX) * dragDirection
|
|
57
104
|
if (Math.abs(delta) > SIDEBAR_DRAG_THRESHOLD_PX) {
|
|
58
105
|
dragMoved = true
|
|
@@ -63,26 +110,14 @@
|
|
|
63
110
|
if (!dragMoved) return
|
|
64
111
|
if (sidebar.state === 'collapsed') {
|
|
65
112
|
if (delta > 0) {
|
|
66
|
-
|
|
67
|
-
document.body.style.cursor = ''
|
|
68
|
-
document.body.style.userSelect = ''
|
|
69
|
-
isDragging = false
|
|
70
|
-
sidebar.isResizing = false
|
|
71
|
-
dragMoved = false
|
|
72
|
-
dragEndTime = Date.now()
|
|
113
|
+
resizeCommitted = true
|
|
73
114
|
sidebar.setOpen(true)
|
|
74
115
|
}
|
|
75
116
|
return
|
|
76
117
|
}
|
|
77
118
|
const targetWidth = dragStartWidthPx + delta
|
|
78
|
-
if (targetWidth <
|
|
79
|
-
|
|
80
|
-
document.body.style.cursor = ''
|
|
81
|
-
document.body.style.userSelect = ''
|
|
82
|
-
isDragging = false
|
|
83
|
-
sidebar.isResizing = false
|
|
84
|
-
dragMoved = false
|
|
85
|
-
dragEndTime = Date.now()
|
|
119
|
+
if (targetWidth < SIDEBAR_WIDTH_ICON_PX) {
|
|
120
|
+
resizeCommitted = true
|
|
86
121
|
sidebar.resetWidth()
|
|
87
122
|
sidebar.setOpen(false)
|
|
88
123
|
return
|
|
@@ -90,35 +125,32 @@
|
|
|
90
125
|
sidebar.setWidth(targetWidth)
|
|
91
126
|
}
|
|
92
127
|
|
|
128
|
+
function onWindowPointerUp(e: PointerEvent) {
|
|
129
|
+
if (e.pointerId !== activePointerId) return
|
|
130
|
+
endDrag()
|
|
131
|
+
}
|
|
132
|
+
|
|
93
133
|
function onPointerDown(e: PointerEvent) {
|
|
94
134
|
if (sidebar.isMobile) return
|
|
95
|
-
|
|
96
|
-
const
|
|
135
|
+
if (e.button !== 0) return
|
|
136
|
+
const target = e.currentTarget as HTMLElement
|
|
137
|
+
const sidebarRoot = target.closest('[data-slot="sidebar"]')
|
|
97
138
|
dragDirection = sidebarRoot?.getAttribute('data-side') === 'right' ? -1 : 1
|
|
98
139
|
|
|
99
140
|
const container = sidebarRoot?.querySelector('[data-slot="sidebar-container"]')
|
|
100
141
|
dragStartWidthPx = container instanceof HTMLElement ? container.offsetWidth : 256
|
|
101
142
|
dragStartX = e.clientX
|
|
102
143
|
dragMoved = false
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
144
|
+
activePointerId = e.pointerId
|
|
145
|
+
isPointerDown = true
|
|
146
|
+
tooltipOpen = false
|
|
147
|
+
setGlobalDragStyles()
|
|
148
|
+
window.addEventListener('pointermove', onWindowPointerMove)
|
|
149
|
+
window.addEventListener('pointerup', onWindowPointerUp)
|
|
150
|
+
window.addEventListener('pointercancel', onWindowPointerUp)
|
|
106
151
|
}
|
|
107
152
|
|
|
108
|
-
|
|
109
|
-
const button = e.currentTarget as HTMLButtonElement
|
|
110
|
-
if (button.hasPointerCapture(e.pointerId)) button.releasePointerCapture(e.pointerId)
|
|
111
|
-
document.body.style.cursor = ''
|
|
112
|
-
document.body.style.userSelect = ''
|
|
113
|
-
isDragging = false
|
|
114
|
-
sidebar.isResizing = false
|
|
115
|
-
if (dragMoved) {
|
|
116
|
-
dragEndTime = Date.now()
|
|
117
|
-
dragMoved = false
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const DOUBLE_CLICK_DELAY_MS = 300
|
|
153
|
+
const DOUBLE_CLICK_DELAY_MS = 150
|
|
122
154
|
let pendingClickTimer: ReturnType<typeof setTimeout> | undefined
|
|
123
155
|
|
|
124
156
|
function onClick(e: MouseEvent) {
|
|
@@ -148,7 +180,7 @@
|
|
|
148
180
|
delayDuration={TOOLTIP_HOVER_DELAY_MS}
|
|
149
181
|
disableHoverableContent
|
|
150
182
|
>
|
|
151
|
-
<TooltipPrimitive.Trigger
|
|
183
|
+
<TooltipPrimitive.Trigger>
|
|
152
184
|
{#snippet child({ props })}
|
|
153
185
|
{@const buttonProps = props as HTMLButtonAttributes}
|
|
154
186
|
<button
|
|
@@ -160,17 +192,12 @@
|
|
|
160
192
|
}}
|
|
161
193
|
onpointermove={(e) => {
|
|
162
194
|
buttonProps.onpointermove?.(e)
|
|
163
|
-
|
|
195
|
+
onPointerMoveOnTrigger(e)
|
|
164
196
|
}}
|
|
165
197
|
onpointerdown={(e) => {
|
|
166
198
|
buttonProps.onpointerdown?.(e)
|
|
167
199
|
onPointerDown(e)
|
|
168
200
|
}}
|
|
169
|
-
onpointerup={(e) => {
|
|
170
|
-
buttonProps.onpointerup?.(e)
|
|
171
|
-
onPointerUp(e)
|
|
172
|
-
}}
|
|
173
|
-
onpointercancel={onPointerUp}
|
|
174
201
|
onclick={(e) => {
|
|
175
202
|
buttonProps.onclick?.(e)
|
|
176
203
|
onClick(e)
|
|
@@ -203,19 +230,24 @@
|
|
|
203
230
|
side="bottom"
|
|
204
231
|
align="center"
|
|
205
232
|
sideOffset={TOOLTIP_CURSOR_OFFSET}
|
|
206
|
-
class="px-3 py-2"
|
|
207
233
|
>
|
|
208
|
-
<div class="flex flex-col gap-1
|
|
234
|
+
<div class="flex flex-col gap-1">
|
|
209
235
|
{#if sidebar.state === 'expanded'}
|
|
210
|
-
<div
|
|
236
|
+
<div class="flex w-full items-center justify-between gap-3">
|
|
237
|
+
<span>Drag to resize</span>
|
|
238
|
+
<div class="flex items-center gap-0.5 opacity-0">
|
|
239
|
+
<ShortcutWrapper size="sm" theme="navigation">⌘</ShortcutWrapper>
|
|
240
|
+
<ShortcutWrapper size="sm" theme="navigation">.</ShortcutWrapper>
|
|
241
|
+
</div>
|
|
242
|
+
</div>
|
|
211
243
|
{/if}
|
|
212
|
-
<div class="flex items-center justify-between gap-3">
|
|
244
|
+
<div class="flex w-full items-center justify-between gap-3">
|
|
213
245
|
<span>
|
|
214
246
|
{sidebar.state === 'expanded' ? 'Click to collapse' : 'Click to expand'}
|
|
215
247
|
</span>
|
|
216
|
-
<div class="flex items-center gap-
|
|
217
|
-
<ShortcutWrapper size="
|
|
218
|
-
<ShortcutWrapper size="
|
|
248
|
+
<div class="flex items-center gap-0.5">
|
|
249
|
+
<ShortcutWrapper size="sm" theme="navigation">⌘</ShortcutWrapper>
|
|
250
|
+
<ShortcutWrapper size="sm" theme="navigation">.</ShortcutWrapper>
|
|
219
251
|
</div>
|
|
220
252
|
</div>
|
|
221
253
|
</div>
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
<div
|
|
74
74
|
data-slot="sidebar-gap"
|
|
75
75
|
class={cn(
|
|
76
|
-
'relative w-(--sidebar-width) bg-transparent transition-[width] duration-
|
|
76
|
+
'relative w-(--sidebar-width) bg-transparent transition-[width] duration-150 ease-linear group-data-[resizing=true]:transition-none',
|
|
77
77
|
'group-data-[collapsible=offcanvas]:w-0',
|
|
78
78
|
'group-data-[side=right]:rotate-180',
|
|
79
79
|
variant === 'floating' || variant === 'inset'
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
<div
|
|
85
85
|
data-slot="sidebar-container"
|
|
86
86
|
class={cn(
|
|
87
|
-
'fixed inset-y-0 z-50 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-
|
|
87
|
+
'fixed inset-y-0 z-50 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-150 ease-linear group-data-[resizing=true]:transition-none md:flex',
|
|
88
88
|
side === 'left'
|
|
89
89
|
? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'
|
|
90
90
|
: 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
{side}
|
|
25
25
|
{...rest}
|
|
26
26
|
class={cn(
|
|
27
|
-
'bg-background-default-negative border border-border-inverse z-
|
|
27
|
+
'bg-background-default-negative border border-border-inverse z-1002 rounded-md px-2 py-1 text-base font-medium text-foreground-inverse shadow-md',
|
|
28
28
|
className
|
|
29
29
|
)}
|
|
30
30
|
>
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
{#snippet child({ props })}
|
|
35
35
|
<div
|
|
36
36
|
class={cn(
|
|
37
|
-
'bg-background-default-negative z-
|
|
38
|
-
'data-[side=top]:translate-x-1/2 data-[side=top]:translate-y-[calc(-50
|
|
39
|
-
'data-[side=bottom]:-translate-x-1/2 data-[side=bottom]:-translate-y-[calc(-50
|
|
40
|
-
'data-[side=right]:translate-x-[calc(50
|
|
41
|
-
'data-[side=left]:-translate-y-[calc(50
|
|
37
|
+
'bg-background-default-negative z-1002 size-2.5 rotate-45 rounded-xs',
|
|
38
|
+
'data-[side=top]:translate-x-1/2 data-[side=top]:translate-y-[calc(-50%+2px)]',
|
|
39
|
+
'data-[side=bottom]:-translate-x-1/2 data-[side=bottom]:-translate-y-[calc(-50%+1px)]',
|
|
40
|
+
'data-[side=right]:translate-x-[calc(50%+2px)] data-[side=right]:translate-y-1/2',
|
|
41
|
+
'data-[side=left]:-translate-y-[calc(50%-3px)]',
|
|
42
42
|
arrowClasses
|
|
43
43
|
)}
|
|
44
44
|
{...props}
|