@heyramzi/ui 2.20.0 → 2.21.1

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 (193) hide show
  1. package/README.md +2 -0
  2. package/dist/charts/dashboard/data-table.js +1 -2
  3. package/dist/components/list-page/filter-section.js +1 -1
  4. package/dist/components/list-page/list-table.js +5 -6
  5. package/dist/components/list-page/queue-rail.js +2 -1
  6. package/dist/components/picker/trigger.js +3 -3
  7. package/dist/components/segmented/segmented.js +5 -5
  8. package/dist/components/work-parts/looks.js +1 -1
  9. package/dist/shadcn/alert/alert-variants.js +9 -0
  10. package/dist/shadcn/alert/index.js +1 -1
  11. package/dist/shadcn/badge/badge-variants.js +17 -0
  12. package/dist/shadcn/badge/index.js +1 -1
  13. package/dist/shadcn/dialog/index.js +3 -2
  14. package/dist/shadcn/dropdown-menu/menu-item.js +1 -1
  15. package/dist/shadcn/sheet/index.js +3 -2
  16. package/dist/shadcn/skeleton/index.js +3 -2
  17. package/dist/shadcn/toggle/index.js +1 -1
  18. package/dist/shadcn/toggle/toggle-variants.js +20 -0
  19. package/dist/status/index.js +2 -0
  20. package/dist/status/pill-tint.js +13 -0
  21. package/dist/work/kanban-drag.js +13 -7
  22. package/package.json +23 -23
  23. package/src/ai/confirmation/ConfirmationTitle.svelte +1 -4
  24. package/src/ai/loading-state/PixelLoader.svelte +1 -1
  25. package/src/animations/dropdown.css +19 -10
  26. package/src/animations/modal.css +7 -2
  27. package/src/charts/charts.css +3 -5
  28. package/src/charts/dashboard/dashboard-section.svelte +1 -1
  29. package/src/charts/dashboard/data-table.ts +1 -2
  30. package/src/charts/dashboard/stat-tile.svelte +1 -1
  31. package/src/charts/number-chart.css +8 -7
  32. package/src/charts/pop-value.svelte +68 -0
  33. package/src/charts/primitives/chart-tooltip.svelte +1 -1
  34. package/src/charts/reference-line.css +1 -1
  35. package/src/charts/stat-card.css +4 -4
  36. package/src/components/copy/copy-button.svelte +11 -10
  37. package/src/components/data-table/row-arrow.svelte +1 -1
  38. package/src/components/data-table/row-context-menu.svelte +1 -1
  39. package/src/components/data-table/sortable-head.svelte +2 -2
  40. package/src/components/data-table/table-skeleton.svelte +5 -5
  41. package/src/components/docs/doc-page.svelte +1 -3
  42. package/src/components/docs/on-this-page.svelte +4 -4
  43. package/src/components/field-row/field-row.svelte +1 -1
  44. package/src/components/list-page/detail-empty.svelte +3 -8
  45. package/src/components/list-page/detail-header.svelte +1 -1
  46. package/src/components/list-page/detail-row.svelte +2 -1
  47. package/src/components/list-page/empty-state.svelte +15 -7
  48. package/src/components/list-page/filter-item.svelte +2 -2
  49. package/src/components/list-page/filter-popover.svelte +1 -1
  50. package/src/components/list-page/filter-section.ts +1 -4
  51. package/src/components/list-page/grouped-list.svelte +37 -8
  52. package/src/components/list-page/list-page-shell.svelte +1 -1
  53. package/src/components/list-page/list-table.ts +6 -6
  54. package/src/components/list-page/master-detail.svelte +1 -1
  55. package/src/components/list-page/queue-rail.ts +2 -2
  56. package/src/components/list-page/rail-empty.svelte +1 -1
  57. package/src/components/list-page/rail-row.svelte +5 -5
  58. package/src/components/open-in/open-in.svelte +2 -1
  59. package/src/components/picker/trigger.ts +6 -5
  60. package/src/components/section-card/section-card.svelte +1 -1
  61. package/src/components/section-header/section-header.svelte +4 -2
  62. package/src/components/section-header/section-label.svelte +2 -2
  63. package/src/components/segmented/animated-tabs.svelte +1 -1
  64. package/src/components/segmented/section-runs.svelte +1 -1
  65. package/src/components/segmented/segment.svelte +4 -6
  66. package/src/components/segmented/segmented-track.svelte +18 -52
  67. package/src/components/segmented/segmented.ts +5 -5
  68. package/src/components/table-view/table-view.svelte +43 -24
  69. package/src/components/tags-input/tags-input.svelte +17 -31
  70. package/src/components/work-parts/looks.ts +1 -1
  71. package/src/editor/content.css +3 -3
  72. package/src/editor/editor.svelte +1 -1
  73. package/src/inbox/thread-inbox.svelte +2 -9
  74. package/src/panel/side-panel.svelte +9 -4
  75. package/src/record/info-list.svelte +7 -8
  76. package/src/record/project-list.svelte +1 -1
  77. package/src/record/record-demo.svelte +2 -4
  78. package/src/record/record-rail.svelte +5 -1
  79. package/src/record/record-shell.svelte +1 -1
  80. package/src/record/record-stats.svelte +9 -3
  81. package/src/record/steps-rail.svelte +7 -11
  82. package/src/shadcn/accordion/accordion-trigger.svelte +1 -1
  83. package/src/shadcn/alert/alert-variants.ts +17 -0
  84. package/src/shadcn/alert/alert.svelte +2 -16
  85. package/src/shadcn/alert/index.ts +1 -1
  86. package/src/shadcn/alert-dialog/alert-dialog-content.svelte +5 -1
  87. package/src/shadcn/alert-dialog/alert-dialog-footer.svelte +12 -2
  88. package/src/shadcn/alert-dialog/alert-dialog-header.svelte +1 -1
  89. package/src/shadcn/alert-dialog/alert-dialog-title.svelte +1 -1
  90. package/src/shadcn/badge/badge-variants.ts +23 -0
  91. package/src/shadcn/badge/badge.svelte +2 -20
  92. package/src/shadcn/badge/index.ts +1 -1
  93. package/src/shadcn/bubble/bubble-content.svelte +1 -1
  94. package/src/shadcn/bubble/bubble.svelte +1 -1
  95. package/src/shadcn/button/button.svelte +11 -5
  96. package/src/shadcn/calendar/calendar-month-select.svelte +1 -1
  97. package/src/shadcn/calendar/calendar-year-select.svelte +1 -1
  98. package/src/shadcn/calendar/calendar.svelte +1 -1
  99. package/src/shadcn/card/card.svelte +2 -1
  100. package/src/shadcn/checkbox/checkbox.svelte +1 -1
  101. package/src/shadcn/code-block/code-block-actions.svelte +1 -1
  102. package/src/shadcn/command/command-dialog.svelte +2 -2
  103. package/src/shadcn/command/command-group.svelte +1 -1
  104. package/src/shadcn/command/command-input.svelte +1 -1
  105. package/src/shadcn/command/command-item.svelte +1 -1
  106. package/src/shadcn/dialog/dialog-body.svelte +22 -0
  107. package/src/shadcn/dialog/dialog-content.svelte +19 -4
  108. package/src/shadcn/dialog/dialog-footer.svelte +19 -1
  109. package/src/shadcn/dialog/dialog-header.svelte +6 -1
  110. package/src/shadcn/dialog/dialog-title.svelte +2 -1
  111. package/src/shadcn/dialog/index.ts +3 -0
  112. package/src/shadcn/dropdown-menu/dropdown-menu-content.svelte +5 -1
  113. package/src/shadcn/dropdown-menu/dropdown-menu-sub-content.svelte +1 -1
  114. package/src/shadcn/dropdown-menu/menu-item.ts +1 -1
  115. package/src/shadcn/field/field-separator.svelte +1 -1
  116. package/src/shadcn/hover-card/hover-card-content.svelte +1 -1
  117. package/src/shadcn/input/input.svelte +2 -2
  118. package/src/shadcn/input-otp/input-otp-slot.svelte +1 -1
  119. package/src/shadcn/message-scroller/message-scroller-button.svelte +1 -1
  120. package/src/shadcn/popover/popover-content.svelte +1 -1
  121. package/src/shadcn/radio-group/radio-group-item.svelte +1 -1
  122. package/src/shadcn/scroll-area/scroll-area.svelte +1 -1
  123. package/src/shadcn/select/select-content.svelte +6 -2
  124. package/src/shadcn/select/select-item.svelte +1 -1
  125. package/src/shadcn/select/select-trigger.svelte +1 -1
  126. package/src/shadcn/sheet/index.ts +3 -0
  127. package/src/shadcn/sheet/sheet-body.svelte +22 -0
  128. package/src/shadcn/sheet/sheet-content.svelte +27 -5
  129. package/src/shadcn/sheet/sheet-footer.svelte +14 -2
  130. package/src/shadcn/sheet/sheet-header.svelte +1 -1
  131. package/src/shadcn/sheet/sheet-title.svelte +1 -1
  132. package/src/shadcn/sheet/sheet.css +11 -5
  133. package/src/shadcn/sidebar/sidebar-group-action.svelte +1 -1
  134. package/src/shadcn/sidebar/sidebar-group-label.svelte +1 -1
  135. package/src/shadcn/sidebar/sidebar-inset.svelte +1 -1
  136. package/src/shadcn/sidebar/sidebar-menu-action.svelte +1 -1
  137. package/src/shadcn/sidebar/sidebar-menu-button.svelte +2 -2
  138. package/src/shadcn/sidebar/sidebar-menu-sub-button.svelte +1 -1
  139. package/src/shadcn/sidebar/sidebar-menu.svelte +1 -1
  140. package/src/shadcn/sidebar/sidebar.svelte +1 -1
  141. package/src/shadcn/skeleton/index.ts +3 -0
  142. package/src/shadcn/skeleton/skeleton-delay.svelte +63 -0
  143. package/src/shadcn/skeleton/skeleton-delay.svelte.test.ts +57 -0
  144. package/src/shadcn/skeleton/skeleton.svelte +5 -1
  145. package/src/shadcn/slider/slider.svelte +1 -1
  146. package/src/shadcn/switch/switch.svelte +2 -2
  147. package/src/shadcn/table/table-row.svelte +1 -1
  148. package/src/shadcn/tabs/tabs-list.svelte +1 -1
  149. package/src/shadcn/tabs/tabs-trigger.svelte +2 -1
  150. package/src/shadcn/textarea/textarea.svelte +1 -1
  151. package/src/shadcn/toggle/index.ts +1 -1
  152. package/src/shadcn/toggle/toggle-variants.ts +26 -0
  153. package/src/shadcn/toggle/toggle.svelte +7 -25
  154. package/src/shadcn/toggle-group/toggle-group.svelte +1 -1
  155. package/src/shadcn/tooltip/tooltip-content.svelte +1 -1
  156. package/src/shadcn/trace/trace-collapsible-trigger.svelte +1 -1
  157. package/src/shadcn/trace/trace.svelte +1 -1
  158. package/src/status/README.md +1 -1
  159. package/src/status/index.ts +2 -0
  160. package/src/status/pill-tint.ts +16 -0
  161. package/src/status/status-badge.svelte +21 -7
  162. package/src/status/status-dot.svelte +6 -11
  163. package/src/status/status-pill.svelte +40 -0
  164. package/src/svelte-reexports.test.ts +43 -0
  165. package/src/thread/thread.svelte +54 -136
  166. package/src/tokens/craft.css +55 -36
  167. package/src/tokens/palette.css +16 -9
  168. package/src/work/demo.svelte +48 -42
  169. package/src/work/detail/detail-demo.svelte +33 -24
  170. package/src/work/detail/task-chip.svelte +4 -4
  171. package/src/work/detail/task-detail.svelte +41 -108
  172. package/src/work/detail/task-property.svelte +7 -13
  173. package/src/work/detail/task-thread.svelte +48 -119
  174. package/src/work/docs/doc-editor-page.svelte +5 -4
  175. package/src/work/docs/doc-menu.svelte +9 -4
  176. package/src/work/docs/docs-demo.svelte +4 -4
  177. package/src/work/docs/edited-chip.svelte +11 -4
  178. package/src/work/gantt/gantt-bar.svelte +18 -14
  179. package/src/work/gantt/gantt-grid.svelte +7 -7
  180. package/src/work/gantt/gantt-group-row.svelte +7 -10
  181. package/src/work/gantt/gantt-header.svelte +3 -1
  182. package/src/work/gantt/gantt-task-row.svelte +19 -9
  183. package/src/work/gantt/gantt.css +4 -5
  184. package/src/work/inbox/inbox-card.svelte +32 -10
  185. package/src/work/inbox/inbox-draft.svelte +2 -2
  186. package/src/work/kanban-column.svelte +7 -15
  187. package/src/work/kanban-drag.ts +13 -8
  188. package/src/work/task-gantt.svelte +2 -1
  189. package/src/work/task-list.svelte +54 -53
  190. package/src/work/time/time-chip.svelte +16 -19
  191. package/src/work/time/time-dot.svelte +2 -1
  192. package/src/work/time/time-ring.svelte +2 -3
  193. package/src/work/time/time-tracker.svelte +72 -166
