@bearmenu/ui 0.8.38 → 0.8.40

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.
@@ -36,7 +36,16 @@ var cardVariants = cva(
36
36
  // several-hundred-pixel slab that translates under the cursor is a
37
37
  // wobble rather than a lift. A panel that size delegates interaction to
38
38
  // its children.
39
- elevatedPanel: "bg-card border border-border shadow-[var(--shadow-panel)]"
39
+ elevatedPanel: "bg-card border border-border shadow-[var(--shadow-panel)]",
40
+ // The booking frames' settings/report SECTION card (Settings Rules U0,
41
+ // Reports P0): a smaller, page-content-scale radius than every other
42
+ // variant's `rounded-3xl` — 14px on a phone, 16px from `sm` — carried
43
+ // entirely by `--shadow-card` with no border at all. Not a bigger
44
+ // `elevated`: that variant is fixed at 24px and keeps its hairline in
45
+ // both themes on purpose (see its note); this one is for the specific
46
+ // page-section shape the booking design draws, not a general
47
+ // border-dropping replacement for `elevated`.
48
+ section: "rounded-[14px] bg-card shadow-[var(--shadow-card)] sm:rounded-[16px]"
40
49
  },
41
50
  size: {
42
51
  sm: "[&_[data-slot=card-header]]:p-4 [&_[data-slot=card-content]]:p-4 [&_[data-slot=card-content]]:pt-0 [&_[data-slot=card-footer]]:p-4 [&_[data-slot=card-footer]]:pt-0",
@@ -68,6 +77,11 @@ var cardVariants = cva(
68
77
  variant: "elevated",
69
78
  interactive: true,
70
79
  class: "hover:shadow-[var(--shadow-card-hover)]"
80
+ },
81
+ {
82
+ variant: "section",
83
+ interactive: true,
84
+ class: "hover:shadow-[var(--shadow-card-hover)]"
71
85
  }
72
86
  ],
