@bearmenu/ui 0.6.1 → 0.7.0

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 (69) hide show
  1. package/dist/chunk-A5ONAJCE.js +102 -0
  2. package/dist/chunk-AV777R4G.js +43 -0
  3. package/dist/{chunk-WKMLZDUT.js → chunk-FRPPIXMY.js} +1 -1
  4. package/dist/{chunk-PSR7N36A.js → chunk-HCM6LKM5.js} +1 -1
  5. package/dist/{chunk-YJ6OBKZJ.js → chunk-TL4YU2O5.js} +10 -3
  6. package/dist/chunk-UX6SWAKH.js +320 -0
  7. package/dist/{chunk-7PPCH42H.js → chunk-VQNDZVI7.js} +1 -1
  8. package/dist/chunk-WSRWFA6K.js +26 -0
  9. package/dist/chunk-YLNYXPIH.js +61 -0
  10. package/dist/components/accordion.js +1 -1
  11. package/dist/components/badge.d.ts +2 -1
  12. package/dist/components/badge.js +1 -1
  13. package/dist/components/card.js +127 -4
  14. package/dist/components/combobox.js +2 -2
  15. package/dist/components/command.js +2 -2
  16. package/dist/components/currency-input.js +1 -1
  17. package/dist/components/date-input.js +1 -1
  18. package/dist/components/dialog.js +1 -1
  19. package/dist/components/filter-category-row.d.ts +13 -0
  20. package/dist/components/filter-category-row.js +44 -0
  21. package/dist/components/input-group.d.ts +2 -0
  22. package/dist/components/input-group.js +10 -5
  23. package/dist/components/input.d.ts +1 -0
  24. package/dist/components/input.js +1 -1
  25. package/dist/components/multi-select-combobox.js +3 -3
  26. package/dist/components/phone-frame.js +1 -1
  27. package/dist/components/place-about-tab.d.ts +2 -2
  28. package/dist/components/place-about-tab.js +4 -3
  29. package/dist/components/place-details-mobile.js +5 -3
  30. package/dist/components/place-schedule-week.d.ts +19 -0
  31. package/dist/components/place-schedule-week.js +4 -0
  32. package/dist/components/place-types.d.ts +18 -9
  33. package/dist/components/scroll-fade.js +7 -2
  34. package/dist/components/searchable-select.js +2 -2
  35. package/dist/components/separator.js +3 -26
  36. package/dist/components/sheet.js +1 -1
  37. package/dist/components/sliding-panels.d.ts +1 -0
  38. package/dist/components/sliding-panels.js +22 -6
  39. package/dist/components/sort-option-list.d.ts +16 -0
  40. package/dist/components/sort-option-list.js +46 -0
  41. package/dist/components/tabs.js +98 -17
  42. package/dist/components/tag.js +3 -61
  43. package/dist/components/toast.js +1 -1
  44. package/dist/components/toaster.js +1 -1
  45. package/package.json +23 -113
  46. package/src/components/accordion.tsx +1 -1
  47. package/src/components/badge.tsx +9 -2
  48. package/src/components/card.tsx +22 -18
  49. package/src/components/dialog.tsx +1 -1
  50. package/src/components/filter-category-row.tsx +52 -0
  51. package/src/components/input-group.tsx +9 -4
  52. package/src/components/input.tsx +8 -3
  53. package/src/components/phone-frame.tsx +1 -1
  54. package/src/components/place-about-tab.stories.tsx +24 -13
  55. package/src/components/place-about-tab.test.tsx +92 -38
  56. package/src/components/place-about-tab.tsx +310 -344
  57. package/src/components/place-schedule-week.tsx +128 -0
  58. package/src/components/place-types.ts +27 -8
  59. package/src/components/scroll-fade.tsx +9 -4
  60. package/src/components/sheet.tsx +1 -1
  61. package/src/components/sliding-panels.tsx +33 -6
  62. package/src/components/sort-option-list.tsx +57 -0
  63. package/src/components/tabs.tsx +76 -11
  64. package/src/components/toast.tsx +1 -1
  65. package/src/globals.css +77 -19
  66. package/src/lib/motion.ts +137 -0
  67. package/dist/chunk-BAZFVSSG.js +0 -279
  68. package/dist/chunk-RIDXFY6M.js +0 -38
  69. package/dist/chunk-XK2ZDQVE.js +0 -122