@@ -31,13 +31,20 @@
31
31
  <DialogPrimitive.Content
32
32
  bind:ref
33
33
  data-slot="dialog-content"
34
+ data-close={showCloseButton || undefined}
34
35
  class={cn(
35
- "t-modal bg-background ring-foreground/10 shadow-overlay fixed z-50 grid w-full gap-4 text-sm ring-1 outline-none",
36
+ // The popover surface, white on light: `bg-background` is the grey canvas now. The edge
37
+ // and the depth both come from `shadow-edge-overlay`, so no ring draws a second line.
38
+ "t-modal bg-popover text-popover-foreground shadow-edge-overlay fixed z-50 grid w-full gap-4 text-sm outline-none",
36
39
  // WHY: on a phone a centered card puts its controls at the top of the reach arc and leaves the on-screen keyboard fighting it for the middle of the screen.
37
40
 
38
41
  // Below sm the dialog docks to the bottom edge instead, scrolls inside itself, and clears the home indicator.
39
- "right-0 bottom-0 left-0 max-h-[88svh] overflow-y-auto overscroll-contain rounded-t-xl rounded-b-none p-4 pb-[max(1rem,env(safe-area-inset-bottom))]",
40
- "sm:top-1/2 sm:right-auto sm:bottom-auto sm:left-1/2 sm:max-h-[calc(100svh-4rem)] sm:max-w-md sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-xl sm:p-6",
42
+ "right-0 bottom-0 left-0 max-h-[88svh] overflow-y-auto overscroll-contain rounded-t-2xl rounded-b-none",
43
+ // One padding for every part, held in `--dialog-pad` so the header, the close button and a
44
+ // banded footer all read the same number. A single `p-` class, not `p-4 sm:p-6`: a caller's
45
+ // `p-0` used to cancel only the phone padding and leave 24px on desktop.
46
+ "[--dialog-pad:1rem] sm:[--dialog-pad:1.5rem] p-(--dialog-pad) pb-[max(var(--dialog-pad),env(safe-area-inset-bottom))]",
47
+ "sm:top-1/2 sm:right-auto sm:bottom-auto sm:left-1/2 sm:max-h-[calc(100svh-4rem)] sm:max-w-md sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-2xl",
41
48
  className,
42
49
  )}