73
87
  defaultVariants: {
@@ -4,20 +4,30 @@ import * as React from 'react';
4
4
  import { Drawer as Drawer$1 } from 'vaul';
5
5
  import { jsx, jsxs } from 'react/jsx-runtime';
6
6
 
7
- var DrawerDirectionContext = React.createContext("bottom");
7
+ var DrawerContext = React.createContext({
8
+ direction: "bottom",
9
+ modal: true
10
+ });
8
11
  var Drawer = (_a) => {
9
12
  var _b = _a, {
10
13
  shouldScaleBackground = false,
11
- direction = "bottom"
14
+ direction = "bottom",
15
+ modal = true,
16
+ autoFocus = true
12
17
  } = _b, props = __objRest(_b, [
13
18
  "shouldScaleBackground",
14
- "direction"
19
+ "direction",
20
+ "modal",
21
+ "autoFocus"
15
22
  ]);
16
- return /* @__PURE__ */ jsx(DrawerDirectionContext.Provider, { value: direction, children: /* @__PURE__ */ jsx(
23
+ const context = React.useMemo(() => ({ direction, modal }), [direction, modal]);
24
+ return /* @__PURE__ */ jsx(DrawerContext.Provider, { value: context, children: /* @__PURE__ */ jsx(
17
25
  Drawer$1.Root,
18
26
  __spreadValues({
19
27
  shouldScaleBackground,
20
- direction
28
+ direction,
29
+ modal,
30
+ autoFocus
21
31
  }, props)
22
32
  ) });
23
33
  };
@@ -39,7 +49,7 @@ var DrawerOverlay = React.forwardRef((_a, ref) => {
39
49
  DrawerOverlay.displayName = Drawer$1.Overlay.displayName;
40
50
  var DrawerContent = React.forwardRef((_a, ref) => {
41
51
  var _b = _a, { className, variant = "flush", showHandle, overlayClassName, children } = _b, props = __objRest(_b, ["className", "variant", "showHandle", "overlayClassName", "children"]);
42
- const direction = React.useContext(DrawerDirectionContext);
52
+ const { direction, modal } = React.useContext(DrawerContext);
43
53
  const isVertical = direction === "top" || direction === "bottom";
44
54
  const handleEnabled = showHandle != null ? showHandle : direction === "bottom";
45
55
  const positionClasses = direction === "bottom" ? "inset-x-0 bottom-0 flex-col rounded-t-2xl border-t [padding-bottom:max(env(safe-area-inset-bottom),0px)]" : direction === "top" ? "inset-x-0 top-0 flex-col rounded-b-2xl border-b [padding-top:max(env(safe-area-inset-top),0px)]" : direction === "left" ? "inset-y-0 left-0 h-full w-3/4 max-w-sm flex-col rounded-r-2xl border-r [padding-left:max(env(safe-area-inset-left),0px)]" : "inset-y-0 right-0 h-full w-3/4 max-w-sm flex-col rounded-l-2xl border-l [padding-right:max(env(safe-area-inset-right),0px)]";
@@ -50,6 +60,7 @@ var DrawerContent = React.forwardRef((_a, ref) => {
50
60
  __spreadProps(__spreadValues({
51
61
  ref,
52
62
  "data-slot": "drawer-content",
63
+ "aria-modal": modal ? true : void 0,
53
64
  className: cn(
54
65
  "fixed z-[1000] flex border-border bg-card shadow-[var(--shadow-overlay)]",
55
66
  positionClasses,
@@ -4,7 +4,7 @@ import * as React from 'react';
4
4
  import { VariantProps } from 'class-variance-authority';
5
5
 
6
6
  declare const badgeVariants: (props?: ({
7
- variant?: "default" | "secondary" | "success" | "warning" | "destructive" | "outline" | "glass" | "overlay" | "brown" | "code" | "onPrimary" | "confirmed" | "pending" | "completed" | "assignee" | "softSuccess" | "softWarning" | "softDestructive" | "softNeutral" | null | undefined;
7
+ variant?: "secondary" | "default" | "success" | "warning" | "destructive" | "outline" | "glass" | "overlay" | "brown" | "code" | "onPrimary" | "confirmed" | "pending" | "completed" | "assignee" | "softSuccess" | "softWarning" | "softDestructive" | "softNeutral" | null | undefined;
8
8
  size?: "status" | "chip" | null | undefined;
9
9
  live?: boolean | null | undefined;
10
10
  } & class_variance_authority_types.ClassProp) | undefined) => string;
@@ -3,8 +3,8 @@ import * as React from 'react';
3
3
  import { VariantProps } from 'class-variance-authority';
4
4
 
5
5
  declare const buttonVariants: (props?: ({
6
- variant?: "default" | "link" | "secondary" | "warning" | "destructive" | "outline" | "ghost" | "glass" | "overlay" | "ink" | "brown" | "cta" | null | undefined;
7
- size?: "icon" | "default" | "cta" | "xs" | "sm" | "lg" | "pill" | "cta-sm" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
6
+ variant?: "secondary" | "default" | "link" | "warning" | "destructive" | "outline" | "ghost" | "glass" | "overlay" | "ink" | "brown" | "cta" | null | undefined;
7
+ size?: "default" | "icon" | "cta" | "xs" | "sm" | "lg" | "pill" | "cta-sm" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
8
8
  fullWidth?: boolean | null | undefined;
9
9
  } & class_variance_authority_types.ClassProp) | undefined) => string;
10
10
  interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
@@ -3,12 +3,12 @@ import * as React from 'react';
3
3
  import { VariantProps } from 'class-variance-authority';
4
4
 
5
5
  declare const cardVariants: (props?: ({
6
- variant?: "outline" | "glass" | "muted" | "surface" | "elevated" | "elevatedPanel" | null | undefined;
6
+ variant?: "outline" | "glass" | "section" | "muted" | "surface" | "elevated" | "elevatedPanel" | null | undefined;
7
7
  size?: "default" | "sm" | "lg" | null | undefined;
8
8
  interactive?: boolean | null | undefined;
9
9
  } & class_variance_authority_types.ClassProp) | undefined) => string;
10
10
  declare const Card: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & VariantProps<(props?: ({
11
- variant?: "outline" | "glass" | "muted" | "surface" | "elevated" | "elevatedPanel" | null | undefined;
11
+ variant?: "outline" | "glass" | "section" | "muted" | "surface" | "elevated" | "elevatedPanel" | null | undefined;
12
12
  size?: "default" | "sm" | "lg" | null | undefined;
13
13
  interactive?: boolean | null | undefined;
14
14
  } & class_variance_authority_types.ClassProp) | undefined) => string> & React.RefAttributes<HTMLDivElement>>;
@@ -1,4 +1,4 @@
1
- export { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, cardVariants } from '../chunk-FVSKGCK3.js';
1
+ export { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, cardVariants } from '../chunk-DZHKUUYV.js';
2
2
  import '../chunk-ZLMRVBD7.js';
3
3
  import '../chunk-FEK5XGZW.js';
4
4
  import '../chunk-MMUBH76A.js';
@@ -28,7 +28,7 @@ declare const CommandInput: React.ForwardRefExoticComponent<Omit<Omit<Pick<Pick<
28
28
  ref?: React.Ref<HTMLInputElement>;
29
29
  } & {
30
30
  asChild?: boolean;
31
- }, "asChild" | "key" | keyof React.InputHTMLAttributes<HTMLInputElement>>, "value" | "onChange" | "type"> & {
31
+ }, "asChild" | "key" | keyof React.InputHTMLAttributes<HTMLInputElement>>, "onChange" | "value" | "type"> & {
32
32
  value?: string;
33
33
  onValueChange?: (search: string) => void;
34
34
  } & React.RefAttributes<HTMLInputElement>, "ref"> & React.RefAttributes<HTMLInputElement>>;
@@ -64,7 +64,7 @@ declare const CommandGroup: React.ForwardRefExoticComponent<Omit<{
64
64
  ref?: React.Ref<HTMLDivElement>;
65
65
  } & {
66
66
  asChild?: boolean;
67
- }, keyof React.HTMLAttributes<HTMLDivElement> | "asChild" | "key">, "value" | "heading"> & {
67
+ }, keyof React.HTMLAttributes<HTMLDivElement> | "asChild" | "key">, "heading" | "value"> & {
68
68
  heading?: React.ReactNode;
69
69
  value?: string;
70
70
  forceMount?: boolean;
@@ -82,7 +82,7 @@ declare const CommandItem: React.ForwardRefExoticComponent<Omit<{
82
82
  ref?: React.Ref<HTMLDivElement>;
83
83
  } & {
84
84
  asChild?: boolean;
85
- }, keyof React.HTMLAttributes<HTMLDivElement> | "asChild" | "key">, "value" | "onSelect" | "disabled"> & {
85
+ }, keyof React.HTMLAttributes<HTMLDivElement> | "asChild" | "key">, "onSelect" | "value" | "disabled"> & {
86
86
  disabled?: boolean;
87
87
  onSelect?: (value: string) => void;
88
88
  value?: string;
@@ -4,8 +4,15 @@ import * as DialogPrimitive from '@radix-ui/react-dialog';
4
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
5
5
  import * as React from 'react';
6
6
 
7
+ /**
8
+ * `autoFocus` defaults to `true` here, where vaul defaults it to `false`.
9
+ * vaul's default cancels Radix's open auto-focus, so focus never enters the
10
+ * sheet, Radix's FocusScope never engages, and Tab walks the page behind a
11
+ * modal drawer. A caller that must not move focus on open passes
12
+ * `autoFocus={false}`.
13
+ */
7
14
  declare const Drawer: {
8
- ({ shouldScaleBackground, direction, ...props }: React.ComponentProps<typeof Drawer$1.Root>): react_jsx_runtime.JSX.Element;
15
+ ({ shouldScaleBackground, direction, modal, autoFocus, ...props }: React.ComponentProps<typeof Drawer$1.Root>): react_jsx_runtime.JSX.Element;
9
16
  displayName: string;
10
17
  };
11
18
  declare const DrawerTrigger: React.ForwardRefExoticComponent<DialogPrimitive.DialogTriggerProps & React.RefAttributes<HTMLButtonElement>>;
@@ -1,3 +1,3 @@
1
- export { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger } from '../chunk-XLHMF6F5.js';
1
+ export { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger } from '../chunk-NF5UMLSL.js';
2
2
  import '../chunk-FEK5XGZW.js';
3
3
  import '../chunk-MMUBH76A.js';
@@ -3,7 +3,14 @@ import * as React from 'react';
3
3
  type EmptyStateAction = {
4
4
  label: string;
5
5
  onClick: () => void;
6
+ /**
7
+ * Rendered before the label, sized like the DS button's own icons (the
8
+ * `Button` base class forces every child `<svg>` to 16px) — "Try again"
9
+ * carries a refresh glyph, "New reservation" a plus.
10
+ */
11
+ icon?: React.ReactNode;
6
12
  };
13
+ type EmptyStateVariant = "default" | "search" | "error";
7
14
  interface EmptyStateProps {
8
15
  title: string;
9
16
  description: string;
@@ -11,10 +18,40 @@ interface EmptyStateProps {
11
18
  illustration?: React.ReactNode;
12
19
  action?: EmptyStateAction;
13
20
  secondaryAction?: EmptyStateAction;
14
- variant?: "default" | "search" | "error";
21
+ /**
22
+ * The primary action's style. Defaults by variant: `outline` for `error`
23
+ * (try again) and `search` (clear filters) — a recovery step, not the page's
24
+ * main call to action — and a filled `default` for the plain empty state,
25
+ * where the action is usually "create the first one".
26
+ */
27
+ actionVariant?: "default" | "outline";
28
+ variant?: EmptyStateVariant;
15
29
  size?: "sm" | "md" | "lg";
30
+ /**
31
+ * `card` draws the booking pages' whole-body state card (reports/02-p4,
32
+ * calendar/02-c2): a 14px-radius card surface (16px from `sm`) with the
33
+ * resting card shadow and no border. `none` (the default) leaves the
34
+ * surface to the container it sits in.
35
+ */
36
+ surface?: "none" | "card";
16
37
  className?: string;
17
38
  }
39
+ /**
40
+ * EmptyState — an icon tile, a title, one line of body and an optional action,
41
+ * spaced as the booking frames draw them (reports/02-p4, calendar/02-c2): a
42
+ * 64px tile (72px from `sm`) with a 28px glyph, 16px to the title, 12px from
43
+ * title to body, 16px from body to the action. The action is full-width on a
44
+ * phone and hugs its label from `sm`.
45
+ *
46
+ * The tile is 20px-radius (22px from `sm`); the title is 16px on a phone,
47
+ * 18px from `sm`. On `surface="card"` the card itself is 14px-radius (16px
48
+ * from `sm`), no border, with 20px side padding to the action row — measured
49
+ * off the frames' DOM (reports/02-p4, calendar/02-c2), not eyeballed.
50
+ *
51
+ * The error variant says "error" with its glyph and its tile's wash, not by
52
+ * painting the title and body red: red body copy is both harder to read and
53
+ * louder than a load failure the user can retry.
54
+ */
18
55
  declare const EmptyState: React.ForwardRefExoticComponent<EmptyStateProps & React.RefAttributes<HTMLDivElement>>;
19
56
  declare const SearchEmptyState: React.ForwardRefExoticComponent<Omit<EmptyStateProps, "icon" | "variant"> & React.RefAttributes<HTMLDivElement>>;
20
57
  declare const ErrorEmptyState: React.ForwardRefExoticComponent<Omit<EmptyStateProps, "icon" | "variant"> & React.RefAttributes<HTMLDivElement>>;
@@ -5,7 +5,7 @@ import { Text } from '../chunk-ZLMRVBD7.js';
5
5
  import { cn } from '../chunk-FEK5XGZW.js';
6
6
  import { __objRest, __spreadProps, __spreadValues } from '../chunk-MMUBH76A.js';
7
7
  import * as React from 'react';
8
- import { FileX, AlertCircle, Search } from 'lucide-react';
8
+ import { AlertCircle, Search, FileX } from 'lucide-react';
9
9
  import { jsxs, jsx } from 'react/jsx-runtime';
10
10
 
11
11
  var sizeStyles = {
@@ -13,6 +13,16 @@ var sizeStyles = {
13
13
  md: "py-12 px-6",
14
14
  lg: "py-16 px-8"
15
15
  };
16
+ var DEFAULT_ACTION_VARIANT = {
17
+ default: "default",
18
+ search: "outline",
19
+ error: "outline"
20
+ };
21
+ var DEFAULT_ICON = {
22
+ default: /* @__PURE__ */ jsx(FileX, { className: "text-muted-foreground", "aria-hidden": true }),
23
+ search: /* @__PURE__ */ jsx(Search, { className: "text-muted-foreground", "aria-hidden": true }),
24
+ error: /* @__PURE__ */ jsx(AlertCircle, { className: "text-destructive", "aria-hidden": true })
25
+ };
16
26
  var EmptyState = React.forwardRef(
17
27
  (_a, ref) => {
18
28
  var _b = _a, {
@@ -22,8 +32,10 @@ var EmptyState = React.forwardRef(
22
32
  illustration,
23
33
  action,
24
34
  secondaryAction,
35
+ actionVariant,
25
36
  variant = "default",
26
37
  size = "md",
38
+ surface = "none",
27
39
  className
28
40
  } = _b, props = __objRest(_b, [
29
41
  "title",
@@ -32,21 +44,12 @@ var EmptyState = React.forwardRef(
32
44
  "illustration",
33
45
  "action",
34
46
  "secondaryAction",
47
+ "actionVariant",
35
48
  "variant",
36
49
  "size",
50
+ "surface",
37
51
  "className"
38
52
  ]);
39
- const getDefaultIcon = () => {
40
- switch (variant) {
41
- case "search":
42
- return /* @__PURE__ */ jsx(Search, { className: "h-12 w-12 text-muted-foreground/50" });
43
- case "error":
44
- return /* @__PURE__ */ jsx(AlertCircle, { className: "h-12 w-12 text-destructive/50" });
45
- default:
46
- return /* @__PURE__ */ jsx(FileX, { className: "h-12 w-12 text-muted-foreground/50" });
47
- }
48
- };
49
- const textColor = variant === "error" ? "destructive" : "muted";
50
53
  return /* @__PURE__ */ jsxs(
51
54
  "div",
52
55
  __spreadProps(__spreadValues({
@@ -55,16 +58,43 @@ var EmptyState = React.forwardRef(
55
58
  className: cn(
56
59
  "flex flex-col items-center justify-center text-center",
57
60
  sizeStyles[size],
61
+ surface === "card" && "rounded-[14px] bg-card px-5 shadow-[var(--shadow-card)] sm:rounded-[16px]",
58
62
  className
59
63
  )
60
64
  }, props), {
61
65
  children: [
62
- illustration ? /* @__PURE__ */ jsx("div", { className: "mb-6", children: illustration }) : /* @__PURE__ */ jsx("div", { className: "mb-4", children: icon || getDefaultIcon() }),
63
- /* @__PURE__ */ jsx(Text, { as: "h3", weight: "semibold", color: textColor, className: "text-lg mb-2", children: title }),
64
- /* @__PURE__ */ jsx(Text, { as: "p", color: textColor, className: "text-sm max-w-md mb-6", children: description }),
65
- (action || secondaryAction) && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
66
- action && /* @__PURE__ */ jsx(Button, { onClick: action.onClick, variant: "default", className: "glass-hover", children: action.label }),
67
- secondaryAction && /* @__PURE__ */ jsx(Button, { onClick: secondaryAction.onClick, variant: "outline", className: "glass-hover", children: secondaryAction.label })
66
+ illustration ? /* @__PURE__ */ jsx("div", { className: "mb-6", children: illustration }) : /* @__PURE__ */ jsx(
67
+ "span",
68
+ {
69
+ "data-slot": "empty-state-icon",
70
+ className: cn(
71
+ // The glyph size is the tile's, whatever size the caller's icon
72
+ // node asked for — a 40px icon in a 64px tile has no margin.
73
+ "mb-4 flex size-16 shrink-0 items-center justify-center rounded-[20px] border border-border shadow-sm sm:size-18 sm:rounded-[22px] [&_svg]:size-7",
74
+ variant === "error" ? "bg-destructive/5" : "bg-card"
75
+ ),
76
+ children: icon != null ? icon : DEFAULT_ICON[variant]
77
+ }
78
+ ),
79
+ /* @__PURE__ */ jsx(Text, { as: "h3", weight: "semibold", className: "text-base sm:text-lg", children: title }),
80
+ description ? /* @__PURE__ */ jsx(Text, { as: "p", color: "muted", className: "mt-3 max-w-md text-sm", children: description }) : null,
81
+ (action || secondaryAction) && /* @__PURE__ */ jsxs("div", { className: "mt-4 flex w-full flex-col gap-3 sm:w-auto sm:flex-row sm:items-center", children: [
82
+ action && /* @__PURE__ */ jsxs(
83
+ Button,
84
+ {
85
+ onClick: action.onClick,
86
+ variant: actionVariant != null ? actionVariant : DEFAULT_ACTION_VARIANT[variant],
87
+ className: "glass-hover",
88
+ children: [
89
+ action.icon,
90
+ action.label
91
+ ]
92
+ }
93
+ ),
94
+ secondaryAction && /* @__PURE__ */ jsxs(Button, { onClick: secondaryAction.onClick, variant: "outline", className: "glass-hover", children: [
95
+ secondaryAction.icon,
96
+ secondaryAction.label
97
+ ] })
68
98
  ] })
69
99
  ]
70
100
  })
@@ -1,6 +1,6 @@
1
1
  import { useMediaQuery, DESKTOP_MEDIA_QUERY } from '../chunk-OPVKL4VS.js';
2
2
  import { Sheet, SheetContent, SheetTitle, SheetDescription } from '../chunk-LAEVMNJN.js';
3
- import { Drawer, DrawerContent, DrawerTitle, DrawerDescription } from '../chunk-XLHMF6F5.js';
3
+ import { Drawer, DrawerContent, DrawerTitle, DrawerDescription } from '../chunk-NF5UMLSL.js';
4
4
  import { Dialog, DialogContent, DialogTitle, DialogDescription } from '../chunk-IQIJCMG2.js';
5
5
  import { cn } from '../chunk-FEK5XGZW.js';
6
6
  import { __spreadProps, __spreadValues } from '../chunk-MMUBH76A.js';
@@ -59,15 +59,14 @@ var ResponsiveOverlay = React.forwardRef(
59
59
  }, ref) => {
60
60
  const isWide = useMediaQuery(wideFrom === "lg" ? DESKTOP_MEDIA_QUERY : MD_MEDIA_QUERY);
61
61
  const container = isWide ? desktop : "drawer";
62
- const titleId = React.useId();
63
- const subtitleId = React.useId();
64
62
  useFocusReturn(open);
63
+ const describedBy = subtitle ? {} : { "aria-describedby": void 0 };
65
64
  const Title = CONTAINER_TITLE[container];
66
65
  const Description = CONTAINER_DESCRIPTION[container];
67
66
  const header = /* @__PURE__ */ jsxs("div", { "data-slot": "responsive-overlay-header", className: "flex items-start gap-3 px-5 pt-5", children: [
68
67
  /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
69
- /* @__PURE__ */ jsx(Title, { id: titleId, className: "text-[19px] font-bold leading-tight", children: title }),
70
- subtitle ? /* @__PURE__ */ jsx(Description, { id: subtitleId, className: "mt-1 text-[13px] text-muted-foreground", children: subtitle }) : null
68
+ /* @__PURE__ */ jsx(Title, { className: "text-[19px] font-bold leading-tight", children: title }),
69
+ subtitle ? /* @__PURE__ */ jsx(Description, { className: "mt-1 text-[13px] text-muted-foreground", children: subtitle }) : null
71
70
  ] }),
72
71
  /* @__PURE__ */ jsxs(
73
72
  "button",
@@ -102,17 +101,16 @@ var ResponsiveOverlay = React.forwardRef(
102
101
  if (container === "sheet") {
103
102
  return /* @__PURE__ */ jsx(Sheet, { open, onOpenChange, modal, children: /* @__PURE__ */ jsxs(
104
103
  SheetContent,
105
- __spreadProps(__spreadValues({
104
+ __spreadProps(__spreadValues(__spreadProps(__spreadValues({
106
105
  ref,
107
106
  side: "right",
108
107
  attachment: "inset",
109
108
  hideClose: true,
110
- overlayClassName: "bg-scrim-overlay backdrop-blur-none",
111
- "aria-labelledby": titleId,
112
- "aria-describedby": subtitle ? subtitleId : void 0,
109
+ overlayClassName: "bg-scrim-overlay backdrop-blur-none"
110
+ }, describedBy), {
113
111
  "data-slot": "responsive-overlay-sheet",
114
112
  "data-modal": modal ? "true" : "false"
115
- }, modal ? {} : { onInteractOutside: (event) => event.preventDefault() }), {
113
+ }), modal ? {} : { onInteractOutside: (event) => event.preventDefault() }), {
116
114
  className: cn(
117
115
  "flex w-[420px] max-w-[calc(100vw-1.5rem)] flex-col gap-0 bg-card p-0",
118
116
  className
@@ -128,13 +126,12 @@ var ResponsiveOverlay = React.forwardRef(
128
126
  if (container === "dialog") {
129
127
  return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(
130
128
  DialogContent,
131
- {
129
+ __spreadProps(__spreadValues({
132
130
  ref,
133
131
  size,
134
132
  showCloseButton: false,
135
- overlayClassName: "bg-scrim-overlay backdrop-blur-none",
136
- "aria-labelledby": titleId,
137
- "aria-describedby": subtitle ? subtitleId : void 0,
133
+ overlayClassName: "bg-scrim-overlay backdrop-blur-none"
134
+ }, describedBy), {
138
135
  className: cn(
139
136
  // The dialog's own `grid gap-4 p-6` would put air between the
140
137
  // header, the body and the band the frames draw flush.
@@ -146,23 +143,22 @@ var ResponsiveOverlay = React.forwardRef(
146
143
  body,
147
144
  foot
148
145
  ]
149
- }
146
+ })
150
147
  ) });
151
148
  }
152
149
  return /* @__PURE__ */ jsx(Drawer, { open, onOpenChange, children: /* @__PURE__ */ jsxs(
153
150
  DrawerContent,
154
- {
151
+ __spreadProps(__spreadValues({
155
152
  ref,
156
- overlayClassName: "bg-scrim-overlay",
157
- "aria-labelledby": titleId,
158
- "aria-describedby": subtitle ? subtitleId : void 0,
153
+ overlayClassName: "bg-scrim-overlay"
154
+ }, describedBy), {
159
155
  className: cn("flex max-h-[85vh] flex-col p-0", className),
160
156
  children: [
161
157
  header,
162
158
  body,
163
159
  foot
164
160
  ]
165
- }
161
+ })
166
162
  ) });
167
163
  }
168
164
  );
@@ -4,11 +4,11 @@ import { VariantProps } from 'class-variance-authority';
4
4
 
5
5
  declare const spinnerVariants: (props?: ({
6
6
  size?: "default" | "xs" | "sm" | "lg" | "xl" | null | undefined;
7
- tone?: "default" | "inherit" | "primary" | "destructive" | null | undefined;
7
+ tone?: "primary" | "default" | "inherit" | "destructive" | null | undefined;
8
8
  } & class_variance_authority_types.ClassProp) | undefined) => string;
9
9
  declare const Spinner: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLSpanElement> & VariantProps<(props?: ({
10
10
  size?: "default" | "xs" | "sm" | "lg" | "xl" | null | undefined;
11
- tone?: "default" | "inherit" | "primary" | "destructive" | null | undefined;
11
+ tone?: "primary" | "default" | "inherit" | "destructive" | null | undefined;
12
12
  } & class_variance_authority_types.ClassProp) | undefined) => string> & {
13
13
  /** Visually-hidden label for screen readers. Defaults to "Loading". */
14
14
  label?: string;
@@ -3,11 +3,11 @@ import * as React from 'react';
3
3
  import { VariantProps } from 'class-variance-authority';
4
4
 
5
5
  declare const tagVariants: (props?: ({
6
- variant?: "default" | "primary" | "success" | "warning" | "destructive" | "outline" | "quiet" | null | undefined;
6
+ variant?: "primary" | "default" | "success" | "warning" | "destructive" | "outline" | "quiet" | null | undefined;
7
7
  size?: "default" | "sm" | "lg" | null | undefined;
8
8
  } & class_variance_authority_types.ClassProp) | undefined) => string;
9
9
  declare const Tag: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLSpanElement> & VariantProps<(props?: ({
10
- variant?: "default" | "primary" | "success" | "warning" | "destructive" | "outline" | "quiet" | null | undefined;
10
+ variant?: "primary" | "default" | "success" | "warning" | "destructive" | "outline" | "quiet" | null | undefined;
11
11
  size?: "default" | "sm" | "lg" | null | undefined;
12
12
  } & class_variance_authority_types.ClassProp) | undefined) => string> & {
13
13
  onRemove?: () => void;
@@ -22,8 +22,8 @@ import { VariantProps } from 'class-variance-authority';
22
22
  * Weights are 400 / 600 / 700. 500 is not in the system.
23
23
  */
24
24
  declare const textVariants: (props?: ({
25
- variant?: "body" | "small" | "display" | "h2" | "h3" | "label" | "caption" | "h1" | "h4" | "body-lg" | "body-sm" | "overline" | null | undefined;
26
- color?: "default" | "inherit" | "primary" | "destructive" | "muted" | "primary-foreground" | null | undefined;
25
+ variant?: "small" | "body" | "display" | "h2" | "h3" | "label" | "caption" | "h1" | "h4" | "body-lg" | "body-sm" | "overline" | null | undefined;
26
+ color?: "primary" | "default" | "inherit" | "destructive" | "muted" | "primary-foreground" | null | undefined;
27
27
  weight?: "bold" | "medium" | "normal" | "semibold" | null | undefined;
28
28
  leading?: "none" | "normal" | "tight" | "snug" | "relaxed" | "loose" | null | undefined;
29
29
  tracking?: "normal" | "tight" | "wide" | "wider" | null | undefined;
@@ -1,6 +1,6 @@
1
1
  import { Separator } from '../chunk-NWZGSLPU.js';
2
2
  import { Skeleton } from '../chunk-XBBEX4SF.js';
3
- import { Card } from '../chunk-FVSKGCK3.js';
3
+ import { Card } from '../chunk-DZHKUUYV.js';
4
4
  import '../chunk-ZLMRVBD7.js';
5
5
  import { cn } from '../chunk-FEK5XGZW.js';
6
6
  import { __objRest, __spreadValues } from '../chunk-MMUBH76A.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bearmenu/ui",
3
- "version": "0.8.38",
3
+ "version": "0.8.40",
4
4
  "description": "BearMenu design system — shared UI tokens, primitives, and components",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -11,7 +11,7 @@ const meta = {
11
11
  argTypes: {
12
12
  variant: {
13
13
  control: "select",
14
- options: ["glass", "surface"],
14
+ options: ["glass", "surface", "outline", "muted", "elevated", "elevatedPanel", "section"],
15
15
  },
16
16
  },
17
17
  } satisfies Meta<typeof Card>;
@@ -47,6 +47,25 @@ export const Surface: Story = {
47
47
  ),
48
48
  };
49
49
 
50
+ /**
51
+ * The booking frames' settings/report section shape (Settings Rules U0,
52
+ * Reports P0): 14px radius on a phone, 16px from `sm`, shadow only, no
53
+ * border. Distinct from `elevated`, which is a fixed 24px with a hairline.
54
+ */
55
+ export const Section: Story = {
56
+ render: () => (
57
+ <Card variant="section" className="w-[350px]">
58
+ <CardHeader>
59
+ <CardTitle>Booking rules</CardTitle>
60
+ <CardDescription>How far ahead guests can book, and the slot length.</CardDescription>
61
+ </CardHeader>
62
+ <CardContent>
63
+ <p className="text-sm text-muted-foreground">Section content goes here.</p>
64
+ </CardContent>
65
+ </Card>
66
+ ),
67
+ };
68
+
50
69
  export const WithForm: Story = {
51
70
  render: () => (
52
71
  <Card className="w-[350px]">
@@ -0,0 +1,27 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { render, screen } from "@testing-library/react";
3
+ import { Card } from "./card";
4
+
5
+ describe("Card", () => {
6
+ it("draws the section variant borderless, at the booking frames' radius", () => {
7
+ render(<Card variant="section">Content</Card>);
8
+ const card = screen.getByText("Content");
9
+ expect(card).toHaveClass("rounded-[14px]", "sm:rounded-[16px]", "bg-card");
10
+ expect(card).not.toHaveClass("border", "border-border");
11
+ });
12
+
13
+ it("keeps elevated's fixed radius and hairline, unaffected by the new variant", () => {
14
+ render(<Card variant="elevated">Content</Card>);
15
+ const card = screen.getByText("Content");
16
+ expect(card).toHaveClass("rounded-3xl", "border", "border-border");
17
+ });
18
+
19
+ it("steps section's shadow up on hover when interactive", () => {
20
+ render(
21
+ <Card variant="section" interactive>
22
+ Content
23
+ </Card>
24
+ );
25
+ expect(screen.getByText("Content")).toHaveClass("hover:shadow-[var(--shadow-card-hover)]");
26
+ });
27
+ });
@@ -35,6 +35,15 @@ const cardVariants = cva(
35
35
  // wobble rather than a lift. A panel that size delegates interaction to
36
36
  // its children.
37
37
  elevatedPanel: "bg-card border border-border shadow-[var(--shadow-panel)]",
38
+ // The booking frames' settings/report SECTION card (Settings Rules U0,
39
+ // Reports P0): a smaller, page-content-scale radius than every other
40
+ // variant's `rounded-3xl` — 14px on a phone, 16px from `sm` — carried
41
+ // entirely by `--shadow-card` with no border at all. Not a bigger
42
+ // `elevated`: that variant is fixed at 24px and keeps its hairline in
43
+ // both themes on purpose (see its note); this one is for the specific
44
+ // page-section shape the booking design draws, not a general
45
+ // border-dropping replacement for `elevated`.
46
+ section: "rounded-[14px] bg-card shadow-[var(--shadow-card)] sm:rounded-[16px]",
38
47
  },
39
48
  size: {
40
49
  sm: "[&_[data-slot=card-header]]:p-4 [&_[data-slot=card-content]]:p-4 [&_[data-slot=card-content]]:pt-0 [&_[data-slot=card-footer]]:p-4 [&_[data-slot=card-footer]]:pt-0",
@@ -68,6 +77,11 @@ const cardVariants = cva(
68
77
  interactive: true,
69
78
  class: "hover:shadow-[var(--shadow-card-hover)]",
70
79
  },
80
+ {
81
+ variant: "section",
82
+ interactive: true,
83
+ class: "hover:shadow-[var(--shadow-card-hover)]",
84
+ },
71
85
  ],
72
86
  defaultVariants: {
73
87
  variant: "surface",