@warmio/ui 1.3.0 → 1.5.2

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.
@@ -0,0 +1,24 @@
1
+ Fluid Functionalism
2
+ https://github.com/mickadesign/fluid-functionalism
3
+
4
+ MIT License
5
+
6
+ Copyright (c) 2026 Micka Touillaud
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ of this software and associated documentation files (the "Software"), to deal
10
+ in the Software without restriction, including without limitation the rights
11
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ copies of the Software, and to permit persons to whom the Software is
13
+ furnished to do so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in all
16
+ copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ SOFTWARE.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # `@warmio/ui`
2
2
 
3
- Portable React components shared by Warm products. Install `@warmio/ui@1.3.0` with the exact
4
- `@warmio/design@1.5.0` CSS/primitive contract, import `@warmio/design/globals.css` once, and add
3
+ Portable React components shared by Warm products. The next package version is `@warmio/ui@1.5.2`
4
+ with the exact `@warmio/design@1.10.0` CSS/primitive contract. Import `@warmio/design/globals.css` once, and add
5
5
  the package's compiled files to Tailwind's source detection:
6
6
 
7
7
  ## Why these files are separate
@@ -19,13 +19,17 @@ deployment permission to publish packages.
19
19
  @source '../node_modules/@warmio/ui/dist';