43
50
  {...restProps}
@@ -46,7 +53,15 @@
46
53
  {#if showCloseButton}
47
54
  <DialogPrimitive.Close data-slot="dialog-close">
48
55
  {#snippet child({ props })}
49
- <Button variant="ghost" class="absolute top-4 right-4" size="sm" icon {...props}>
56
+ <!-- Centred on the title's 24px line, the glyph's right edge on the content edge:
57
+ a 32px button sits 4px above and 8px past the padding. -->
58
+ <Button
59
+ variant="ghost"
60
+ class="absolute top-[calc(var(--dialog-pad)-0.25rem)] right-[calc(var(--dialog-pad)-0.5rem)]"
61
+ size="sm"
62
+ icon
63
+ {...props}
64
+ >
50
65
  <X size={16} />
51
66
  <span class="sr-only">Close</span>
52
67
  </Button>
@@ -9,16 +9,34 @@
9
9
  class: className,
10
10
  children,
11
11
  showCloseButton = false,
12
+ band = false,
12
13
  ...restProps
13
14
  }: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
14
15
  showCloseButton?: boolean;
16
+ /**
17
+ * Draw the footer as a band: a hairline on top and a quiet surface out to both edges
18
+ * and the bottom corners. It cancels the content's `--dialog-pad` with a negative
19
+ * margin, so it only works as the content's last child. A bare `data-band` attribute
20
+ * does the same, for callers on a release that predates this prop.
21
+ */
22
+ band?: boolean;
15
23
  } = $props();
16
24
  </script>
17
25
 
18
26
  <div
19
27
  bind:this={ref}
20
28
  data-slot="dialog-footer"
21
- class={cn("gap-2 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className)}
29
+ data-band={band || undefined}
30
+ class={cn(
31
+ "flex flex-col-reverse gap-2 sm:flex-row sm:items-center sm:justify-end",
32
+ // The band. The bottom margin matches the content's bottom padding, safe area included,
33
+ // so the surface reaches the edge on a phone docked over the home indicator too.
34
+ "data-band:border-border data-band:bg-muted/50 data-band:mt-2 data-band:border-t",
35
+ "data-band:mx-[calc(-1*var(--dialog-pad))] data-band:px-(--dialog-pad) data-band:py-4",
36
+ "data-band:mb-[calc(-1*max(var(--dialog-pad),env(safe-area-inset-bottom)))]",
37
+ "data-band:pb-[max(1rem,env(safe-area-inset-bottom))] sm:data-band:pb-4",
38
+ className,
39
+ )}
22
40
  {...restProps}
23
41
  >
24
42
  {@render children?.()}
@@ -10,10 +10,15 @@
10
10
  }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
11
11
  </script>
12
12
 
13
+ <!-- The content pads it. With a close button the title stops 32px short of it,
14
+ so a long title wraps instead of running under the X. -->
13
15
  <div
14
16
  bind:this={ref}
15
17
  data-slot="dialog-header"
16
- class={cn("gap-2 flex flex-col", className)}
18
+ class={cn(
19
+ "flex flex-col gap-1.5 in-data-close:pe-8",
20
+ className,
21
+ )}
17
22
  {...restProps}
18
23
  >
19
24
  {@render children?.()}
@@ -9,9 +9,10 @@
9
9
  }: DialogPrimitive.TitleProps = $props();
10
10
  </script>
11
11
 
12
+ <!-- 16px on a 24px line: the close button centres on that line. -->
12
13
  <DialogPrimitive.Title
13
14
  bind:ref
14
15
  data-slot="dialog-title"
15
- class={cn("leading-none font-medium", className)}
16
+ class={cn("text-base leading-6 font-semibold tracking-tight", className)}
16
17
  {...restProps}
17
18
  />
@@ -8,6 +8,7 @@ import Content from "./dialog-content.svelte";
8
8
  import Description from "./dialog-description.svelte";
9
9
  import Trigger from "./dialog-trigger.svelte";
10
10
  import Close from "./dialog-close.svelte";
11
+ import Body from "./dialog-body.svelte";
11
12
 
