@bearmenu/ui 0.8.27 → 0.8.29

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 (52) hide show
  1. package/dist/{chunk-QG6I2ILT.js → chunk-GESB7GCF.js} +1 -1
  2. package/dist/{chunk-VEFKZIK6.js → chunk-GTQSGDYF.js} +1 -1
  3. package/dist/{chunk-PDTPO6NG.js → chunk-JWTN7MNK.js} +1 -1
  4. package/dist/{chunk-AHHDC7ML.js → chunk-VSRGEB36.js} +1 -1
  5. package/dist/{chunk-MCOHLWRS.js → chunk-ZJMCU7MI.js} +1 -1
  6. package/dist/{chunk-IEIJP73R.js → chunk-ZU4NAYN7.js} +26 -4
  7. package/dist/components/badge.d.ts +3 -2
  8. package/dist/components/badge.js +1 -1
  9. package/dist/components/banner.d.ts +4 -1
  10. package/dist/components/banner.js +6 -1
  11. package/dist/components/booking-row.js +1 -1
  12. package/dist/components/button.d.ts +1 -1
  13. package/dist/components/card.d.ts +2 -2
  14. package/dist/components/combobox.js +2 -2
  15. package/dist/components/command.d.ts +15 -15
  16. package/dist/components/command.js +2 -2
  17. package/dist/components/concept-convergence.js +1 -1
  18. package/dist/components/currency-input.js +1 -1
  19. package/dist/components/date-input.js +1 -1
  20. package/dist/components/dialog.js +1 -1
  21. package/dist/components/drawer.js +1 -1
  22. package/dist/components/field.js +4 -5
  23. package/dist/components/filter-category-row.js +1 -1
  24. package/dist/components/input.js +1 -1
  25. package/dist/components/item.d.ts +2 -2
  26. package/dist/components/menu-item.js +3 -3
  27. package/dist/components/multi-select-combobox.js +3 -3
  28. package/dist/components/party-counter.js +1 -1
  29. package/dist/components/place-card.js +1 -1
  30. package/dist/components/place-details-mobile.js +1 -1
  31. package/dist/components/searchable-select.js +2 -2
  32. package/dist/components/sheet.js +1 -1
  33. package/dist/components/signature-chip.js +2 -2
  34. package/dist/components/spinner.d.ts +2 -2
  35. package/dist/components/tag.d.ts +2 -2
  36. package/dist/components/text.d.ts +3 -3
  37. package/dist/components/textarea.js +1 -1
  38. package/dist/components/time-slot.js +6 -3
  39. package/dist/components/toggle.d.ts +1 -1
  40. package/dist/components/top-ranking-entry.js +3 -3
  41. package/package.json +1 -1
  42. package/src/components/badge.tsx +24 -3
  43. package/src/components/banner.tsx +12 -2
  44. package/src/components/dialog.tsx +1 -1
  45. package/src/components/drawer.tsx +1 -1
  46. package/src/components/field.tsx +4 -5
  47. package/src/components/input.tsx +1 -1
  48. package/src/components/party-counter.tsx +3 -1
  49. package/src/components/sheet.tsx +1 -1
  50. package/src/components/textarea.tsx +1 -1
  51. package/src/components/time-slot.tsx +10 -3
  52. package/src/globals.css +31 -1
@@ -1,4 +1,4 @@
1
- import { Badge } from './chunk-IEIJP73R.js';
1
+ import { Badge } from './chunk-ZU4NAYN7.js';
2
2
  import { cn } from './chunk-FEK5XGZW.js';
3
3
  import { jsx } from 'react/jsx-runtime';
4
4
 
@@ -24,7 +24,7 @@ var inputVariants = cva(
24
24
  */
25
25
  appearance: {
26
26
  default: "",
27
- booking: "h-[46px] rounded-[11px] bg-card px-[13px] py-0 text-[14px] leading-[1.2] focus-visible:bg-card focus-visible:ring-ring aria-invalid:border-[oklch(0.52_0.16_25)] dark:aria-invalid:border-destructive"
27
+ booking: "h-[46px] rounded-[11px] bg-card px-[13px] py-0 text-[14px] leading-[1.2] focus-visible:bg-card focus-visible:ring-ring aria-invalid:border-destructive-ink"
28
28
  }
29
29
  },