20
20
  ```
21
21
 
22
- The `1.3.0` public UI surface contains the Warm badge, Text and `StackedDisplay`, DropdownMenu,
22
+ The `1.5.2` public UI surface keeps the Warm badge, Text and `StackedDisplay`, DropdownMenu,
23
23
  Sheet, the complete responsive Sidebar family, and the `ProductHeader` composition. `Button`,
24
- `ButtonLink`, `Logo`, and `WarmLogoIcon` are directly owned by `@warmio/design@1.5.0` and are
24
+ `ButtonLink`, `Logo`, and `WarmLogoIcon` are directly owned by `@warmio/design@1.10.0` and are
25
25
  re-exported through UI where applicable. `ProductHeader` owns the responsive frame,
26
26
  breadcrumb/title semantics, leading slot, action slot, and optional portal targets used by Warm
27
27
  product shells. Styling is sealed: use documented semantic properties and layout wrappers, never
28
28
  `className` or `style` overrides. DropdownMenu interaction feedback requires the exact public peer
29
- `cuelume@0.1.0`.
29
+ `cuelume@0.1.0`. Fluid-derived menu, sidebar, and sheet interactions require `motion@^12.42.2`.
30
+
31
+ The closed props and Warm styling remain unchanged. Motion respects live reduced-motion
32
+ preferences. Adapted Fluid source is covered by `LICENSES/fluid-functionalism.txt`.
33
+ These versions require publication before independently deployed consumers can install them.
30
34
 
31
35
  The published artifact is standalone and never imports private `warm-app` workspace packages.
package/dist/badge.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Badge
3
- } from "./chunks/chunk-ICC7GQXS.js";
3
+ } from "./chunks/chunk-3AVFUXCV.js";
4
4
  import "./chunks/chunk-VIB7OX7D.js";
5
5
  export {
6
6
  Badge
package/dist/button.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  Button,
3
3
  ButtonLink
4
- } from "./chunks/chunk-GKEYV2XW.js";
4
+ } from "./chunks/chunk-GY4XJ6EX.js";
5
5
  export {
6
6
  Button,
7
7
  ButtonLink
@@ -1,3 +1,9 @@
1
+ import {
2
+ FluidMenuHighlights
3
+ } from "./chunk-F74Y4WRX.js";
4
+ import {
5
+ FluidOverlay
6
+ } from "./chunk-JXSJTIX7.js";
1
7
  import {
2
8
  cn
3
9
  } from "./chunk-VIB7OX7D.js";
@@ -6,76 +12,6 @@ import {
6
12
  import * as React from "react";
7
13
  import { Menu as MenuPrimitive } from "@base-ui/react/menu";
8
14
  import { CheckIcon } from "lucide-react";
9
-
10
- // ../ui/src/lib/interaction-feedback.ts
11
- import { play, setEnabled } from "cuelume";
12
-
13
- // ../ui/src/lib/haptic.ts
14
- var supportsHaptic = globalThis.window?.matchMedia?.("(pointer: coarse)").matches ?? false;
15
- function getWarmCapacitor(win) {
16
- return win?.Capacitor;
17
- }
18
- function isIosCapacitorApp(win = globalThis.window) {
19
- const capacitor = getWarmCapacitor(win);
20
- return capacitor?.getPlatform?.() === "ios" && capacitor?.isNativePlatform?.() === true;
21
- }
22
- function hasVibrate(nav) {
23
- return "vibrate" in nav && typeof nav.vibrate === "function";
24
- }
25
- function triggerIosCapacitorHaptic() {
26
- const haptics = getWarmCapacitor(globalThis.window)?.Plugins?.Haptics;
27
- void haptics?.impact?.({ style: "LIGHT" }).catch(() => {
28
- });
29
- }
30
- function haptic(pattern = 50) {
31
- try {
32
- if (isIosCapacitorApp()) {
33
- triggerIosCapacitorHaptic();
34
- return;
35
- }
36
- if (!supportsHaptic) return;
37
- if (hasVibrate(navigator)) {
38
- navigator.vibrate(pattern);
39
- return;
40
- }
41
- const label = document.createElement("label");
42
- label.ariaHidden = "true";
43
- label.style.display = "none";
44
- const input = document.createElement("input");
45
- input.type = "checkbox";
46
- input.setAttribute("switch", "");
47
- label.appendChild(input);
48
- try {
49
- document.head.appendChild(label);
50
- label.click();
51
- } finally {
52
- document.head.removeChild(label);
53
- }
54
- } catch {
55
- }
56
- }
57
-
58
- // ../ui/src/lib/interaction-feedback.ts
59
- var soundByIntent = {
60
- press: "press",
61
- selection: "tick",
62
- toggle: "toggle"
63
- };
64
- var soundsEnabled = false;
65
- setEnabled(false);
66
- function triggerInteractionFeedback(intent, options = {}) {
67
- if (options.haptic) {
68
- haptic();
69
- }
70
- if (!soundsEnabled) return;
71
- if (globalThis.document?.hidden) return;
72
- try {
73
- play(soundByIntent[intent]);
74
- } catch {
75
- }
76
- }
77
-
78
- // ../ui/src/warmio/dropdown-menu.tsx
79
15
  import { jsx, jsxs } from "react/jsx-runtime";
80
16
  function DropdownMenu(props) {
81
17
  return /* @__PURE__ */ jsx(MenuPrimitive.Root, { ...props });
@@ -122,20 +58,23 @@ function DropdownMenuContent({
122
58
  side,
123
59
  sideOffset,
124
60
  className: "isolate z-50 outline-none",
125
- children: /* @__PURE__ */ jsx(
61
+ children: /* @__PURE__ */ jsxs(
126
62
  MenuPrimitive.Popup,
127
63
  {
128
64
  ref,
129
65
  "data-slot": "dropdown-menu-content",
66
+ "data-fluid-menu": "menu",
67
+ render: (popupProps, state) => /* @__PURE__ */ jsx(FluidOverlay, { props: popupProps, state, motion: "menu", tier: "fast" }),
130
68
  className: cn(
131
- "z-[var(--z-popover)] max-h-(--available-height) origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover p-2 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 outline-none",
69
+ "relative isolate z-[var(--z-popover)] max-h-(--available-height) origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover p-2 text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-none data-closed:overflow-hidden [&_[data-fluid-menu-item]:is(:focus,[data-highlighted],[data-popup-open],[data-open],[aria-checked=true])]:bg-transparent!",
132
70
  dropdownMenuContentSizeClasses[size],
133
- dropdownMenuContentSpacingClasses[spacing],
134
- "data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
135
- "data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95 motion-reduce:animate-none"
71
+ dropdownMenuContentSpacingClasses[spacing]
136
72
  ),
137
73
  ...props,
138
- children
74
+ children: [
75
+ children,
76
+ /* @__PURE__ */ jsx(FluidMenuHighlights, { kind: "menu" })
77
+ ]
139
78
  }
140
79
  )
141
80
  }
@@ -164,7 +103,7 @@ function DropdownMenuItem({
164
103
  "data-slot": "dropdown-menu-item",
165
104
  "data-inset": inset,
166
105
  "data-variant": variant,
167
- className: "group/dropdown-menu-item relative flex w-full cursor-default items-center gap-2 rounded-lg px-2 py-2 text-sm outline-hidden select-none not-data-[variant=destructive]:focus:bg-sidebar-accent not-data-[variant=destructive]:focus:text-sidebar-accent-foreground not-data-[variant=destructive]:focus:**:text-sidebar-accent-foreground data-inset:pl-4 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
106
+ className: "group/dropdown-menu-item relative flex w-full cursor-default items-center gap-2 rounded-lg px-2 py-2 outline-hidden select-none not-data-[variant=destructive]:focus:bg-sidebar-accent not-data-[variant=destructive]:focus:text-sidebar-accent-foreground not-data-[variant=destructive]:focus:**:text-sidebar-accent-foreground data-inset:pl-4 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
168
107
  ...props
169
108
  }
170
109
  );
@@ -186,7 +125,7 @@ function DropdownMenuLinkItem({
186
125
  "data-slot": "dropdown-menu-item",
187
126
  "data-inset": inset,
188
127
  "data-variant": variant,
189
- className: "group/dropdown-menu-item relative flex w-full cursor-default items-center gap-2 rounded-lg px-2 py-2 text-sm outline-hidden select-none not-data-[variant=destructive]:focus:bg-sidebar-accent not-data-[variant=destructive]:focus:text-sidebar-accent-foreground not-data-[variant=destructive]:focus:**:text-sidebar-accent-foreground data-inset:pl-4 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
128
+ className: "group/dropdown-menu-item relative flex w-full cursor-default items-center gap-2 rounded-lg px-2 py-2 outline-hidden select-none not-data-[variant=destructive]:focus:bg-sidebar-accent not-data-[variant=destructive]:focus:text-sidebar-accent-foreground not-data-[variant=destructive]:focus:**:text-sidebar-accent-foreground data-inset:pl-4 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
190
129
  render: /* @__PURE__ */ jsx("a", { href, children }),
191
130
  ...props
192
131
  }
@@ -203,7 +142,6 @@ function DropdownMenuCheckboxItem({
203
142
  ...props
204
143
  }) {
205
144
  const handleCheckedChange = (nextChecked, eventDetails) => {
206
- triggerInteractionFeedback("toggle");
207
145
  onCheckedChange?.(nextChecked, eventDetails);
208
146
  };
209
147
  return /* @__PURE__ */ jsxs(
@@ -212,7 +150,7 @@ function DropdownMenuCheckboxItem({
212
150
  ref,
213
151
  "data-slot": "dropdown-menu-checkbox-item",
214
152
  "data-inset": inset,
215
- className: "relative flex cursor-default items-center gap-2 rounded-lg py-2 pr-4 pl-2 text-sm outline-hidden select-none focus:bg-sidebar-accent focus:text-sidebar-accent-foreground focus:**:text-sidebar-accent-foreground data-inset:pl-4 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
153
+ className: "relative flex cursor-default items-center gap-2 rounded-lg py-2 pr-4 pl-2 outline-hidden select-none focus:bg-sidebar-accent focus:text-sidebar-accent-foreground focus:**:text-sidebar-accent-foreground data-inset:pl-4 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
216
154
  checked,
217
155
  onCheckedChange: handleCheckedChange,
218
156
  ...props,
@@ -237,7 +175,6 @@ function DropdownMenuRadioGroup({
237
175
  ...props
238
176
  }) {
239
177
  const handleValueChange = (value, eventDetails) => {
240
- triggerInteractionFeedback("selection");
241
178
  onValueChange?.(value, eventDetails);
242
179
  };
243
180
  return /* @__PURE__ */ jsx(
@@ -253,7 +190,6 @@ function DropdownMenuRadioItem({
253
190
  children,
254
191
  inset,
255
192
  className: _className,
256
- presentation,
257
193
  ref,
258
194
  style: _style,
259
195
  ...props
@@ -265,8 +201,7 @@ function DropdownMenuRadioItem({
265
201
  "data-slot": "dropdown-menu-radio-item",
266
202
  "data-inset": inset,
267
203
  className: cn(
268
- "relative flex cursor-default items-center gap-2 rounded-lg py-2 pr-4 pl-2 text-sm outline-hidden select-none focus:bg-sidebar-accent focus:text-sidebar-accent-foreground focus:**:text-sidebar-accent-foreground data-inset:pl-4 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
269
- presentation === "selectMenu" && "min-h-12 text-base"
204
+ "relative flex cursor-default items-center gap-2 rounded-lg py-2 pr-4 pl-2 outline-hidden select-none focus:bg-sidebar-accent focus:text-sidebar-accent-foreground focus:**:text-sidebar-accent-foreground data-inset:pl-4 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
270
205
  ),
271
206
  ...props,
272
207
  children: [
@@ -296,7 +231,7 @@ function DropdownMenuLabel({
296
231
  ref,
297
232
  "data-slot": "dropdown-menu-label",
298
233
  "data-inset": inset,
299
- className: "px-2 py-2 text-xs font-bold text-muted-foreground data-inset:pl-4",
234
+ className: "px-2 py-2 data-inset:pl-4",
300
235
  ...props
301
236
  }
302
237
  );
@@ -6,7 +6,7 @@ import {
6
6
  import { jsx } from "react/jsx-runtime";
7
7
  var badgeToneClassNameByTone = {
8
8
  default: "border-border bg-muted text-foreground",
9
- info: "border-info/20 bg-info/10 text-info",
9
+ info: "border-info-border bg-info-bg-subtle text-info-text",
10
10
  success: "border-success-border bg-success/10 text-success",
11
11
  warning: "border-warning-border bg-warning/10 text-warning",
12
12
  destructive: "border-destructive/20 bg-destructive/10 text-destructive"
@@ -19,12 +19,12 @@ var solidBadgeToneClassNameByTone = {
19
19
  destructive: "border-destructive bg-destructive text-destructive-foreground"
20
20
  };
21
21
  var badgeSizeClassNameBySize = {
22
- sm: "h-5 px-2 py-2 text-xs",
23
- default: "h-6 px-2 py-2 text-xs"
22
+ sm: "h-5 px-2 py-0",
23
+ default: "h-6 px-2 py-0"
24
24
  };
25
25
  var badgeCircleClassNameBySize = {
26
- sm: "size-5 px-0 py-0 text-xs leading-none",
27
- default: "size-6 px-0 py-0 text-xs leading-none"
26
+ sm: "size-5 px-0 py-0",
27
+ default: "size-6 px-0 py-0"
28
28
  };
29
29
  function Badge({
30
30
  tone,
@@ -49,14 +49,16 @@ function Badge({
49
49
  "data-shape": shape,
50
50
  "data-surface": surface,
51
51
  "data-placement": placement,
52
+ "data-size": size,
52
53
  id,
53
54
  "aria-label": ariaLabel,
54
55
  className: cn(
55
- "inline-flex w-fit max-w-full items-center justify-center gap-2 overflow-hidden rounded-full border font-bold whitespace-nowrap transition-colors",
56
+ "inline-flex w-fit max-w-full items-center justify-center gap-2 overflow-hidden rounded-full border whitespace-nowrap transition-colors",
56
57
  emphasis === "solid" ? solidBadgeToneClassNameByTone[resolvedTone] : badgeToneClassNameByTone[resolvedTone],
57
58
  badgeSizeClassNameBySize[size],
58
59
  shape === "circle" && badgeCircleClassNameBySize[size],
59
60
  surface === "floating" && "border-background ring-2 ring-background",
61
+ placement === "inline" && "align-middle",
60
62
  placement === "top-end" && "pointer-events-none absolute -right-2 -top-2 z-10",
61
63
  width === "metric" && "w-12",
62
64
  width === "compact" && "min-w-6",
@@ -6,7 +6,7 @@ import {
6
6
  SheetHeader,
7
7
  SheetTitle,
8
8
  SheetTrigger
9
- } from "./chunk-YTDMREDR.js";
9
+ } from "./chunk-A2NLFM6R.js";
10
10
 
11
11
  // ../ui/src/warmio/sheet.tsx
12
12
  import { jsx } from "react/jsx-runtime";
@@ -29,17 +29,10 @@ function SheetContent2({
29
29
  width = "default",
30
30
  ...props
31
31
  }) {
32
- const navigationClassName = presentation === "navigation" ? `w-[var(--sidebar-width-mobile)] gap-0 overflow-hidden border-border bg-sidebar p-0 text-foreground duration-200 ease-in-out data-open:fade-in-100 data-closed:fade-out-100${responsive === "mobileOnly" ? " md:hidden" : ""}` : void 0;
33
- const widthClassName = width === "full" ? "w-full data-[side=left]:sm:max-w-none data-[side=right]:sm:max-w-none" : width === "wide" ? "w-full data-[side=left]:sm:max-w-lg data-[side=right]:sm:max-w-lg" : void 0;
34
- const contentClassName = presentation === "scroll" ? `overflow-y-auto${widthClassName ? ` ${widthClassName}` : ""}` : navigationClassName ?? widthClassName;
35
- return /* @__PURE__ */ jsx(
36
- SheetContent,
37
- {
38
- ...props,
39
- className: contentClassName,
40
- overlayClassName: presentation === "navigation" ? "duration-200 ease-in-out" : void 0
41
- }
42
- );
32
+ const navigationClassName = presentation === "navigation" ? `max-lg:w-auto lg:w-[var(--sidebar-width-mobile)] gap-0 overflow-hidden border-border bg-sidebar p-0 text-foreground${responsive === "mobileOnly" ? " md:hidden" : ""}` : void 0;
33
+ const widthClassName = width === "full" ? "w-full data-[side=left]:sm:max-w-none data-[side=right]:sm:max-w-none data-[side=responsive]:lg:max-w-none" : width === "wide" ? "w-full data-[side=left]:sm:max-w-lg data-[side=right]:sm:max-w-lg data-[side=responsive]:lg:max-w-lg" : void 0;
34
+ const contentClassName = presentation === "scroll" ? widthClassName : navigationClassName ?? widthClassName;
35
+ return /* @__PURE__ */ jsx(SheetContent, { ...props, className: contentClassName });
43
36
  }
44
37
  function SheetFooter2({ className: _className, style: _style, ...props }) {
45
38
  return /* @__PURE__ */ jsx(SheetFooter, { ...props });
@@ -63,7 +56,8 @@ function SheetTitle2({
63
56
  SheetTitle,
64
57
  {
65
58
  ...props,
66
- className: presentation === "navigation" ? "min-w-0 truncate text-left text-base font-bold text-foreground" : void 0
59
+ "data-presentation": presentation,
60
+ className: presentation === "navigation" ? "min-w-0 truncate text-left text-foreground" : void 0
67
61
  }
68
62
  );
69
63
  }
@@ -1,3 +1,6 @@
1
+ import {
2
+ FluidOverlay
3
+ } from "./chunk-JXSJTIX7.js";
1
4
  import {
2
5
  cn
3
6
  } from "./chunk-VIB7OX7D.js";
@@ -21,20 +24,20 @@ var buttonVariants = cva(
21
24
  variants: {
22
25
  variant: {
23
26
  default: "bg-[var(--button-primary-bg)] bg-[image:var(--button-primary-gradient)] text-[color:var(--button-primary-foreground)] shadow-[var(--button-primary-shadow)] hover:bg-[var(--button-primary-hover)] hover:bg-[image:var(--button-primary-gradient-hover)] active:bg-[var(--button-primary-active)]",
24
- outline: "bg-background shadow-[var(--button-outline-shadow)] hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:bg-[var(--warm-surface-raised-dark,var(--input))] dark:[--button-outline-shadow:inset_0_1px_0_rgb(255_255_255_/_0.1)] dark:hover:bg-[var(--warm-surface-raised-hover-dark,var(--muted))]",
27
+ outline: "bg-background shadow-[var(--button-outline-shadow)] hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:bg-[var(--warm-surface-raised-dark,var(--input))] dark:hover:bg-[var(--warm-surface-raised-hover-dark,var(--muted))]",
25
28
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
26
29
  ghost: "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
27
30
  destructive: "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
28
- link: "underline-offset-4 decoration-current hover:underline"
31
+ link: "decoration-current hover:underline"
29
32
  },
30
33
  size: {
31
34
  default: "h-9 gap-2 rounded-full px-4 in-data-[slot=button-group]:rounded-full has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
32
35
  xs: "h-6 gap-2 rounded-full px-2 text-xs in-data-[slot=button-group]:rounded-full has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-3",
33
36
  sm: "h-8 gap-2 rounded-full px-2 in-data-[slot=button-group]:rounded-full has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
34
37
  md: "h-9 gap-2 rounded-full px-4 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
35
- lg: "h-11 gap-2 rounded-full px-4 text-base has-data-[icon=inline-end]:pr-4 has-data-[icon=inline-start]:pl-4",
36
- xl: "h-12 gap-2 rounded-full px-4 text-base has-data-[icon=inline-end]:pr-4 has-data-[icon=inline-start]:pl-4",
37
- jumbo: "h-14 gap-2 rounded-full px-4 text-lg font-bold has-data-[icon=inline-end]:pr-4 has-data-[icon=inline-start]:pl-4 [&_svg:not([class*='size-'])]:size-5",
38
+ lg: "h-11 gap-2 rounded-full px-4 text-sm has-data-[icon=inline-end]:pr-4 has-data-[icon=inline-start]:pl-4",
39
+ xl: "h-12 gap-2 rounded-full px-4 text-sm has-data-[icon=inline-end]:pr-4 has-data-[icon=inline-start]:pl-4",
40
+ jumbo: "h-14 gap-2 rounded-full px-4 text-sm font-medium has-data-[icon=inline-end]:pr-4 has-data-[icon=inline-start]:pl-4 [&_svg:not([class*='size-'])]:size-5",
38
41
  option: "h-auto min-h-16 items-start justify-start gap-2 whitespace-normal rounded-full px-4 py-4 text-sm",
39
42
  icon: "size-9",
40
43
  "icon-round": "size-9 rounded-full",
@@ -81,6 +84,7 @@ function Button({
81
84
  // ../ui/src/components/sheet.tsx
82
85
  import { XIcon } from "lucide-react";
83
86
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
87
+ var SheetCloseSlotContext = React2.createContext(null);
84
88
  function Sheet(props) {
85
89
  return /* @__PURE__ */ jsx2(SheetPrimitive.Root, { ...props });
86
90
  }
@@ -101,68 +105,90 @@ function SheetOverlay({ className, ...props }) {
101
105
  {
102
106
  "data-slot": "sheet-overlay",
103
107
  className: cn(
104
- "fixed inset-0 z-[var(--z-overlay-backdrop)] duration-100 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
108
+ "fixed inset-0 z-[var(--z-overlay-backdrop)]",
105
109
  MODAL_BACKDROP_CLASS_NAME,
106
110
  className
107
111
  ),
108
- ...props
112
+ ...props,
113
+ render: (props2, state) => /* @__PURE__ */ jsx2(FluidOverlay, { props: props2, state, motion: "backdrop", tier: "moderate" })
109
114
  }
110
115
  );
111
116
  }
112
117
  function SheetContent({
113
118
  className,
114
119
  children,
115
- side = "right",
120
+ side = "responsive",
116
121
  showCloseButton = true,
117
122
  overlayClassName,
123
+ render,
118
124
  ...props
119
125
  }) {
126
+ const closeButton = showCloseButton ? /* @__PURE__ */ jsxs(
127
+ SheetPrimitive.Close,
128
+ {
129
+ "data-slot": "sheet-close",
130
+ render: /* @__PURE__ */ jsx2(Button, { variant: "ghost", className: "border border-border", size: "icon-sm" }),
131
+ children: [
132
+ /* @__PURE__ */ jsx2(XIcon, {}),
133
+ /* @__PURE__ */ jsx2("span", { className: "sr-only", children: "Close" })
134
+ ]
135
+ }
136
+ ) : null;
120
137
  return /* @__PURE__ */ jsxs(SheetPortal, { children: [
121
138
  /* @__PURE__ */ jsx2(SheetOverlay, { className: overlayClassName }),
122
- /* @__PURE__ */ jsxs(
139
+ /* @__PURE__ */ jsx2(
123
140
  SheetPrimitive.Popup,
124
141
  {
125
142
  "data-slot": "sheet-content",
126
143
  "data-side": side,
127
144
  className: cn(
128
- "fixed z-[calc(var(--z-overlay-backdrop)+1)] flex flex-col gap-4 bg-popover bg-clip-padding text-sm text-popover-foreground shadow-lg transition duration-200 ease-in-out data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:max-h-[calc(100dvh-var(--safe-area-inset-top)-var(--safe-area-inset-bottom))] data-[side=bottom]:overflow-y-auto data-[side=bottom]:border-t data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:max-h-[calc(100dvh-var(--safe-area-inset-top)-var(--safe-area-inset-bottom))] data-[side=top]:overflow-y-auto data-[side=top]:border-b data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-[side=bottom]:data-open:slide-in-from-bottom-10 data-[side=left]:data-open:slide-in-from-left-10 data-[side=right]:data-open:slide-in-from-right-10 data-[side=top]:data-open:slide-in-from-top-10 data-closed:animate-out data-closed:fade-out-0 data-[side=bottom]:data-closed:slide-out-to-bottom-10 data-[side=left]:data-closed:slide-out-to-left-10 data-[side=right]:data-closed:slide-out-to-right-10 data-[side=top]:data-closed:slide-out-to-top-10 motion-reduce:animate-none motion-reduce:transition-none",
145
+ "fixed z-[calc(var(--z-overlay-backdrop)+1)] flex min-h-0 flex-col gap-0 rounded-xl border border-border bg-popover bg-clip-padding text-popover-foreground shadow-lg data-[side=left]:w-3/4 data-[side=right]:w-3/4 data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm data-[side=responsive]:lg:w-3/4 data-[side=responsive]:lg:max-w-sm",
129
146
  className
130
147
  ),
131
148
  ...props,
132
- children: [
133
- children,
134
- showCloseButton && /* @__PURE__ */ jsxs(
135
- SheetPrimitive.Close,
136
- {
137
- "data-slot": "sheet-close",
138
- render: /* @__PURE__ */ jsx2(
139
- Button,
140
- {
141
- variant: "ghost",
142
- className: "absolute top-[max(1rem,var(--safe-area-inset-top))] right-[max(1rem,var(--safe-area-inset-right))]",
143
- size: "icon-sm"
144
- }
145
- ),
146
- children: [
147
- /* @__PURE__ */ jsx2(XIcon, {}),
148
- /* @__PURE__ */ jsx2("span", { className: "sr-only", children: "Close" })
149
- ]
150
- }
151
- )
152
- ]
149
+ render: (props2, state) => /* @__PURE__ */ jsx2(
150
+ FluidOverlay,
151
+ {
152
+ props: props2,
153
+ state,
154
+ render,
155
+ motion: "sheet",
156
+ side,
157
+ tier: "moderate"
158
+ }
159
+ ),
160
+ children: /* @__PURE__ */ jsx2(SheetCloseSlotContext.Provider, { value: closeButton, children })
153
161
  }
154
162
  )
155
163
  ] });
156
164
  }
157
- function SheetHeader({ className, ...props }) {
158
- return /* @__PURE__ */ jsx2("div", { "data-slot": "sheet-header", className: cn("flex flex-col gap-2 p-4", className), ...props });
165
+ function SheetHeader({ className, children, ...props }) {
166
+ const closeButton = React2.useContext(SheetCloseSlotContext);
167
+ return /* @__PURE__ */ jsxs(
168
+ "div",
169
+ {
170
+ "data-slot": "sheet-header",
171
+ className: cn(
172
+ "grid grid-cols-[minmax(0,1fr)_auto] items-start gap-x-4 gap-y-2 p-4",
173
+ className
174
+ ),
175
+ ...props,
176
+ children: [
177
+ children,
178
+ closeButton
179
+ ]
180
+ }
181
+ );
159
182
  }
160
183
  function SheetFooter({ className, ...props }) {
161
184
  return /* @__PURE__ */ jsx2(
162
185
  "div",
163
186
  {
164
187
  "data-slot": "sheet-footer",
165
- className: cn("mt-auto flex flex-col gap-2 p-4", className),
188
+ className: cn(
189
+ "mt-auto flex w-full flex-row flex-wrap items-center justify-end gap-2 border-t border-border p-4 [&>:first-child]:me-auto [&>:only-child]:me-0",
190
+ className
191
+ ),
166
192
  ...props
167
193
  }
168
194
  );
@@ -172,7 +198,7 @@ function SheetTitle({ className, ...props }) {
172
198
  SheetPrimitive.Title,
173
199
  {
174
200
  "data-slot": "sheet-title",
175
- className: cn("font-heading font-bold text-foreground", className),
201
+ className: cn("text-foreground", className),
176
202
  ...props
177
203
  }
178
204
  );
@@ -182,7 +208,7 @@ function SheetDescription({ className, ...props }) {
182
208
  SheetPrimitive.Description,
183
209
  {
184
210
  "data-slot": "sheet-description",
185
- className: cn("text-sm text-muted-foreground", className),
211
+ className: cn("text-muted-foreground", className),
186
212
  ...props
187
213
  }
188
214
  );