@invopop/popui 0.1.97 → 0.1.98

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.
Files changed (87) hide show
  1. package/dist/CounterWidget.svelte +18 -1
  2. package/dist/GlobalSearch.svelte +1 -1
  3. package/dist/MenuItem.svelte +1 -1
  4. package/dist/index.d.ts +36 -1
  5. package/dist/index.js +74 -0
  6. package/dist/separator/index.d.ts +2 -0
  7. package/dist/separator/index.js +4 -0
  8. package/dist/separator/separator.svelte +21 -0
  9. package/dist/separator/separator.svelte.d.ts +4 -0
  10. package/dist/sheet/index.d.ts +11 -0
  11. package/dist/sheet/index.js +13 -0
  12. package/dist/sheet/sheet-close.svelte +7 -0
  13. package/dist/sheet/sheet-close.svelte.d.ts +4 -0
  14. package/dist/sheet/sheet-content.svelte +65 -0
  15. package/dist/sheet/sheet-content.svelte.d.ts +15 -0
  16. package/dist/sheet/sheet-description.svelte +17 -0
  17. package/dist/sheet/sheet-description.svelte.d.ts +4 -0
  18. package/dist/sheet/sheet-footer.svelte +20 -0
  19. package/dist/sheet/sheet-footer.svelte.d.ts +5 -0
  20. package/dist/sheet/sheet-header.svelte +20 -0
  21. package/dist/sheet/sheet-header.svelte.d.ts +5 -0
  22. package/dist/sheet/sheet-overlay.svelte +20 -0
  23. package/dist/sheet/sheet-overlay.svelte.d.ts +4 -0
  24. package/dist/sheet/sheet-portal.svelte +7 -0
  25. package/dist/sheet/sheet-portal.svelte.d.ts +3 -0
  26. package/dist/sheet/sheet-title.svelte +17 -0
  27. package/dist/sheet/sheet-title.svelte.d.ts +4 -0
  28. package/dist/sheet/sheet-trigger.svelte +7 -0
  29. package/dist/sheet/sheet-trigger.svelte.d.ts +4 -0
  30. package/dist/sheet/sheet.svelte +7 -0
  31. package/dist/sheet/sheet.svelte.d.ts +3 -0
  32. package/dist/sidebar/constants.d.ts +10 -0
  33. package/dist/sidebar/constants.js +10 -0
  34. package/dist/sidebar/context.svelte.d.ts +23 -0
  35. package/dist/sidebar/context.svelte.js +58 -0
  36. package/dist/sidebar/index.d.ts +25 -0
  37. package/dist/sidebar/index.js +27 -0
  38. package/dist/sidebar/is-mobile.svelte.d.ts +4 -0
  39. package/dist/sidebar/is-mobile.svelte.js +7 -0
  40. package/dist/sidebar/sidebar-content.svelte +25 -0
  41. package/dist/sidebar/sidebar-content.svelte.d.ts +5 -0
  42. package/dist/sidebar/sidebar-footer.svelte +21 -0
  43. package/dist/sidebar/sidebar-footer.svelte.d.ts +5 -0
  44. package/dist/sidebar/sidebar-group-action.svelte +33 -0
  45. package/dist/sidebar/sidebar-group-action.svelte.d.ts +11 -0
  46. package/dist/sidebar/sidebar-group-content.svelte +21 -0
  47. package/dist/sidebar/sidebar-group-content.svelte.d.ts +5 -0
  48. package/dist/sidebar/sidebar-group-label.svelte +33 -0
  49. package/dist/sidebar/sidebar-group-label.svelte.d.ts +11 -0
  50. package/dist/sidebar/sidebar-group.svelte +21 -0
  51. package/dist/sidebar/sidebar-group.svelte.d.ts +5 -0
  52. package/dist/sidebar/sidebar-header.svelte +21 -0
  53. package/dist/sidebar/sidebar-header.svelte.d.ts +5 -0
  54. package/dist/sidebar/sidebar-input.svelte +23 -0
  55. package/dist/sidebar/sidebar-input.svelte.d.ts +5 -0
  56. package/dist/sidebar/sidebar-inset.svelte +23 -0
  57. package/dist/sidebar/sidebar-inset.svelte.d.ts +5 -0
  58. package/dist/sidebar/sidebar-menu-action.svelte +37 -0
  59. package/dist/sidebar/sidebar-menu-action.svelte.d.ts +12 -0
  60. package/dist/sidebar/sidebar-menu-badge.svelte +24 -0
  61. package/dist/sidebar/sidebar-menu-badge.svelte.d.ts +5 -0
  62. package/dist/sidebar/sidebar-menu-button.svelte +102 -0
  63. package/dist/sidebar/sidebar-menu-button.svelte.d.ts +51 -0
  64. package/dist/sidebar/sidebar-menu-item.svelte +21 -0
  65. package/dist/sidebar/sidebar-menu-item.svelte.d.ts +5 -0
  66. package/dist/sidebar/sidebar-menu-skeleton.svelte +35 -0
  67. package/dist/sidebar/sidebar-menu-skeleton.svelte.d.ts +8 -0
  68. package/dist/sidebar/sidebar-menu-sub-button.svelte +39 -0
  69. package/dist/sidebar/sidebar-menu-sub-button.svelte.d.ts +13 -0
  70. package/dist/sidebar/sidebar-menu-sub-item.svelte +21 -0
  71. package/dist/sidebar/sidebar-menu-sub-item.svelte.d.ts +5 -0
  72. package/dist/sidebar/sidebar-menu-sub.svelte +24 -0
  73. package/dist/sidebar/sidebar-menu-sub.svelte.d.ts +5 -0
  74. package/dist/sidebar/sidebar-menu.svelte +21 -0
  75. package/dist/sidebar/sidebar-menu.svelte.d.ts +5 -0
  76. package/dist/sidebar/sidebar-provider.svelte +47 -0
  77. package/dist/sidebar/sidebar-provider.svelte.d.ts +9 -0
  78. package/dist/sidebar/sidebar-rail.svelte +165 -0
  79. package/dist/sidebar/sidebar-rail.svelte.d.ts +5 -0
  80. package/dist/sidebar/sidebar-separator.svelte +19 -0
  81. package/dist/sidebar/sidebar-separator.svelte.d.ts +13 -0
  82. package/dist/sidebar/sidebar-trigger.svelte +35 -0
  83. package/dist/sidebar/sidebar-trigger.svelte.d.ts +5 -0
  84. package/dist/sidebar/sidebar.svelte +106 -0
  85. package/dist/sidebar/sidebar.svelte.d.ts +10 -0
  86. package/dist/tailwind.theme.css +20 -0
  87. package/package.json +2 -1