@@ -0,0 +1,46 @@
1
+ import { cn } from '../chunk-FEK5XGZW.js';
2
+ import '../chunk-3GWWZKX7.js';
3
+ import { Check } from 'lucide-react';
4
+ import { jsx, jsxs } from 'react/jsx-runtime';
5
+
6
+ function SortOptionList({
7
+ options,
8
+ value,
9
+ onChange,
10
+ ariaLabel,
11
+ className
12
+ }) {
13
+ return /* @__PURE__ */ jsx(
14
+ "div",
15
+ {
16
+ role: "radiogroup",
17
+ "aria-label": ariaLabel,
18
+ className: cn("px-2 pb-6", className),
19
+ children: options.map((option) => {
20
+ const isActive = option.value === value;
21
+ return /* @__PURE__ */ jsxs(
22
+ "button",
23
+ {
24
+ type: "button",
25
+ role: "radio",
26
+ "aria-checked": isActive,
27
+ onClick: () => onChange(option.value),
28
+ className: cn(
29
+ "flex w-full items-center justify-between rounded-lg px-3 py-3 text-left text-sm cursor-pointer",
30
+ "transition-colors duration-150 motion-reduce:transition-none",
31
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30",
32
+ isActive ? "bg-accent/10 text-accent font-semibold" : "text-foreground hover:bg-muted/50"
33
+ ),
34
+ children: [
35
+ /* @__PURE__ */ jsx("span", { children: option.label }),
36
+ isActive && /* @__PURE__ */ jsx(Check, { className: "h-4 w-4", "aria-hidden": true })
37
+ ]
38
+ },
39
+ option.value
40
+ );
41
+ })
42
+ }
43
+ );
44
+ }
45
+
46
+ export { SortOptionList };
@@ -1,12 +1,38 @@
1
1
  import { cn } from '../chunk-FEK5XGZW.js';
2
- import { __objRest, __spreadValues, __spreadProps } from '../chunk-3GWWZKX7.js';
2
+ import { __spreadValues, __objRest, __spreadProps } from '../chunk-3GWWZKX7.js';
3
3
  import * as React from 'react';
4
4
  import * as TabsPrimitive from '@radix-ui/react-tabs';
5
- import { jsx } from 'react/jsx-runtime';
5
+ import { motion } from 'framer-motion';
6
+ import { jsx, jsxs } from 'react/jsx-runtime';
6
7
 
8
+ var springSnappy = {
9
+ type: "spring",
10
+ damping: 30,
11
+ stiffness: 380
12
+ };
13
+ var springSmooth = {
14
+ type: "spring",
15
+ damping: 30,
16
+ stiffness: 220
17
+ };
18
+ var springSoft = {
19
+ type: "spring",
20
+ damping: 35,
21
+ stiffness: 140
22
+ };
23
+ var archetype = {
24
+ /** Drawer / Sheet / Dialog entrance. Surface arrives first; content layers after. */
25
+ surfaceOpen: __spreadValues({}, springSmooth),
26
+ /** First-reveal stagger for card grids. Per-item spring. Cap stagger at 8 items. */
27
+ listReveal: __spreadValues({}, springSoft),
28
+ /** Bottom-sheet / side-drawer entry. */
29
+ edgeEnter: __spreadValues({}, springSmooth),
30
+ /** Active tab pill, active filter chip — use with Framer Motion `layoutId`. */
31
+ indicatorMorph: __spreadValues({}, springSnappy)};
7
32
  var TabsContext = React.createContext({
8
33
  variant: "pill",
9
- orientation: "horizontal"
34
+ orientation: "horizontal",
35
+ indicatorId: "tabs-indicator"
10
36
  });
