@invopop/popui 0.1.93 → 0.1.95
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/MenuItem.svelte
CHANGED
|
@@ -1,22 +1,13 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import MenuItem from './MenuItem.svelte'
|
|
3
|
-
import { flip, shift, offset } from 'svelte-floating-ui/dom'
|
|
4
|
-
import { createFloatingActions } from 'svelte-floating-ui'
|
|
5
3
|
import clsx from 'clsx'
|
|
6
|
-
import
|
|
4
|
+
import { cn } from './utils.js'
|
|
5
|
+
import type { MenuItemProps } from './types.ts'
|
|
7
6
|
import { Icon, type IconSource } from '@steeze-ui/svelte-icon'
|
|
8
7
|
import { ChevronDown, ChevronRight } from '@invopop/ui-icons'
|
|
9
|
-
import { FolderL } from '@invopop/ui-icons'
|
|
10
8
|
import { resolveIcon } from './helpers.js'
|
|
11
|
-
import DrawerContext from './DrawerContext.svelte'
|
|
12
9
|
import TagBeta from './TagBeta.svelte'
|
|
13
10
|
|
|
14
|
-
const [floatingRef, floatingContent] = createFloatingActions({
|
|
15
|
-
strategy: 'absolute',
|
|
16
|
-
placement: 'bottom-start',
|
|
17
|
-
middleware: [offset(-4), flip(), shift()]
|
|
18
|
-
})
|
|
19
|
-
|
|
20
11
|
let {
|
|
21
12
|
label = '',
|
|
22
13
|
url = '',
|
|
@@ -24,50 +15,31 @@
|
|
|
24
15
|
collapsable = false,
|
|
25
16
|
open = $bindable(false),
|
|
26
17
|
active = false,
|
|
27
|
-
collapsedSidebar = false,
|
|
28
18
|
iconTheme = 'default',
|
|
29
19
|
icon = undefined,
|
|
20
|
+
imageUrl = undefined,
|
|
30
21
|
beta = false,
|
|
31
22
|
children = undefined,
|
|
23
|
+
action,
|
|
24
|
+
ref = $bindable(null),
|
|
25
|
+
class: className,
|
|
32
26
|
onclick
|
|
33
27
|
}: MenuItemProps = $props()
|
|
34
28
|
|
|
35
29
|
let resolvedIcon: IconSource | undefined = $state()
|
|
36
|
-
let hovered = $state(false)
|
|
37
|
-
let highlight = $state(false)
|
|
38
|
-
let leaveHoverTimeout: ReturnType<typeof setTimeout> | null = null
|
|
39
30
|
let itemStyles = $derived(
|
|
40
|
-
clsx(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
},
|
|
47
|
-
{ 'w-full px-2 py-1.5 h-8': !collapsedSidebar },
|
|
48
|
-
{
|
|
49
|
-
'bg-background-selected-inverse text-white': active
|
|
50
|
-
},
|
|
51
|
-
{ 'hover:bg-background-selected-inverse': !active }
|
|
52
|
-
)
|
|
53
|
-
)
|
|
54
|
-
let iconStyles = $derived(
|
|
55
|
-
clsx({ 'group-hover:text-white text-icon-inverse-bold!': collapsedSidebar })
|
|
31
|
+
clsx('flex-1 min-w-0 px-2 py-1.5 h-8', {
|
|
32
|
+
'text-foreground-inverse font-medium': !isFolderItem,
|
|
33
|
+
'text-foreground-inverse-secondary': isFolderItem && !active,
|
|
34
|
+
'bg-background-selected-inverse text-white': active,
|
|
35
|
+
'hover:bg-background-selected-inverse': !active
|
|
36
|
+
})
|
|
56
37
|
)
|
|
57
38
|
let wrapperStyles = $derived(
|
|
58
39
|
clsx({
|
|
59
|
-
'ml-4 border-l border-white-10 pl-2 pt-0.5 relative': isFolderItem
|
|
40
|
+
'group/menu-item ml-4 border-l border-white-10 pl-2 pt-0.5 relative': isFolderItem
|
|
60
41
|
})
|
|
61
42
|
)
|
|
62
|
-
let items = $derived([
|
|
63
|
-
{ label, value: url, selected: active, icon: resolvedIcon },
|
|
64
|
-
...(children || []).map((c) => ({
|
|
65
|
-
label: c.label || '',
|
|
66
|
-
value: c.url || '',
|
|
67
|
-
selected: c.active,
|
|
68
|
-
icon: FolderL
|
|
69
|
-
}))
|
|
70
|
-
] as DrawerOption[])
|
|
71
43
|
|
|
72
44
|
$effect(() => {
|
|
73
45
|
resolveIcon(icon).then((res) => (resolvedIcon = res))
|
|
@@ -80,84 +52,71 @@
|
|
|
80
52
|
|
|
81
53
|
onclick?.(url)
|
|
82
54
|
}
|
|
83
|
-
|
|
84
|
-
function handleClickChild(value: AnyProp) {
|
|
85
|
-
hovered = false
|
|
86
|
-
onclick?.(value as string)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function handleHover() {
|
|
90
|
-
highlight = true
|
|
91
|
-
if (leaveHoverTimeout) {
|
|
92
|
-
clearTimeout(leaveHoverTimeout)
|
|
93
|
-
}
|
|
94
|
-
hovered = true
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function handleBlur() {
|
|
98
|
-
highlight = false
|
|
99
|
-
leaveHoverTimeout = setTimeout(() => {
|
|
100
|
-
hovered = false
|
|
101
|
-
}, 200)
|
|
102
|
-
}
|
|
103
55
|
</script>
|
|
104
56
|
|
|
105
|
-
<div class={wrapperStyles}>
|
|
106
|
-
{#if isFolderItem
|
|
107
|
-
<div
|
|
57
|
+
<div bind:this={ref} class={cn(wrapperStyles, className)} data-menu-item-root>
|
|
58
|
+
{#if isFolderItem}
|
|
59
|
+
<div
|
|
60
|
+
class={clsx('border-l border-white h-3 w-px absolute top-3.5 left-0 -m-px', {
|
|
61
|
+
'opacity-0 group-hover/menu-item:opacity-100': !active
|
|
62
|
+
})}
|
|
63
|
+
data-menu-item-tree-indicator
|
|
64
|
+
></div>
|
|
108
65
|
{/if}
|
|
109
|
-
<
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
66
|
+
<div class={clsx('flex items-center', { 'gap-1.5': action })} data-menu-item-row>
|
|
67
|
+
<button
|
|
68
|
+
onclick={handleClick}
|
|
69
|
+
title={label}
|
|
70
|
+
data-menu-item-button
|
|
71
|
+
class="cursor-pointer {itemStyles} text-base border border-transparent flex items-center justify-between hover:text-white focus:text-white rounded-lg"
|
|
72
|
+
>
|
|
73
|
+
<span class="flex items-center space-x-1.5 min-w-0 flex-1" data-menu-item-content>
|
|
74
|
+
{#if imageUrl}
|
|
75
|
+
<img
|
|
76
|
+
src={imageUrl}
|
|
77
|
+
alt={label}
|
|
78
|
+
class="size-4 shrink-0 rounded bg-white object-contain"
|
|
79
|
+
data-menu-item-image
|
|
80
|
+
/>
|
|
81
|
+
{:else if resolvedIcon}
|
|
82
|
+
<Icon
|
|
83
|
+
src={resolvedIcon}
|
|
84
|
+
theme={iconTheme}
|
|
85
|
+
class="h-4 w-4 text-icon-inverse"
|
|
86
|
+
data-menu-item-icon
|
|
87
|
+
/>
|
|
88
|
+
{/if}
|
|
89
|
+
<span class="truncate tracking-normal" data-menu-item-label>{label}</span>
|
|
123
90
|
{#if beta}
|
|
124
91
|
<TagBeta />
|
|
125
92
|
{/if}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
>
|
|
136
|
-
<Icon src={open ? ChevronDown : ChevronRight} class="h-4 w-4 text-white-40" />
|
|
137
|
-
</button>
|
|
138
|
-
{/if}
|
|
139
|
-
</button>
|
|
140
|
-
{#if children?.length}
|
|
141
|
-
{#if collapsedSidebar}
|
|
142
|
-
{#if hovered}
|
|
143
|
-
<div
|
|
144
|
-
use:floatingContent
|
|
145
|
-
role="contentinfo"
|
|
146
|
-
onmouseenter={handleHover}
|
|
147
|
-
onmouseleave={handleBlur}
|
|
148
|
-
class="pt-4 z-30"
|
|
93
|
+
</span>
|
|
94
|
+
{#if collapsable}
|
|
95
|
+
<button
|
|
96
|
+
class="cursor-pointer"
|
|
97
|
+
data-menu-item-chevron
|
|
98
|
+
onclick={(e) => {
|
|
99
|
+
e.stopPropagation()
|
|
100
|
+
open = !open
|
|
101
|
+
}}
|
|
149
102
|
>
|
|
150
|
-
<
|
|
151
|
-
</
|
|
103
|
+
<Icon src={open ? ChevronDown : ChevronRight} class="h-4 w-4 text-white-40" />
|
|
104
|
+
</button>
|
|
152
105
|
{/if}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
</li>
|
|
159
|
-
{/each}
|
|
160
|
-
</ul>
|
|
106
|
+
</button>
|
|
107
|
+
{#if action}
|
|
108
|
+
<span class="shrink-0" data-menu-item-action>
|
|
109
|
+
{@render action()}
|
|
110
|
+
</span>
|
|
161
111
|
{/if}
|
|
112
|
+
</div>
|
|
113
|
+
{#if children?.length && (open || !collapsable)}
|
|
114
|
+
<ul data-menu-item-children>
|
|
115
|
+
{#each children as child}
|
|
116
|
+
<li>
|
|
117
|
+
<MenuItem {...child} isFolderItem {onclick} />
|
|
118
|
+
</li>
|
|
119
|
+
{/each}
|
|
120
|
+
</ul>
|
|
162
121
|
{/if}
|
|
163
122
|
</div>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import MenuItem from './MenuItem.svelte';
|
|
2
2
|
import type { MenuItemProps } from './types.ts';
|
|
3
|
-
declare const MenuItem: import("svelte").Component<MenuItemProps, {}, "open">;
|
|
3
|
+
declare const MenuItem: import("svelte").Component<MenuItemProps, {}, "open" | "ref">;
|
|
4
4
|
type MenuItem = ReturnType<typeof MenuItem>;
|
|
5
5
|
export default MenuItem;
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
bind:ref
|
|
19
19
|
data-slot="alert-dialog-content"
|
|
20
20
|
class={cn(
|
|
21
|
-
'bg-background fixed left-1/2 top-1/2 z-[1002] flex flex-col w-full max-w-lg -translate-x-1/2 -translate-y-1/2 rounded-xl overflow-clip',
|
|
21
|
+
'bg-background border border-border fixed left-1/2 top-1/2 z-[1002] flex flex-col w-full max-w-lg -translate-x-1/2 -translate-y-1/2 rounded-xl overflow-clip',
|
|
22
22
|
className
|
|
23
23
|
)}
|
|
24
24
|
>
|
package/dist/types.d.ts
CHANGED
|
@@ -533,11 +533,14 @@ export interface MenuItemProps {
|
|
|
533
533
|
collapsable?: boolean;
|
|
534
534
|
open?: boolean;
|
|
535
535
|
active?: boolean;
|
|
536
|
-
collapsedSidebar?: boolean;
|
|
537
536
|
iconTheme?: IconTheme;
|
|
538
537
|
icon?: IconSource | string | undefined;
|
|
538
|
+
imageUrl?: string;
|
|
539
539
|
beta?: boolean;
|
|
540
540
|
children?: MenuItemProps[] | undefined;
|
|
541
|
+
action?: Snippet;
|
|
542
|
+
ref?: HTMLDivElement | null;
|
|
543
|
+
class?: string;
|
|
541
544
|
onclick?: (url: string) => void;
|
|
542
545
|
}
|
|
543
546
|
export interface MenuItemCollapsibleProps {
|