30
30
  defaultVariants: {
@@ -26,7 +26,7 @@ var DialogOverlay = React.forwardRef((_a, ref) => {
26
26
  });
27
27
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
28
28
  var dialogContentVariants = cva(
29
- "fixed left-[50%] top-[50%] z-[1000] grid w-full translate-x-[-50%] translate-y-[-50%] gap-4 bg-card p-6 shadow-2xl data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:duration-[var(--duration-deliberate)] data-[state=closed]:duration-[var(--duration-exit-standard)] data-[state=open]:ease-[var(--ease-enter)] data-[state=closed]:ease-[var(--ease-exit)] data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 rounded-2xl border border-border",
29
+ "fixed left-[50%] top-[50%] z-[1000] grid w-full translate-x-[-50%] translate-y-[-50%] gap-4 bg-card p-6 shadow-[var(--shadow-overlay)] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:duration-[var(--duration-deliberate)] data-[state=closed]:duration-[var(--duration-exit-standard)] data-[state=open]:ease-[var(--ease-enter)] data-[state=closed]:ease-[var(--ease-exit)] data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 rounded-2xl border border-border",
30
30
  {
31
31
  variants: {
32
32
  size: {
@@ -1,4 +1,4 @@
1
- import { SignatureChip } from './chunk-QG6I2ILT.js';
1
+ import { SignatureChip } from './chunk-GESB7GCF.js';
2
2
  import { cn } from './chunk-FEK5XGZW.js';
3
3
  import { __objRest, __spreadValues } from './chunk-MMUBH76A.js';
4
4
  import { memo } from 'react';
@@ -1,4 +1,4 @@
1
- import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from './chunk-PDTPO6NG.js';
1
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from './chunk-JWTN7MNK.js';
2
2
  import { cn } from './chunk-FEK5XGZW.js';
3
3
  import { __objRest, __spreadValues, __spreadProps } from './chunk-MMUBH76A.js';
4
4
  import * as React from 'react';
@@ -29,9 +29,24 @@ var badgeVariants = cva(
29
29
  */
30
30
  // `border-0`: the base's transparent hairline would add 2px to each
31
31
  // side the design does not have.
32
- confirmed: "rounded-full border-0 bg-success/15 px-[9px] py-[3px] text-[10.5px] leading-[1.2] font-bold text-[oklch(0.38_0.1_155)] dark:text-success",
32
+ confirmed: "rounded-full border-0 bg-success/15 px-[9px] py-[3px] text-[10.5px] leading-[1.2] font-bold text-success-ink",
33
33
  pending: "rounded-full border-0 bg-warning/20 px-[9px] py-[3px] text-[10.5px] leading-[1.2] font-bold text-[oklch(0.42_0.1_70)] dark:text-warning",
34
- code: "rounded-full border-0 bg-surface-2 px-[9px] py-[3px] font-mono text-[10.5px] leading-[1.2] font-bold tabular-nums text-ink-secondary"
34
+ code: "rounded-full border-0 bg-surface-2 px-[9px] py-[3px] font-mono text-[10.5px] leading-[1.2] font-bold tabular-nums text-ink-secondary",
35
+ /**
36
+ * A booking that is over — "Completed", "Missed". The quiet sibling
37
+ * of `confirmed` / `pending`: the same pill, the muted ink, because
38
+ * nothing about it needs acting on.
39
+ */
40
+ completed: "rounded-full border-0 bg-muted px-[9px] py-[3px] text-[10.5px] leading-[1.2] font-bold text-muted-foreground"
41
+ },
42
+ /**
43
+ * `status` is the taller pill the booking design draws beside a
44
+ * summary — the same ink and radius, more air. `chip` (the default) is
45
+ * the inline one that sits in a row of text.
46
+ */
47
+ size: {
48
+ chip: "",
49
+ status: "py-[11px]"
35
50
  },
36
51
  // v1.0 motion: "live" surface signal — applies `live-pulse` archetype.
37
52
  // Pair with a colored variant (e.g. variant="destructive" live).
@@ -42,13 +57,20 @@ var badgeVariants = cva(
42
57
  },
43
58
  defaultVariants: {
44
59
  variant: "default",
60
+ size: "chip",
45
61
  live: false
46
62
  }
47
63
  }
48
64
  );
49
65
  function Badge(_a) {
50
- var _b = _a, { className, variant, live, as: Tag = "div" } = _b, props = __objRest(_b, ["className", "variant", "live", "as"]);
51
- return /* @__PURE__ */ jsx(Tag, __spreadValues({ "data-slot": "badge", className: cn(badgeVariants({ variant, live }), className) }, props));
66
+ var _b = _a, { className, variant, size, live, as: Tag = "div" } = _b, props = __objRest(_b, ["className", "variant", "size", "live", "as"]);
67
+ return /* @__PURE__ */ jsx(
68
+ Tag,
69
+ __spreadValues({
70
+ "data-slot": "badge",
71
+ className: cn(badgeVariants({ variant, size, live }), className)
72
+ }, props)
73
+ );
52
74
  }
53
75
 
54
76
  export { Badge, badgeVariants };
@@ -4,7 +4,8 @@ import * as React from 'react';
4
4
  import { VariantProps } from 'class-variance-authority';
5
5
 
6
6
  declare const badgeVariants: (props?: ({
7
- variant?: "default" | "destructive" | "warning" | "success" | "outline" | "secondary" | "glass" | "overlay" | "brown" | "code" | "onPrimary" | "confirmed" | "pending" | null | undefined;
7
+ variant?: "code" | "default" | "destructive" | "outline" | "secondary" | "glass" | "overlay" | "brown" | "warning" | "success" | "onPrimary" | "confirmed" | "pending" | "completed" | null | undefined;
8
+ size?: "status" | "chip" | null | undefined;
8
9
  live?: boolean | null | undefined;
9
10
  } & class_variance_authority_types.ClassProp) | undefined) => string;
10
11
  interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {
@@ -18,6 +19,6 @@ interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<
18
19
  */
19
20
  as?: "div" | "span";
20
21
  }
21
- declare function Badge({ className, variant, live, as: Tag, ...props }: BadgeProps): react_jsx_runtime.JSX.Element;
22
+ declare function Badge({ className, variant, size, live, as: Tag, ...props }: BadgeProps): react_jsx_runtime.JSX.Element;
22
23
 
23
24
  export { Badge, type BadgeProps, badgeVariants };
@@ -1,3 +1,3 @@
1
- export { Badge, badgeVariants } from '../chunk-IEIJP73R.js';
1
+ export { Badge, badgeVariants } from '../chunk-ZU4NAYN7.js';
2
2
  import '../chunk-FEK5XGZW.js';
3
3
  import '../chunk-MMUBH76A.js';
@@ -26,7 +26,10 @@ declare const bannerVariants: (props?: ({
26
26
  tone?: "warning" | "info" | null | undefined;
27
27
  } & class_variance_authority_types.ClassProp) | undefined) => string;
28
28
  type BannerProps = Omit<React.HTMLAttributes<HTMLDivElement>, "title"> & VariantProps<typeof bannerVariants> & {
29
- /** A lucide icon, drawn at 16px beside the text. */
29
+ /**
30
+ * A lucide icon, drawn at 16px beside the text. Omit it for the tone's
31
+ * own glyph; pass `null` for a note with no icon at all.
32
+ */
30
33
  icon?: React.ReactNode;
31
34
  /** The bold first line — "19:30 just went". */
32
35
  title?: React.ReactNode;
@@ -1,6 +1,7 @@
1
1
  import { cn } from '../chunk-FEK5XGZW.js';
2
2
  import { __objRest, __spreadProps, __spreadValues } from '../chunk-MMUBH76A.js';
3
3
  import { cva } from 'class-variance-authority';
4
+ import { TriangleAlert, Info } from 'lucide-react';
4
5
  import { jsxs, jsx } from 'react/jsx-runtime';
5
6
 
6
7
  var bannerVariants = cva(
@@ -15,10 +16,14 @@ var bannerVariants = cva(
15
16
  defaultVariants: { tone: "info" }
16
17
  }
17
18
  );
19
+ var TONE_ICON = {
20
+ info: /* @__PURE__ */ jsx(Info, { "aria-hidden": true }),
21
+ warning: /* @__PURE__ */ jsx(TriangleAlert, { "aria-hidden": true })
22
+ };
18
23
  function Banner(_a) {
19
24
  var _b = _a, { tone, icon, title, className, children } = _b, props = __objRest(_b, ["tone", "icon", "title", "className", "children"]);
20
25
  return /* @__PURE__ */ jsxs("div", __spreadProps(__spreadValues({ "data-slot": "banner", className: cn(bannerVariants({ tone }), className) }, props), { children: [
21
- icon,
26
+ icon === void 0 ? TONE_ICON[tone != null ? tone : "info"] : icon,
22
27
  /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
23
28
  title ? /* @__PURE__ */ jsx("b", { className: "mb-[3px] block text-[13px] font-bold", children: title }) : null,
24
29
  /* @__PURE__ */ jsx("div", { className: cn(tone === "warning" && title ? "opacity-90" : void 0), children })
@@ -1,4 +1,4 @@
1
- import { Badge } from '../chunk-IEIJP73R.js';
1
+ import { Badge } from '../chunk-ZU4NAYN7.js';
2
2
  import { cn } from '../chunk-FEK5XGZW.js';
3
3
  import { __objRest, __spreadValues } from '../chunk-MMUBH76A.js';
4
4
  import * as React from 'react';
@@ -3,7 +3,7 @@ import * as React from 'react';
3
3
  import { VariantProps } from 'class-variance-authority';
4
4
 
5
5
  declare const buttonVariants: (props?: ({
6
- variant?: "default" | "destructive" | "warning" | "link" | "outline" | "secondary" | "ghost" | "glass" | "overlay" | "ink" | "brown" | "cta" | null | undefined;
6
+ variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | "glass" | "overlay" | "ink" | "brown" | "warning" | "cta" | null | undefined;
7
7
  size?: "default" | "cta" | "xs" | "sm" | "lg" | "pill" | "cta-sm" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
8
8
  fullWidth?: boolean | null | undefined;
9
9
  } & class_variance_authority_types.ClassProp) | undefined) => string;
@@ -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?: "muted" | "outline" | "glass" | "surface" | "elevated" | "elevatedPanel" | null | undefined;
6
+ variant?: "outline" | "glass" | "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?: "muted" | "outline" | "glass" | "surface" | "elevated" | "elevatedPanel" | null | undefined;
11
+ variant?: "outline" | "glass" | "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,6 +1,6 @@
1
1
  import { Popover, PopoverTrigger, PopoverContent } from '../chunk-2ADCZXZJ.js';
2
- import { Command, CommandInput, CommandList, CommandLoading, CommandEmpty, CommandGroup, CommandItem } from '../chunk-MCOHLWRS.js';
3
- import '../chunk-PDTPO6NG.js';
2
+ import { Command, CommandInput, CommandList, CommandLoading, CommandEmpty, CommandGroup, CommandItem } from '../chunk-ZJMCU7MI.js';
3
+ import '../chunk-JWTN7MNK.js';
4
4
  import { Button } from '../chunk-5HHRVJOT.js';
5
5
  import '../chunk-RIH2IS7X.js';
6
6
  import '../chunk-5YNIQ2BL.js';
@@ -4,11 +4,11 @@ import { DialogProps } from '@radix-ui/react-dialog';
4
4
 
5
5
  declare const Command: React.ForwardRefExoticComponent<Omit<{
6
6
  children?: React.ReactNode;
7
- } & Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, keyof React.HTMLAttributes<HTMLDivElement> | "key"> & {
7
+ } & Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "key" | keyof React.HTMLAttributes<HTMLDivElement>> & {
8
8
  ref?: React.Ref<HTMLDivElement>;
9
9
  } & {
10
10
  asChild?: boolean;
11
- }, keyof React.HTMLAttributes<HTMLDivElement> | "asChild" | "key"> & {
11
+ }, "key" | keyof React.HTMLAttributes<HTMLDivElement> | "asChild"> & {
12
12
  label?: string;
13
13
  shouldFilter?: boolean;
14
14
  filter?: (value: string, search: string, keywords?: string[]) => number;
@@ -28,61 +28,61 @@ 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>>, "onChange" | "type" | "value"> & {
31
+ }, "key" | "asChild" | keyof React.InputHTMLAttributes<HTMLInputElement>>, "onChange" | "type" | "value"> & {
32
32
  value?: string;
33
33
  onValueChange?: (search: string) => void;
34
34
  } & React.RefAttributes<HTMLInputElement>, "ref"> & React.RefAttributes<HTMLInputElement>>;
35
35
  declare const CommandList: React.ForwardRefExoticComponent<Omit<{
36
36
  children?: React.ReactNode;
37
- } & Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, keyof React.HTMLAttributes<HTMLDivElement> | "key"> & {
37
+ } & Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "key" | keyof React.HTMLAttributes<HTMLDivElement>> & {
38
38
  ref?: React.Ref<HTMLDivElement>;
39
39
  } & {
40
40
  asChild?: boolean;
41
- }, keyof React.HTMLAttributes<HTMLDivElement> | "asChild" | "key"> & {
41
+ }, "key" | keyof React.HTMLAttributes<HTMLDivElement> | "asChild"> & {
42
42
  label?: string;
43
43
  } & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
44
44
  declare const CommandEmpty: React.ForwardRefExoticComponent<Omit<{
45
45
  children?: React.ReactNode;
46
- } & Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, keyof React.HTMLAttributes<HTMLDivElement> | "key"> & {
46
+ } & Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "key" | keyof React.HTMLAttributes<HTMLDivElement>> & {
47
47
  ref?: React.Ref<HTMLDivElement>;
48
48
  } & {
49
49
  asChild?: boolean;
50
- }, keyof React.HTMLAttributes<HTMLDivElement> | "asChild" | "key"> & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
50
+ }, "key" | keyof React.HTMLAttributes<HTMLDivElement> | "asChild"> & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
51
51
  declare const CommandLoading: React.ForwardRefExoticComponent<Omit<{
52
52
  children?: React.ReactNode;
53
- } & Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, keyof React.HTMLAttributes<HTMLDivElement> | "key"> & {
53
+ } & Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "key" | keyof React.HTMLAttributes<HTMLDivElement>> & {
54
54
  ref?: React.Ref<HTMLDivElement>;
55
55
  } & {
56
56
  asChild?: boolean;
57
- }, keyof React.HTMLAttributes<HTMLDivElement> | "asChild" | "key"> & {
57
+ }, "key" | keyof React.HTMLAttributes<HTMLDivElement> | "asChild"> & {
58
58
  progress?: number;
59
59
  label?: string;
60
60
  } & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
61
61
  declare const CommandGroup: React.ForwardRefExoticComponent<Omit<{
62
62
  children?: React.ReactNode;
63
- } & Omit<Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, keyof React.HTMLAttributes<HTMLDivElement> | "key"> & {
63
+ } & Omit<Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "key" | keyof React.HTMLAttributes<HTMLDivElement>> & {
64
64
  ref?: React.Ref<HTMLDivElement>;
65
65
  } & {
66
66
  asChild?: boolean;
67
- }, keyof React.HTMLAttributes<HTMLDivElement> | "asChild" | "key">, "heading" | "value"> & {
67
+ }, "key" | keyof React.HTMLAttributes<HTMLDivElement> | "asChild">, "heading" | "value"> & {
68
68
  heading?: React.ReactNode;
69
69
  value?: string;
70
70
  forceMount?: boolean;
71
71
  } & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
72
- declare const CommandSeparator: React.ForwardRefExoticComponent<Omit<Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, keyof React.HTMLAttributes<HTMLDivElement> | "key"> & {
72
+ declare const CommandSeparator: React.ForwardRefExoticComponent<Omit<Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "key" | keyof React.HTMLAttributes<HTMLDivElement>> & {
73
73
  ref?: React.Ref<HTMLDivElement>;
74
74
  } & {
75
75
  asChild?: boolean;
76
- }, keyof React.HTMLAttributes<HTMLDivElement> | "asChild" | "key"> & {
76
+ }, "key" | keyof React.HTMLAttributes<HTMLDivElement> | "asChild"> & {
77
77
  alwaysRender?: boolean;
78
78
  } & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
79
79
  declare const CommandItem: React.ForwardRefExoticComponent<Omit<{
80
80
  children?: React.ReactNode;
81
- } & Omit<Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, keyof React.HTMLAttributes<HTMLDivElement> | "key"> & {
81
+ } & Omit<Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "key" | keyof React.HTMLAttributes<HTMLDivElement>> & {
82
82
  ref?: React.Ref<HTMLDivElement>;
83
83
  } & {
84
84
  asChild?: boolean;
85
- }, keyof React.HTMLAttributes<HTMLDivElement> | "asChild" | "key">, "onSelect" | "disabled" | "value"> & {
85
+ }, "key" | keyof React.HTMLAttributes<HTMLDivElement> | "asChild">, "onSelect" | "disabled" | "value"> & {
86
86
  disabled?: boolean;
87
87
  onSelect?: (value: string) => void;
88
88
  value?: string;
@@ -1,4 +1,4 @@
1
- export { Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandLoading, CommandSeparator, CommandShortcut } from '../chunk-MCOHLWRS.js';
2
- import '../chunk-PDTPO6NG.js';
1
+ export { Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandLoading, CommandSeparator, CommandShortcut } from '../chunk-ZJMCU7MI.js';
2
+ import '../chunk-JWTN7MNK.js';
3
3
  import '../chunk-FEK5XGZW.js';
4
4
  import '../chunk-MMUBH76A.js';
@@ -1,7 +1,7 @@
1
1
  import { Convergence } from '../chunk-4XDJXMLF.js';
2
2
  import '../chunk-OIV7B44M.js';
3
3
  import { PhotoGround } from '../chunk-SWD6CJ35.js';
4
- import { Badge } from '../chunk-IEIJP73R.js';
4
+ import { Badge } from '../chunk-ZU4NAYN7.js';
5
5
  import { cn } from '../chunk-FEK5XGZW.js';
6
6
  import '../chunk-MMUBH76A.js';
7
7
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { Input } from '../chunk-VEFKZIK6.js';
1
+ import { Input } from '../chunk-GTQSGDYF.js';
2
2
  import { cn } from '../chunk-FEK5XGZW.js';
3
3
  import { __objRest, __spreadValues } from '../chunk-MMUBH76A.js';
4
4
  import * as React from 'react';
@@ -1,4 +1,4 @@
1
- import { Input } from '../chunk-VEFKZIK6.js';
1
+ import { Input } from '../chunk-GTQSGDYF.js';
2
2
  import { cn } from '../chunk-FEK5XGZW.js';
3
3
  import { __objRest, __spreadValues } from '../chunk-MMUBH76A.js';
4
4
  import * as React from 'react';
@@ -1,3 +1,3 @@
1
- export { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, dialogContentVariants } from '../chunk-PDTPO6NG.js';
1
+ export { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, dialogContentVariants } from '../chunk-JWTN7MNK.js';
2
2
  import '../chunk-FEK5XGZW.js';
3
3
  import '../chunk-MMUBH76A.js';
@@ -51,7 +51,7 @@ var DrawerContent = React.forwardRef((_a, ref) => {
51
51
  ref,
52
52
  "data-slot": "drawer-content",
53
53
  className: cn(
54
- "fixed z-[1000] flex border-border bg-card shadow-2xl",
54
+ "fixed z-[1000] flex border-border bg-card shadow-[var(--shadow-overlay)]",
55
55
  positionClasses,
56
56
  // The single height cap for every vertical drawer. Consumers should
57
57
  // NOT restate it: six app call sites carried an identical
@@ -126,11 +126,10 @@ var FieldError = React.forwardRef(
126
126
  "data-slot": "field-error",
127
127
  className: cn(
128
128
  appearance === "booking" ? (
129
- // The design's error ink: the solid token is too bright for AA
130
- // at 11.5px on white; dark mode's lifted token already clears it.
131
- // Light: the design's ink. Dark: lifted further than the solid
132
- // token, which lands at ~3.8:1 on the card ground at 11.5px.
133
- "m-0 text-[11.5px] leading-[1.2] text-[oklch(0.52_0.16_25)] dark:text-[oklch(0.75_0.13_25)]"
129
+ // `destructive-ink`, not the solid token: red AS TEXT, dark
130
+ // enough for AA on white and lifted enough for the card ground
131
+ // in dark, where the solid one measures ~3.8:1 at 11.5px.
132
+ "m-0 text-[11.5px] leading-[1.2] text-destructive-ink"
134
133
  ) : "text-sm text-destructive",
135
134
  className
136
135
  )
@@ -1,5 +1,5 @@
1
1
  import { Text } from '../chunk-ZLMRVBD7.js';
2
- import { Badge } from '../chunk-IEIJP73R.js';
2
+ import { Badge } from '../chunk-ZU4NAYN7.js';
3
3
  import '../chunk-FEK5XGZW.js';
4
4
  import '../chunk-MMUBH76A.js';
5
5
  import { ChevronRight } from 'lucide-react';
@@ -1,3 +1,3 @@
1
- export { Input, inputVariants } from '../chunk-VEFKZIK6.js';
1
+ export { Input, inputVariants } from '../chunk-GTQSGDYF.js';
2
2
  import '../chunk-FEK5XGZW.js';
3
3
  import '../chunk-MMUBH76A.js';
@@ -3,12 +3,12 @@ import * as React from 'react';
3
3
  import { VariantProps } from 'class-variance-authority';
4
4
 
5
5
  declare const itemVariants: (props?: ({
6
- variant?: "default" | "muted" | "outline" | null | undefined;
6
+ variant?: "default" | "outline" | "muted" | 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 Item: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & VariantProps<(props?: ({
11
- variant?: "default" | "muted" | "outline" | null | undefined;
11
+ variant?: "default" | "outline" | "muted" | 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> & {
@@ -1,5 +1,5 @@
1
- export { MentionSignal, MenuItem } from '../chunk-AHHDC7ML.js';
2
- import '../chunk-QG6I2ILT.js';
3
- import '../chunk-IEIJP73R.js';
1
+ export { MentionSignal, MenuItem } from '../chunk-VSRGEB36.js';
2
+ import '../chunk-GESB7GCF.js';
3
+ import '../chunk-ZU4NAYN7.js';
4
4
  import '../chunk-FEK5XGZW.js';
5
5
  import '../chunk-MMUBH76A.js';
@@ -1,11 +1,11 @@
1
1
  import { Checkbox } from '../chunk-L3CDXVEP.js';
2
2
  import { Popover, PopoverTrigger, PopoverContent } from '../chunk-2ADCZXZJ.js';
3
- import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem } from '../chunk-MCOHLWRS.js';
4
- import '../chunk-PDTPO6NG.js';
3
+ import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem } from '../chunk-ZJMCU7MI.js';
4
+ import '../chunk-JWTN7MNK.js';
5
5
  import { Button } from '../chunk-5HHRVJOT.js';
6
6
  import '../chunk-RIH2IS7X.js';
7
7
  import '../chunk-5YNIQ2BL.js';
8
- import { Badge } from '../chunk-IEIJP73R.js';
8
+ import { Badge } from '../chunk-ZU4NAYN7.js';
9
9
  import { cn } from '../chunk-FEK5XGZW.js';
10
10
  import '../chunk-MMUBH76A.js';
11
11
  import * as React from 'react';
@@ -14,7 +14,7 @@ function PartyCounter({
14
14
  }) {
15
15
  const atMin = value <= min;
16
16
  const atMax = value >= max;
17
- const roundButton = "grid size-9 shrink-0 cursor-pointer place-items-center rounded-full transition-[filter,background-color,opacity] duration-150 motion-reduce:transition-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card disabled:cursor-not-allowed disabled:opacity-40 [&_svg]:size-4";
17
+ const roundButton = "relative grid size-9 shrink-0 cursor-pointer place-items-center rounded-full transition-[filter,background-color,opacity] duration-150 after:absolute after:-inset-1 after:content-[''] motion-reduce:transition-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card disabled:cursor-not-allowed disabled:opacity-40 [&_svg]:size-4";
18
18
  return /* @__PURE__ */ jsxs(
19
19
  "div",
20
20
  {
@@ -6,7 +6,7 @@ import { showsGradeAtom } from '../chunk-I5V446BX.js';
6
6
  import { Separator } from '../chunk-NWZGSLPU.js';
7
7
  import { springSnappy } from '../chunk-OIV7B44M.js';
8
8
  import { Skeleton } from '../chunk-XBBEX4SF.js';
9
- import { Badge } from '../chunk-IEIJP73R.js';
9
+ import { Badge } from '../chunk-ZU4NAYN7.js';
10
10
  import { cn } from '../chunk-FEK5XGZW.js';
11
11
  import { __objRest, __spreadValues } from '../chunk-MMUBH76A.js';
12
12
  import { forwardRef, memo, useState, useMemo } from 'react';
@@ -3,7 +3,7 @@ import '../chunk-FMTJGO76.js';
3
3
  import '../chunk-MWB7S54O.js';
4
4
  import '../chunk-NWZGSLPU.js';
5
5
  import { Text } from '../chunk-ZLMRVBD7.js';
6
- import { Badge } from '../chunk-IEIJP73R.js';
6
+ import { Badge } from '../chunk-ZU4NAYN7.js';
7
7
  import { cn } from '../chunk-FEK5XGZW.js';
8
8
  import '../chunk-MMUBH76A.js';
9
9
  import { useState } from 'react';
@@ -1,6 +1,6 @@
1
1
  import { Popover, PopoverTrigger, PopoverContent } from '../chunk-2ADCZXZJ.js';
2
- import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem } from '../chunk-MCOHLWRS.js';
3
- import '../chunk-PDTPO6NG.js';
2
+ import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem } from '../chunk-ZJMCU7MI.js';
3
+ import '../chunk-JWTN7MNK.js';
4
4
  import { Button } from '../chunk-5HHRVJOT.js';
5
5
  import '../chunk-RIH2IS7X.js';
6
6
  import '../chunk-5YNIQ2BL.js';
@@ -26,7 +26,7 @@ var SheetOverlay = React.forwardRef((_a, ref) => {
26
26
  });
27
27
  SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
28
28
  var sheetVariants = cva(
29
- "fixed z-[1000] gap-4 bg-background border-border shadow-2xl data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:duration-[var(--duration-deliberate)] data-[state=closed]:duration-[var(--duration-exit-standard)] data-[state=open]:ease-[var(--ease-enter)] data-[state=closed]:ease-[var(--ease-exit)]",
29
+ "fixed z-[1000] gap-4 bg-background border-border shadow-[var(--shadow-overlay)] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:duration-[var(--duration-deliberate)] data-[state=closed]:duration-[var(--duration-exit-standard)] data-[state=open]:ease-[var(--ease-enter)] data-[state=closed]:ease-[var(--ease-exit)]",
30
30
  {
31
31
  variants: {
32
32
  side: {
@@ -1,4 +1,4 @@
1
- export { SignatureChip } from '../chunk-QG6I2ILT.js';
2
- import '../chunk-IEIJP73R.js';
1
+ export { SignatureChip } from '../chunk-GESB7GCF.js';
2
+ import '../chunk-ZU4NAYN7.js';
3
3
  import '../chunk-FEK5XGZW.js';
4
4
  import '../chunk-MMUBH76A.js';
@@ -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" | "destructive" | "inherit" | "primary" | null | undefined;
7
+ tone?: "inherit" | "default" | "destructive" | "primary" | 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" | "destructive" | "inherit" | "primary" | null | undefined;
11
+ tone?: "inherit" | "default" | "destructive" | "primary" | 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" | "destructive" | "warning" | "success" | "primary" | "outline" | "quiet" | null | undefined;
6
+ variant?: "default" | "destructive" | "outline" | "warning" | "success" | "primary" | "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" | "destructive" | "warning" | "success" | "primary" | "outline" | "quiet" | null | undefined;
10
+ variant?: "default" | "destructive" | "outline" | "warning" | "success" | "primary" | "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,9 +22,9 @@ 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?: "small" | "display" | "h1" | "h2" | "h3" | "h4" | "body-lg" | "body" | "body-sm" | "caption" | "label" | "overline" | null | undefined;
26
- color?: "default" | "destructive" | "inherit" | "muted" | "primary" | "primary-foreground" | null | undefined;
27
- weight?: "bold" | "normal" | "medium" | "semibold" | null | undefined;
25
+ variant?: "h2" | "h3" | "label" | "body" | "caption" | "h1" | "h4" | "small" | "display" | "body-lg" | "body-sm" | "overline" | null | undefined;
26
+ color?: "inherit" | "default" | "destructive" | "muted" | "primary" | "primary-foreground" | null | undefined;
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;
30
30
  wrap?: "balance" | "pretty" | "nowrap" | null | undefined;
@@ -15,7 +15,7 @@ var textareaVariants = cva(
15
15
  */
16
16
  appearance: {
17
17
  default: "",
18
- booking: "min-h-[66px] resize-none rounded-[11px] bg-card px-[13px] py-3 text-[14px] leading-[1.4] focus-visible:bg-card aria-invalid:border-[oklch(0.52_0.16_25)] dark:aria-invalid:border-destructive"
18
+ booking: "min-h-[66px] resize-none rounded-[11px] bg-card px-[13px] py-3 text-[14px] leading-[1.4] focus-visible:bg-card aria-invalid:border-destructive-ink"
19
19
  }
20
20
  },
21
21
  defaultVariants: { appearance: "default" }
@@ -26,9 +26,12 @@ function TimeSlot({
26
26
  // Content sits at the top: a slot without a meta line in a row with
27
27
  // one is stretched by the grid, and the time must not drop to the middle.
28
28
  "flex w-full cursor-pointer flex-col items-center justify-start rounded-[11px] border px-1 py-2 text-center leading-[1.2]",
29
- "transition-[border-color,filter] duration-150 motion-reduce:transition-none",
29
+ // A press state, not just hover: this is the most-tapped control in
30
+ // the flow and the primary device has no hover at all, so without it
31
+ // a tap gives nothing back until the fill repaints.
32
+ "transition-[border-color,filter,transform] duration-150 not-disabled:active:scale-[0.98] motion-reduce:transition-none",
30
33
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
31
- selected ? "border-transparent bg-[image:var(--gradient-primary)] text-white hover:brightness-[0.94]" : "border-border bg-card text-foreground hover:border-accent/50",
34
+ selected ? "border-transparent bg-[image:var(--gradient-primary)] text-primary-foreground hover:brightness-[0.94]" : "border-border bg-card text-foreground hover:border-accent/50",
32
35
  unavailable && "cursor-not-allowed opacity-[0.32] hover:border-border"
33
36
  ),
34
37
  children: [
@@ -47,7 +50,7 @@ function TimeSlot({
47
50
  {
48
51
  className: cn(
49
52
  "mt-[3px] block text-[9.5px] leading-[1.2]",
50
- selected ? "text-white/80" : tone === "waitlist" ? "text-muted-foreground" : "text-accent"
53
+ selected ? "text-primary-foreground/80" : tone === "waitlist" ? "text-muted-foreground" : "text-accent"
51
54
  ),
52
55
  children: meta
53
56
  }
@@ -5,7 +5,7 @@ import * as TogglePrimitive from '@radix-ui/react-toggle';
5
5
  import { VariantProps } from 'class-variance-authority';
6
6
 
7
7
  declare const toggleVariants: (props?: ({
8
- variant?: "default" | "tab" | "outline" | "chip" | "segmented" | null | undefined;
8
+ variant?: "tab" | "default" | "outline" | "chip" | "segmented" | null | undefined;
9
9
  size?: "default" | "sm" | "lg" | null | undefined;
10
10
  } & class_variance_authority_types.ClassProp) | undefined) => string;
11
11
  declare function Toggle({ className, variant, size, ...props }: React.ComponentProps<typeof TogglePrimitive.Root> & VariantProps<typeof toggleVariants>): react_jsx_runtime.JSX.Element;
@@ -1,8 +1,8 @@
1
- import { MenuItem } from '../chunk-AHHDC7ML.js';
2
- import '../chunk-QG6I2ILT.js';
1
+ import { MenuItem } from '../chunk-VSRGEB36.js';
2
+ import '../chunk-GESB7GCF.js';
3
3
  import { Separator } from '../chunk-NWZGSLPU.js';
4
4
  import { Skeleton } from '../chunk-XBBEX4SF.js';
5
- import '../chunk-IEIJP73R.js';
5
+ import '../chunk-ZU4NAYN7.js';
6
6
  import { cn } from '../chunk-FEK5XGZW.js';
7
7
  import { __objRest, __spreadValues } from '../chunk-MMUBH76A.js';
8
8
  import { MapPin, Star, MessageSquareQuote } from 'lucide-react';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bearmenu/ui",
3
- "version": "0.8.27",
3
+ "version": "0.8.29",
4
4
  "packageManager": "pnpm@10.28.1",
5
5
  "description": "BearMenu design system — shared UI tokens, primitives, and components",
6
6
  "license": "UNLICENSED",
@@ -34,10 +34,26 @@ const badgeVariants = cva(
34
34
  // `border-0`: the base's transparent hairline would add 2px to each
35
35
  // side the design does not have.
36
36
  confirmed:
37
- "rounded-full border-0 bg-success/15 px-[9px] py-[3px] text-[10.5px] leading-[1.2] font-bold text-[oklch(0.38_0.1_155)] dark:text-success",
37
+ "rounded-full border-0 bg-success/15 px-[9px] py-[3px] text-[10.5px] leading-[1.2] font-bold text-success-ink",
38
38
  pending:
39
39
  "rounded-full border-0 bg-warning/20 px-[9px] py-[3px] text-[10.5px] leading-[1.2] font-bold text-[oklch(0.42_0.1_70)] dark:text-warning",
40
40
  code: "rounded-full border-0 bg-surface-2 px-[9px] py-[3px] font-mono text-[10.5px] leading-[1.2] font-bold tabular-nums text-ink-secondary",
41
+ /**
42
+ * A booking that is over — "Completed", "Missed". The quiet sibling
43
+ * of `confirmed` / `pending`: the same pill, the muted ink, because
44
+ * nothing about it needs acting on.
45
+ */
46
+ completed:
47
+ "rounded-full border-0 bg-muted px-[9px] py-[3px] text-[10.5px] leading-[1.2] font-bold text-muted-foreground",
48
+ },
49
+ /**
50
+ * `status` is the taller pill the booking design draws beside a
51
+ * summary — the same ink and radius, more air. `chip` (the default) is
52
+ * the inline one that sits in a row of text.
53
+ */
54
+ size: {
55
+ chip: "",
56
+ status: "py-[11px]",
41
57
  },
42
58
  // v1.0 motion: "live" surface signal — applies `live-pulse` archetype.
43
59
  // Pair with a colored variant (e.g. variant="destructive" live).
@@ -48,6 +64,7 @@ const badgeVariants = cva(
48
64
  },
49
65
  defaultVariants: {
50
66
  variant: "default",
67
+ size: "chip",
51
68
  live: false,
52
69
  },
53
70
  }
@@ -66,9 +83,13 @@ export interface BadgeProps
66
83
  as?: "div" | "span";
67
84
  }
68
85
 
69
- function Badge({ className, variant, live, as: Tag = "div", ...props }: BadgeProps) {
86
+ function Badge({ className, variant, size, live, as: Tag = "div", ...props }: BadgeProps) {
70
87
  return (
71
- <Tag data-slot="badge" className={cn(badgeVariants({ variant, live }), className)} {...props} />
88
+ <Tag
89
+ data-slot="badge"
90
+ className={cn(badgeVariants({ variant, size, live }), className)}
91
+ {...props}
92
+ />
72
93
  );
73
94
  }
74
95
 
@@ -1,5 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { cva, type VariantProps } from "class-variance-authority";
3
+ import { Info, TriangleAlert } from "lucide-react";
3
4
  import { cn } from "../lib/utils";
4
5
 
5
6
  /**
@@ -37,16 +38,25 @@ const bannerVariants = cva(
37
38
 
38
39
  export type BannerProps = Omit<React.HTMLAttributes<HTMLDivElement>, "title"> &
39
40
  VariantProps<typeof bannerVariants> & {
40
- /** A lucide icon, drawn at 16px beside the text. */
41
+ /**
42
+ * A lucide icon, drawn at 16px beside the text. Omit it for the tone's
43
+ * own glyph; pass `null` for a note with no icon at all.
44
+ */
41
45
  icon?: React.ReactNode;
42
46
  /** The bold first line — "19:30 just went". */
43
47
  title?: React.ReactNode;
44
48
  };
45
49
 
50
+ /** Each tone's own glyph, so a caller never has to remember which. */
51
+ const TONE_ICON = {
52
+ info: <Info aria-hidden />,
53
+ warning: <TriangleAlert aria-hidden />,
54
+ } as const;
55
+
46
56
  function Banner({ tone, icon, title, className, children, ...props }: BannerProps) {
47
57
  return (
48
58
  <div data-slot="banner" className={cn(bannerVariants({ tone }), className)} {...props}>
49
- {icon}
59
+ {icon === undefined ? TONE_ICON[tone ?? "info"] : icon}
50
60
  <div className="min-w-0">
51
61
  {title ? <b className="mb-[3px] block text-[13px] font-bold">{title}</b> : null}
52
62
  <div className={cn(tone === "warning" && title ? "opacity-90" : undefined)}>{children}</div>
@@ -28,7 +28,7 @@ const DialogOverlay = React.forwardRef<
28
28
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
29
29
 
30
30
  const dialogContentVariants = cva(
31
- "fixed left-[50%] top-[50%] z-[1000] grid w-full translate-x-[-50%] translate-y-[-50%] gap-4 bg-card p-6 shadow-2xl data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:duration-[var(--duration-deliberate)] data-[state=closed]:duration-[var(--duration-exit-standard)] data-[state=open]:ease-[var(--ease-enter)] data-[state=closed]:ease-[var(--ease-exit)] data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 rounded-2xl border border-border",
31
+ "fixed left-[50%] top-[50%] z-[1000] grid w-full translate-x-[-50%] translate-y-[-50%] gap-4 bg-card p-6 shadow-[var(--shadow-overlay)] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:duration-[var(--duration-deliberate)] data-[state=closed]:duration-[var(--duration-exit-standard)] data-[state=open]:ease-[var(--ease-enter)] data-[state=closed]:ease-[var(--ease-exit)] data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 rounded-2xl border border-border",
32
32
  {
33
33
  variants: {
34
34
  size: {
@@ -69,7 +69,7 @@ const DrawerContent = React.forwardRef<
69
69
  ref={ref}
70
70
  data-slot="drawer-content"
71
71
  className={cn(
72
- "fixed z-[1000] flex border-border bg-card shadow-2xl",
72
+ "fixed z-[1000] flex border-border bg-card shadow-[var(--shadow-overlay)]",
73
73
  positionClasses,
74
74
  // The single height cap for every vertical drawer. Consumers should
75
75
  // NOT restate it: six app call sites carried an identical
@@ -154,11 +154,10 @@ const FieldError = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<H
154
154
  data-slot="field-error"
155
155
  className={cn(
156
156
  appearance === "booking"
157
- ? // The design's error ink: the solid token is too bright for AA
158
- // at 11.5px on white; dark mode's lifted token already clears it.
159
- // Light: the design's ink. Dark: lifted further than the solid
160
- // token, which lands at ~3.8:1 on the card ground at 11.5px.
161
- "m-0 text-[11.5px] leading-[1.2] text-[oklch(0.52_0.16_25)] dark:text-[oklch(0.75_0.13_25)]"
157
+ ? // `destructive-ink`, not the solid token: red AS TEXT, dark
158
+ // enough for AA on white and lifted enough for the card ground
159
+ // in dark, where the solid one measures ~3.8:1 at 11.5px.
160
+ "m-0 text-[11.5px] leading-[1.2] text-destructive-ink"
162
161
  : "text-sm text-destructive",
163
162
  className
164
163
  )}
@@ -23,7 +23,7 @@ const inputVariants = cva(
23
23
  appearance: {
24
24
  default: "",
25
25
  booking:
26
- "h-[46px] rounded-[11px] bg-card px-[13px] py-0 text-[14px] leading-[1.2] focus-visible:bg-card focus-visible:ring-ring aria-invalid:border-[oklch(0.52_0.16_25)] dark:aria-invalid:border-destructive",
26
+ "h-[46px] rounded-[11px] bg-card px-[13px] py-0 text-[14px] leading-[1.2] focus-visible:bg-card focus-visible:ring-ring aria-invalid:border-destructive-ink",
27
27
  },
28
28
  },
29
29
  defaultVariants: {
@@ -50,8 +50,10 @@ export function PartyCounter({
50
50
  const atMin = value <= min;
51
51
  const atMax = value >= max;
52
52
 
53
+ // 36px circle, 44px target: the counter sits in a 52px row, so the tap
54
+ // band can grow past the drawn button without reaching its neighbour.
53
55
  const roundButton =
54
- "grid size-9 shrink-0 cursor-pointer place-items-center rounded-full transition-[filter,background-color,opacity] duration-150 motion-reduce:transition-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card disabled:cursor-not-allowed disabled:opacity-40 [&_svg]:size-4";
56
+ "relative grid size-9 shrink-0 cursor-pointer place-items-center rounded-full transition-[filter,background-color,opacity] duration-150 after:absolute after:-inset-1 after:content-[''] motion-reduce:transition-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card disabled:cursor-not-allowed disabled:opacity-40 [&_svg]:size-4";
55
57
 
56
58
  return (
57
59
  <div
@@ -46,7 +46,7 @@ SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
46
46
  * separates the two and a border only draws a hard line around the radius.
47
47
  */
48
48
  const sheetVariants = cva(
49
- "fixed z-[1000] gap-4 bg-background border-border shadow-2xl data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:duration-[var(--duration-deliberate)] data-[state=closed]:duration-[var(--duration-exit-standard)] data-[state=open]:ease-[var(--ease-enter)] data-[state=closed]:ease-[var(--ease-exit)]",
49
+ "fixed z-[1000] gap-4 bg-background border-border shadow-[var(--shadow-overlay)] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:duration-[var(--duration-deliberate)] data-[state=closed]:duration-[var(--duration-exit-standard)] data-[state=open]:ease-[var(--ease-enter)] data-[state=closed]:ease-[var(--ease-exit)]",
50
50
  {
51
51
  variants: {
52
52
  side: {
@@ -14,7 +14,7 @@ const textareaVariants = cva(
14
14
  appearance: {
15
15
  default: "",
16
16
  booking:
17
- "min-h-[66px] resize-none rounded-[11px] bg-card px-[13px] py-3 text-[14px] leading-[1.4] focus-visible:bg-card aria-invalid:border-[oklch(0.52_0.16_25)] dark:aria-invalid:border-destructive",
17
+ "min-h-[66px] resize-none rounded-[11px] bg-card px-[13px] py-3 text-[14px] leading-[1.4] focus-visible:bg-card aria-invalid:border-destructive-ink",
18
18
  },
19
19
  },
20
20
  defaultVariants: { appearance: "default" },
@@ -63,10 +63,13 @@ export function TimeSlot({
63
63
  // Content sits at the top: a slot without a meta line in a row with
64
64
  // one is stretched by the grid, and the time must not drop to the middle.
65
65
  "flex w-full cursor-pointer flex-col items-center justify-start rounded-[11px] border px-1 py-2 text-center leading-[1.2]",
66
- "transition-[border-color,filter] duration-150 motion-reduce:transition-none",
66
+ // A press state, not just hover: this is the most-tapped control in
67
+ // the flow and the primary device has no hover at all, so without it
68
+ // a tap gives nothing back until the fill repaints.
69
+ "transition-[border-color,filter,transform] duration-150 not-disabled:active:scale-[0.98] motion-reduce:transition-none",
67
70
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
68
71
  selected
69
- ? "border-transparent bg-[image:var(--gradient-primary)] text-white hover:brightness-[0.94]"
72
+ ? "border-transparent bg-[image:var(--gradient-primary)] text-primary-foreground hover:brightness-[0.94]"
70
73
  : "border-border bg-card text-foreground hover:border-accent/50",
71
74
  unavailable && "cursor-not-allowed opacity-[0.32] hover:border-border"
72
75
  )}
@@ -83,7 +86,11 @@ export function TimeSlot({
83
86
  <span
84
87
  className={cn(
85
88
  "mt-[3px] block text-[9.5px] leading-[1.2]",
86
- selected ? "text-white/80" : tone === "waitlist" ? "text-muted-foreground" : "text-accent"
89
+ selected
90
+ ? "text-primary-foreground/80"
91
+ : tone === "waitlist"
92
+ ? "text-muted-foreground"
93
+ : "text-accent"
87
94
  )}
88
95
  >
89
96
  {meta}
package/src/globals.css CHANGED
@@ -80,8 +80,20 @@ h6 {
80
80
  wells and highlighted rows. Neutral on purpose — its call sites pair it
81
81
  with `text-accent`, and the text is what carries the meaning. */
82
82
  --accent-subtle: oklch(0.945 0 0);
83
- --destructive: oklch(0.577 0.245 27.325);
83
+ /* The house red, not Shadcn's factory one. The default sat at chroma
84
+ 0.245 — louder than anything else in this palette, and the same
85
+ out-shouting that got a 0.22 "ember" rejected for the accent. This is
86
+ --destructive-ink's value, so a destructive fill and a destructive label
87
+ are finally the same red; white on it measures 5.97:1 (was 4.77:1). */
88
+ --destructive: oklch(0.52 0.16 25);
84
89
  --destructive-foreground: oklch(0.985 0 0);
90
+ /**
91
+ * Destructive and success as INK — a red or green label on a card, where
92
+ * the solid tokens above (tuned for fills, and for text on --background)
93
+ * fall short of AA. Light mode darkens, dark mode lifts.
94
+ */
95
+ --destructive-ink: oklch(0.52 0.16 25);
96
+ --success-ink: oklch(0.42 0.13 155);
85
97
  --border: oklch(0.895 0 0);
86
98
  --input: oklch(0.895 0 0);
87
99
  --ring: oklch(0.25 0.05 35);
@@ -149,6 +161,12 @@ h6 {
149
161
  the least attributable place for a colour cast. */
150
162
  --shadow-panel: 0 1px 2px oklch(0.52 0 0 / 0.04), 0 4px 16px -4px oklch(0.52 0 0 / 0.07);
151
163
 
164
+ /* The dim behind a sheet or a dialog. It has to be mode-aware: this value
165
+ over a white page separates plane 2 from plane 0 by 3.6:1, and the same
166
+ value over a near-black one dims nothing at all (the dark block below
167
+ carries the deeper, more opaque sibling). */
168
+ --scrim: oklch(0.16 0.01 55 / 0.5);
169
+
152
170
  /* Brown variant — replaces hardcoded #482E1F across button/badge */
153
171
  --brown: oklch(0.31 0.05 45);
154
172
  --brown-foreground: oklch(0.985 0 0);
@@ -271,6 +289,9 @@ h6 {
271
289
  /* AA-compliant on dark surfaces but dialed back from 0.68 to soften eye strain */
272
290
  --destructive: oklch(0.58 0.17 25.7);
273
291
  --destructive-foreground: oklch(0.985 0 0);
292
+ /** Lifted for text on `--card`, where the solid token measures ~3.8:1. */
293
+ --destructive-ink: oklch(0.72 0.15 25);
294
+ --success-ink: oklch(0.72 0.15 155);
274
295
  --border: oklch(0.32 0.01 45);
275
296
  --input: oklch(0.32 0.01 45);
276
297
  --ring: oklch(0.98 0 0);
@@ -295,6 +316,11 @@ h6 {
295
316
  --shadow-card-hover: 0 4px 16px oklch(0 0 0 / 0.3), 0 1px 4px oklch(0 0 0 / 0.2);
296
317
  --shadow-overlay: 0 8px 32px oklch(0 0 0 / 0.4), 0 2px 8px oklch(0 0 0 / 0.25);
297
318
  --shadow-panel: 0 1px 3px oklch(0 0 0 / 0.24), 0 8px 24px -8px oklch(0 0 0 / 0.34);
319
+ /* Deeper and more opaque than light's: on a 0.155 canvas the light value
320
+ composites to the canvas itself, leaving a sheet with no edge at all —
321
+ in dark, elevation is carried by the scrim and by lightness, not by a
322
+ shadow nobody can see. */
323
+ --scrim: oklch(0.05 0.01 55 / 0.78);
298
324
  --sidebar: oklch(0.205 0 0);
299
325
  --sidebar-foreground: oklch(0.985 0 0);
300
326
  --sidebar-primary: oklch(0.488 0.243 264.376);
@@ -360,6 +386,10 @@ h6 {
360
386
  --color-accent-foreground: var(--accent-foreground);
361
387
  --color-destructive: var(--destructive);
362
388
  --color-destructive-foreground: var(--destructive-foreground);
389
+ --color-destructive-ink: var(--destructive-ink);
390
+ --color-success-ink: var(--success-ink);
391
+ /* `bg-scrim` — the dim behind a sheet or a dialog. */
392
+ --color-scrim: var(--scrim);
363
393
  --color-border: var(--border);
364
394
  --color-input: var(--input);
365
395
  --color-ring: var(--ring);