@invopop/popui 0.1.100 → 0.1.101
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,6 +20,7 @@
|
|
|
20
20
|
let dragStartWidthPx = 0
|
|
21
21
|
let dragMoved = false
|
|
22
22
|
let dragDirection: 1 | -1 = 1
|
|
23
|
+
let activePointerId: number | null = null
|
|
23
24
|
|
|
24
25
|
let isDragging = $state(false)
|
|
25
26
|
let tooltipOpen = $state(false)
|
|
@@ -29,6 +30,8 @@
|
|
|
29
30
|
const TOOLTIP_HOVER_DELAY_MS = 700
|
|
30
31
|
const TOOLTIP_CURSOR_OFFSET = 12
|
|
31
32
|
|
|
33
|
+
let tooltipDelay = $derived(isDragging ? Number.MAX_SAFE_INTEGER : TOOLTIP_HOVER_DELAY_MS)
|
|
34
|
+
|
|
32
35
|
let cursorAnchor = $derived.by(() => {
|
|
33
36
|
const x = cursorX
|
|
34
37
|
const y = cursorY
|
|
@@ -37,6 +40,9 @@
|
|
|
37
40
|
}
|
|
38
41
|
})
|
|
39
42
|
|
|
43
|
+
const POST_DRAG_CLICK_GUARD_MS = 250
|
|
44
|
+
let dragEndTime = 0
|
|
45
|
+
|
|
40
46
|
function onPointerEnter(e: PointerEvent) {
|
|
41
47
|
const sidebarRoot = (e.currentTarget as HTMLElement).closest('[data-slot="sidebar"]')
|
|
42
48
|
dragDirection = sidebarRoot?.getAttribute('data-side') === 'right' ? -1 : 1
|
|
@@ -44,15 +50,33 @@
|
|
|
44
50
|
cursorY = e.clientY
|
|
45
51
|
}
|
|
46
52
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
53
|
+
function onPointerMoveOnTrigger(e: PointerEvent) {
|
|
54
|
+
if (activePointerId !== null) return
|
|
55
|
+
cursorX = e.clientX
|
|
56
|
+
cursorY = e.clientY
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function endDrag() {
|
|
60
|
+
if (activePointerId !== null) {
|
|
61
|
+
window.removeEventListener('pointermove', onWindowPointerMove)
|
|
62
|
+
window.removeEventListener('pointerup', onWindowPointerUp)
|
|
63
|
+
window.removeEventListener('pointercancel', onWindowPointerUp)
|
|
64
|
+
activePointerId = null
|
|
65
|
+
}
|
|
66
|
+
document.body.style.cursor = ''
|
|
67
|
+
document.body.style.userSelect = ''
|
|
68
|
+
isDragging = false
|
|
69
|
+
sidebar.isResizing = false
|
|
70
|
+
if (dragMoved) {
|
|
71
|
+
dragEndTime = Date.now()
|
|
72
|
+
dragMoved = false
|
|
73
|
+
}
|
|
74
|
+
}
|
|
50
75
|
|
|
51
|
-
function
|
|
76
|
+
function onWindowPointerMove(e: PointerEvent) {
|
|
77
|
+
if (e.pointerId !== activePointerId) return
|
|
52
78
|
cursorX = e.clientX
|
|
53
79
|
cursorY = e.clientY
|
|
54
|
-
const button = e.currentTarget as HTMLButtonElement
|
|
55
|
-
if (!button.hasPointerCapture(e.pointerId)) return
|
|
56
80
|
const delta = (e.clientX - dragStartX) * dragDirection
|
|
57
81
|
if (Math.abs(delta) > SIDEBAR_DRAG_THRESHOLD_PX) {
|
|
58
82
|
dragMoved = true
|
|
@@ -63,26 +87,14 @@
|
|
|
63
87
|
if (!dragMoved) return
|
|
64
88
|
if (sidebar.state === 'collapsed') {
|
|
65
89
|
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()
|
|
90
|
+
endDrag()
|
|
73
91
|
sidebar.setOpen(true)
|
|
74
92
|
}
|
|
75
93
|
return
|
|
76
94
|
}
|
|
77
95
|
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()
|
|
96
|
+
if (targetWidth < SIDEBAR_WIDTH_ICON_PX) {
|
|
97
|
+
endDrag()
|
|
86
98
|
sidebar.resetWidth()
|
|
87
99
|
sidebar.setOpen(false)
|
|
88
100
|
return
|
|
@@ -90,35 +102,31 @@
|
|
|
90
102
|
sidebar.setWidth(targetWidth)
|
|
91
103
|
}
|
|
92
104
|
|
|
105
|
+
function onWindowPointerUp(e: PointerEvent) {
|
|
106
|
+
if (e.pointerId !== activePointerId) return
|
|
107
|
+
endDrag()
|
|
108
|
+
}
|
|
109
|
+
|
|
93
110
|
function onPointerDown(e: PointerEvent) {
|
|
94
111
|
if (sidebar.isMobile) return
|
|
95
|
-
|
|
96
|
-
const
|
|
112
|
+
if (e.button !== 0) return
|
|
113
|
+
const target = e.currentTarget as HTMLElement
|
|
114
|
+
const sidebarRoot = target.closest('[data-slot="sidebar"]')
|
|
97
115
|
dragDirection = sidebarRoot?.getAttribute('data-side') === 'right' ? -1 : 1
|
|
98
116
|
|
|
99
117
|
const container = sidebarRoot?.querySelector('[data-slot="sidebar-container"]')
|
|
100
118
|
dragStartWidthPx = container instanceof HTMLElement ? container.offsetWidth : 256
|
|
101
119
|
dragStartX = e.clientX
|
|
102
120
|
dragMoved = false
|
|
103
|
-
|
|
121
|
+
activePointerId = e.pointerId
|
|
104
122
|
document.body.style.cursor = 'col-resize'
|
|
105
123
|
document.body.style.userSelect = 'none'
|
|
124
|
+
window.addEventListener('pointermove', onWindowPointerMove)
|
|
125
|
+
window.addEventListener('pointerup', onWindowPointerUp)
|
|
126
|
+
window.addEventListener('pointercancel', onWindowPointerUp)
|
|
106
127
|
}
|
|
107
128
|
|
|
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
|
|
129
|
+
const DOUBLE_CLICK_DELAY_MS = 150
|
|
122
130
|
let pendingClickTimer: ReturnType<typeof setTimeout> | undefined
|
|
123
131
|
|
|
124
132
|
function onClick(e: MouseEvent) {
|
|
@@ -145,10 +153,10 @@
|
|
|
145
153
|
|
|
146
154
|
<TooltipPrimitive.Root
|
|
147
155
|
bind:open={tooltipOpen}
|
|
148
|
-
delayDuration={
|
|
156
|
+
delayDuration={tooltipDelay}
|
|
149
157
|
disableHoverableContent
|
|
150
158
|
>
|
|
151
|
-
<TooltipPrimitive.Trigger
|
|
159
|
+
<TooltipPrimitive.Trigger>
|
|
152
160
|
{#snippet child({ props })}
|
|
153
161
|
{@const buttonProps = props as HTMLButtonAttributes}
|
|
154
162
|
<button
|
|
@@ -160,17 +168,12 @@
|
|
|
160
168
|
}}
|
|
161
169
|
onpointermove={(e) => {
|
|
162
170
|
buttonProps.onpointermove?.(e)
|
|
163
|
-
|
|
171
|
+
onPointerMoveOnTrigger(e)
|
|
164
172
|
}}
|
|
165
173
|
onpointerdown={(e) => {
|
|
166
174
|
buttonProps.onpointerdown?.(e)
|
|
167
175
|
onPointerDown(e)
|
|
168
176
|
}}
|
|
169
|
-
onpointerup={(e) => {
|
|
170
|
-
buttonProps.onpointerup?.(e)
|
|
171
|
-
onPointerUp(e)
|
|
172
|
-
}}
|
|
173
|
-
onpointercancel={onPointerUp}
|
|
174
177
|
onclick={(e) => {
|
|
175
178
|
buttonProps.onclick?.(e)
|
|
176
179
|
onClick(e)
|
|
@@ -203,19 +206,24 @@
|
|
|
203
206
|
side="bottom"
|
|
204
207
|
align="center"
|
|
205
208
|
sideOffset={TOOLTIP_CURSOR_OFFSET}
|
|
206
|
-
class="px-3 py-2"
|
|
207
209
|
>
|
|
208
|
-
<div class="flex flex-col gap-1
|
|
210
|
+
<div class="flex flex-col gap-1">
|
|
209
211
|
{#if sidebar.state === 'expanded'}
|
|
210
|
-
<div
|
|
212
|
+
<div class="flex w-full items-center justify-between gap-3">
|
|
213
|
+
<span>Drag to resize</span>
|
|
214
|
+
<div class="flex items-center gap-0.5 opacity-0">
|
|
215
|
+
<ShortcutWrapper size="sm" theme="navigation">⌘</ShortcutWrapper>
|
|
216
|
+
<ShortcutWrapper size="sm" theme="navigation">.</ShortcutWrapper>
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
211
219
|
{/if}
|
|
212
|
-
<div class="flex items-center justify-between gap-3">
|
|
220
|
+
<div class="flex w-full items-center justify-between gap-3">
|
|
213
221
|
<span>
|
|
214
222
|
{sidebar.state === 'expanded' ? 'Click to collapse' : 'Click to expand'}
|
|
215
223
|
</span>
|
|
216
|
-
<div class="flex items-center gap-
|
|
217
|
-
<ShortcutWrapper size="
|
|
218
|
-
<ShortcutWrapper size="
|
|
224
|
+
<div class="flex items-center gap-0.5">
|
|
225
|
+
<ShortcutWrapper size="sm" theme="navigation">⌘</ShortcutWrapper>
|
|
226
|
+
<ShortcutWrapper size="sm" theme="navigation">.</ShortcutWrapper>
|
|
219
227
|
</div>
|
|
220
228
|
</div>
|
|
221
229
|
</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}
|