@invopop/popui 0.1.94 → 0.1.96
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 +72 -107
- package/dist/MenuItem.svelte.d.ts +1 -1
- package/dist/types.d.ts +4 -1
- package/package.json +1 -1
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,40 @@
|
|
|
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
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
30
|
+
let rowStyles = $derived(
|
|
31
|
+
clsx('flex items-center rounded-lg border border-transparent p-1', {
|
|
32
|
+
'gap-1.5': action || collapsable,
|
|
33
|
+
'bg-background-selected-inverse': active,
|
|
34
|
+
'hover:bg-background-selected-inverse': !active
|
|
35
|
+
})
|
|
36
|
+
)
|
|
37
|
+
let buttonStyles = $derived(
|
|
40
38
|
clsx(
|
|
41
|
-
|
|
42
|
-
{ 'text-foreground-inverse-secondary': isFolderItem && !active },
|
|
39
|
+
'flex-1 min-w-0 h-6 cursor-pointer text-base flex items-center hover:text-white focus:text-white',
|
|
43
40
|
{
|
|
44
|
-
'
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
{
|
|
49
|
-
'bg-background-selected-inverse text-white': active
|
|
50
|
-
},
|
|
51
|
-
{ 'hover:bg-background-selected-inverse': !active }
|
|
41
|
+
'text-foreground-inverse font-medium': !isFolderItem,
|
|
42
|
+
'text-foreground-inverse-secondary': isFolderItem && !active,
|
|
43
|
+
'text-white': active
|
|
44
|
+
}
|
|
52
45
|
)
|
|
53
46
|
)
|
|
54
|
-
let iconStyles = $derived(
|
|
55
|
-
clsx({ 'group-hover:text-white text-icon-inverse-bold!': collapsedSidebar })
|
|
56
|
-
)
|
|
57
47
|
let wrapperStyles = $derived(
|
|
58
48
|
clsx({
|
|
59
|
-
'ml-4 border-l border-white-10 pl-2 pt-0.5 relative': isFolderItem
|
|
49
|
+
'group/menu-item ml-4 border-l border-white-10 pl-2 pt-0.5 relative': isFolderItem
|
|
60
50
|
})
|
|
61
51
|
)
|
|
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
52
|
|
|
72
53
|
$effect(() => {
|
|
73
54
|
resolveIcon(icon).then((res) => (resolvedIcon = res))
|
|
@@ -80,84 +61,68 @@
|
|
|
80
61
|
|
|
81
62
|
onclick?.(url)
|
|
82
63
|
}
|
|
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
64
|
</script>
|
|
104
65
|
|
|
105
|
-
<div class={wrapperStyles}>
|
|
106
|
-
{#if isFolderItem
|
|
107
|
-
<div
|
|
66
|
+
<div bind:this={ref} class={cn(wrapperStyles, className)} data-menu-item-root>
|
|
67
|
+
{#if isFolderItem}
|
|
68
|
+
<div
|
|
69
|
+
class={clsx('border-l border-white h-3 w-px absolute top-3.5 left-0 -m-px', {
|
|
70
|
+
'opacity-0 group-hover/menu-item:opacity-100': !active
|
|
71
|
+
})}
|
|
72
|
+
data-menu-item-tree-indicator
|
|
73
|
+
></div>
|
|
108
74
|
{/if}
|
|
109
|
-
<
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
75
|
+
<div class={rowStyles} data-menu-item-row>
|
|
76
|
+
<button
|
|
77
|
+
onclick={handleClick}
|
|
78
|
+
title={label}
|
|
79
|
+
data-menu-item-button
|
|
80
|
+
class={buttonStyles}
|
|
81
|
+
>
|
|
82
|
+
<span class="flex items-center space-x-1.5 min-w-0 flex-1" data-menu-item-content>
|
|
83
|
+
{#if imageUrl}
|
|
84
|
+
<img
|
|
85
|
+
src={imageUrl}
|
|
86
|
+
alt={label}
|
|
87
|
+
class="size-4 shrink-0 rounded bg-white object-contain"
|
|
88
|
+
data-menu-item-image
|
|
89
|
+
/>
|
|
90
|
+
{:else if resolvedIcon}
|
|
91
|
+
<Icon
|
|
92
|
+
src={resolvedIcon}
|
|
93
|
+
theme={iconTheme}
|
|
94
|
+
class="h-4 w-4 text-icon-inverse"
|
|
95
|
+
data-menu-item-icon
|
|
96
|
+
/>
|
|
97
|
+
{/if}
|
|
98
|
+
<span class="truncate tracking-normal" data-menu-item-label>{label}</span>
|
|
123
99
|
{#if beta}
|
|
124
100
|
<TagBeta />
|
|
125
101
|
{/if}
|
|
126
|
-
|
|
127
|
-
</
|
|
128
|
-
{#if
|
|
102
|
+
</span>
|
|
103
|
+
</button>
|
|
104
|
+
{#if action}
|
|
105
|
+
<span class="shrink-0" data-menu-item-action>
|
|
106
|
+
{@render action()}
|
|
107
|
+
</span>
|
|
108
|
+
{/if}
|
|
109
|
+
{#if collapsable}
|
|
129
110
|
<button
|
|
130
|
-
class="cursor-pointer"
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
open = !open
|
|
134
|
-
}}
|
|
111
|
+
class="shrink-0 cursor-pointer"
|
|
112
|
+
data-menu-item-chevron
|
|
113
|
+
onclick={() => (open = !open)}
|
|
135
114
|
>
|
|
136
115
|
<Icon src={open ? ChevronDown : ChevronRight} class="h-4 w-4 text-white-40" />
|
|
137
116
|
</button>
|
|
138
117
|
{/if}
|
|
139
|
-
</
|
|
140
|
-
{#if children?.length}
|
|
141
|
-
|
|
142
|
-
{#
|
|
143
|
-
<
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
class="pt-4 z-30"
|
|
149
|
-
>
|
|
150
|
-
<DrawerContext autofocus onclick={handleClickChild} {items} />
|
|
151
|
-
</div>
|
|
152
|
-
{/if}
|
|
153
|
-
{:else if open || !collapsable}
|
|
154
|
-
<ul>
|
|
155
|
-
{#each children as child}
|
|
156
|
-
<li>
|
|
157
|
-
<MenuItem {...child} isFolderItem {onclick} />
|
|
158
|
-
</li>
|
|
159
|
-
{/each}
|
|
160
|
-
</ul>
|
|
161
|
-
{/if}
|
|
118
|
+
</div>
|
|
119
|
+
{#if children?.length && (open || !collapsable)}
|
|
120
|
+
<ul data-menu-item-children>
|
|
121
|
+
{#each children as child}
|
|
122
|
+
<li>
|
|
123
|
+
<MenuItem {...child} isFolderItem {onclick} />
|
|
124
|
+
</li>
|
|
125
|
+
{/each}
|
|
126
|
+
</ul>
|
|
162
127
|
{/if}
|
|
163
128
|
</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;
|
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 {
|