@@ -0,0 +1,35 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from 'svelte/elements'
3
+ import { cn, type WithElementRef } from '../utils.js'
4
+ import { Skeleton } from '../skeleton/index.js'
5
+
6
+ let {
7
+ ref = $bindable(null),
8
+ class: className,
9
+ showIcon = false,
10
+ children,
11
+ ...restProps
12
+ }: WithElementRef<HTMLAttributes<HTMLElement>> & {
13
+ showIcon?: boolean
14
+ } = $props()
15
+
16
+ const width = `${Math.floor(Math.random() * 40) + 50}%`
17
+ </script>
18
+
19
+ <div
20
+ bind:this={ref}
21
+ data-slot="sidebar-menu-skeleton"
22
+ data-sidebar="menu-skeleton"
23
+ class={cn('flex h-8 items-center gap-2 rounded-md px-2', className)}
24
+ {...restProps}
25
+ >
26
+ {#if showIcon}
27
+ <Skeleton class="size-4 rounded-md" data-sidebar="menu-skeleton-icon" />
28
+ {/if}
29
+ <Skeleton
30
+ class="h-4 max-w-(--skeleton-width) flex-1"
31
+ data-sidebar="menu-skeleton-text"
32
+ style="--skeleton-width: {width};"
33
+ />
34
+ {@render children?.()}
35
+ </div>
@@ -0,0 +1,8 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ import { type WithElementRef } from '../utils.js';
3
+ type $$ComponentProps = WithElementRef<HTMLAttributes<HTMLElement>> & {
4
+ showIcon?: boolean;
5
+ };
6
+ declare const SidebarMenuSkeleton: import("svelte").Component<$$ComponentProps, {}, "ref">;
7
+ type SidebarMenuSkeleton = ReturnType<typeof SidebarMenuSkeleton>;
8
+ export default SidebarMenuSkeleton;
@@ -0,0 +1,39 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte'
3
+ import type { HTMLAnchorAttributes } from 'svelte/elements'
4
+ import { cn, type WithElementRef } from '../utils.js'
5
+
6
+ let {
7
+ ref = $bindable(null),
8
+ children,
9
+ child,
10
+ class: className,
11
+ size = 'md',
12
+ isActive = false,
13
+ ...restProps
14
+ }: WithElementRef<HTMLAnchorAttributes> & {
15
+ child?: Snippet<[{ props: Record<string, unknown> }]>
16
+ size?: 'sm' | 'md'
17
+ isActive?: boolean
18
+ } = $props()
19
+
20
+ const mergedProps = $derived({
21
+ class: cn(
22
+ 'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-hidden focus-visible:ring-2 group-data-[collapsible=icon]:hidden disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 data-[size=md]:text-sm data-[size=sm]:text-xs',
23
+ className
24
+ ),
25
+ 'data-slot': 'sidebar-menu-sub-button',
26
+ 'data-sidebar': 'menu-sub-button',
27
+ 'data-size': size,
28
+ 'data-active': isActive,
29
+ ...restProps
30
+ })
31
+ </script>
32
+
33
+ {#if child}
34
+ {@render child({ props: mergedProps })}
35
+ {:else}
36
+ <a bind:this={ref} {...mergedProps}>
37
+ {@render children?.()}
38
+ </a>
39
+ {/if}
@@ -0,0 +1,13 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAnchorAttributes } from 'svelte/elements';
3
+ import { type WithElementRef } from '../utils.js';
4
+ type $$ComponentProps = WithElementRef<HTMLAnchorAttributes> & {
5
+ child?: Snippet<[{
6
+ props: Record<string, unknown>;
7
+ }]>;
8
+ size?: 'sm' | 'md';
9
+ isActive?: boolean;
10
+ };
11
+ declare const SidebarMenuSubButton: import("svelte").Component<$$ComponentProps, {}, "ref">;
12
+ type SidebarMenuSubButton = ReturnType<typeof SidebarMenuSubButton>;
13
+ export default SidebarMenuSubButton;
@@ -0,0 +1,21 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from 'svelte/elements'
3
+ import { cn, type WithElementRef } from '../utils.js'
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ children,
8
+ class: className,
9
+ ...restProps
10
+ }: WithElementRef<HTMLAttributes<HTMLLIElement>> = $props()
11
+ </script>
12
+
13
+ <li
14
+ bind:this={ref}
15
+ data-slot="sidebar-menu-sub-item"
16
+ data-sidebar="menu-sub-item"
17
+ class={cn('group/menu-sub-item relative', className)}
18
+ {...restProps}
19
+ >
20
+ {@render children?.()}
21
+ </li>
@@ -0,0 +1,5 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ import { type WithElementRef } from '../utils.js';
3
+ declare const SidebarMenuSubItem: import("svelte").Component<WithElementRef<HTMLAttributes<HTMLLIElement>>, {}, "ref">;
4
+ type SidebarMenuSubItem = ReturnType<typeof SidebarMenuSubItem>;
5
+ export default SidebarMenuSubItem;
@@ -0,0 +1,24 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from 'svelte/elements'
3
+ import { cn, type WithElementRef } from '../utils.js'
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLAttributes<HTMLUListElement>> = $props()
11
+ </script>
12
+
13
+ <ul
14
+ bind:this={ref}
15
+ data-slot="sidebar-menu-sub"
16
+ data-sidebar="menu-sub"
17
+ class={cn(
18
+ 'border-sidebar-border mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5 group-data-[collapsible=icon]:hidden',
19
+ className
20
+ )}
21
+ {...restProps}
22
+ >
23
+ {@render children?.()}
24
+ </ul>
@@ -0,0 +1,5 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ import { type WithElementRef } from '../utils.js';
3
+ declare const SidebarMenuSub: import("svelte").Component<WithElementRef<HTMLAttributes<HTMLUListElement>>, {}, "ref">;
4
+ type SidebarMenuSub = ReturnType<typeof SidebarMenuSub>;
5
+ export default SidebarMenuSub;
@@ -0,0 +1,21 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from 'svelte/elements'
3
+ import { cn, type WithElementRef } from '../utils.js'
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLAttributes<HTMLUListElement>, HTMLUListElement> = $props()
11
+ </script>
12
+
13
+ <ul
14
+ bind:this={ref}
15
+ data-slot="sidebar-menu"
16
+ data-sidebar="menu"
17
+ class={cn('flex w-full min-w-0 flex-col gap-1', className)}
18
+ {...restProps}
19
+ >
20
+ {@render children?.()}
21
+ </ul>
@@ -0,0 +1,5 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ import { type WithElementRef } from '../utils.js';
3
+ declare const SidebarMenu: import("svelte").Component<WithElementRef<HTMLAttributes<HTMLUListElement>, HTMLUListElement>, {}, "ref">;
4
+ type SidebarMenu = ReturnType<typeof SidebarMenu>;
5
+ export default SidebarMenu;
@@ -0,0 +1,47 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from 'svelte/elements'
3
+ import * as Tooltip from '../tooltip/index.js'
4
+ import { cn, type WithElementRef } from '../utils.js'
5
+ import { SIDEBAR_COOKIE_MAX_AGE, SIDEBAR_COOKIE_NAME, SIDEBAR_WIDTH_ICON } from './constants.js'
6
+ import { setSidebar } from './context.svelte.js'
7
+
8
+ let {
9
+ ref = $bindable(null),
10
+ open = $bindable(true),
11
+ onOpenChange = () => {},
12
+ class: className,
13
+ style,
14
+ children,
15
+ ...restProps
16
+ }: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
17
+ open?: boolean
18
+ onOpenChange?: (open: boolean) => void
19
+ } = $props()
20
+
21
+ const sidebar = setSidebar({
22
+ open: () => open,
23
+ setOpen: (value: boolean) => {
24
+ open = value
25
+ onOpenChange(value)
26
+ document.cookie = `${SIDEBAR_COOKIE_NAME}=${open}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
27
+ }
28
+ })
29
+ </script>
30
+
31
+ <svelte:window onkeydown={sidebar.handleShortcutKeydown} />
32
+
33
+ <Tooltip.Provider delayDuration={0}>
34
+ <div
35
+ data-slot="sidebar-wrapper"
36
+ style="--sidebar-width: {sidebar.width}; --sidebar-width-icon: {SIDEBAR_WIDTH_ICON}; {style ??
37
+ ''}"
38
+ class={cn(
39
+ 'group/sidebar-wrapper flex min-h-svh w-full has-data-[variant=inset]:bg-sidebar',
40
+ className
41
+ )}
42
+ bind:this={ref}
43
+ {...restProps}
44
+ >
45
+ {@render children?.()}
46
+ </div>
47
+ </Tooltip.Provider>
@@ -0,0 +1,9 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ import { type WithElementRef } from '../utils.js';
3
+ type $$ComponentProps = WithElementRef<HTMLAttributes<HTMLDivElement>> & {
4
+ open?: boolean;
5
+ onOpenChange?: (open: boolean) => void;
6
+ };
7
+ declare const SidebarProvider: import("svelte").Component<$$ComponentProps, {}, "open" | "ref">;
8
+ type SidebarProvider = ReturnType<typeof SidebarProvider>;
9
+ export default SidebarProvider;
@@ -0,0 +1,165 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from 'svelte/elements'
3
+ import ShortcutWrapper from '../ShortcutWrapper.svelte'
4
+ import { cn, type WithElementRef } from '../utils.js'
5
+ import { SIDEBAR_DRAG_THRESHOLD_PX } from './constants.js'
6
+ import { useSidebar } from './context.svelte.js'
7
+
8
+ let {
9
+ ref = $bindable(null),
10
+ class: className,
11
+ children,
12
+ ...restProps
13
+ }: WithElementRef<HTMLAttributes<HTMLButtonElement>, HTMLButtonElement> = $props()
14
+
15
+ const sidebar = useSidebar()
16
+
17
+ let dragStartX = 0
18
+ let dragStartWidthPx = 0
19
+ let dragMoved = false
20
+ let dragDirection: 1 | -1 = 1
21
+
22
+ let isHovering = $state(false)
23
+ let isDragging = $state(false)
24
+ let tooltipVisible = $derived(isHovering && !isDragging)
25
+ let tooltipX = $state(0)
26
+ let tooltipY = $state(0)
27
+ let tooltipWidth = $state(0)
28
+ let tooltipHeight = $state(0)
29
+
30
+ const TOOLTIP_CURSOR_OFFSET = 12
31
+ const TOOLTIP_VIEWPORT_PADDING = 8
32
+
33
+ let tooltipLeft = $derived.by(() => {
34
+ if (tooltipWidth === 0 || typeof window === 'undefined') return tooltipX
35
+ const desired = tooltipX - tooltipWidth / 2
36
+ const minX = TOOLTIP_VIEWPORT_PADDING
37
+ const maxX = window.innerWidth - tooltipWidth - TOOLTIP_VIEWPORT_PADDING
38
+ return Math.max(minX, Math.min(maxX, desired))
39
+ })
40
+
41
+ let tooltipTop = $derived.by(() => {
42
+ const desired = tooltipY + TOOLTIP_CURSOR_OFFSET
43
+ if (tooltipHeight === 0 || typeof window === 'undefined') return desired
44
+ const maxY = window.innerHeight - tooltipHeight - TOOLTIP_VIEWPORT_PADDING
45
+ return Math.min(maxY, desired)
46
+ })
47
+
48
+ function updateTooltipPosition(e: PointerEvent) {
49
+ tooltipX = e.clientX
50
+ tooltipY = e.clientY
51
+ }
52
+
53
+ function onPointerEnter(e: PointerEvent) {
54
+ const sidebarRoot = (e.currentTarget as HTMLElement).closest('[data-slot="sidebar"]')
55
+ dragDirection = sidebarRoot?.getAttribute('data-side') === 'right' ? -1 : 1
56
+ updateTooltipPosition(e)
57
+ isHovering = true
58
+ }
59
+
60
+ function onPointerLeave() {
61
+ isHovering = false
62
+ }
63
+
64
+ function onPointerDown(e: PointerEvent) {
65
+ if (sidebar.state !== 'expanded' || sidebar.isMobile) return
66
+ const button = e.currentTarget as HTMLButtonElement
67
+ const sidebarRoot = button.closest('[data-slot="sidebar"]')
68
+ dragDirection = sidebarRoot?.getAttribute('data-side') === 'right' ? -1 : 1
69
+
70
+ const container = sidebarRoot?.querySelector('[data-slot="sidebar-container"]')
71
+ dragStartWidthPx = container instanceof HTMLElement ? container.offsetWidth : 256
72
+ dragStartX = e.clientX
73
+ dragMoved = false
74
+ button.setPointerCapture(e.pointerId)
75
+ document.body.style.cursor = 'col-resize'
76
+ document.body.style.userSelect = 'none'
77
+ }
78
+
79
+ function onPointerMove(e: PointerEvent) {
80
+ if (tooltipVisible) updateTooltipPosition(e)
81
+ const button = e.currentTarget as HTMLButtonElement
82
+ if (!button.hasPointerCapture(e.pointerId)) return
83
+ const delta = (e.clientX - dragStartX) * dragDirection
84
+ if (Math.abs(delta) > SIDEBAR_DRAG_THRESHOLD_PX) {
85
+ dragMoved = true
86
+ isDragging = true
87
+ }
88
+ if (dragMoved) sidebar.setWidth(dragStartWidthPx + delta)
89
+ }
90
+
91
+ function onPointerUp(e: PointerEvent) {
92
+ const button = e.currentTarget as HTMLButtonElement
93
+ if (button.hasPointerCapture(e.pointerId)) button.releasePointerCapture(e.pointerId)
94
+ document.body.style.cursor = ''
95
+ document.body.style.userSelect = ''
96
+ isDragging = false
97
+ }
98
+
99
+ function onClick(e: MouseEvent) {
100
+ if (dragMoved) {
101
+ e.preventDefault()
102
+ e.stopPropagation()
103
+ dragMoved = false
104
+ return
105
+ }
106
+ sidebar.toggle()
107
+ }
108
+ </script>
109
+
110
+ <button
111
+ bind:this={ref}
112
+ data-sidebar="rail"
113
+ data-slot="sidebar-rail"
114
+ aria-label="Toggle Sidebar"
115
+ tabindex={-1}
116
+ type="button"
117
+ onpointerenter={onPointerEnter}
118
+ onpointerleave={onPointerLeave}
119
+ onpointerdown={onPointerDown}
120
+ onpointermove={onPointerMove}
121
+ onpointerup={onPointerUp}
122
+ onpointercancel={onPointerUp}
123
+ onclick={onClick}
124
+ class={cn(
125
+ 'absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 sm:flex',
126
+ 'after:absolute after:inset-y-0 after:left-1/2 after:w-[2px]',
127
+ 'hover:after:bg-sidebar-border',
128
+ 'group-data-[side=left]:cursor-w-resize group-data-[side=right]:cursor-e-resize',
129
+ '[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize',
130
+ 'hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full',
131
+ '[[data-side=left][data-collapsible=offcanvas]_&]:-right-2',
132
+ '[[data-side=right][data-collapsible=offcanvas]_&]:-left-2',
133
+ className
134
+ )}
135
+ {...restProps}
136
+ >
137
+ {@render children?.()}
138
+ </button>
139
+
140
+ {#if tooltipVisible}
141
+ <div
142
+ role="tooltip"
143
+ bind:offsetWidth={tooltipWidth}
144
+ bind:offsetHeight={tooltipHeight}
145
+ class="fixed z-[1002] pointer-events-none rounded-md border border-border-inverse bg-background-default-negative px-3 py-2 text-sm font-medium text-foreground-inverse leading-5 tracking-tight shadow-md"
146
+ style="left: {tooltipLeft}px; top: {tooltipTop}px; visibility: {tooltipWidth > 0
147
+ ? 'visible'
148
+ : 'hidden'};"
149
+ >
150
+ <div class="flex flex-col gap-1.5">
151
+ {#if sidebar.state === 'expanded'}
152
+ <div>Drag to resize</div>
153
+ {/if}
154
+ <div class="flex items-center justify-between gap-3">
155
+ <span>
156
+ {sidebar.state === 'expanded' ? 'Click to collapse' : 'Click to expand'}
157
+ </span>
158
+ <div class="flex items-center gap-1">
159
+ <ShortcutWrapper size="md" theme="navigation">⌘</ShortcutWrapper>
160
+ <ShortcutWrapper size="md" theme="navigation">.</ShortcutWrapper>
161
+ </div>
162
+ </div>
163
+ </div>
164
+ </div>
165
+ {/if}
@@ -0,0 +1,5 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ import { type WithElementRef } from '../utils.js';
3
+ declare const SidebarRail: import("svelte").Component<WithElementRef<HTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, {}, "ref">;
4
+ type SidebarRail = ReturnType<typeof SidebarRail>;
5
+ export default SidebarRail;
@@ -0,0 +1,19 @@
1
+ <script lang="ts">
2
+ import type { ComponentProps } from 'svelte'
3
+ import { Separator } from '../separator/index.js'
4
+ import { cn } from '../utils.js'
5
+
6
+ let {
7
+ ref = $bindable(null),
8
+ class: className,
9
+ ...restProps
10
+ }: ComponentProps<typeof Separator> = $props()
11
+ </script>
12
+
13
+ <Separator
14
+ bind:ref
15
+ data-slot="sidebar-separator"
16
+ data-sidebar="separator"
17
+ class={cn('bg-sidebar-border mx-2 w-auto', className)}
18
+ {...restProps}
19
+ />
@@ -0,0 +1,13 @@
1
+ declare const SidebarSeparator: import("svelte").Component<Omit<{
2
+ orientation?: import("bits-ui").Orientation;
3
+ decorative?: boolean;
4
+ }, "children" | "child"> & {
5
+ child?: import("svelte").Snippet<[{
6
+ props: Record<string, unknown>;
7
+ }]> | undefined;
8
+ children?: import("svelte").Snippet<[]> | undefined;
9
+ style?: import("bits-ui").StyleProperties | string | null | undefined;
10
+ ref?: HTMLElement | null | undefined;
11
+ } & import("bits-ui").Without<import("bits-ui").BitsPrimitiveDivAttributes, import("bits-ui").SeparatorRootPropsWithoutHTML>, {}, "ref">;
12
+ type SidebarSeparator = ReturnType<typeof SidebarSeparator>;
13
+ export default SidebarSeparator;
@@ -0,0 +1,35 @@
1
+ <script lang="ts">
2
+ import type { HTMLButtonAttributes } from 'svelte/elements'
3
+ import { SidebarShow } from '@invopop/ui-icons'
4
+ import { Icon } from '@steeze-ui/svelte-icon'
5
+ import { cn, type WithElementRef } from '../utils.js'
6
+ import { useSidebar } from './context.svelte.js'
7
+
8
+ let {
9
+ ref = $bindable(null),
10
+ class: className,
11
+ onclick,
12
+ ...restProps
13
+ }: WithElementRef<HTMLButtonAttributes, HTMLButtonElement> = $props()
14
+
15
+ const sidebar = useSidebar()
16
+ </script>
17
+
18
+ <button
19
+ bind:this={ref}
20
+ data-sidebar="trigger"
21
+ data-slot="sidebar-trigger"
22
+ type="button"
23
+ class={cn(
24
+ 'inline-flex size-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sidebar-ring disabled:pointer-events-none disabled:opacity-50',
25
+ className
26
+ )}
27
+ onclick={(e) => {
28
+ onclick?.(e)
29
+ sidebar.toggle()
30
+ }}
31
+ {...restProps}
32
+ >
33
+ <Icon src={SidebarShow} class="size-4" />
34
+ <span class="sr-only">Toggle Sidebar</span>
35
+ </button>
@@ -0,0 +1,5 @@
1
+ import type { HTMLButtonAttributes } from 'svelte/elements';
2
+ import { type WithElementRef } from '../utils.js';
3
+ declare const SidebarTrigger: import("svelte").Component<WithElementRef<HTMLButtonAttributes, HTMLButtonElement>, {}, "ref">;
4
+ type SidebarTrigger = ReturnType<typeof SidebarTrigger>;
5
+ export default SidebarTrigger;
@@ -0,0 +1,106 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from 'svelte/elements'
3
+ import * as Sheet from '../sheet/index.js'
4
+ import { cn, type WithElementRef } from '../utils.js'
5
+ import { SIDEBAR_WIDTH_MOBILE } from './constants.js'
6
+ import { useSidebar } from './context.svelte.js'
7
+
8
+ let {
9
+ ref = $bindable(null),
10
+ side = 'left',
11
+ variant = 'sidebar',
12
+ collapsible = 'offcanvas',
13
+ class: className,
14
+ children,
15
+ ...restProps
16
+ }: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
17
+ side?: 'left' | 'right'
18
+ variant?: 'sidebar' | 'floating' | 'inset'
19
+ collapsible?: 'offcanvas' | 'icon' | 'none'
20
+ } = $props()
21
+
22
+ const sidebar = useSidebar()
23
+ </script>
24
+
25
+ {#if collapsible === 'none'}
26
+ <div
27
+ class={cn(
28
+ 'bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col',
29
+ className
30
+ )}
31
+ bind:this={ref}
32
+ {...restProps}
33
+ >
34
+ {@render children?.()}
35
+ </div>
36
+ {:else if sidebar.isMobile}
37
+ <Sheet.Root
38
+ bind:open={() => sidebar.openMobile, (v) => sidebar.setOpenMobile(v)}
39
+ {...restProps}
40
+ >
41
+ <Sheet.Content
42
+ data-sidebar="sidebar"
43
+ data-slot="sidebar"
44
+ data-mobile="true"
45
+ class={cn(
46
+ 'bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden',
47
+ className
48
+ )}
49
+ style="--sidebar-width: {SIDEBAR_WIDTH_MOBILE};"
50
+ {side}
51
+ showCloseButton={false}
52
+ >
53
+ <Sheet.Header class="sr-only">
54
+ <Sheet.Title>Sidebar</Sheet.Title>
55
+ <Sheet.Description>Displays the mobile sidebar.</Sheet.Description>
56
+ </Sheet.Header>
57
+ <div class="flex h-full w-full flex-col">
58
+ {@render children?.()}
59
+ </div>
60
+ </Sheet.Content>
61
+ </Sheet.Root>
62
+ {:else}
63
+ <div
64
+ bind:this={ref}
65
+ class="text-sidebar-foreground group peer hidden md:block"
66
+ data-state={sidebar.state}
67
+ data-collapsible={sidebar.state === 'collapsed' ? collapsible : ''}
68
+ data-variant={variant}
69
+ data-side={side}
70
+ data-slot="sidebar"
71
+ >
72
+ <div
73
+ data-slot="sidebar-gap"
74
+ class={cn(
75
+ 'relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear',
76
+ 'group-data-[collapsible=offcanvas]:w-0',
77
+ 'group-data-[side=right]:rotate-180',
78
+ variant === 'floating' || variant === 'inset'
79
+ ? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+1rem)]'
80
+ : 'group-data-[collapsible=icon]:w-(--sidebar-width-icon)'
81
+ )}
82
+ ></div>
83
+ <div
84
+ data-slot="sidebar-container"
85
+ class={cn(
86
+ 'fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex',
87
+ side === 'left'
88
+ ? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'
89
+ : 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',
90
+ variant === 'floating' || variant === 'inset'
91
+ ? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+1rem+2px)]'
92
+ : 'group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l',
93
+ className
94
+ )}
95
+ {...restProps}
96
+ >
97
+ <div
98
+ data-sidebar="sidebar"
99
+ data-slot="sidebar-inner"
100
+ class="flex size-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:shadow-sm group-data-[variant=floating]:ring-1 group-data-[variant=floating]:ring-sidebar-border"
101
+ >
102
+ {@render children?.()}
103
+ </div>
104
+ </div>
105
+ </div>
106
+ {/if}
@@ -0,0 +1,10 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ import { type WithElementRef } from '../utils.js';
3
+ type $$ComponentProps = WithElementRef<HTMLAttributes<HTMLDivElement>> & {
4
+ side?: 'left' | 'right';
5
+ variant?: 'sidebar' | 'floating' | 'inset';
6
+ collapsible?: 'offcanvas' | 'icon' | 'none';
7
+ };
8
+ declare const Sidebar: import("svelte").Component<$$ComponentProps, {}, "ref">;
9
+ type Sidebar = ReturnType<typeof Sidebar>;
10
+ export default Sidebar;
@@ -837,6 +837,26 @@
837
837
  --text-xs: 10px;
838
838
  --text-xs--line-height: 12px;
839
839
  --text-xs--letter-spacing: var(--tracking-wide);
840
+
841
+ /* ============================================
842
+ SHADCN-COMPATIBLE TOKEN ALIASES (Sheet, Separator, Sidebar)
843
+ ============================================ */
844
+
845
+ /* Generic aliases used by Sheet and Sidebar.Input */
846
+ --color-foreground-secondary: var(--color-foreground-default-secondary);
847
+ --color-input: var(--color-border-default-default);
848
+ --color-ring: var(--color-foreground-default-default);
849
+
850
+ /* Sidebar — defaults to the brand-bold (inverse/dark) surface so popui's
851
+ Sidebar matches the existing dark chrome out of the box. */
852
+ --color-sidebar: var(--color-background-default-bold);
853
+ --color-sidebar-foreground: var(--color-foreground-inverse-default);
854
+ --color-sidebar-primary: var(--color-foreground-inverse-default);
855
+ --color-sidebar-primary-foreground: var(--color-background-default-bold);
856
+ --color-sidebar-accent: var(--color-background-selected-inverse);
857
+ --color-sidebar-accent-foreground: var(--color-foreground-inverse-default);
858
+ --color-sidebar-border: var(--color-border-inverse-default);
859
+ --color-sidebar-ring: var(--color-border-inverse-secondary);
840
860
  }
841
861
 
842
862
  @layer theme {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@invopop/popui",
3
3
  "license": "MIT",
4
- "version": "0.1.97",
4
+ "version": "0.1.98",
5
5
  "repository": {
6
6
  "url": "https://github.com/invopop/popui"
7
7
  },
@@ -106,6 +106,7 @@
106
106
  "svelte-intersection-observer-action": "^0.0.4",
107
107
  "svelte-portal": "^2.2.1",
108
108
  "svelte-sonner": "^1.0.5",
109
+ "svelte-toolbelt": "^0.10.6",
109
110
  "svelte-transition": "^0.0.17",
110
111
  "svelte-viewport-info": "^1.0.2",
111
112
  "tailwind-variants": "^1.0.0",