File size: 3,805 Bytes
41a5ab2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
<script lang="ts" module>

	import { tv, type VariantProps } from 'tailwind-variants';



	export const sidebarMenuButtonVariants = tv({

		base: 'peer/menu-button outline-hidden ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground group-has-data-[sidebar=menu-action]/menu-item:pr-8 data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm transition-[width,height,padding] focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:font-medium [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',

		variants: {

			variant: {

				default: 'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',

				outline:

					'bg-background hover:bg-sidebar-accent hover:text-sidebar-accent-foreground shadow-[0_0_0_1px_var(--sidebar-border)] hover:shadow-[0_0_0_1px_var(--sidebar-accent)]'

			},

			size: {

				default: 'h-8 text-sm',

				sm: 'h-7 text-xs',

				lg: 'group-data-[collapsible=icon]:p-0! h-12 text-sm'

			}

		},

		defaultVariants: {

			variant: 'default',

			size: 'default'

		}

	});



	export type SidebarMenuButtonVariant = VariantProps<typeof sidebarMenuButtonVariants>['variant'];

	export type SidebarMenuButtonSize = VariantProps<typeof sidebarMenuButtonVariants>['size'];

</script>



<script lang="ts">

	import * as Tooltip from '$lib/components/ui/tooltip/index.js';

	import {

		cn,

		type WithElementRef,

		type WithoutChildrenOrChild

	} from '$lib/components/ui/utils.js';

	import { mergeProps } from 'bits-ui';

	import type { ComponentProps, Snippet } from 'svelte';

	import type { HTMLAttributes } from 'svelte/elements';

	import { useSidebar } from './context.svelte.js';



	let {

		ref = $bindable(null),

		class: className,

		children,

		child,

		variant = 'default',

		size = 'default',

		isActive = false,

		tooltipContent,

		tooltipContentProps,

		...restProps

	}: WithElementRef<HTMLAttributes<HTMLButtonElement>, HTMLButtonElement> & {

		isActive?: boolean;

		variant?: SidebarMenuButtonVariant;

		size?: SidebarMenuButtonSize;

		tooltipContent?: Snippet | string;

		tooltipContentProps?: WithoutChildrenOrChild<ComponentProps<typeof Tooltip.Content>>;

		child?: Snippet<[{ props: Record<string, unknown> }]>;

	} = $props();



	const sidebar = useSidebar();



	const buttonProps = $derived({

		class: cn(sidebarMenuButtonVariants({ variant, size }), className),

		'data-slot': 'sidebar-menu-button',

		'data-sidebar': 'menu-button',

		'data-size': size,

		'data-active': isActive,

		...restProps

	});

</script>



{#snippet Button({ props }: { props?: Record<string, unknown> })}

	{@const mergedProps = mergeProps(buttonProps, props)}

	{#if child}

		{@render child({ props: mergedProps })}

	{:else}

		<button bind:this={ref} {...mergedProps}>

			{@render children?.()}

		</button>

	{/if}

{/snippet}



{#if !tooltipContent}

	{@render Button({})}

{:else}

	<Tooltip.Root>

		<Tooltip.Trigger>

			{#snippet child({ props })}

				{@render Button({ props })}

			{/snippet}

		</Tooltip.Trigger>



		<Tooltip.Content

			side="right"

			align="center"

			hidden={sidebar.state !== 'collapsed' || sidebar.isMobile}

			{...tooltipContentProps}

		>

			{#if typeof tooltipContent === 'string'}

				{tooltipContent}

			{:else if tooltipContent}

				{@render tooltipContent()}

			{/if}

		</Tooltip.Content>

	</Tooltip.Root>

{/if}