12
13
  export {
13
14
  Root,
@@ -20,6 +21,7 @@ export {
20
21
  Content,
21
22
  Description,
22
23
  Close,
24
+ Body,
23
25
  //
24
26
  Root as Dialog,
25
27
  Title as DialogTitle,
@@ -31,4 +33,5 @@ export {
31
33
  Content as DialogContent,
32
34
  Description as DialogDescription,
33
35
  Close as DialogClose,
36
+ Body as DialogBody,
34
37
  };
@@ -8,6 +8,8 @@
8
8
  ref = $bindable(null),
9
9
  sideOffset = 4,
10
10
  align = "start",
11
+ // Keeps 8px between the menu and the viewport edge, matching the `100vw-1rem` width cap.
12
+ collisionPadding = 8,
11
13
  portalProps,
12
14
  class: className,
13
15
  ...restProps
@@ -22,8 +24,10 @@
22
24
  data-slot="dropdown-menu-content"
23
25
  {sideOffset}
24
26
  {align}
27
+ {collisionPadding}
25
28
  class={cn(
26
- "t-dropdown ring-foreground/10 bg-popover text-popover-foreground min-w-32 rounded-xl p-1 shadow-raised ring-1 z-50 w-(--bits-dropdown-menu-anchor-width) max-h-[var(--bits-floating-available-height,100svh)] max-w-[calc(100vw-1rem)] overflow-x-hidden overflow-y-auto overscroll-contain outline-none data-closed:overflow-hidden",
29
+ // 14px around 10px rows inside a 4px inset, so the corners run concentric.
30
+ "t-dropdown bg-popover text-popover-foreground min-w-32 rounded-xl p-1 shadow-edge-raised z-50 w-(--bits-dropdown-menu-anchor-width) max-h-[var(--bits-floating-available-height,100svh)] max-w-[calc(100vw-1rem)] overflow-x-hidden overflow-y-auto overscroll-contain outline-none data-closed:overflow-hidden",
27
31
  className,
28
32
  )}
29
33
  {...restProps}
@@ -13,7 +13,7 @@
13
13
  bind:ref
14
14
  data-slot="dropdown-menu-sub-content"
15
15
  class={cn(
16
- "t-dropdown ring-foreground/10 bg-popover text-popover-foreground min-w-[96px] rounded-xl p-1 shadow-raised ring-1 z-50 w-auto",
16
+ "t-dropdown bg-popover text-popover-foreground min-w-[96px] rounded-xl p-1 shadow-edge-raised z-50 w-auto",
17
17
  className,
18
18
  )}
19
19
  {...restProps}
@@ -24,7 +24,7 @@ import { tv, type VariantProps } from "tailwind-variants";
24
24
  * A row has to look the same either way, so it answers to both.
25
25
  */
26
26
  export const menuItemClass = tv({
27
- base: "relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-disabled:pointer-events-none data-disabled:opacity-50 disabled:pointer-events-none disabled:opacity-50",
27
+ base: "relative flex cursor-default items-center gap-1.5 rounded-lg px-1.5 py-1 text-sm outline-hidden select-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-disabled:pointer-events-none data-disabled:opacity-50 disabled:pointer-events-none disabled:opacity-50",
28
28
  variants: {
29
29
  variant: {
30
30
  default:
@@ -26,7 +26,7 @@
26
26
  <Separator class="absolute inset-0 top-1/2" />
27
27
  {#if children}
28
28
  <span
29
- class="bg-background text-muted-foreground relative mx-auto block w-fit px-2"
29
+ class="bg-card text-muted-foreground relative mx-auto block w-fit px-2"
30
30
  data-slot="field-separator-content"
31
31
  >
32
32
  {@render children()}
@@ -23,7 +23,7 @@
23
23
  {align}
24
24
  {sideOffset}
25
25
  class={cn(
26
- "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-end-2 data-[side=right]:slide-in-from-start-2 data-[side=top]:slide-in-from-bottom-2 z-50 mt-3 w-64 rounded-md border p-4 shadow-md outline-hidden outline-none",
26
+ "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-end-2 data-[side=right]:slide-in-from-start-2 data-[side=top]:slide-in-from-bottom-2 z-50 mt-3 w-64 rounded-2xl p-4 shadow-edge-raised outline-hidden outline-none",
27
27
  className,
28
28
  )}
29
29
  {...restProps}
@@ -25,7 +25,7 @@
25
25
  bind:this={ref}
26
26
  data-slot={dataSlot}
27
27
  class={cn(
28
- "dark:bg-input/30 border-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 disabled:bg-input/50 dark:disabled:bg-input/80 h-8 any-pointer-coarse:h-11 rounded-lg border bg-transparent px-2.5 py-1 text-base shadow-field transition-[color,background-color,box-shadow] duration-[var(--duration-quick)] ease-[var(--ease-smooth-out)] file:h-6 file:text-sm file:font-medium focus-visible:ring-3 aria-invalid:ring-3 md:text-sm file:text-foreground placeholder:text-muted-foreground w-full min-w-0 outline-none file:inline-flex file:border-0 file:bg-transparent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
28
+ "dark:bg-input/30 border-input enabled:hover:border-foreground/20 focus-visible:border-ring focus-visible:shadow-(--ring-focus) aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 disabled:bg-input/50 dark:disabled:bg-input/80 h-8 any-pointer-coarse:h-11 rounded-lg border bg-transparent px-2.5 py-1 text-base shadow-field transition-[color,background-color,border-color,box-shadow] duration-[var(--duration-quick)] ease-[var(--ease-smooth-out)] file:h-6 file:text-sm file:font-medium aria-invalid:ring-3 md:text-sm file:text-foreground placeholder:text-muted-foreground w-full min-w-0 outline-none file:inline-flex file:border-0 file:bg-transparent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
29
29
  className,
30
30
  )}
31
31
  type="file"
@@ -38,7 +38,7 @@
38
38
  bind:this={ref}
39
39
  data-slot={dataSlot}
40
40
  class={cn(
41
- "dark:bg-input/30 border-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 disabled:bg-input/50 dark:disabled:bg-input/80 h-8 any-pointer-coarse:h-11 rounded-lg border bg-transparent px-2.5 py-1 text-base shadow-field transition-[color,background-color,box-shadow] duration-[var(--duration-quick)] ease-[var(--ease-smooth-out)] file:h-6 file:text-sm file:font-medium focus-visible:ring-3 aria-invalid:ring-3 md:text-sm file:text-foreground placeholder:text-muted-foreground w-full min-w-0 outline-none file:inline-flex file:border-0 file:bg-transparent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
41
+ "dark:bg-input/30 border-input enabled:hover:border-foreground/20 focus-visible:border-ring focus-visible:shadow-(--ring-focus) aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 disabled:bg-input/50 dark:disabled:bg-input/80 h-8 any-pointer-coarse:h-11 rounded-lg border bg-transparent px-2.5 py-1 text-base shadow-field transition-[color,background-color,border-color,box-shadow] duration-[var(--duration-quick)] ease-[var(--ease-smooth-out)] file:h-6 file:text-sm file:font-medium aria-invalid:ring-3 md:text-sm file:text-foreground placeholder:text-muted-foreground w-full min-w-0 outline-none file:inline-flex file:border-0 file:bg-transparent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
42
42
  className,
43
43
  )}
44
44
  {type}
@@ -17,7 +17,7 @@
17
17
  class={cn(
18
18
  "border-input aria-invalid:border-destructive dark:bg-input/30 relative flex size-9 items-center justify-center border-y border-e text-sm transition-[border-color,box-shadow,background-color] outline-none first:rounded-s-md first:border-s last:rounded-e-md",
19
19
  cell.isActive &&
20
- "border-ring ring-ring/50 bg-accent/50 aria-invalid:border-destructive dark:aria-invalid:ring-destructive/40 aria-invalid:ring-destructive/20 ring-offset-background z-10 ring-[3px]",
20
+ "border-ring ring-ring/50 bg-accent/50 aria-invalid:border-destructive dark:aria-invalid:ring-destructive/40 aria-invalid:ring-destructive/20 ring-offset-card z-10 ring-[3px]",
21
21
  className,
22
22
  )}
23
23
  {...restProps}
@@ -28,7 +28,7 @@
28
28
  data-size={size}
29
29
  {direction}
30
30
  class={cn(
31
- "absolute inset-s-1/2 -translate-x-1/2 border-border bg-background text-foreground transition-[translate,scale,opacity] duration-200 hover:bg-muted hover:text-foreground data-[active=false]:pointer-events-none data-[active=false]:scale-95 data-[active=false]:opacity-0 data-[active=false]:duration-400 data-[active=false]:ease-[cubic-bezier(0.7,0,0.84,0)] data-[active=true]:translate-y-0 data-[active=true]:scale-100 data-[active=true]:opacity-100 data-[active=true]:ease-[cubic-bezier(0.23,1,0.32,1)] data-[direction=end]:bottom-4 data-[direction=end]:data-[active=false]:translate-y-full data-[direction=start]:top-4 data-[direction=start]:data-[active=false]:-translate-y-full rtl:translate-x-1/2 data-[direction=start]:[&_svg]:rotate-180",
31
+ "absolute inset-s-1/2 -translate-x-1/2 border-border bg-card text-foreground transition-[translate,scale,opacity] duration-200 hover:bg-muted hover:text-foreground data-[active=false]:pointer-events-none data-[active=false]:scale-95 data-[active=false]:opacity-0 data-[active=false]:duration-400 data-[active=false]:ease-[cubic-bezier(0.7,0,0.84,0)] data-[active=true]:translate-y-0 data-[active=true]:scale-100 data-[active=true]:opacity-100 data-[active=true]:ease-[cubic-bezier(0.23,1,0.32,1)] data-[direction=end]:bottom-4 data-[direction=end]:data-[active=false]:translate-y-full data-[direction=start]:top-4 data-[direction=start]:data-[active=false]:-translate-y-full rtl:translate-x-1/2 data-[direction=start]:[&_svg]:rotate-180",
32
32
  className
33
33
  )}
34
34
  {...restProps}
@@ -30,7 +30,7 @@
30
30
  {align}
31
31
  {collisionPadding}
32
32
  class={cn(
33
- "t-dropdown bg-popover text-popover-foreground ring-foreground/10 rounded-xl p-4 text-sm shadow-raised ring-1 z-50 w-72 max-h-[var(--bits-floating-available-height,100svh)] max-w-[calc(100vw-1rem)] overflow-y-auto overscroll-contain outline-hidden",
33
+ "t-dropdown bg-popover text-popover-foreground rounded-2xl p-4 text-sm shadow-edge-raised z-50 w-72 max-h-[var(--bits-floating-available-height,100svh)] max-w-[calc(100vw-1rem)] overflow-y-auto overscroll-contain outline-hidden",
34
34
  className,
35
35
  )}
36
36
  {...restProps}
@@ -14,7 +14,7 @@
14
14
  bind:ref
15
15
  data-slot="radio-group-item"
16
16
  class={cn(
17
- "border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 relative after:absolute after:-inset-2 any-pointer-coarse:after:-inset-3.5 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
17
+ "border-input text-primary focus-visible:border-ring aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 relative after:absolute after:-inset-2 any-pointer-coarse:after:-inset-3.5 aspect-square size-4 shrink-0 rounded-full border shadow-field transition-[color,box-shadow] outline-none focus-visible:shadow-(--ring-focus) disabled:cursor-not-allowed disabled:opacity-50",
18
18
  className,
19
19
  )}
20
20
  {...restProps}
@@ -29,7 +29,7 @@
29
29
  <ScrollAreaPrimitive.Viewport
30
30
  bind:ref={viewportRef}
31
31
  data-slot="scroll-area-viewport"
32
- class="cn-scroll-area-viewport focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1"
32
+ class="cn-scroll-area-viewport size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:shadow-(--ring-focus) focus-visible:outline-1"
33
33
  >
34
34
  {@render children?.()}
35
35
  </ScrollAreaPrimitive.Viewport>
@@ -11,6 +11,8 @@
11
11
  ref = $bindable(null),
12
12
  class: className,
13
13
  sideOffset = 4,
14
+ // 8px between the list and the viewport edge, as the dropdown and popover keep.
15
+ collisionPadding = 8,
14
16
  portalProps,
15
17
  children,
16
18
  preventScroll = true,
@@ -24,10 +26,12 @@
24
26
  <SelectPrimitive.Content
25
27
  bind:ref
26
28
  {sideOffset}
29
+ {collisionPadding}
27
30
  {preventScroll}
28
31
  data-slot="select-content"
29
32
  class={cn(
30
- "t-dropdown bg-popover text-popover-foreground ring-foreground/10 min-w-36 rounded-xl shadow-raised ring-1 relative isolate z-50 max-h-[var(--bits-floating-available-height,100svh)] max-w-[calc(100vw-1rem)] overflow-x-hidden overflow-y-auto overscroll-contain",
33
+ // 14px around 10px rows inside a 4px inset, so the corners run concentric.
34
+ "t-dropdown bg-popover text-popover-foreground min-w-36 rounded-xl shadow-edge-raised relative isolate z-50 max-h-[var(--bits-floating-available-height,100svh)] max-w-[calc(100vw-1rem)] overflow-x-hidden overflow-y-auto overscroll-contain",
31
35
  className,
32
36
  )}
33
37
  {...restProps}
@@ -35,7 +39,7 @@
35
39
  <SelectScrollUpButton />
36
40
  <SelectPrimitive.Viewport
37
41
  class={cn(
38
- "h-(--bits-select-anchor-height) w-full min-w-(--bits-select-anchor-width) scroll-my-1",
42
+ "h-(--bits-select-anchor-height) w-full min-w-(--bits-select-anchor-width) scroll-my-1 p-1",
39
43
  )}
40
44
  >
41
45
  {@render children?.()}
@@ -18,7 +18,7 @@
18
18
  {value}
19
19
  data-slot="select-item"
20
20
  class={cn(
21
- "focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 focus:bg-accent data-highlighted:bg-accent data-highlighted:text-accent-foreground focus:text-accent-foreground relative flex w-full cursor-default items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
21
+ "focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground gap-2 rounded-lg py-1.5 pr-8 pl-2 text-sm [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 focus:bg-accent data-highlighted:bg-accent data-highlighted:text-accent-foreground focus:text-accent-foreground relative flex w-full cursor-default items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
22
22
  className,
23
23
  )}
24
24
  {...restProps}
@@ -19,7 +19,7 @@
19
19
  data-slot="select-trigger"
20
20
  data-size={size}
21
21
  class={cn(
22
- "border-input data-placeholder:text-muted-foreground dark:bg-input/30 dark:hover:bg-input/50 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 gap-1.5 rounded-md border bg-transparent py-1 pr-2 pl-2.5 text-sm shadow-xs transition-[color,box-shadow] focus-visible:ring-3 aria-invalid:ring-3 data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:text-[0.8rem] relative data-[size=sm]:after:absolute data-[size=sm]:after:top-1/2 data-[size=sm]:after:left-0 data-[size=sm]:after:h-[max(100%,2rem)] data-[size=sm]:after:w-full data-[size=sm]:after:-translate-y-1/2 *:data-[slot=select-value]:flex *:data-[slot=select-value]:gap-1.5 [&_svg:not([class*='size-'])]:size-4 flex w-fit items-center justify-between whitespace-nowrap outline-none disabled:cursor-not-allowed disabled:opacity-50 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
22
+ "border-input data-placeholder:text-muted-foreground dark:bg-input/30 dark:hover:bg-input/50 enabled:hover:border-foreground/20 focus-visible:border-ring focus-visible:shadow-(--ring-focus) aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 gap-1.5 rounded-lg border bg-transparent py-1 pr-2 pl-2.5 text-sm shadow-field transition-[color,background-color,border-color,box-shadow] duration-[var(--duration-quick)] ease-[var(--ease-smooth-out)] aria-invalid:ring-3 data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:text-[0.8rem] relative data-[size=sm]:after:absolute data-[size=sm]:after:top-1/2 data-[size=sm]:after:left-0 data-[size=sm]:after:h-[max(100%,2rem)] data-[size=sm]:after:w-full data-[size=sm]:after:-translate-y-1/2 *:data-[slot=select-value]:flex *:data-[slot=select-value]:gap-1.5 [&_svg:not([class*='size-'])]:size-4 flex w-fit items-center justify-between whitespace-nowrap outline-none disabled:cursor-not-allowed disabled:opacity-50 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
23
23
  className,
24
24
  )}
25
25
  {...restProps}
@@ -8,6 +8,7 @@ import Header from "./sheet-header.svelte";
8
8
  import Footer from "./sheet-footer.svelte";
9
9
  import Title from "./sheet-title.svelte";
10
10
  import Description from "./sheet-description.svelte";
11
+ import Body from "./sheet-body.svelte";
11
12
 
12
13
  export {
13
14
  Root,
@@ -20,6 +21,7 @@ export {
20
21
  Footer,
21
22
  Title,
22
23
  Description,
24
+ Body,
23
25
  //
24
26
  Root as Sheet,
25
27
  Close as SheetClose,
@@ -31,4 +33,5 @@ export {
31
33
  Footer as SheetFooter,
32
34
  Title as SheetTitle,
33
35
  Description as SheetDescription,
36
+ Body as SheetBody,
34
37
  };
@@ -0,0 +1,22 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ import { cn, type WithElementRef } from "../../lib/utils.js";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
11
+ </script>
12
+
13
+ <!-- The scrolling middle of a sheet, padded like the header and footer so the three
14
+ share one left edge. It takes the height the header and footer leave. -->
15
+ <div
16
+ bind:this={ref}
17
+ data-slot="sheet-body"
18
+ class={cn("flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto overscroll-contain px-4", className)}
19
+ {...restProps}
20
+ >
21
+ {@render children?.()}
22
+ </div>
@@ -19,6 +19,7 @@
19
19
  class: className,
20
20
  side = "right",
21
21
  showCloseButton = true,
22
+ floating,
22
23
  portalProps,
23
24
  children,
24
25
  ...restProps
@@ -26,20 +27,38 @@
26
27
  portalProps?: WithoutChildrenOrChild<ComponentProps<typeof SheetPortal>>;
27
28
  side?: Side;
28
29
  showCloseButton?: boolean;
30
+ /**
31
+ * From `sm` up the sheet floats 8px off the viewport edge at the overlay radius, like
32
+ * SidePanel. On by default for left and right sheets; `floating={false}` keeps one flush.
33
+ * Under `sm` it stays full bleed, since a phone needs the width.
34
+ */
35
+ floating?: boolean;
29
36
  children: Snippet;
30
37
  } = $props();
31
38
 
39
+ // Side sheets float unless a caller opts out; a bottom sheet stays docked.
40
+ const floats = $derived(floating ?? side !== "bottom");
41
+
32
42
  // Plain side utilities, not `data-[side=x]:` variants, because the variant outranks a
33
43
  // caller's `sm:max-w-xl` and tailwind-merge can't dedupe across modifier sets.
34
44
  const SIDE_CLASS: Record<Side, string> = {
35
45
  // h-dvh, not h-full: on iOS Safari a fixed panel sizes against the layout
36
46
  // viewport, which is taller than the visible area, so h-full hides the footer.
37
- right: "inset-y-0 right-0 h-dvh w-3/4 border-l sm:max-w-sm",
38
- left: "inset-y-0 left-0 h-dvh w-3/4 border-r sm:max-w-sm",
47
+ // No side border: `shadow-edge-overlay` draws the hairline and the depth.
48
+ right: "inset-y-0 right-0 h-dvh w-3/4 sm:max-w-sm",
49
+ left: "inset-y-0 left-0 h-dvh w-3/4 sm:max-w-sm",
39
50
  // Full width, capped at 80vh so the overlay stays visible. The safe-area
40
51
  // padding keeps the last row clear of the home indicator.
41
52
  bottom:
42
- "inset-x-0 bottom-0 h-auto max-h-[80vh] w-full rounded-t-lg border-t pb-[env(safe-area-inset-bottom)]",
53
+ "inset-x-0 bottom-0 h-auto max-h-[80vh] w-full rounded-t-2xl pb-[env(safe-area-inset-bottom)]",
54
+ };
55
+
56
+ // Floating: an 8px inset (`2`) on the sheet's own sides, the height cut by both gutters,
57
+ // and the overlay radius on every corner (DESIGN.md rule 2).
58
+ const FLOATING_CLASS: Record<Side, string> = {
59
+ right: "sm:inset-y-2 sm:right-2 sm:h-[calc(100dvh-1rem)] sm:rounded-2xl",
60
+ left: "sm:inset-y-2 sm:left-2 sm:h-[calc(100dvh-1rem)] sm:rounded-2xl",
61
+ bottom: "sm:inset-x-2 sm:bottom-2 sm:w-[calc(100%-1rem)] sm:rounded-2xl",
43
62
  };
44
63
  </script>
45
64
 
@@ -49,9 +68,12 @@
49
68
  bind:ref
50
69
  data-slot="sheet-content"
51
70
  data-side={side}
71
+ data-floating={floats || undefined}
72
+ data-close={showCloseButton || undefined}
52
73
  class={cn(
53
- "t-sheet bg-background fixed z-50 flex flex-col gap-4 bg-clip-padding text-sm shadow-overlay",
74
+ "t-sheet bg-popover text-popover-foreground fixed z-50 flex flex-col gap-4 bg-clip-padding text-sm shadow-edge-overlay",
54
75
  SIDE_CLASS[side],
76
+ floats && FLOATING_CLASS[side],
55
77
  className,
56
78
  )}
57
79
  {...restProps}
@@ -60,7 +82,7 @@
60
82
  {#if showCloseButton}
61
83
  <SheetPrimitive.Close data-slot="sheet-close">
62
84
  {#snippet child({ props })}
63
- <Button variant="ghost" class="absolute top-3 right-3" size="sm" icon {...props}>
85
+ <Button variant="ghost" class="absolute top-3 right-2" size="sm" icon {...props}>
64
86
  <X size={16} />
65
87
  <span class="sr-only">Close</span>
66
88
  </Button>
@@ -6,14 +6,26 @@
6
6
  ref = $bindable(null),
7
7
  class: className,
8
8
  children,
9
+ band = false,
9
10
  ...restProps
10
- }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
11
+ }: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
12
+ /**
13
+ * A hairline on top and a quiet surface edge to edge, following the sheet's bottom
14
+ * corners when it floats. A bare `data-band` attribute does the same.
15
+ */
16
+ band?: boolean;
17
+ } = $props();
11
18
  </script>
12
19
 
13
20
  <div
14
21
  bind:this={ref}
15
22
  data-slot="sheet-footer"
16
- class={cn("gap-2 p-4 mt-auto flex flex-col", className)}
23
+ data-band={band || undefined}
24
+ class={cn(
25
+ "mt-auto flex flex-col gap-2 p-4",
26
+ "data-band:border-border data-band:bg-muted/50 data-band:border-t data-band:rounded-b-[inherit] data-band:flex-col-reverse data-band:sm:flex-row data-band:sm:justify-end",
27
+ className,
28
+ )}
17
29
  {...restProps}
18
30
  >
19
31
  {@render children?.()}
@@ -13,7 +13,7 @@
13
13
  <div
14
14
  bind:this={ref}
15
15
  data-slot="sheet-header"
16
- class={cn("gap-0.5 p-4 flex flex-col", className)}
16
+ class={cn("flex flex-col gap-1 p-4 in-data-close:pe-12", className)}
17
17
  {...restProps}
18
18
  >
19
19
  {@render children?.()}
@@ -12,6 +12,6 @@
12
12
  <SheetPrimitive.Title
13
13
  bind:ref
14
14
  data-slot="sheet-title"
15
- class={cn("text-foreground text-base font-medium", className)}
15
+ class={cn("text-foreground text-base leading-6 font-semibold tracking-tight", className)}
16
16
  {...restProps}
17
17
  />
@@ -1,10 +1,12 @@
1
1
  /* The sheet slide: transitions.dev panel reveal, owned by the sheet. */
2
2
 
3
+ /* The same 300ms open and 250ms close as before, named. DESIGN.md hasn't decided
4
+ whether the sheet takes Vaul's 500ms drawer timing, so the values hold. */
3
5
  :root {
4
- --sheet-open-dur: 300ms;
5
- --sheet-close-dur: 250ms;
6
+ --sheet-open-dur: var(--duration-slow);
7
+ --sheet-close-dur: var(--duration-fast);
6
8
  --sheet-translate: 100%;
7
- --sheet-ease: cubic-bezier(0.22, 1, 0.36, 1);
9
+ --sheet-ease: var(--ease-smooth-out);
8
10
  }
9
11
 
10
12
  .t-sheet {
@@ -41,8 +43,12 @@
41
43
  opacity var(--sheet-open-dur) var(--sheet-ease);
42
44
  }
43
45
 
46
+ /* Reduced motion keeps the fade and drops the slide (DESIGN.md rule 13). */
44
47
  @media (prefers-reduced-motion: reduce) {
45
- .t-sheet {
46
- transition: none !important;
48
+ .t-sheet,
49
+ .t-sheet[data-side],
50
+ .t-sheet[data-state] {
51
+ transform: none;
52
+ transition-property: opacity;
47
53
  }
48
54
  }
@@ -15,7 +15,7 @@
15
15
 
16
16
  const mergedProps = $derived({
17
17
  class: cn(
18
- "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 w-5 rounded-md p-0 focus-visible:ring-2 [&>svg]:size-4 flex aspect-square items-center justify-center outline-hidden transition-transform group-data-[collapsible=icon]:hidden after:absolute after:-inset-2 lg:after:hidden [&>svg]:shrink-0",
18
+ "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 w-5 rounded-md p-0 focus-visible:shadow-(--ring-focus) [&>svg]:size-4 flex aspect-square items-center justify-center outline-hidden transition-transform group-data-[collapsible=icon]:hidden after:absolute after:-inset-2 lg:after:hidden [&>svg]:shrink-0",
19
19
  className,
20
20
  ),
21
21
  "data-slot": "sidebar-group-action",
@@ -15,7 +15,7 @@
15
15
 
16
16
  const mergedProps = $derived({
17
17
  class: cn(
18
- "text-sidebar-foreground/90 ring-sidebar-ring h-8 rounded-md px-2 text-xs font-medium transition-[margin,opacity] duration-[var(--duration-fast)] ease-[var(--ease-smooth-out)] group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0 group-data-[collapsible=icon]:pointer-events-none focus-visible:ring-2 [&>svg]:size-4 flex shrink-0 items-center outline-hidden [&>svg]:shrink-0",
18
+ "text-sidebar-foreground/90 ring-sidebar-ring h-8 rounded-md px-2 text-xs font-medium transition-[margin,opacity] duration-[var(--duration-fast)] ease-[var(--ease-smooth-out)] group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0 group-data-[collapsible=icon]:pointer-events-none focus-visible:shadow-(--ring-focus) [&>svg]:size-4 flex shrink-0 items-center outline-hidden [&>svg]:shrink-0",
19
19
  className,
20
20
  ),
21
21
  "data-slot": "sidebar-group-label",
@@ -14,7 +14,7 @@
14
14
  bind:this={ref}
15
15
  data-slot="sidebar-inset"
16
16
  class={cn(
17
- "bg-background transition-[margin] duration-[var(--duration-fast)] ease-[var(--ease-smooth-out)] motion-reduce:transition-none lg:peer-data-[variant=inset]:m-2 lg:peer-data-[variant=inset]:ml-0 lg:peer-data-[variant=inset]:rounded-xl lg:peer-data-[variant=inset]:shadow-sm lg:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2 relative flex min-h-0 w-full flex-1 flex-col",
17
+ "bg-background transition-[margin] duration-[var(--duration-fast)] ease-[var(--ease-smooth-out)] motion-reduce:transition-none lg:peer-data-[variant=inset]:m-2 lg:peer-data-[variant=inset]:ml-0 lg:peer-data-[variant=inset]:rounded-3xl lg:peer-data-[variant=inset]:bg-card lg:peer-data-[variant=inset]:shadow-card lg:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2 relative flex min-h-0 w-full flex-1 flex-col",
18
18
  className,
19
19
  )}
20
20
  {...restProps}
@@ -17,7 +17,7 @@
17
17
 
18
18
  const mergedProps = $derived({
19
19
  class: cn(
20
- "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 aspect-square w-5 rounded-md p-0 peer-data-[size=default]/menu-button:top-1.5 peer-data-[size=lg]/menu-button:top-2.5 peer-data-[size=sm]/menu-button:top-1 focus-visible:ring-2 [&>svg]:size-4 flex items-center justify-center outline-hidden transition-transform group-data-[collapsible=icon]:hidden after:absolute after:-inset-2 lg:after:hidden [&>svg]:shrink-0",
20
+ "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-foreground/4 hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 aspect-square w-5 rounded-md p-0 peer-data-[size=default]/menu-button:top-1.5 peer-data-[size=lg]/menu-button:top-2.5 peer-data-[size=sm]/menu-button:top-1 focus-visible:shadow-(--ring-focus) [&>svg]:size-4 flex items-center justify-center outline-hidden transition-[background-color,color,transform] duration-[var(--duration-quick)] ease-[var(--ease-smooth-out)] group-data-[collapsible=icon]:hidden after:absolute after:-inset-2 lg:after:hidden [&>svg]:shrink-0",
21
21
  showOnHover &&
22
22
  "peer-data-active/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-open:opacity-100 lg:opacity-0",
23
23
  className,
@@ -2,10 +2,10 @@
2
2
  import { tv, type VariantProps } from "tailwind-variants";
3
3
 
4
4
  export const sidebarMenuButtonVariants = tv({
5
- base: "ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:text-sidebar-accent-foreground data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground gap-2 rounded-md p-2 text-left text-sm transition-[width,height,padding,background-color,color] duration-[var(--duration-fast)] ease-[var(--ease-smooth-out)] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! focus-visible:ring-2 data-active:font-medium peer/menu-button group/menu-button flex w-full items-center overflow-hidden outline-hidden disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 [&>span:last-child]:truncate",
5
+ base: "ring-sidebar-ring hover:bg-sidebar-foreground/4 hover:text-sidebar-accent-foreground active:bg-sidebar-foreground/8 active:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:text-sidebar-accent-foreground data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground gap-2 rounded-md p-2 text-left text-sm transition-[width,height,padding,background-color,color] duration-[var(--duration-fast)] ease-[var(--ease-smooth-out)] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! focus-visible:shadow-(--ring-focus) data-active:font-medium peer/menu-button group/menu-button flex w-full items-center overflow-hidden outline-hidden disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 [&>span:last-child]:truncate",
6
6
  variants: {
7
7
  variant: {
8
- default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
8
+ default: "hover:bg-sidebar-foreground/4 hover:text-sidebar-accent-foreground",
9
9
  outline:
10
10
  "bg-background hover:bg-sidebar-accent hover:text-sidebar-accent-foreground shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]",
11
11
  },
@@ -19,7 +19,7 @@
19
19
 
20
20
  const mergedProps = $derived({
21
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:bg-sidebar-accent data-active:text-sidebar-accent-foreground h-7 gap-2 rounded-md px-2 any-pointer-coarse:h-11 focus-visible:ring-2 data-[size=md]:text-sm data-[size=sm]:text-xs [&>svg]:size-4 flex min-w-0 -translate-x-px items-center overflow-hidden outline-hidden 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]:shrink-0",
22
+ "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-foreground/4 hover:text-sidebar-accent-foreground active:bg-sidebar-foreground/8 active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:text-sidebar-accent-foreground h-7 gap-2 rounded-md px-2 transition-[background-color,color] duration-[var(--duration-quick)] ease-[var(--ease-smooth-out)] any-pointer-coarse:h-11 focus-visible:shadow-(--ring-focus) data-[size=md]:text-sm data-[size=sm]:text-xs [&>svg]:size-4 flex min-w-0 -translate-x-px items-center overflow-hidden outline-hidden 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]:shrink-0",
23
23
  className,
24
24
  ),
25
25
  "data-slot": "sidebar-menu-sub-button",
@@ -14,7 +14,7 @@
14
14
  bind:this={ref}
15
15
  data-slot="sidebar-menu"
16
16
  data-sidebar="menu"
17
- class={cn("gap-0 flex w-full min-w-0 flex-col", className)}
17
+ class={cn("gap-0.5 flex w-full min-w-0 flex-col", className)}
18
18
  {...restProps}
19
19
  >
20
20
  {@render children?.()}
@@ -100,7 +100,7 @@
100
100
  <div
101
101
  data-sidebar="sidebar"
102
102
  data-slot="sidebar-inner"
103
- class="bg-sidebar group-data-[variant=floating]:ring-sidebar-border group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:shadow-sm group-data-[variant=floating]:ring-1 flex size-full flex-col"
103
+ class="bg-sidebar group-data-[variant=floating]:rounded-xl group-data-[variant=floating]:shadow-card flex size-full flex-col"
104
104
  >
105
105
  {@render children?.()}
106
106
  </div>