11
37
  var Tabs = React.forwardRef((_a, ref) => {
12
38
  var _b = _a, { className, orientation = "horizontal" } = _b, props = __objRest(_b, ["className", "orientation"]);
@@ -29,7 +55,8 @@ var TabsList = React.forwardRef((_a, ref) => {
29
55
  var _b = _a, { className, variant = "pill", scrollable, children } = _b, props = __objRest(_b, ["className", "variant", "scrollable", "children"]);
30
56
  const orientation = props["aria-orientation"] === "vertical" ? "vertical" : "horizontal";
31
57
  const allowScroll = scrollable != null ? scrollable : orientation === "horizontal";
32
- return /* @__PURE__ */ jsx(TabsContext.Provider, { value: { variant, orientation }, children: /* @__PURE__ */ jsx(
58
+ const indicatorId = React.useId();
59
+ return /* @__PURE__ */ jsx(TabsContext.Provider, { value: { variant, orientation, indicatorId }, children: /* @__PURE__ */ jsx(
33
60
  TabsPrimitive.List,
34
61
  __spreadProps(__spreadValues({
35
62
  ref,
@@ -46,36 +73,90 @@ var TabsList = React.forwardRef((_a, ref) => {
46
73
  });
47
74
  TabsList.displayName = TabsPrimitive.List.displayName;
48
75
  var TabsTrigger = React.forwardRef((_a, ref) => {
49
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
50
- const { variant, orientation } = React.useContext(TabsContext);
51
- return /* @__PURE__ */ jsx(
76
+ var _b = _a, { className, children } = _b, props = __objRest(_b, ["className", "children"]);
77
+ const { variant, orientation, indicatorId } = React.useContext(TabsContext);
78
+ const triggerRef = React.useRef(null);
79
+ const [isActive, setIsActive] = React.useState(false);
80
+ React.useEffect(() => {
81
+ const node = triggerRef.current;
82
+ if (!node) return;
83
+ const sync = () => setIsActive(node.getAttribute("data-state") === "active");
84
+ sync();
85
+ const observer = new MutationObserver(sync);
86
+ observer.observe(node, { attributes: true, attributeFilter: ["data-state"] });
87
+ return () => observer.disconnect();
88
+ }, []);
89
+ const composedRef = React.useCallback(
90
+ (node) => {
91
+ triggerRef.current = node;
92
+ if (typeof ref === "function") ref(node);
93
+ else if (ref) ref.current = node;
94
+ },
95
+ [ref]
96
+ );
97
+ return /* @__PURE__ */ jsxs(
52
98
  TabsPrimitive.Trigger,
53
- __spreadValues({
54
- ref,
99
+ __spreadProps(__spreadValues({
100
+ ref: composedRef,
55
101
  "data-slot": "tabs-trigger",
56
102
  className: cn(
57
- "inline-flex items-center justify-center whitespace-nowrap text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
58
- variant === "pill" && "rounded-xl px-4 py-1.5 text-muted-foreground hover:text-foreground data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
59
- variant === "underline" && orientation === "horizontal" && "relative h-11 rounded-none border-b-2 border-transparent px-4 text-muted-foreground hover:text-foreground data-[state=active]:border-primary data-[state=active]:text-foreground",
60
- variant === "underline" && orientation === "vertical" && "relative rounded-none border-r-2 border-transparent px-4 py-2 -mr-px text-muted-foreground hover:text-foreground data-[state=active]:border-primary data-[state=active]:text-foreground justify-start",
103
+ "relative inline-flex items-center justify-center whitespace-nowrap text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
104
+ variant === "pill" && "rounded-xl px-4 py-1.5 text-muted-foreground hover:text-foreground data-[state=active]:text-foreground",
105
+ variant === "underline" && orientation === "horizontal" && "h-11 rounded-none px-4 text-muted-foreground hover:text-foreground data-[state=active]:text-foreground",
106
+ variant === "underline" && orientation === "vertical" && "rounded-none px-4 py-2 -mr-px text-muted-foreground hover:text-foreground data-[state=active]:text-foreground justify-start",
61
107
  className
62
108
  )
63
- }, props)
109
+ }, props), {
110
+ children: [
111
+ isActive && /* @__PURE__ */ jsx(
112
+ motion.span,
113
+ {
114
+ "aria-hidden": true,
115
+ layoutId: indicatorId,
116
+ transition: archetype.indicatorMorph,
117
+ className: cn(
118
+ "absolute inset-0 -z-0 motion-reduce:hidden",
119
+ variant === "pill" && "rounded-xl bg-background shadow-sm",
120
+ variant === "underline" && orientation === "horizontal" && "border-b-2 border-primary",
121
+ variant === "underline" && orientation === "vertical" && "border-r-2 border-primary"
122
+ )
123
+ }
124
+ ),
125
+ isActive && /* @__PURE__ */ jsx(
126
+ "span",
127
+ {
128
+ "aria-hidden": true,
129
+ className: cn(
130
+ "absolute inset-0 -z-0 hidden motion-reduce:block",
131
+ variant === "pill" && "rounded-xl bg-background shadow-sm",
132
+ variant === "underline" && orientation === "horizontal" && "border-b-2 border-primary",
133
+ variant === "underline" && orientation === "vertical" && "border-r-2 border-primary"
134
+ )
135
+ }
136
+ ),
137
+ /* @__PURE__ */ jsx("span", { className: "relative z-10 flex items-center gap-2", children })
138
+ ]
139
+ })
64
140
  );
65
141
  });
66
142
  TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
67
143
  var TabsContent = React.forwardRef((_a, ref) => {
68
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
144
+ var _b = _a, { className, children } = _b, props = __objRest(_b, ["className", "children"]);
69
145
  return /* @__PURE__ */ jsx(
70
146
  TabsPrimitive.Content,
71
- __spreadValues({
147
+ __spreadProps(__spreadValues({
72
148
  ref,
73
149
  "data-slot": "tabs-content",
74
150
  className: cn(
75
151
  "flex-1 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-md",
152
+ // v1.0 motion: content-swap on activation. CSS animation so this works
153
+ // even outside a Framer-Motion-wrapped layout. Disabled for reduced-motion.
154
+ "data-[state=active]:animate-in data-[state=active]:fade-in-0 data-[state=active]:slide-in-from-bottom-1 data-[state=active]:duration-[var(--duration-quick)] data-[state=active]:ease-[var(--ease-standard)] motion-reduce:data-[state=active]:animate-none",
76
155
  className
77
156
  )
78
- }, props)
157
+ }, props), {
158
+ children
159
+ })
79
160
  );
80
161
  });
81
162
  TabsContent.displayName = TabsPrimitive.Content.displayName;
@@ -1,61 +1,3 @@
1
- import { cn } from '../chunk-FEK5XGZW.js';
2
- import { __objRest, __spreadProps, __spreadValues } from '../chunk-3GWWZKX7.js';
3
- import * as React from 'react';
4
- import { X } from 'lucide-react';
5
- import { cva } from 'class-variance-authority';
6
- import { jsxs, jsx } from 'react/jsx-runtime';
7
-
8
- var tagVariants = cva(
9
- "inline-flex items-center gap-1 rounded-full border text-xs font-medium transition-colors",
10
- {
11
- variants: {
12
- variant: {
13
- default: "border-border bg-muted text-foreground",
14
- primary: "border-primary/30 bg-primary/10 text-primary",
15
- success: "border-success/30 bg-success/10 text-success",
16
- warning: "border-warning/30 bg-warning/10 text-warning",
17
- destructive: "border-destructive/30 bg-destructive/10 text-destructive",
18
- outline: "border-border bg-transparent text-foreground"
19
- },
20
- size: {
21
- sm: "h-5 px-2 text-[10px]",
22
- default: "h-6 px-2.5",
23
- lg: "h-7 px-3 text-sm"
24
- }
25
- },
26
- defaultVariants: {
27
- variant: "default",
28
- size: "default"
29
- }
30
- }
31
- );
32
- var Tag = React.forwardRef(
33
- (_a, ref) => {
34
- var _b = _a, { className, variant, size, onRemove, removeLabel = "Remove", children } = _b, props = __objRest(_b, ["className", "variant", "size", "onRemove", "removeLabel", "children"]);
35
- return /* @__PURE__ */ jsxs(
36
- "span",
37
- __spreadProps(__spreadValues({
38
- ref,
39
- "data-slot": "tag",
40
- className: cn(tagVariants({ variant, size }), className)
41
- }, props), {
42
- children: [
43
- children,
44
- onRemove && /* @__PURE__ */ jsx(
45
- "button",
46
- {
47
- type: "button",
48
- "aria-label": removeLabel,
49
- onClick: onRemove,
50
- className: "-mr-0.5 inline-flex size-3.5 items-center justify-center rounded-full transition-colors hover:bg-foreground/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
51
- children: /* @__PURE__ */ jsx(X, { className: "size-3" })
52
- }
53
- )
54
- ]
55
- })
56
- );
57
- }
58
- );
59
- Tag.displayName = "Tag";
60
-
61
- export { Tag, tagVariants };
1
+ export { Tag, tagVariants } from '../chunk-YLNYXPIH.js';
2
+ import '../chunk-FEK5XGZW.js';
3
+ import '../chunk-3GWWZKX7.js';
@@ -1,3 +1,3 @@
1
- export { Toast, ToastAction, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport } from '../chunk-7PPCH42H.js';
1
+ export { Toast, ToastAction, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport } from '../chunk-VQNDZVI7.js';
2
2
  import '../chunk-FEK5XGZW.js';
3
3
  import '../chunk-3GWWZKX7.js';
@@ -1,5 +1,5 @@
1
- import { ToastProvider, Toast, ToastTitle, ToastDescription, ToastClose, ToastViewport } from '../chunk-7PPCH42H.js';
2
1
  import { useToast } from '../chunk-EBAMCZDW.js';
2
+ import { ToastProvider, Toast, ToastTitle, ToastDescription, ToastClose, ToastViewport } from '../chunk-VQNDZVI7.js';
3
3
  import '../chunk-FEK5XGZW.js';
4
4
  import { __objRest, __spreadProps, __spreadValues } from '../chunk-3GWWZKX7.js';
5
5
  import { jsxs, jsx } from 'react/jsx-runtime';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bearmenu/ui",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "BearMenu design system — shared UI tokens, primitives, and components",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -17,119 +17,19 @@
17
17
  ],
18
18
  "exports": {
19
19
  "./globals.css": "./src/globals.css",
20
- "./components/accordion": "./src/components/accordion.tsx",
21
- "./components/alert-dialog": "./src/components/alert-dialog.tsx",
22
- "./components/alert": "./src/components/alert.tsx",
23
- "./components/aspect-ratio": "./src/components/aspect-ratio.tsx",
24
- "./components/avatar": "./src/components/avatar.tsx",
25
- "./components/badge": "./src/components/badge.tsx",
26
- "./components/breadcrumb": "./src/components/breadcrumb.tsx",
27
- "./components/button-group": "./src/components/button-group.tsx",
28
- "./components/button": "./src/components/button.tsx",
29
- "./components/calendar": "./src/components/calendar.tsx",
30
- "./components/card": "./src/components/card.tsx",
31
- "./components/carousel": "./src/components/carousel.tsx",
32
- "./components/checkbox": "./src/components/checkbox.tsx",
33
- "./components/circular-progress": "./src/components/circular-progress.tsx",
34
- "./components/collapsible": "./src/components/collapsible.tsx",
35
- "./components/combobox": "./src/components/combobox.tsx",
36
- "./components/command": "./src/components/command.tsx",
37
- "./components/currency-input": "./src/components/currency-input.tsx",
38
- "./components/date-input": "./src/components/date-input.tsx",
39
- "./components/description-list": "./src/components/description-list.tsx",
40
- "./components/dialog": "./src/components/dialog.tsx",
41
- "./components/drawer": "./src/components/drawer.tsx",
42
- "./components/dropdown-menu": "./src/components/dropdown-menu.tsx",
43
- "./components/empty-state": "./src/components/empty-state.tsx",
44
- "./components/field": "./src/components/field.tsx",
45
- "./components/form": "./src/components/form.tsx",
46
- "./components/haptic-button": "./src/components/haptic-button.tsx",
47
- "./components/input-group": "./src/components/input-group.tsx",
48
- "./components/input-otp": "./src/components/input-otp.tsx",
49
- "./components/input": "./src/components/input.tsx",
50
- "./components/item": "./src/components/item.tsx",
51
- "./components/kbd": "./src/components/kbd.tsx",
52
- "./components/label": "./src/components/label.tsx",
53
- "./components/lazy-markdown": "./src/components/lazy-markdown.tsx",
54
- "./components/link-button": "./src/components/link-button.tsx",
55
- "./components/markdown-renderer": "./src/components/markdown-renderer.tsx",
56
- "./components/multi-select-combobox": "./src/components/multi-select-combobox.tsx",
57
- "./components/multi-select-menu": "./src/components/multi-select-menu.tsx",
58
- "./components/native-select": "./src/components/native-select.tsx",
59
- "./components/pagination": "./src/components/pagination.tsx",
60
- "./components/phone-frame": "./src/components/phone-frame.tsx",
61
- "./components/place-about-tab": "./src/components/place-about-tab.tsx",
62
- "./components/place-card": "./src/components/place-card.tsx",
63
- "./components/place-details-mobile": "./src/components/place-details-mobile.tsx",
64
- "./components/place-types": "./src/components/place-types.ts",
65
- "./components/popover": "./src/components/popover.tsx",
66
- "./components/progress": "./src/components/progress.tsx",
67
- "./components/radio-group": "./src/components/radio-group.tsx",
68
- "./components/rating": "./src/components/rating.tsx",
69
- "./components/scroll-area": "./src/components/scroll-area.tsx",
70
- "./components/scroll-fade": "./src/components/scroll-fade.tsx",
71
- "./components/search-bar": "./src/components/search-bar.tsx",
72
- "./components/searchable-select": "./src/components/searchable-select.tsx",
73
- "./components/select": "./src/components/select.tsx",
74
- "./components/selection-bar": "./src/components/selection-bar.tsx",
75
- "./components/separator": "./src/components/separator.tsx",
76
- "./components/sheet": "./src/components/sheet.tsx",
77
- "./components/skeleton-card": "./src/components/skeleton-card.tsx",
78
- "./components/skeleton": "./src/components/skeleton.tsx",
79
- "./components/slider": "./src/components/slider.tsx",
80
- "./components/sliding-panels": "./src/components/sliding-panels.tsx",
81
- "./components/sonner": "./src/components/sonner.tsx",
82
- "./components/spinner": "./src/components/spinner.tsx",
83
- "./components/stepper": "./src/components/stepper.tsx",
84
- "./components/sticky-container": "./src/components/sticky-container.tsx",
85
- "./components/switch": "./src/components/switch.tsx",
86
- "./components/table": "./src/components/table.tsx",
87
- "./components/tabs": "./src/components/tabs.tsx",
88
- "./components/tag-group": "./src/components/tag-group.tsx",
89
- "./components/tag": "./src/components/tag.tsx",
90
- "./components/text": "./src/components/text.tsx",
91
- "./components/textarea": "./src/components/textarea.tsx",
92
- "./components/toast": "./src/components/toast.tsx",
93
- "./components/toaster": "./src/components/toaster.tsx",
94
- "./components/toggle-group": "./src/components/toggle-group.tsx",
95
- "./components/toggle": "./src/components/toggle.tsx",
96
- "./components/tooltip": "./src/components/tooltip.tsx",
97
- "./components/use-mobile": "./src/components/use-mobile.tsx",
98
- "./components/use-toast": "./src/components/use-toast.ts",
99
- "./hooks/use-haptic": "./src/hooks/use-haptic.ts",
100
- "./hooks/use-mobile": "./src/hooks/use-mobile.ts",
101
- "./hooks/use-mounted-theme": "./src/hooks/use-mounted-theme.ts",
102
- "./hooks/use-sticky": "./src/hooks/use-sticky.ts",
103
- "./lib/utils": "./src/lib/utils.ts"
104
- },
105
- "publishConfig": {
106
- "exports": {
107
- "./globals.css": "./src/globals.css",
108
- "./components/*": {
109
- "types": "./dist/components/*.d.ts",
110
- "import": "./dist/components/*.js"
111
- },
112
- "./hooks/*": {
113
- "types": "./dist/hooks/*.d.ts",
114
- "import": "./dist/hooks/*.js"
115
- },
116
- "./lib/*": {
117
- "types": "./dist/lib/*.d.ts",
118
- "import": "./dist/lib/*.js"
119
- }
20
+ "./components/*": {
21
+ "types": "./dist/components/*.d.ts",
22
+ "import": "./dist/components/*.js"
23
+ },
24
+ "./hooks/*": {
25
+ "types": "./dist/hooks/*.d.ts",
26
+ "import": "./dist/hooks/*.js"
27
+ },
28
+ "./lib/*": {
29
+ "types": "./dist/lib/*.d.ts",
30
+ "import": "./dist/lib/*.js"
120
31
  }
121
32
  },
122
- "scripts": {
123
- "storybook": "storybook dev -p 6006",
124
- "build-storybook": "storybook build",
125
- "build": "tsup",
126
- "dev": "tsup --watch",
127
- "typecheck": "tsc --noEmit",
128
- "test": "vitest run",
129
- "test:watch": "vitest",
130
- "clean": "rm -rf dist",
131
- "prepublishOnly": "pnpm run build"
132
- },
133
33
  "peerDependencies": {
134
34
  "@hookform/resolvers": "^3.0.0 || ^5.0.0",
135
35
  "@radix-ui/react-accordion": "*",
@@ -237,5 +137,15 @@
237
137
  "vaul": "^1.1.2",
238
138
  "vitest": "^4.1.5",
239
139
  "zod": "^3.25.67"
140
+ },
141
+ "scripts": {
142
+ "storybook": "storybook dev -p 6006",
143
+ "build-storybook": "storybook build",
144
+ "build": "tsup",
145
+ "dev": "tsup --watch",
146
+ "typecheck": "tsc --noEmit",
147
+ "test": "vitest run",
148
+ "test:watch": "vitest",
149
+ "clean": "rm -rf dist"
240
150
  }
241
- }
151
+ }
@@ -38,7 +38,7 @@ const AccordionTrigger = React.forwardRef<
38
38
  {...props}
39
39
  >
40
40
  {children}
41
- <ChevronDown className="size-4 shrink-0 text-muted-foreground transition-transform duration-200" />
41
+ <ChevronDown className="size-4 shrink-0 text-muted-foreground transition-transform duration-[var(--duration-quick)] ease-[var(--ease-standard)]" />
42
42
  </AccordionPrimitive.Trigger>
43
43
  </AccordionPrimitive.Header>
44
44
  ));
@@ -22,9 +22,16 @@ const badgeVariants = cva(
22
22
  "border-transparent bg-warning text-warning-foreground",
23
23
  brown: "border-transparent bg-brown text-brown-foreground",
24
24
  },
25
+ // v1.0 motion: "live" surface signal — applies `live-pulse` archetype.
26
+ // Pair with a colored variant (e.g. variant="destructive" live).
27
+ live: {
28
+ true: "motion-live-pulse motion-reduce:animate-none",
29
+ false: "",
30
+ },
25
31
  },
26
32
  defaultVariants: {
27
33
  variant: "default",
34
+ live: false,
28
35
  },
29
36
  }
30
37
  );
@@ -32,8 +39,8 @@ const badgeVariants = cva(
32
39
  export interface BadgeProps
33
40
  extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {}
34
41
 
35
- function Badge({ className, variant, ...props }: BadgeProps) {
36
- return <div data-slot="badge" className={cn(badgeVariants({ variant }), className)} {...props} />;
42
+ function Badge({ className, variant, live, ...props }: BadgeProps) {
43
+ return <div data-slot="badge" className={cn(badgeVariants({ variant, live }), className)} {...props} />;
37
44
  }
38
45
 
39
46
  export { Badge, badgeVariants };
@@ -3,25 +3,29 @@ import { cva, type VariantProps } from "class-variance-authority";
3
3
  import { cn } from "../lib/utils";
4
4
  import { textVariants } from "./text";
5
5
 
6
- const cardVariants = cva("rounded-3xl text-card-foreground transition-colors", {
7
- variants: {
8
- variant: {
9
- surface: "bg-card border border-border",
10
- glass: "glass",
11
- outline: "bg-transparent border border-border",
12
- muted: "bg-muted border border-transparent",
6
+ const cardVariants = cva(
7
+ "rounded-3xl text-card-foreground transition-[background-color,border-color] duration-[var(--duration-quick)] ease-[var(--ease-standard)]",
8
+ {
9
+ variants: {
10
+ variant: {
11
+ surface: "bg-card border border-border",
12
+ glass: "glass",
13
+ outline: "bg-transparent border border-border",
14
+ muted: "bg-muted border border-transparent",
15
+ },
16
+ size: {
17
+ 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",
18
+ default:
19
+ "[&_[data-slot=card-header]]:p-6 [&_[data-slot=card-content]]:p-6 [&_[data-slot=card-content]]:pt-0 [&_[data-slot=card-footer]]:p-6 [&_[data-slot=card-footer]]:pt-0",
20
+ lg: "[&_[data-slot=card-header]]:p-8 [&_[data-slot=card-content]]:p-8 [&_[data-slot=card-content]]:pt-0 [&_[data-slot=card-footer]]:p-8 [&_[data-slot=card-footer]]:pt-0",
21
+ },
22
+ // Interactive variant follows v1.0 `press-response` archetype:
23
+ // hover lift via shadow + translate (200ms), press scale-down (instant).
24
+ interactive: {
25
+ true: "cursor-pointer transition-[transform,border-color,box-shadow] duration-[var(--duration-quick)] ease-[var(--ease-standard)] hover:border-primary/40 hover:-translate-y-0.5 hover:shadow-md active:scale-[0.97] active:duration-[var(--duration-instant)] motion-reduce:hover:translate-y-0 motion-reduce:active:scale-100",
26
+ false: "",
27
+ },
13
28
  },
14
- size: {
15
- 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",
16
- default:
17
- "[&_[data-slot=card-header]]:p-6 [&_[data-slot=card-content]]:p-6 [&_[data-slot=card-content]]:pt-0 [&_[data-slot=card-footer]]:p-6 [&_[data-slot=card-footer]]:pt-0",
18
- lg: "[&_[data-slot=card-header]]:p-8 [&_[data-slot=card-content]]:p-8 [&_[data-slot=card-content]]:pt-0 [&_[data-slot=card-footer]]:p-8 [&_[data-slot=card-footer]]:pt-0",
19
- },
20
- interactive: {
21
- true: "cursor-pointer hover:border-primary/40 hover:-translate-y-0.5 transition-[transform,border-color] duration-200",
22
- false: "",
23
- },
24
- },
25
29
  defaultVariants: {
26
30
  variant: "surface",
27
31
  size: "default",
@@ -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 duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 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-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",
32
32
  {
33
33
  variants: {
34
34
  size: {
@@ -0,0 +1,52 @@
1
+ "use client";
2
+
3
+ import { ChevronRight, type LucideIcon } from "lucide-react";
4
+ import { Badge } from "./badge";
5
+ import { Text } from "./text";
6
+
7
+ interface FilterCategoryRowProps {
8
+ icon: LucideIcon;
9
+ label: string;
10
+ description: string;
11
+ count?: number;
12
+ onClick: () => void;
13
+ }
14
+
15
+ export function FilterCategoryRow({
16
+ icon: Icon,
17
+ label,
18
+ description,
19
+ count = 0,
20
+ onClick,
21
+ }: FilterCategoryRowProps) {
22
+ return (
23
+ <button
24
+ type="button"
25
+ onClick={onClick}
26
+ className="flex items-center justify-between w-full py-3 transition-colors hover:bg-muted/50 rounded-lg px-2 -mx-2"
27
+ >
28
+ <div className="flex items-center gap-3">
29
+ <Icon
30
+ aria-hidden="true"
31
+ className="w-5 h-5 text-muted-foreground flex-shrink-0"
32
+ />
33
+ <div className="text-left">
34
+ <Text as="p" weight="medium">
35
+ {label}
36
+ </Text>
37
+ <Text as="p" variant="body-sm" color="muted">
38
+ {description}
39
+ </Text>
40
+ </div>
41
+ </div>
42
+ <div className="flex items-center gap-2">
43
+ {count > 0 && (
44
+ <Badge variant="secondary" className="text-xs">
45
+ {count}
46
+ </Badge>
47
+ )}
48
+ <ChevronRight className="w-5 h-5 text-muted-foreground" />
49
+ </div>
50
+ </button>
51
+ );
52
+ }
@@ -6,7 +6,7 @@ import { cva, type VariantProps } from "class-variance-authority";
6
6
  import { cn } from "../lib/utils";
7
7
 
8
8
  const inputGroupVariants = cva(
9
- "flex items-center w-full rounded-xl border border-border bg-background text-base md:text-sm text-foreground transition-colors focus-within:outline-none focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 has-[input:disabled]:cursor-not-allowed has-[input:disabled]:opacity-50 aria-invalid:border-destructive aria-invalid:focus-within:ring-destructive/40",
9
+ "flex items-center w-full border border-border bg-background text-base md:text-sm text-foreground transition-colors focus-within:outline-none focus-within:ring-2 focus-within:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 has-[input:disabled]:cursor-not-allowed has-[input:disabled]:opacity-50 aria-invalid:border-destructive aria-invalid:focus-within:ring-destructive/40",
10
10
  {
11
11
  variants: {
12
12
  size: {
@@ -14,9 +14,14 @@ const inputGroupVariants = cva(
14
14
  default: "h-11",
15
15
  lg: "h-12",
16
16
  },
17
+ shape: {
18
+ rounded: "rounded-xl focus-within:ring-ring",
19
+ pill: "rounded-full shadow-[var(--shadow-card)] focus-within:ring-accent/30",
20
+ },
17
21
  },
18
22
  defaultVariants: {
19
23
  size: "default",
24
+ shape: "rounded",
20
25
  },
21
26
  }
22
27
  );
@@ -27,12 +32,12 @@ const InputGroupContext = React.createContext<InputGroupContextValue>({});
27
32
  const InputGroup = React.forwardRef<
28
33
  HTMLDivElement,
29
34
  React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof inputGroupVariants>
30
- >(({ className, size, children, ...props }, ref) => (
31
- <InputGroupContext.Provider value={{ size }}>
35
+ >(({ className, size, shape, children, ...props }, ref) => (
36
+ <InputGroupContext.Provider value={{ size, shape }}>
32
37
  <div
33
38
  ref={ref}
34
39
  data-slot="input-group"
35
- className={cn(inputGroupVariants({ size }), className)}
40
+ className={cn(inputGroupVariants({ size, shape }), className)}
36
41
  {...props}
37
42
  >
38
43
  {children}